diff --git a/src/api/pbx-devices.js b/src/api/pbx-devices.js
index d6ffbf44..81170083 100644
--- a/src/api/pbx-devices.js
+++ b/src/api/pbx-devices.js
@@ -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)
+ })
+ })
+}
diff --git a/src/components/pages/PbxConfiguration/CscPbxDevice.vue b/src/components/pages/PbxConfiguration/CscPbxDevice.vue
index dec3acdd..c5416d9f 100644
--- a/src/components/pages/PbxConfiguration/CscPbxDevice.vue
+++ b/src/components/pages/PbxConfiguration/CscPbxDevice.vue
@@ -1,159 +1,64 @@
-
-
+
+
+
{{ device.station_name }}
-
+
{{ $t('MAC address') }}: {{ device.identifier }}
-
+
{{ $t('Phone model') }}: {{ profile.name }}
-
-
-
- {{ $t('Remove') }}
-
-
-
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/src/i18n/en.json b/src/i18n/en.json
index d51771a0..9df4e107 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -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",
diff --git a/src/pages/CscPagePbxDeviceDetails.vue b/src/pages/CscPagePbxDeviceDetails.vue
new file mode 100644
index 00000000..87162d90
--- /dev/null
+++ b/src/pages/CscPagePbxDeviceDetails.vue
@@ -0,0 +1,415 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/CscPagePbxDevices.vue b/src/pages/CscPagePbxDevices.vue
index ab53b6b7..2a044430 100644
--- a/src/pages/CscPagePbxDevices.vue
+++ b/src/pages/CscPagePbxDevices.vue
@@ -79,8 +79,9 @@
-
-
+
{
@@ -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,
diff --git a/src/store/pbx-devices.js b/src/store/pbx-devices.js
index ec725003..2507e0a6 100644
--- a/src/store/pbx-devices.js
+++ b/src/store/pbx-devices.js
@@ -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)
+ })
}
}
}