MT#58736 Improve Cloud PBX Device configuration adding some preferences

- Changing list view to 8 rows with 3 columns.
- Preferences/Edit are now open in a separate page.
- Adding the new 4 preferences ( - Admin Name/ Disable web GUI/ User config priority over-provisioning/FW upgrade disable) together with the existing parameters.

Change-Id: Iae92c3313c592f7662587f52d0d4c9293ba41a97
mr13.0
Nouhaila Idrissi Zouggari 11 months ago committed by Nouhaila Idrissi-Zouggari
parent 35a4b263ea
commit f11e89813e

@ -7,9 +7,11 @@ import {
import _ from 'lodash'
import {
getList,
httpApi,
patchAdd,
patchRemove,
patchReplace,
patchReplaceFull,
httpApi
patchReplaceFull
} from './common'
export function getDevices (options) {
@ -26,6 +28,20 @@ export function getDevices (options) {
})
})
}
export function getDevicesPreferences (options) {
return new Promise((resolve, reject) => {
let requestOptions = options || {}
requestOptions = _.merge(requestOptions, {
path: 'api/pbxfielddevicepreferences/',
root: '_embedded.ngcp:pbxfielddevicepreferences'
})
getList(requestOptions).then((list) => {
resolve(list)
}).catch((err) => {
reject(err)
})
})
}
export function getDeviceList (options) {
return new Promise((resolve, reject) => {
@ -182,3 +198,36 @@ export async function loadDeviceModel (modelId) {
})
})
}
export function setPreferenceDevice (deviceId, deviceValue, fieldName) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
if (deviceValue === undefined || deviceValue === null || deviceValue === '' || (Array.isArray(deviceValue) && !deviceValue.length)) {
return patchRemove({
path: 'api/pbxfielddevicepreferences/' + deviceId,
fieldPath: fieldName
})
}
return patchReplaceFull({
path: 'api/pbxfielddevicepreferences/' + deviceId,
fieldPath: fieldName,
value: deviceValue
})
}).then((device) => {
resolve(device)
}).catch((err) => {
const errCode = err.status + ''
if (errCode === '422') {
return patchAdd({
path: 'api/pbxfielddevicepreferences/' + deviceId,
fieldPath: fieldName,
value: deviceValue
})
}
}).then((device) => {
resolve(device.data)
}).catch((err) => {
reject(err)
})
})
}

@ -1,159 +1,64 @@
<template>
<csc-list-item
icon="fas fa-fax"
:image="imageUrl"
:odd="odd"
:expanded="expanded"
:loading="loading"
@toggle="toggle"
<q-item
class="cursor-pointer"
clickable
@click="goDeviceDetails"
>
<template
#title
<q-item-section
side
center
no-wrap
>
<img
class="csc-list-item-head-image"
:src="imageUrl"
>
</q-item-section>
<q-item-section>
<csc-list-item-title>
{{ device.station_name }}
</csc-list-item-title>
<q-slide-transition>
<csc-list-item-subtitle
v-if="!expanded"
>
<csc-list-item-subtitle>
{{ $t('MAC address') }}: {{ device.identifier }}
</csc-list-item-subtitle>
</q-slide-transition>
<q-slide-transition>
<csc-list-item-subtitle
v-if="!expanded"
>
<csc-list-item-subtitle>
{{ $t('Phone model') }}: {{ profile.name }}
</csc-list-item-subtitle>
</q-slide-transition>
</template>
<template
#menu
>
<csc-list-menu-item
icon="delete"
icon-color="negative"
@click="deleteDevice"
>
{{ $t('Remove') }}
</csc-list-menu-item>
</template>
<template
#body
</q-item-section>
<q-item-section
side
top
>
<q-input
v-model="changes.stationName"
:label="$t('Station name')"
@keyup.enter="save"
>
<template
v-if="hasStationNameChanged"
#append
>
<csc-input-button-save
@click.stop="save"
/>
<csc-input-button-reset
@click.stop="resetStationName"
/>
</template>
</q-input>
<q-field
:label="$t('MAC address')"
>
<q-input
v-model="changes.identifier"
@keyup.enter="save"
<csc-more-menu>
<csc-popup-menu-item
icon="delete"
color="negative"
:label="$t('Remove')"
@click="deleteDevice"
/>
<csc-fade>
<csc-form-save-button
v-if="hasIdentifierChanged"
@click="save"
/>
</csc-fade>
<csc-fade>
<csc-form-reset-button
v-if="hasIdentifierChanged"
@click="resetIdentifier"
/>
</csc-fade>
</q-field>
<csc-pbx-model-select
v-model="changes.profile"
:profiles="profiles"
:profile-map="profileMap"
:has-reset-button="false"
@opened="$emit('model-select-opened')"
@input="selectedProfile"
>
<template
v-if="hasProfileChanged"
#append
>
<csc-input-button-save
@click.stop="save"
/>
<csc-input-button-reset
@click.stop="resetProfile"
/>
</template>
</csc-pbx-model-select>
<csc-pbx-device-config
v-if="modelImage"
:device="device"
:model="model"
:model-image="modelImage"
:loading="subscribersLoading"
:subscribers="subscribers"
:subscriber-map="subscriberMap"
@keysChanged="saveKeys"
/>
</template>
</csc-list-item>
</csc-more-menu>
</q-item-section>
</q-item>
</template>
<script>
import CscPbxModelSelect from '../PbxConfiguration/CscPbxModelSelect'
import CscPbxDeviceConfig from '../PbxConfiguration/CscPbxDeviceConfig'
import CscListItem from '../../CscListItem'
import CscListItemTitle from '../../CscListItemTitle'
import CscListItemSubtitle from '../../CscListItemSubtitle'
import CscFade from '../../transitions/CscFade'
import CscFormSaveButton from '../../form/CscFormSaveButton'
import CscFormResetButton from '../../form/CscFormResetButton'
import CscListMenuItem from '../../CscListMenuItem'
import CscInputButtonSave from 'components/form/CscInputButtonSave'
import CscInputButtonReset from 'components/form/CscInputButtonReset'
import CscMoreMenu from 'components/CscMoreMenu'
import CscPopupMenuItem from 'components/CscPopupMenuItem'
export default {
name: 'CscPbxDevice',
components: {
CscInputButtonReset,
CscInputButtonSave,
CscListMenuItem,
CscListItem,
CscListItemTitle,
CscListItemSubtitle,
CscFade,
CscFormSaveButton,
CscFormResetButton,
CscPbxModelSelect,
CscPbxDeviceConfig
CscMoreMenu,
CscPopupMenuItem
},
props: {
odd: {
type: Boolean,
default: false
},
expanded: {
type: Boolean,
default: false
},
loading: {
type: Boolean,
default: false
},
device: {
type: Object,
default: null
@ -162,16 +67,6 @@ export default {
type: Object,
default: null
},
profiles: {
type: Array,
default () {
return []
}
},
profileMap: {
type: Object,
default: null
},
model: {
type: Object,
default: null
@ -179,61 +74,18 @@ export default {
modelImage: {
type: Object,
default: null
},
modelImageMap: {
type: Object,
default: null
},
subscribers: {
type: Array,
default () {
return []
}
},
subscribersLoading: {
type: Boolean,
default: false
},
subscriberOptions: {
type: Array,
default () {
return []
}
},
subscriberMap: {
type: Object,
default: null
}
},
emits: ['save-profile', 'save-identifier', 'save-station-name', 'save-keys', 'remove', 'expand', 'collapse', 'load-model', 'expanded', 'model-select-opened'],
data () {
return {
changes: this.getData()
}
},
emits: ['remove', 'load-model'],
computed: {
imageUrl () {
if (this.modelImage && this.modelImage.url) {
return this.modelImage.url
}
return null
},
hasStationNameChanged () {
return this.changes.stationName !== this.device.station_name
},
hasIdentifierChanged () {
return this.changes.identifier !== this.device.identifier
},
hasProfileChanged () {
return this.changes.profile !== this.device.profile_id
}
},
watch: {
expanded (expanded) {
if (expanded) {
this.$emit('expanded')
}
},
profile () {
this.$emit('load-model')
}
@ -242,67 +94,23 @@ export default {
this.$emit('load-model')
},
methods: {
getData () {
return {
stationName: this.device.station_name,
identifier: this.device.identifier,
profile: this.device.profile_id
}
},
toggle () {
if (this.expanded) {
this.$emit('collapse')
} else {
this.$emit('expand')
}
},
resetStationName () {
this.changes.stationName = this.device.station_name
},
resetIdentifier () {
this.changes.identifier = this.device.identifier
},
selectedProfile (profileId) {
this.changes.profile = profileId
},
resetProfile () {
this.changes.profile = this.device.profile_id
},
deleteDevice () {
if (this.$refs.listItem) {
this.$refs.listItem.closePopoverMenu()
}
this.$emit('remove')
},
saveKeys (keys) {
this.$emit('save-keys', {
deviceId: this.device.id,
keys: keys
})
},
save () {
if (this.hasStationNameChanged) {
this.$emit('save-station-name', {
deviceId: this.device.id,
stationName: this.changes.stationName
})
}
if (this.hasIdentifierChanged) {
this.$emit('save-identifier', {
deviceId: this.device.id,
identifier: this.changes.identifier
})
}
if (this.hasProfileChanged) {
this.$emit('save-profile', {
deviceId: this.device.id,
profileId: this.changes.profile
})
}
goDeviceDetails () {
this.$router.push('/user/pbx-configuration/device/' + this.device.id)
}
}
}
</script>
<style lang="sass" rel="stylesheet/sass">
.csc-list-item-head-image
width: 32px
height: 32px
position: relative
overflow: hidden
</style>

@ -24,6 +24,7 @@
"Add time range": "Add time range",
"Added group {group}": "Added group {group}",
"Added seat {seat}": "Added seat {seat}",
"Admin name": "Admin name",
"After": "After",
"Alias Number": "Alias Number",
"Alias Numbers": "Alias Numbers",
@ -57,6 +58,8 @@
"Busy Lamp Field": "Busy Lamp Field",
"CDR": "CDR",
"CLI": "CLI",
"CSTA Client": "CSTA Client",
"CSTA Controller": "CSTA Controller",
"Call": "Call",
"Call Blocking": "Call Blocking",
"Call Forwarding": "Call Forwarding",
@ -70,6 +73,7 @@
"Call back": "Call back",
"Call ended": "Call ended",
"Call forwarded": "Call forwarded",
"Call holded": "Call holded",
"Call recordings": "Call recordings",
"CallID": "CallID",
"Callee": "Callee",
@ -121,6 +125,7 @@
"Custom Announcements": "Custom Announcements",
"Custom sound": "Custom sound",
"Customer Details": "Customer Details",
"Customer Phonebook": "Customer Phonebook",
"Daily": "Daily",
"Dashboard": "Dashboard",
"Data is in the clipboard": "Data is in the clipboard",
@ -129,6 +134,7 @@
"Default sound": "Default sound",
"Default sound set for all seats and groups": "Default sound set for all seats and groups",
"Delete": "Delete",
"Delete customer phonebook": "Delete customer phonebook",
"Delete destination": "Delete destination",
"Delete forwarding": "Delete forwarding",
"Delete recording": "Delete recording",
@ -148,8 +154,10 @@
"Devices": "Devices",
"Direction": "Direction",
"Disable": "Disable",
"Disable phone web interface": "Disable phone web interface",
"Display Name": "Display Name",
"Do not ring primary number": "Do not ring primary number",
"Download CSV": "Download CSV",
"Download fax": "Download fax",
"Download voicemail": "Download voicemail",
"Duration": "Duration",
@ -168,6 +176,7 @@
"Expires": "Expires",
"Extension": "Extension",
"Extension Settings": "Extension Settings",
"FW Upgrade disable": "FW Upgrade disable",
"Fax": "Fax",
"Fax Settings": "Fax Settings",
"Fax to Mail and Sendfax": "Fax to Mail and Sendfax",
@ -220,6 +229,7 @@
"If available": "If available",
"If busy": "If busy",
"If not available": "If not available",
"Ignore Members Call Forwards when Hunting": "Ignore Members Call Forwards when Hunting",
"In": "In",
"In call with": "In call with",
"In call with {number}": "In call with {number}",
@ -330,12 +340,17 @@
"Phone number": "Phone number",
"Pilot": "Pilot",
"Play all files in loop": "Play all files in loop",
"Play announcement before call setup": "Play announcement before call setup",
"Play announcement before routing to CFU/CFNA": "Play announcement before routing to CFU/CFNA",
"Play announcement to callee after answer": "Play announcement to callee after answer",
"Please fill or remove the empty slots": "Please fill or remove the empty slots",
"Please select an option": "Please select an option",
"Powered by": "Powered by",
"Preferences": "Preferences",
"Primary Number": "Primary Number",
"Privacy": "Privacy",
"Private": "Private",
"Purge existing": "Purge existing",
"Q-Value": "Q-Value",
"QR code unavailable. Please retry later": "QR code unavailable. Please retry later",
"Quality": "Quality",
@ -461,6 +476,7 @@
"There are no ACLs yet": "There are no ACLs yet",
"There are no Key Renew Notify Emails yet": "There are no Key Renew Notify Emails yet",
"There was an error, please retry later": "There was an error, please retry later",
"This number is already in use.": "This number is already in use.",
"Thursday": "Thursday",
"Time": "Time",
"Time is invalid": "Time is invalid",
@ -486,13 +502,16 @@
"Updated {field} for device {device} successfully": "Updated {field} for device {device} successfully",
"Updated {field} for manager secretary config {msConfig} successfully": "Updated {field} for manager secretary config {msConfig} successfully",
"Updated {field} for sound set {soundSet} successfully": "Updated {field} for sound set {soundSet} successfully",
"Updated {field} successfully": "Updated {field} successfully",
"Upload": "Upload",
"Upload CSV": "Upload CSV",
"Use Parent": "Use Parent",
"Use RegExp": "Use RegExp",
"Use as default for all seats and groups": "Use as default for all seats and groups",
"Use custom number": "Use custom number",
"Use language specific preset": "Use language specific preset",
"User Agent": "User Agent",
"User config priority over provisioning": "User config priority over provisioning",
"User settings": "User settings",
"Username": "Username",
"Using Bye": "Using Bye",
@ -579,6 +598,12 @@
"ring": "ring",
"second": "second",
"seconds": "seconds",
"the behavior of the members call forwards from a Cloud PBX subscriber when it is called within a huntgroup": "the behavior of the members call forwards from a Cloud PBX subscriber when it is called within a huntgroup",
"the playback announcement as early media before Call Forward Unconditional or Unavailable": "the playback announcement as early media before Call Forward Unconditional or Unavailable",
"the playback announcement as early media before send the call to callee": "the playback announcement as early media before send the call to callee",
"the playback announcement to callee after he answered the call": "the playback announcement to callee after he answered the call",
"the right of this subscriber to be controlled by a CTI subscriber within the same customer using uaCSTA via SIP": "the right of this subscriber to be controlled by a CTI subscriber within the same customer using uaCSTA via SIP",
"the right this subscriber to initiate CTI sessions to other subscribers within the same customer using uaCSTA via SIP": "the right this subscriber to initiate CTI sessions to other subscribers within the same customer using uaCSTA via SIP",
"the visibility of the number within own PBX": "the visibility of the number within own PBX",
"to": "to",
"unavailable": "unavailable",

@ -0,0 +1,415 @@
<template>
<csc-page-sticky-tabs
id="csc-page-pbx-devices-details"
ref="pageSticky"
:value="selectedTab"
>
<template
#tabs
>
<q-breadcrumbs
class="q-item absolute absolute-left text-weight-light"
active-color="primary"
separator-color="primary"
>
<q-breadcrumbs-el
key="devices"
class="cursor-pointer"
to="/user/pbx-configuration/devices"
:label="$t('Devices')"
icon="fas fa-fax"
/>
<q-breadcrumbs-el
v-if="deviceSelected"
key="device"
:label="deviceSelected.station_name"
/>
</q-breadcrumbs>
<q-tab
v-for="tab in tabs"
:key="tab.value"
class="d-flex justify-content-center"
:name="tab.value"
:icon="tab.icon"
:label="tab.label"
:default="tab.value === selectedTab"
@click="selectTab(tab.value)"
/>
</template>
<q-item
v-if="selectedTab === 'preferences'"
class="col col-xs-12 col-md-6"
>
<q-list
v-if="changes"
class="col-xs-12 col-md-6 q-mr-xl"
side
top
>
<q-input
v-model="changes.station_name"
:label="$t('Station name')"
:disable="isLoading"
@keyup.enter="save"
>
<template
v-if="hasStationNameChanged"
#append
>
<csc-input-button-save
@click.stop="save"
/>
<csc-input-button-reset
@click.stop="resetStationName"
/>
</template>
</q-input>
<q-input
v-model="changes.identifier"
:disable="isLoading"
:label="$t('MAC address')"
@keyup.enter="save"
>
<template
v-if="hasIdentifierChanged"
#append
>
<csc-input-button-save
@click.stop="save"
/>
<csc-input-button-reset
@click.stop="resetIdentifier"
/>
</template>
</q-input>
<csc-pbx-model-select
v-model="changes.profile_id"
:profiles="deviceProfileList"
:profile-map="deviceProfileMap"
:has-reset-button="false"
@opened="$emit('model-select-opened')"
@input="selectedProfile"
>
<template
v-if="hasProfileChanged"
#append
>
<csc-input-button-save
@click.stop="save"
/>
<csc-input-button-reset
@click.stop="resetProfile"
/>
</template>
</csc-pbx-model-select>
</q-list>
<q-list
v-if="changes"
class="col-xs-12 col-md-5 q-mr-xl"
side
top
>
<q-input
v-model="changes.admin_name"
:label="$t('Admin name')"
:disable="isLoadingPreferences"
@keyup.enter="save"
>
<template
v-if="hasAdminNameChanged"
#append
>
<csc-input-button-save
@click.stop="save"
/>
<csc-input-button-reset
@click.stop="resetAdminName"
/>
</template>
</q-input>
<q-toggle
v-model="changes.web_gui_dis"
class="q-pa-sm"
:label="$t('Disable phone web interface')"
:disable="isLoadingPreferences"
@update:model-value="changeGui"
/>
<q-toggle
v-model="changes.user_conf_priority"
class="q-pa-sm"
:label="$t('User config priority over provisioning')"
:disable="isLoadingPreferences"
@update:model-value="changeUserConfig"
/>
<q-toggle
v-model="changes.FW_upg_dis"
class="q-pa-sm"
:label="$t('FW Upgrade disable')"
:disable="isLoadingPreferences"
@update:model-value="changeFW"
/>
</q-list>
<q-list
v-if="changes"
class="col-xs-12 col-md-16 q-mr-xl"
>
<csc-pbx-device-config
v-if="deviceModelImageMap[deviceProfileMap[deviceSelected.profile_id].device_id]"
:device="deviceSelected"
:model="deviceModelMap[deviceProfileMap[deviceSelected.profile_id].device_id]"
:model-image="deviceModelImageMap[deviceProfileMap[deviceSelected.profile_id].device_id]"
:loading="isSubscribersRequesting"
:subscribers="subscriberList"
:subscriber-map="subscriberMap"
:device-preferences="true"
@keysChanged="keysSave"
/>
</q-list>
</q-item>
</csc-page-sticky-tabs>
</template>
<script>
import CscInputButtonReset from 'components/form/CscInputButtonReset'
import CscInputButtonSave from 'components/form/CscInputButtonSave'
import CscPageStickyTabs from 'components/CscPageStickyTabs'
import CscPbxDeviceConfig from 'components/pages/PbxConfiguration/CscPbxDeviceConfig'
import CscPbxModelSelect from 'components/pages/PbxConfiguration/CscPbxModelSelect'
import useValidate from '@vuelidate/core'
import {
mapActions,
mapGetters,
mapMutations,
mapState
} from 'vuex'
import { RequestState } from 'src/store/common'
import {
showGlobalError,
showToast
} from 'src/helpers/ui'
export default {
name: 'CscPagePbxDeviceDetails',
components: {
CscPageStickyTabs,
CscInputButtonSave,
CscInputButtonReset,
CscPbxModelSelect,
CscPbxDeviceConfig
},
props: {
initialTab: {
type: String,
default: 'preferences'
},
device: {
type: Object,
default: null
}
},
data () {
return {
changes: null,
id: this.$route.params.id,
selectedTab: this.initialTab,
v$: useValidate()
}
},
computed: {
...mapState('pbxDevices', [
'deviceSelected',
'deviceUpdateError',
'devicePreferencesUpdateError',
'deviceUpdateState',
'devicePreferencesUpdateState',
'devicePreferencesSelected'
]),
...mapState('pbx', [
'deviceProfileList',
'deviceProfileMap',
'deviceModelImageMap',
'deviceModelMap',
'subscriberList',
'subscriberMap'
]),
...mapGetters('pbx', [
'getSubscriberOptions',
'isSubscribersRequesting'
]),
...mapGetters('pbxDevices', [
'getDeviceUpdateToastMessage',
'getDevicePreferencesUpdateToastMessage',
'isDeviceLoading',
'isDevicePreferencesLoading'
]),
tabs () {
return [
{
label: this.$t('Preferences'),
value: 'preferences',
icon: 'perm_phone_msg'
}
]
},
isLoading () {
return this.isDeviceLoading(this.deviceSelected.id)
},
isLoadingPreferences () {
return this.isDevicePreferencesLoading(this.devicePreferencesSelected.id)
},
hasStationNameChanged () {
return this.changes.station_name !== this.deviceSelected.station_name
},
hasIdentifierChanged () {
return this.changes.identifier !== this.deviceSelected.identifier
},
hasProfileChanged () {
return this.changes.profile_id !== this.deviceSelected.profile_id
},
imageUrl () {
if (this.modelImage && this.modelImage.url) {
return this.modelImage.url
}
return null
},
hasAdminNameChanged () {
return this.changes.admin_name !== this.devicePreferencesSelected.admin_name
}
},
watch: {
deviceSelected () {
this.changes = this.getDeviceData()
},
deviceUpdateState (state) {
if (state === RequestState.succeeded) {
showToast(this.getDeviceUpdateToastMessage)
} else if (state === RequestState.failed) {
showGlobalError(this.deviceUpdateError)
}
},
devicePreferencesUpdateState (state) {
if (state === RequestState.succeeded) {
showToast(this.getDevicePreferencesUpdateToastMessage)
} else if (state === RequestState.failed) {
showGlobalError(this.devicePreferencesUpdateError)
}
}
},
mounted () {
this.expandDevice(this.id)
this.expandDevicePreferences(this.id)
this.loadSubscribers()
},
methods: {
...mapMutations('pbxDevices', [
'expandDevice',
'expandDevicePreferences'
]),
...mapActions('pbxDevices', [
'setDeviceKeys',
'setDeviceStationName',
'setDeviceIdentifier',
'setDeviceProfile',
'setAdminName',
'setGui',
'setUserConfig',
'setFW'
]),
...mapActions('pbx', [
'loadSubscribers'
]),
getDeviceData () {
return (this.deviceSelected && this.devicePreferencesSelected)
? {
station_name: this.deviceSelected.station_name,
identifier: this.deviceSelected.identifier,
profile_id: this.deviceSelected.profile_id,
admin_name: this.devicePreferencesSelected.admin_name ? this.devicePreferencesSelected.admin_name : undefined,
web_gui_dis: this.devicePreferencesSelected.web_gui_dis ? this.devicePreferencesSelected.web_gui_dis : false,
user_conf_priority: this.devicePreferencesSelected.user_conf_priority ? this.devicePreferencesSelected.user_conf_priority : false,
FW_upg_dis: this.devicePreferencesSelected.FW_upg_dis ? this.devicePreferencesSelected.FW_upg_dis : false
}
: null
},
resetStationName () {
this.changes.station_name = this.deviceSelected.station_name
},
resetIdentifier () {
this.changes.identifier = this.deviceSelected.identifier
},
resetAdminName () {
this.changes.admin_name = this.devicePreferencesSelected.admin_name
},
selectedProfile (profileId) {
this.changes.profile_id = profileId
},
resetProfile () {
this.changes.profile_id = this.deviceSelected.profile_id
},
selectTab (tabName) {
if (this.selectedTab !== tabName) {
this.forceTabReload(tabName)
}
},
forceTabReload (tabName) {
this.selectedTab = tabName
},
keysSave (keys) {
this.setDeviceKeys({
deviceId: this.deviceSelected.id,
keys: keys
})
},
save () {
if (this.hasStationNameChanged) {
this.setDeviceStationName({
deviceId: this.deviceSelected.id,
stationName: this.changes.station_name
})
}
if (this.hasIdentifierChanged) {
this.setDeviceIdentifier({
deviceId: this.deviceSelected.id,
identifier: this.changes.identifier
})
}
if (this.hasProfileChanged) {
this.setDeviceProfile({
deviceId: this.deviceSelected.id,
profileId: this.changes.profile_id
})
}
if (this.hasAdminNameChanged) {
this.setAdminName({
deviceId: this.devicePreferencesSelected.id,
adminName: this.changes.admin_name
})
}
},
changeGui () {
this.setGui({
deviceId: this.devicePreferencesSelected.id,
webGui: this.changes.web_gui_dis
})
},
changeUserConfig () {
this.setUserConfig({
deviceId: this.devicePreferencesSelected.id,
userConf: this.changes.user_conf_priority
})
},
changeFW () {
this.setFW({
deviceId: this.devicePreferencesSelected.id,
FWupg: this.changes.FW_upg_dis
})
}
}
}
</script>
<style>
.no-wrap {
flex-wrap: wrap;
}
</style>

@ -79,8 +79,9 @@
<csc-list-spinner
v-if="isDeviceListRequesting && !(isDeviceCreating || isDeviceRemoving || isDeviceUpdating)"
/>
<csc-list
<q-list
v-if="!isDeviceListEmpty && deviceListVisibility === 'visible'"
class="row justify-start items-start"
>
<csc-fade
v-for="(device, index) in deviceListItems"
@ -88,36 +89,20 @@
>
<csc-pbx-device
:key="device.id"
:odd="(index % 2) === 0"
:expanded="isDeviceExpanded(device.id)"
:loading="isDeviceLoading(device.id)"
:device="device"
:class="'col-xs-12 col-md-6 col-lg-4 csc-item-' + ((index % 2 === 0)?'odd':'even')"
:profile="deviceProfileMap[device.profile_id]"
:profiles="deviceProfileList"
:profile-map="deviceProfileMap"
:model="deviceModelMap[deviceProfileMap[device.profile_id].device_id]"
:model-image="deviceModelImageMap[deviceProfileMap[device.profile_id].device_id]"
:model-image-map="deviceModelImageMap"
:subscribers="subscriberList"
:subscriber-map="subscriberMap"
:subscribers-loading="isSubscribersRequesting"
:subscriber-options="getSubscriberOptions"
@load-model="loadDeviceModel({
type: 'all',
deviceId: deviceProfileMap[device.profile_id].device_id
})"
@expand="expandDevice(device.id)"
@collapse="collapseDevice"
@expanded="deviceExpanded"
@remove="openDeviceRemovalDialog(device.id)"
@save-station-name="setDeviceStationName"
@save-identifier="setDeviceIdentifier"
@save-profile="setDeviceProfile"
@save-keys="setDeviceKeys"
@model-select-opened="loadDeviceModels('front_thumb')"
/>
</csc-fade>
</csc-list>
</q-list>
<div
v-if="isDeviceListEmpty && !isDeviceListRequesting && hasFilters"
class="row justify-center csc-no-entities"
@ -148,7 +133,6 @@ import {
mapMutations
} from 'vuex'
import CscPage from 'components/CscPage'
import CscList from 'components/CscList'
import CscPbxDevice from 'components/pages/PbxConfiguration/CscPbxDevice'
import CscFade from 'components/transitions/CscFade'
import CscListSpinner from 'components/CscListSpinner'
@ -175,7 +159,6 @@ export default {
CscListActionButton,
CscFade,
CscPage,
CscList,
CscPbxDevice,
CscListSpinner
},
@ -206,7 +189,6 @@ export default {
'deviceListLastPage',
'deviceListVisibility',
'deviceCreationState',
'deviceUpdateState',
'deviceRemovalState'
]),
...mapGetters('pbxDevices', [
@ -237,13 +219,6 @@ export default {
showGlobalError(this.deviceCreationError)
}
},
deviceUpdateState (state) {
if (state === RequestState.succeeded) {
showToast(this.getDeviceUpdateToastMessage)
} else if (state === RequestState.failed) {
showGlobalError(this.deviceUpdateError)
}
},
deviceRemovalState (state) {
if (state === RequestState.succeeded) {
this.$scrollTo(this.$parent.$el)
@ -256,12 +231,12 @@ export default {
mounted () {
this.$scrollTo(this.$parent.$el)
this.loadDeviceListItemsFiltered()
this.loadDevicePreferencesListItems()
},
methods: {
...mapActions('pbx', [
'loadDeviceModel',
'loadDeviceModels',
'loadSubscribers'
'loadDeviceModels'
]),
...mapMutations('pbxDevices', [
'expandDevice',
@ -273,6 +248,7 @@ export default {
]),
...mapActions('pbxDevices', [
'loadDeviceListItems',
'loadDevicePreferencesListItems',
'createDevice',
'removeDevice',
'setDeviceStationName',
@ -308,9 +284,6 @@ export default {
this.loadDeviceListItemsFiltered()
}
},
deviceExpanded () {
this.loadSubscribers()
},
openDeviceRemovalDialog (deviceId) {
if (this.$refs.removeDialog) {
this.deviceRemovalRequesting(deviceId)

@ -1,47 +1,48 @@
import { PROFILE_ATTRIBUTE_MAP, PROFILE_ATTRIBUTES_MAP } from 'src/constants'
import CscLayoutMain from 'src/layouts/CscLayoutMain'
import CscLayoutLogin from 'src/layouts/CscLayoutLogin'
import CscPageLogin from 'src/pages/CscPageLogin'
import CscPageHome from 'src/pages/CscPageHome'
import CscPageConversations from 'src/pages/CscPageConversations'
import CscLayoutMain from 'src/layouts/CscLayoutMain'
import CscPageCallBlockingIncoming from 'src/pages/CscPageCallBlockingIncoming'
import CscPageCallBlockingOutgoing from 'src/pages/CscPageCallBlockingOutgoing'
import CscPageCallBlockingPrivacy from 'src/pages/CscPageCallBlockingPrivacy'
import CscPageCallRecording from 'src/pages/CscPageCallRecording'
import CscPageReminder from 'src/pages/CscPageReminder'
import CscPageSpeedDial from 'src/pages/CscPageSpeedDial'
import CscPagePbxGroups from 'src/pages/CscPagePbxGroups'
import CscPagePbxGroupDetails from 'src/pages/CscPagePbxGroupDetails'
import CscPagePbxSeats from 'src/pages/CscPagePbxSeats'
import CscPageCallSettings from 'pages/CscPageCallSettings'
import CscPageCf from 'pages/CscPageCf'
import CscPageConversations from 'src/pages/CscPageConversations'
import CscPageCustomerPhonebook from 'src/pages/CscPageCustomerPhonebook'
import CscPagePbxSeatDetails from 'src/pages/CscPagePbxSeatDetails'
import CscPagePbxDevices from 'src/pages/CscPagePbxDevices'
import CscPageCustomerPhonebookAdd from 'src/pages/CscPageCustomerPhonebookAdd'
import CscPageCustomerPhonebookDetails from 'src/pages/CscPageCustomerPhonebookDetails'
import CscPageCustomerPhonebookUpload from 'src/pages/CscPageCustomerPhonebookUpload'
import CscPageDashboard from 'pages/CscPageDashboard'
import CscPageError404 from 'src/pages/CscPageError404'
import CscPageFaxSettings from 'src/pages/CscPageFaxSettings'
import CscPageHome from 'src/pages/CscPageHome'
import CscPageLogin from 'src/pages/CscPageLogin'
import CscPagePbxAutoAttendant from 'src/pages/CscPagePbxAutoAttendant'
import CscPagePbxCallQueues from 'src/pages/CscPagePbxCallQueues'
import CscPagePbxSoundSets from 'src/pages/CscPagePbxSoundSets'
import CscPagePbxDeviceDetails from 'src/pages/CscPagePbxDeviceDetails'
import CscPagePbxDevices from 'src/pages/CscPagePbxDevices'
import CscPagePbxGroupDetails from 'src/pages/CscPagePbxGroupDetails'
import CscPagePbxGroups from 'src/pages/CscPagePbxGroups'
import CscPagePbxMsConfigs from 'src/pages/CscPagePbxMsConfigs'
import CscPagePbxAutoAttendant from 'src/pages/CscPagePbxAutoAttendant'
import CscPageVoicebox from 'src/pages/CscPageVoicebox'
import CscPageFaxSettings from 'src/pages/CscPageFaxSettings'
import CscPageUserSettings from 'src/pages/CscPageUserSettings'
import CscPageError404 from 'src/pages/CscPageError404'
import CscRecoverPassword from 'src/pages/CscRecoverPassword'
import CscPageCf from 'pages/CscPageCf'
import CscPageCallSettings from 'pages/CscPageCallSettings'
import CscPageRegisteredDevices from 'pages/CscPageRegisteredDevices'
import CscPageSubscriberPhonebook from 'pages/CscPageSubscriberPhonebook'
import CscPagePbxSeatDetails from 'src/pages/CscPagePbxSeatDetails'
import CscPagePbxSeats from 'src/pages/CscPagePbxSeats'
import CscPagePbxSettingsAutoAttendant from 'pages/CscPagePbxSettingsAutoAttendant'
import CscPageDashboard from 'pages/CscPageDashboard'
import CscPagePbxSettingsMsConfigs from 'pages/CscPagePbxSettingsMsConfigs'
import CscPagePbxSettingsCallQueues from 'pages/CscPagePbxSettingsCallQueues'
import CscPagePbxSettingsMsConfigs from 'pages/CscPagePbxSettingsMsConfigs'
import CscPagePbxSoundSetDetails from 'src/pages/CscPagePbxSoundSetDetails'
import CscPageSubscriberPhonebookDetails from 'src/pages/CscPageSubscriberPhonebookDetails'
import CscPageCustomerPhonebookDetails from 'src/pages/CscPageCustomerPhonebookDetails'
import CscPageSubscriberPhonebookAdd from 'src/pages/CscPageSubscriberPhonebookAdd'
import CscPageCustomerPhonebookAdd from 'src/pages/CscPageCustomerPhonebookAdd'
import CscPageCustomerPhonebookUpload from 'src/pages/CscPageCustomerPhonebookUpload'
import CscPagePbxSoundSets from 'src/pages/CscPagePbxSoundSets'
import CscPagePbxStatisticsCdr from 'src/pages/CscPagePbxStatisticsCdr'
import CscPageRegisteredDevices from 'pages/CscPageRegisteredDevices'
import CscPageReminder from 'src/pages/CscPageReminder'
import CscPageSpeedDial from 'src/pages/CscPageSpeedDial'
import CscPageSubscriberPhonebook from 'pages/CscPageSubscriberPhonebook'
import CscPageSubscriberPhonebookAdd from 'src/pages/CscPageSubscriberPhonebookAdd'
import CscPageSubscriberPhonebookDetails from 'src/pages/CscPageSubscriberPhonebookDetails'
import CscPageUserSettings from 'src/pages/CscPageUserSettings'
import CscPageVoicebox from 'src/pages/CscPageVoicebox'
import CscRecoverPassword from 'src/pages/CscRecoverPassword'
import { i18n } from 'src/boot/i18n'
const getToken = (route) => {
@ -106,7 +107,7 @@ const routes = [
component: CscPageSubscriberPhonebookAdd,
meta: {
get title () {
return i18n.global.tc('Add Phoneboossdsk')
return i18n.global.tc('Add Phonebook')
}
}
},
@ -294,6 +295,18 @@ const routes = [
}
}
},
{
path: 'pbx-configuration/device/:id',
component: CscPagePbxDeviceDetails,
meta: {
get title () {
return i18n.global.tc('PBX Configuration')
},
get subtitle () {
return i18n.global.tc('Devices')
}
}
},
{
path: 'pbx-configuration/seat/:id',
component: CscPagePbxSeatDetails,

@ -5,13 +5,15 @@ import {
} from './common'
import _ from 'lodash'
import {
getDeviceList,
createDevice,
getDeviceList,
getDevicesPreferences,
removeDevice,
setDeviceStationName,
setDeviceIdentifier,
setDeviceKeys,
setDeviceProfile,
setDeviceKeys
setDeviceStationName,
setPreferenceDevice
} from '../api/pbx-devices'
import {
i18n
@ -20,40 +22,81 @@ import {
export default {
namespaced: true,
state: {
deviceListState: RequestState.initiated,
deviceListVisibility: 'visible',
deviceListItems: [],
deviceCreating: null,
deviceCreationError: null,
deviceCreationState: CreationState.initiated,
deviceListCurrentPage: 1,
deviceListItems: [],
deviceListLastPage: null,
deviceListState: RequestState.initiated,
deviceListVisibility: 'visible',
deviceMap: {},
devicePreferencesListItems: [],
devicePreferencesListState: RequestState.initiated,
devicePreferencesMap: {},
devicePreferencesRemovalState: RequestState.initiated,
devicePreferencesRemoving: null,
devicePreferencesSelected: null,
devicePreferencesUpdateError: null,
devicePreferencesUpdateState: RequestState.initiated,
devicePreferencesUpdating: null,
devicePreferencesUpdatingField: null,
deviceRemovalError: null,
deviceRemovalState: RequestState.initiated,
deviceRemoving: null,
deviceSelected: null,
deviceCreating: null,
deviceCreationState: CreationState.initiated,
deviceCreationError: null,
deviceUpdating: null,
deviceUpdatingField: null,
deviceUpdateState: RequestState.initiated,
deviceUpdateError: null,
deviceRemoving: null,
deviceRemovalState: RequestState.initiated,
deviceRemovalError: null,
deviceMapById: {}
deviceUpdateState: RequestState.initiated,
deviceUpdating: null,
deviceUpdatingField: null
},
getters: {
isDeviceListEmpty (state) {
return Array.isArray(state.deviceListItems) && state.deviceListItems.length === 0
getDeviceCreatingName (state) {
return _.get(state, 'deviceCreating.stationName', '')
},
isDeviceListRequesting (state) {
return state.deviceListState === RequestState.requesting
getDeviceCreationToastMessage (state, getters) {
return i18n.global.tc('Created device {device} successfully', {
device: getters.getDeviceCreatingName
})
},
isDeviceExpanded (state) {
return (id) => {
return state.deviceSelected !== null && state.deviceSelected.id === id
getDevicePreferencesUpdateToastMessage (state, getters) {
return i18n.global.tc('Updated {field} successfully', {
field: getters.getDevicePreferencesUpdatingField
})
},
getDevicePreferencesUpdatingField (state) {
return state.devicePreferencesUpdatingField
},
getDevicePreferencesUpdatingName (state) {
return _.get(state, 'devicePreferencesUpdating.admin_name', '')
},
getDeviceRemoveDialogMessage (state, getters) {
if (getters.isDeviceRemoving) {
return i18n.global.tc('You are about to remove device {device}', {
device: getters.getDeviceRemovingName
})
}
return ''
},
isDeviceListPaginationActive (state, getters) {
const requesting = !getters.isDeviceListRequesting || getters.isDeviceCreating ||
getters.isDeviceRemoving || getters.isDeviceUpdating
return !getters.isDeviceListEmpty && requesting && state.deviceListLastPage > 1
getDeviceRemovingName (state) {
return _.get(state, 'deviceRemoving.station_name', '')
},
getDeviceRemovalToastMessage (state, getters) {
return i18n.global.tc('Removed device {device} successfully', {
device: getters.getDeviceRemovingName
})
},
getDeviceUpdateToastMessage (state, getters) {
return i18n.global.tc('Updated {field} for device {device} successfully', {
device: getters.getDeviceUpdatingName,
field: getters.getDeviceUpdatingField
})
},
getDeviceUpdatingField (state) {
return state.deviceUpdatingField
},
getDeviceUpdatingName (state) {
return _.get(state, 'deviceUpdating.station_name', '')
},
isDeviceAddFormDisabled (state) {
return state.deviceCreationState === CreationState.initiated ||
@ -62,11 +105,21 @@ export default {
isDeviceCreating (state) {
return state.deviceCreationState === CreationState.creating
},
isDeviceRemoving (state) {
return state.deviceRemovalState === RequestState.requesting
isDeviceExpanded (state) {
return (id) => {
return state.deviceSelected !== null && state.deviceSelected.id === id
}
},
isDeviceUpdating (state) {
return state.deviceUpdateState === RequestState.requesting
isDeviceListEmpty (state) {
return Array.isArray(state.deviceListItems) && state.deviceListItems.length === 0
},
isDeviceListPaginationActive (state, getters) {
const requesting = !getters.isDeviceListRequesting || getters.isDeviceCreating ||
getters.isDeviceRemoving || getters.isDeviceUpdating
return !getters.isDeviceListEmpty && requesting && state.deviceListLastPage > 1
},
isDeviceListRequesting (state) {
return state.deviceListState === RequestState.requesting
},
isDeviceLoading (state, getters) {
return (deviceId) => {
@ -74,41 +127,23 @@ export default {
(getters.isDeviceRemoving && state.deviceRemoving.id === deviceId)
}
},
getDeviceRemovingName (state) {
return _.get(state, 'deviceRemoving.station_name', '')
},
getDeviceCreatingName (state) {
return _.get(state, 'deviceCreating.stationName', '')
},
getDeviceUpdatingName (state) {
return _.get(state, 'deviceUpdating.station_name', '')
},
getDeviceUpdatingField (state) {
return state.deviceUpdatingField
},
getDeviceRemoveDialogMessage (state, getters) {
if (getters.isDeviceRemoving) {
return i18n.global.tc('You are about to remove device {device}', {
device: getters.getDeviceRemovingName
})
isDevicePreferencesLoading (state, getters) {
return (devicePreferencesId) => {
return (getters.isDevicePreferencesUpdating && state.devicePreferencesUpdating.id === devicePreferencesId) ||
(getters.isDevicePreferencesRemoving && state.devicePreferencesRemoving.id === devicePreferencesId)
}
return ''
},
getDeviceCreationToastMessage (state, getters) {
return i18n.global.tc('Created device {device} successfully', {
device: getters.getDeviceCreatingName
})
isDevicePreferencesRemoving (state) {
return state.devicePreferencesRemovalState === RequestState.requesting
},
getDeviceUpdateToastMessage (state, getters) {
return i18n.global.tc('Updated {field} for device {device} successfully', {
device: getters.getDeviceUpdatingName,
field: getters.getDeviceUpdatingField
})
isDevicePreferencesUpdating (state) {
return state.devicePreferencesUpdateState === RequestState.requesting
},
getDeviceRemovalToastMessage (state, getters) {
return i18n.global.tc('Removed device {device} successfully', {
device: getters.getDeviceRemovingName
})
isDeviceRemoving (state) {
return state.deviceRemovalState === RequestState.requesting
},
isDeviceUpdating (state) {
return state.deviceUpdateState === RequestState.requesting
}
},
mutations: {
@ -135,9 +170,20 @@ export default {
})
state.deviceListVisibility = 'visible'
},
devicePreferencesListItemsSucceeded (state, options) {
state.devicePreferencesListState = RequestState.succeeded
state.devicePreferencesListItems = _.get(options, 'devicesPreferences', [])
state.devicePreferencesMap = {}
state.devicePreferencesListItems.forEach((devicePreferences) => {
state.devicePreferencesMap[devicePreferences.id] = devicePreferences
})
},
deviceListItemsFailed (state) {
state.deviceListState = RequestState.failed
},
devicePreferencesListItemsFailed (state) {
state.devicePreferencesListState = RequestState.failed
},
deviceCreationRequesting (state, device) {
state.deviceCreationState = CreationState.creating
state.deviceCreating = device
@ -154,6 +200,11 @@ export default {
state.deviceUpdatingField = options.deviceField
state.deviceUpdateState = RequestState.requesting
},
devicePreferencesUpdateRequesting (state, options) {
state.devicePreferencesUpdating = state.devicePreferencesMap[options.deviceId]
state.devicePreferencesUpdatingField = options.devicePreferencesField
state.devicePreferencesUpdateState = RequestState.requesting
},
deviceUpdateSucceeded (state, device) {
state.deviceUpdateState = RequestState.succeeded
delete state.deviceMap[device.id]
@ -163,12 +214,33 @@ export default {
state.deviceListItems[i] = device
}
}
if (state.deviceSelected !== null && state.deviceSelected.id === device.id) {
state.deviceSelected = device
}
},
devicePreferencesUpdateSucceeded (state, device) {
state.devicePreferencesUpdateState = RequestState.succeeded
delete state.devicePreferencesMap[device.id]
state.devicePreferencesMap[device.id] = device
for (let i = 0; i < state.devicePreferencesListItems.length; i++) {
if (state.devicePreferencesListItems[i].id === device.id) {
state.devicePreferencesListItems[i] = device
}
}
if (state.devicePreferencesSelected !== null && state.devicePreferencesSelected.id === device.id) {
state.devicePreferencesSelected = device
}
},
deviceUpdateFailed (state, err) {
state.deviceUpdating = null
state.deviceUpdateState = RequestState.failed
state.deviceUpdateError = err
},
devicePreferencesUpdateFailed (state, err) {
state.devicePreferencesUpdating = null
state.devicePreferencesUpdateState = RequestState.failed
state.devicePreferencesUpdateError = err
},
deviceRemovalRequesting (state, id) {
state.deviceRemovalState = RequestState.requesting
state.deviceRemoving = state.deviceMap[id]
@ -187,6 +259,9 @@ export default {
expandDevice (state, deviceId) {
state.deviceSelected = state.deviceMap[deviceId]
},
expandDevicePreferences (state, devicePreferencesId) {
state.devicePreferencesSelected = state.devicePreferencesMap[devicePreferencesId]
},
collapseDevice (state) {
state.deviceSelected = null
},
@ -226,13 +301,29 @@ export default {
})
})
},
loadDevicePreferencesListItems (context) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return getDevicesPreferences()
}).then((devicesPreferences) => {
context.commit('devicePreferencesListItemsSucceeded', {
devicesPreferences: devicesPreferences.items
})
resolve()
}).catch((err) => {
context.commit('devicePreferencesListItemsFailed', err.message)
reject(err)
})
})
},
createDevice (context, deviceData) {
context.commit('deviceCreationRequesting', deviceData)
createDevice(deviceData).then(() => {
return context.dispatch('loadDeviceListItems', {
context.dispatch('loadDeviceListItems', {
page: 1,
clearList: false
})
context.dispatch('loadDevicePreferencesListItems')
}).then(() => {
context.commit('deviceCreationSucceeded')
}).catch((err) => {
@ -295,6 +386,50 @@ export default {
}).catch((err) => {
context.commit('deviceUpdateFailed', err.message)
})
},
setAdminName (context, options) {
context.commit('devicePreferencesUpdateRequesting', {
deviceId: options.deviceId,
devicePreferencesField: i18n.global.tc('Admin name')
})
setPreferenceDevice(options.deviceId, options.adminName, 'admin_name').then((device) => {
context.commit('devicePreferencesUpdateSucceeded', device)
}).catch((err) => {
context.commit('devicePreferencesUpdateFailed', err.message)
})
},
setFW (context, options) {
context.commit('devicePreferencesUpdateRequesting', {
deviceId: options.deviceId,
devicePreferencesField: i18n.global.tc('FW Upgrade disable')
})
setPreferenceDevice(options.deviceId, options.FWupg, 'FW_upg_dis').then((device) => {
context.commit('devicePreferencesUpdateSucceeded', device)
}).catch((err) => {
context.commit('devicePreferencesUpdateFailed', err.message)
})
},
setGui (context, options) {
context.commit('devicePreferencesUpdateRequesting', {
deviceId: options.deviceId,
devicePreferencesField: i18n.global.tc('Disable phone web interface')
})
setPreferenceDevice(options.deviceId, options.webGui, 'web_gui_dis').then((device) => {
context.commit('devicePreferencesUpdateSucceeded', device)
}).catch((err) => {
context.commit('devicePreferencesUpdateFailed', err.message)
})
},
setUserConfig (context, options) {
context.commit('devicePreferencesUpdateRequesting', {
deviceId: options.deviceId,
devicePreferencesField: i18n.global.tc('User config priority over provisioning')
})
setPreferenceDevice(options.deviceId, options.userConf, 'user_conf_priority').then((device) => {
context.commit('devicePreferencesUpdateSucceeded', device)
}).catch((err) => {
context.commit('devicePreferencesUpdateFailed', err.message)
})
}
}
}

Loading…
Cancel
Save