diff --git a/src/api/call-forwarding.js b/src/api/call-forwarding.js index c1feebbb..9dc960b4 100644 --- a/src/api/call-forwarding.js +++ b/src/api/call-forwarding.js @@ -41,14 +41,16 @@ export async function cfGetMostRecentDestinationSetByName (params) { export async function cfLoadSourceSets (subscriberId) { return getList({ resource: 'cfsourcesets', - params: (subscriberId) ? { subscriber_id: subscriberId } : {} + params: (subscriberId) ? { subscriber_id: subscriberId } : {}, + all: true }) } export async function cfLoadTimeSets (subscriberId) { return getList({ resource: 'cftimesets', - params: (subscriberId) ? { subscriber_id: subscriberId } : {} + params: (subscriberId) ? { subscriber_id: subscriberId } : {}, + all: true }) } diff --git a/src/components/call-forwarding/CscCfConditionPopupCustom.vue b/src/components/call-forwarding/CscCfConditionPopupCustom.vue new file mode 100644 index 00000000..71e4d956 --- /dev/null +++ b/src/components/call-forwarding/CscCfConditionPopupCustom.vue @@ -0,0 +1,33 @@ +<template> + <csc-cf-condition-popup + ref="popup" + > + <csc-cf-group-condition-custom + :times="times" + @close="closePopup" + /> + </csc-cf-condition-popup> +</template> + +<script> +import CscCfConditionPopup from 'components/call-forwarding/CscCfConditionPopup' +import CscCfGroupConditionCustom from 'components/call-forwarding/CscCfGroupConditionCustom' +export default { + name: 'CscCfConditionPopupCustom', + components: { + CscCfConditionPopup, + CscCfGroupConditionCustom + }, + props: { + times: { + type: Object, + required: true + } + }, + methods: { + closePopup () { + this.$refs.popup.close() + } + } +} +</script> diff --git a/src/components/call-forwarding/CscCfGroupConditionCustom.vue b/src/components/call-forwarding/CscCfGroupConditionCustom.vue new file mode 100644 index 00000000..eb24731e --- /dev/null +++ b/src/components/call-forwarding/CscCfGroupConditionCustom.vue @@ -0,0 +1,50 @@ +<template> + <csc-cf-group-condition + :title="$t('Custom time set')" + icon="today" + :loading="$wait.is('csc-cf-time-set-create')" + v-bind="$attrs" + @close="$emit('close')" + > + <q-list + separator + class="q-pa-md" + > + <q-item + v-for="(date, index) in times" + :key="index" + > + <q-item-section> + <q-item-label overline> + {{ $t('Period') }} + </q-item-label> + <q-item-label> + {{ date.from }} + </q-item-label> + <q-item-label> + {{ date.to }} + </q-item-label> + </q-item-section> + </q-item> + </q-list> + </csc-cf-group-condition> +</template> + +<script> + +import CscCfGroupCondition from 'components/call-forwarding/CscCfGroupCondition' + +export default { + name: 'CscCfGroupConditionOfficeHours', + components: { + CscCfGroupCondition + }, + props: { + times: { + type: Object, + required: true + } + }, + emits: ['close', 'back'] +} +</script> diff --git a/src/components/call-forwarding/CscCfGroupConditionDate.vue b/src/components/call-forwarding/CscCfGroupConditionDate.vue index 73796168..c31b78be 100644 --- a/src/components/call-forwarding/CscCfGroupConditionDate.vue +++ b/src/components/call-forwarding/CscCfGroupConditionDate.vue @@ -23,7 +23,7 @@ flat color="negative" icon="delete" - @click="deleteSourceSetEvent" + @click="deleteTimeSetEvent" /> <q-btn :label="$t('Save')" @@ -125,12 +125,14 @@ export default { } this.$emit('close') }, - async deleteSourceSetEvent () { + async deleteTimeSetEvent () { await this.deleteTimeSet({ mapping: this.mapping, id: this.timeSet.id, subscriberId: this.subscriberId }) + + this.$emit('close') } } } diff --git a/src/components/call-forwarding/CscCfGroupConditionDateRange.vue b/src/components/call-forwarding/CscCfGroupConditionDateRange.vue index 2a9f19a6..94ad276d 100644 --- a/src/components/call-forwarding/CscCfGroupConditionDateRange.vue +++ b/src/components/call-forwarding/CscCfGroupConditionDateRange.vue @@ -42,7 +42,7 @@ flat color="negative" icon="delete" - @click="deleteSourceSetEvent" + @click="deleteTimeSetEvent" /> <q-btn v-if="!invalidDateset" @@ -144,12 +144,14 @@ export default { } this.$emit('close') }, - async deleteSourceSetEvent () { + async deleteTimeSetEvent () { await this.deleteTimeSet({ mapping: this.mapping, id: this.timeSet.id, subscriberId: this.subscriberId }) + + this.$emit('close') } } } diff --git a/src/components/call-forwarding/CscCfGroupConditionOfficeHours.vue b/src/components/call-forwarding/CscCfGroupConditionOfficeHours.vue index d6a03428..379472fc 100644 --- a/src/components/call-forwarding/CscCfGroupConditionOfficeHours.vue +++ b/src/components/call-forwarding/CscCfGroupConditionOfficeHours.vue @@ -469,15 +469,13 @@ export default { } }, async deleteTimeSetEvent () { - try { - await this.deleteTimeSet({ - mapping: this.mapping, - id: this.timeSet.id, - subscriberId: this.subscriberId - }) - } catch (e) { - showGlobalError(e) - } + await this.deleteTimeSet({ + mapping: this.mapping, + id: this.timeSet.id, + subscriberId: this.subscriberId + }) + + this.$emit('close') } } } diff --git a/src/components/call-forwarding/CscCfGroupConditionWeekdays.vue b/src/components/call-forwarding/CscCfGroupConditionWeekdays.vue index afb4d71c..0d9d3a17 100644 --- a/src/components/call-forwarding/CscCfGroupConditionWeekdays.vue +++ b/src/components/call-forwarding/CscCfGroupConditionWeekdays.vue @@ -117,6 +117,8 @@ export default { id: this.timeSet.id, subscriberId: this.subscriberId }) + + this.$emit('close') } } } diff --git a/src/components/call-forwarding/CscCfGroupItem.vue b/src/components/call-forwarding/CscCfGroupItem.vue index c712e372..505f9f8e 100644 --- a/src/components/call-forwarding/CscCfGroupItem.vue +++ b/src/components/call-forwarding/CscCfGroupItem.vue @@ -265,7 +265,7 @@ export default { }).onOk(async data => { this.$wait.start(this.waitIdentifier) if (this.destinationSet.destinations.length > 1) { - await this.removeDestination(payload) + await this.triggerRemoveDestination(payload) this.setAnnouncement() } else { this.$emit('delete-last', payload) @@ -273,6 +273,13 @@ export default { this.$wait.end(this.waitIdentifier) }) }, + async triggerRemoveDestination (payload) { + try { + await this.removeDestination(payload) + } catch (e) { + showGlobalError(e.message) + } + }, async updateDestinationTimeoutEvent (payload) { this.$wait.start(this.waitIdentifier) await this.updateDestinationTimeout(payload) diff --git a/src/components/call-forwarding/CscCfGroupTitle.vue b/src/components/call-forwarding/CscCfGroupTitle.vue index 50292d48..a19910d4 100644 --- a/src/components/call-forwarding/CscCfGroupTitle.vue +++ b/src/components/call-forwarding/CscCfGroupTitle.vue @@ -144,7 +144,6 @@ > {{ $t('office hours are') }} <span - :class="clickableClasses" > <q-icon @@ -161,12 +160,15 @@ /> </span> </template> - <span - v-else - :class="clickableClasses" - > - {{ $filters.timeSetTimes(timeSet.times) }} - </span> + <template v-else> + <span :class="clickableClasses"> + {{ $t('Custom time set') }} + <csc-cf-condition-popup-custom + data-cy="csc-condtion-custom" + :times="$filters.timeSetTimes(timeSet.times)" + /> + </span> + </template> </template> <template v-if="!sourceSet || !timeSet" @@ -365,9 +367,10 @@ import CscMoreMenu from 'components/CscMoreMenu' import CscPopupMenuItemDelete from 'components/CscPopupMenuItemDelete' import CscPopupMenuItem from 'components/CscPopupMenuItem' import CscCfConditionPopupAll from 'components/call-forwarding/CscCfConditionPopupAll' -import CscCfConditionPopupDate from 'components/call-forwarding/CscCfConditionPopupDate' import CscCfConditionPopupCallFrom from 'components/call-forwarding/CscCfConditionPopupCallFrom' import CscCfConditionPopupCallNotFrom from 'components/call-forwarding/CscCfConditionPopupCallNotFrom' +import CscCfConditionPopupCustom from 'components/call-forwarding/CscCfConditionPopupCustom' +import CscCfConditionPopupDate from 'components/call-forwarding/CscCfConditionPopupDate' import CscCfConditionPopupDateRange from 'components/call-forwarding/CscCfConditionPopupDateRange' import CscCfConditionPopupWeekdays from 'components/call-forwarding/CscCfConditionPopupWeekdays' import CscCfConditionPopupOfficeHours from 'components/call-forwarding/CscCfConditionPopupOfficeHours' @@ -375,6 +378,7 @@ import destination from 'src/mixins/destination' export default { name: 'CscCfGroupTitle', components: { + CscCfConditionPopupCustom, CscCfConditionPopupOfficeHours, CscCfConditionPopupWeekdays, CscCfConditionPopupDateRange, diff --git a/src/components/pages/CallForward/CscCallForwardDetails.vue b/src/components/pages/CallForward/CscCallForwardDetails.vue index a7c6729b..87468be8 100644 --- a/src/components/pages/CallForward/CscCallForwardDetails.vue +++ b/src/components/pages/CallForward/CscCallForwardDetails.vue @@ -109,7 +109,7 @@ export default { props: { id: { type: String, - default: '' + required: true } }, data () { @@ -146,8 +146,8 @@ export default { return null } }, - mounted () { - this.loadMappingsFull(this.id) + async mounted () { + await this.loadMappingsFull(this.id) }, methods: { ...mapActions('callForwarding', [ diff --git a/src/filters/time-set.js b/src/filters/time-set.js index b49c143b..9b0943b7 100644 --- a/src/filters/time-set.js +++ b/src/filters/time-set.js @@ -34,6 +34,25 @@ export function getDayNameByNumber (dayNumber, isShortName = false) { return isShortName ? daysShortNamesMap[dayNumber] : daysNamesMap[dayNumber] } +export function getMonthNameByNumber (monthNumber) { + const monthsNamesMap = [ + i18n.global.tc('January'), + i18n.global.tc('February'), + i18n.global.tc('March'), + i18n.global.tc('April'), + i18n.global.tc('May'), + i18n.global.tc('June'), + i18n.global.tc('July'), + i18n.global.tc('August'), + i18n.global.tc('September'), + i18n.global.tc('October'), + i18n.global.tc('November'), + i18n.global.tc('December') + ] + + return monthsNamesMap[monthNumber] +} + export function timeSetDateExact (times) { return times[0].year + '/' + times[0].month + '/' + times[0].mday } @@ -73,6 +92,67 @@ export function timeSetOfficeHoursSameTime (times) { return weekdaysStr } -export function timeSetTimes () { - return '...' +export function timeSetTimes (timeSets) { + return timeSets.map((timeSet) => { + const timeSetMap = createTimeSetMap(timeSet) + + const from = formatTimeSetValues(timeSetMap, 'from') + const to = formatTimeSetValues(timeSetMap, 'to') + + return { + from: formatTimeString(from), + to: formatTimeString(to) + } + }) +} + +function createTimeSetMap (timeSet) { + const timeSetMap = { + hour: { from: null, to: null }, + mday: { from: null, to: null }, + minute: { from: null, to: null }, + month: { from: null, to: null }, + wday: { from: null, to: null }, + year: { from: null, to: null } + } + + Object.keys(timeSet).forEach((key) => { + // 1. Case: not set + if (timeSet[key] === null) { + timeSetMap[key] = { from: null, to: null } + // 2. Case: range + } else if (timeSet[key].includes('-')) { + const [from, to] = timeSet[key].split('-') + timeSetMap[key] = { from, to } + // 3. Case: single value + } else { + timeSetMap[key] = { from: timeSet[key], to: null } + } + }) + + return timeSetMap +} + +function formatTimeSetValues (timeSetMap, type) { + const defaultTime = '00' + const defaultDay = 'DD' + const defaultMonth = 'MM' + const defaultYear = 'YYYY' + + return { + year: timeSetMap.year[type] || defaultYear, + month: getMonthNameByNumber(timeSetMap.month[type]) || defaultMonth, + wDay: getDayNameByNumber(timeSetMap.wday[type]) ? `${getDayNameByNumber(timeSetMap.wday[type])},` : '', + mDay: timeSetMap.mday[type] || defaultDay, + hour: formatTime(timeSetMap.hour[type]) || defaultTime, + minutes: formatTime(timeSetMap.minute[type]) || defaultTime + } +} + +function formatTimeString (timeSetValues) { + return `${timeSetValues.mDay} ${timeSetValues.month} ${timeSetValues.year}, ${timeSetValues.wDay} ${timeSetValues.hour}:${timeSetValues.minutes}` +} + +function formatTime (time) { + return (time !== null && time < 10) ? `0${time}` : time } diff --git a/src/helpers/kamailio-timesets-converter.js b/src/helpers/kamailio-timesets-converter.js index 75836c54..75e6fea8 100644 --- a/src/helpers/kamailio-timesets-converter.js +++ b/src/helpers/kamailio-timesets-converter.js @@ -1,4 +1,5 @@ - +// ---- 1. Implementation for Times ranges and day of the week ---- +// ------------------------------------------ /* humanReadableTimeset = [{ weekday: 1..7, @@ -72,7 +73,7 @@ export function validateHumanTimesets (hTimeset) { /** * Function resort timesets by "weekday" and "from" and combines closest timesets or duplicates - * Important! Before use this function please validate you timeses for correctness. + * Important! Before use this function please validate you timesets for correctness. * @param hTimeset {humanReadableTimeset} * @returns {humanReadableTimeset} */ @@ -289,7 +290,11 @@ export function validateKamailioRange (kamailioRangeStr = '', minValue, maxValue } } } - +/** + * Validates Kamailio Timesets with day of week to human readable format + * @param kTimeset {Array} - Kamailio timeset with day of the week, hour and minute + * throws {Error} - if the Kamailio timeset has invalid format + */ export function validateKamailioTimesets (kTimeset) { kTimeset.forEach(timesetItem => { let { wday, hour, minute } = timesetItem @@ -318,11 +323,16 @@ export function validateKamailioTimesets (kTimeset) { }) } +/** +* Converts Kamailio timeset with day of week to human readable format +* @param kTimeset {Array} - Kamailio timeset with day of the week, hour and minute +* retuns {Array} - human readable timeset with weekday, from and to +*/ export function kamailioTimesetToHuman (kTimeset = []) { validateKamailioTimesets(kTimeset) - // convert Kamailio timeset into Human readable format - const hTimesetRaw = kTimeset.map(timesetItem => { + // convert Kamailio timeset into human readable format + const hTimesetRaw = kTimeset.map((timesetItem) => { let { wday, hour, minute } = timesetItem hour = getAsTrimmedString(hour) minute = getAsTrimmedString(minute) @@ -378,7 +388,7 @@ export function kamailioTimesetToHuman (kTimeset = []) { return res } -// ---- implementation for date ranges ---- +// ---- 2. Implementation for date ranges ---- // ------------------------------------------ /* @@ -672,7 +682,11 @@ export function humanDatesetToKamailio (hDateset = []) { return kamailioDateset } - +/** + * Validates Kamailio Datesets Ranges (Year, Month, Day) + * @param kDateset {Array} - Kamailio Dateset (Year, Month, Day) + * throws {Error} - if the Kamailio dateset has invalid format + */ export function validateKamailioDatesets (kDateset) { kDateset.forEach(datesetItem => { let { year, month, mday } = datesetItem @@ -700,12 +714,16 @@ export function validateKamailioDatesets (kDateset) { }) }) } - +/** +* Converts Kamailio Dateset to human readable Date Range format +* @param kDateset {Date} - Kamaillio Dateset with Year, Month and Day +* retun {Array} - human readable data range with from and to year, month and day. +*/ export function kamailioDatesetToHuman (kDateset = []) { validateKamailioDatesets(kDateset) - // convert Kamailio dateset into Human readable format - const hDatesetRaw = kDateset.map(datesetItem => { + // convert Kamailio dateset into human readable format + const hDatesetRaw = kDateset.map((datesetItem) => { let { year, month, mday } = datesetItem year = getAsTrimmedString(year) month = getAsTrimmedString(month) diff --git a/src/i18n/de.json b/src/i18n/de.json index a7c8b63d..7eaa9f4c 100644 --- a/src/i18n/de.json +++ b/src/i18n/de.json @@ -47,8 +47,10 @@ "An error occured while trying to unassign the speed dial slot. Please try again": "Kurzwahl-Eintrag konnte nicht geändert werden. Bitte erneut versuchen", "Application": "Anwendung", "Apps": "Apps", + "April": "April", "Assigned slot {slot}": "Zugewiesene Kurzwahl {slot}", "Attach voicemail to email notification": "Voicemail als Anhang in E-Mail-Benachrichtigung", + "August": "August", "Auto Attendant": "Anrufmenü", "Block Incoming": "Eingehende Anrufe blockieren", "Block Incoming/Outgoing": "Ein-/Ausgehende Anrufe blockieren", @@ -127,12 +129,15 @@ "Custom Announcement": "Benutzerdefinierte Ansage", "Custom Announcements": "Individuelle Ansagen", "Custom sound": "Benutzerdefinierter Sound", + "Custom time set": "Custom time set", + "Custom time sets": "Custom time sets", "Customer Details": "Kunden-Details", "Customer Phonebook": "Customer Phonebook", "Daily": "Täglich", "Dashboard": "Übersicht", "Data is in the clipboard": "Daten wurden in die Zwischenablage kopiert", "Data loading error": "Fehler beim Laden von Daten", + "December": "Dezember", "Default": "Standard", "Default sound": "Standard-Sound", "Default sound set for all seats and groups": "Standard-Sound-Set für alle Nebenstellen und Gruppen", @@ -176,6 +181,7 @@ "End time": "Endzeit", "English": "Deutsch", "Enter a number to dial": "Geben Sie eine Telefonnummer zum Anwählen an", + "Entity belongs to admin": "Diese Einheit gehört dem Admin", "Expires": "Läuft aus", "Extension": "Durchwahl", "Extension Settings": "Erweiterungseinstellungen", @@ -185,6 +191,7 @@ "Fax to mail and sendfax": "„Fax to Mail“ und „Sendfax“", "Fax2Mail": "Fax2Mail", "Faxes": "Faxe", + "February": "Februar", "File": "Datei", "File Type": "Dateityp", "Filter": "Filtern", @@ -251,8 +258,11 @@ "Input a valid phone number": "Geben Sie eine gültige Telefonnummer ein", "Interval when the secret key is automatically renewed.": "Zeitraum, nach dem der Geheimschlüssel automatisch erneuert wird.", "Italian": "Italienisch", + "January": "Januar", "Join conference": "Konferenz beitreten", "Join conference with name": "Konferenz beitreten mit Name", + "July": "Juli", + "June": "Juni", "Lamp/Key": "Lampe/Taste", "Lamps/Keys": "Lampen/Tasten", "Language": "Sprache", @@ -272,8 +282,10 @@ "Manager Secretary": "Geschäftsführungssekretariat", "Manager Secretary feature": "Manager Sekretär Funktion", "ManagerSecretary": "Geschäftsführungssekretariat", + "March": "März", "Maximum allowed extension is {max}": "Die maximal zulässige Länge der Durchwahl ist {max}", "Maximum calls in queue": "Maximale Anzahl an Anrufen in der Warteschlange", + "May": "Mai", "Me": "Ich", "Messages": "Nachrichten", "Minimum allowed extension is {min}": "Die minimal zulässige Länge der Durchwahlnummer ist {min}", @@ -327,10 +339,12 @@ "No speed dials found": "Keine Kurzwahl gefunden", "Normal": "Normal", "Not modified yet": "Bisher nicht geändert", + "November": "November", "Number": "Nummer", "Number list": "Nummernliste", "Number list name": "Name der Nummernliste", "Numbers": "Nummern", + "October": "Oktober", "Office Hours Announcement": "Bürozeiten Ansage", "On weekdays": "An Werktagen", "Only incoming calls from listed numbers are allowed": "Es sind nur eingehende Anrufe von aufgelisteten Nummern erlaubt", @@ -351,6 +365,7 @@ "Password confirm": "Passwort bestätigen", "Password is not strong enough": "Passwort ist nicht sicher genug", "Passwords must be equal": "Passwörter müssen übereinstimmen", + "Period": "Period", "Phone model": "Telefonmodell", "Phone number": "Rufnummer", "Pilot": "Hauptteilnehmer", @@ -448,6 +463,7 @@ "Send": "Senden", "Send Fax": "Sende Fax", "Sending fax completed successfully.": "Fax wurde erfolgreich gesendet.", + "September": "September", "Serial Ringing": "Serielles Klingeln", "Session expired, please login again": "Sitzung abgelaufen, bitte erneut anmelden", "Set your Extension settings": "Legen Sie Ihre Erweiterungseinstellungen fest", diff --git a/src/i18n/en.json b/src/i18n/en.json index 3918a1cd..5a1e4cf8 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -45,8 +45,10 @@ "An error occured while trying to send the fax. Please try again": "An error occured while trying to send the fax. Please try again", "An error occured while trying to unassign the speed dial slot. Please try again": "An error occured while trying to unassign the speed dial slot. Please try again", "Apps": "Apps", + "April": "April", "Assigned slot {slot}": "Assigned slot {slot}", "Attach voicemail to email notification": "Attach voicemail to email notification", + "August": "August", "Auto Attendant": "Auto Attendant", "Block Incoming": "Block Incoming", "Block Incoming/Outgoing": "Block Incoming/Outgoing", @@ -118,11 +120,14 @@ "Custom Announcement": "Custom Announcement", "Custom Announcements": "Custom Announcements", "Custom sound": "Custom sound", + "Custom time set": "Custom time set", + "Custom time sets": "Custom time sets", "Customer Details": "Customer Details", "Daily": "Daily", "Dashboard": "Dashboard", "Data is in the clipboard": "Data is in the clipboard", "Data loading error": "Data loading error", + "December": "December", "Default": "Default", "Default sound": "Default sound", "Default sound set for all seats and groups": "Default sound set for all seats and groups", @@ -162,6 +167,7 @@ "End time": "End time", "English": "English", "Enter a number to dial": "Enter a number to dial", + "Entity belongs to admin": "Entity belongs to admin", "Expires": "Expires", "Extension": "Extension", "Extension Settings": "Extension Settings", @@ -170,6 +176,7 @@ "Fax to mail and sendfax": "Fax to Mail and Sendfax", "Fax2Mail": "Fax2Mail", "Faxes": "Faxes", + "February": "February", "File": "File", "File Type": "File Type", "Filter": "Filter", @@ -233,6 +240,9 @@ "Input a valid phone number": "Input a valid phone number", "Interval when the secret key is automatically renewed.": "Interval when the secret key is automatically renewed.", "Italian": "Italian", + "January": "January", + "July": "July", + "June": "June", "Lamp/Key": "Lamp/Key", "Lamps/Keys": "Lamps/Keys", "Language": "Language", @@ -249,8 +259,10 @@ "Mail to Fax": "Mail to Fax", "Manager Secretary": "Manager Secretary", "Manager Secretary feature": "Manager Secretary feature", + "March": "March", "Maximum allowed extension is {max}": "Maximum allowed extension is {max}", "Maximum calls in queue": "Maximum calls in queue", + "May": "May", "Me": "Me", "Messages": "Messages", "Minimum allowed extension is {min}": "Minimum allowed extension is {min}", @@ -299,10 +311,12 @@ "No speed dials found": "No speed dials found", "Normal": "Normal", "Not modified yet": "Not modified yet", + "November": "November", "Number": "Number", "Number list": "Number list", "Number list name": "Number list name", "Numbers": "Numbers", + "October": "October", "Office Hours Announcement": "Office Hours Announcement", "On weekdays": "On weekdays", "Only incoming calls from listed numbers are allowed": "Only incoming calls from listed numbers are allowed", @@ -321,6 +335,7 @@ "Password confirm": "Password confirm", "Password is not strong enough": "Password is not strong enough", "Passwords must be equal": "Passwords must be equal", + "Period": "Period", "Phone model": "Phone model", "Phone number": "Phone number", "Pilot": "Pilot", @@ -412,6 +427,7 @@ "Send": "Send", "Send Fax": "Send Fax", "Sending fax completed successfully.": "Sending fax completed successfully.", + "September": "September", "Serial Ringing": "Serial Ringing", "Session expired, please login again": "Session expired, please login again", "Set your Extension settings": "Set your Extension settings", diff --git a/src/i18n/es.json b/src/i18n/es.json index 658d03d1..5d435f63 100644 --- a/src/i18n/es.json +++ b/src/i18n/es.json @@ -47,8 +47,10 @@ "An error occured while trying to unassign the speed dial slot. Please try again": "Se produjo un error al intentar remover la ranura de marcación rápida. Por favor, inténtelo nuevamente.", "Application": "Aplicación", "Apps": "Aplicaciones", + "April": "Abril", "Assigned slot {slot}": "Ranura {slot} asignada", "Attach voicemail to email notification": "Adjuntar correo de voz a notificación de correo electrónico", + "August": "Agosto", "Auto Attendant": "Asistente Automático", "Block Incoming": "Bloquear Entrantes", "Block Incoming/Outgoing": "Bloquear Entrantes/Salientes", @@ -127,12 +129,15 @@ "Custom Announcement": "Anuncio Personalizado", "Custom Announcements": "Anuncios Personalizados", "Custom sound": "Sonido personalizado", + "Custom time set": "Custom time set", + "Custom time sets": "Custom time sets", "Customer Details": "Detalles de cliente", "Customer Phonebook": "Customer Phonebook", "Daily": "Diariamente", "Dashboard": "Tablero", "Data is in the clipboard": "Data is in the clipboard", "Data loading error": "Data loading error", + "December": "Diciembre", "Default": "Predeterminado", "Default sound": "Sonido predeterminado", "Default sound set for all seats and groups": "Conjunto de sonido predeterminado para todos los asientos y grupos", @@ -176,6 +181,7 @@ "End time": "Hora de finalización", "English": "Español", "Enter a number to dial": "Introduzca un número para marcar", + "Entity belongs to admin": "Esta entidad pertenece a admin", "Expires": "Expira", "Extension": "Extensión", "Extension Settings": "Configuración de la extensión", @@ -185,6 +191,7 @@ "Fax to mail and sendfax": "Fax a Correo y Envío de Fax", "Fax2Mail": "Fax2Mail", "Faxes": "Faxes", + "February": "Febrero", "File": "Archivo", "File Type": "Tipos de archivo", "Filter": "Filtrar", @@ -251,8 +258,11 @@ "Input a valid phone number": "Ingrese un número de teléfono válido", "Interval when the secret key is automatically renewed.": "Intervalo en el que la clave secreta se renueva automáticamente.", "Italian": "Italiano", + "January": "Enero", "Join conference": "Unirse a la conferencia", "Join conference with name": "Unirse a la conferencia con nombre", + "July": "Julio", + "June": "Junio", "Lamp/Key": "Indicador/Tecla", "Lamps/Keys": "Indicadores/Teclas", "Language": "Idioma", @@ -273,8 +283,10 @@ "Manager Secretary": "Jefe-Asistente", "Manager Secretary feature": "Manager Secretary feature", "ManagerSecretary": "Jefe-Asistente", + "March": "Marzo", "Maximum allowed extension is {max}": "La extensión máxima permitida es {max}", "Maximum calls in queue": "Máximo de llamadas en cola", + "May": "Mayo", "Me": "Me", "Messages": "Messages", "Minimum allowed extension is {min}": "La extensión mínima permitida es {min}", @@ -326,10 +338,12 @@ "No speed dials found": "No se encontraron marcaciones rápidas", "Normal": "Normal", "Not modified yet": "No se ha modificado todavía", + "November": "Noviembre", "Number": "Número", "Number list": "Lista de números", "Number list name": "Nombre de la lista de números", "Numbers": "Números", + "October": "Octubre", "Office Hours Announcement": "Office Hours Announcement", "On weekdays": "En días de la semana", "Only incoming calls from listed numbers are allowed": "Permitir solo los números listados", @@ -350,6 +364,7 @@ "Password confirm": "Password confirm", "Password is not strong enough": "La contraseña no es lo suficientemente fuerte", "Passwords must be equal": "Las contraseñas deben ser iguales", + "Period": "Period", "Phone model": "Modelo de teléfono", "Phone number": "Número de teléfono", "Pilot": "Piloto", @@ -448,6 +463,7 @@ "Send": "Enviar", "Send Fax": "Enviar Fax", "Sending fax completed successfully.": "Envío de fax completado exitosamente.", + "September": "Septiembre", "Serial Ringing": "Llamada en serie", "Session expired, please login again": "Session expired, please login again", "Session language successfully changed": "Idioma de la sesión modificado exitosamente.", diff --git a/src/i18n/fr.json b/src/i18n/fr.json index 015d97c5..14ed74ff 100644 --- a/src/i18n/fr.json +++ b/src/i18n/fr.json @@ -47,8 +47,10 @@ "An error occured while trying to unassign the speed dial slot. Please try again": "Une erreur est survenue lors de la séassignation de l'emplacement de numérotation abrégée. Veuillez réessayer", "Application": "Application", "Apps": "Apps", + "April": "Avril", "Assigned slot {slot}": "Emplacement {slot} attribué", "Attach voicemail to email notification": "Joindre le message vocal à l'e-mail de notification", + "August": "Août", "Auto Attendant": "Association auto", "Block Incoming": "Bloquer les appels entrants", "Block Incoming/Outgoing": "Bloquer les entrants/sortants", @@ -127,12 +129,15 @@ "Custom Announcement": "Annonce personnalisée", "Custom Announcements": "Annonces personnalisées", "Custom sound": "Son personnalisé", + "Custom time set": "Custom time set", + "Custom time sets": "Custom time sets", "Customer Details": "Détails du client", "Customer Phonebook": "Annuaire du client", "Daily": "Quotidien", "Dashboard": "Tableau de bord", "Data is in the clipboard": "Données dans le presse-papiers", "Data loading error": "Data loading error", + "December": "Décembre", "Default": "Défaut", "Default sound": "Son par défaut", "Default sound set for all seats and groups": "Son par défaut défini pour tous les sièges et groupes", @@ -176,6 +181,7 @@ "End time": "Date de fin", "English": "Français", "Enter a number to dial": "Enter a number to dial", + "Entity belongs to admin": "Cette entité appartient à l’administrateur", "Expires": "Expire", "Extension": "Extension", "Extension Settings": "Paramètres des extensions", @@ -185,6 +191,7 @@ "Fax to mail and sendfax": "Fax à E-mail et Sendfax", "Fax2Mail": "Fax2Mail", "Faxes": "Télécopies", + "February": "Février", "File": "Fichier", "File Type": "Type de fichier", "Filter": "Filtrer", @@ -251,8 +258,11 @@ "Input a valid phone number": "Saisissez un numéro de téléphone valide", "Interval when the secret key is automatically renewed.": "Intervalle où la clé secrète est automatiquement renouvelée.", "Italian": "Italien", + "January": "Janvier", "Join conference": "Rejoindre la conférence", "Join conference with name": "Rejoindre la conférence avec le nom", + "July": "Juillet", + "June": "Juin", "Lamp/Key": "Lampe/clé", "Lamps/Keys": "Lampes/clés", "Language": "Langue", @@ -272,8 +282,10 @@ "Manager Secretary": "Manager Secretary", "Manager Secretary feature": "Manager Secretary feature", "ManagerSecretary": "ManagerSecretary", + "March": "Mars", "Maximum allowed extension is {max}": "L'extension maximale autorisée est de {max}", "Maximum calls in queue": "Nombre maximum d'appels dans la file d'attente", + "May": "Mai", "Me": "Me", "Messages": "Messages", "Minimum allowed extension is {min}": "L'extension minimale autorisée est de {min}", @@ -327,10 +339,12 @@ "No speed dials found": "Aucun numéro abrégé trouvé", "Normal": "Normal", "Not modified yet": "Pas encore modifié", + "November": "Novembre", "Number": "Numéro", "Number list": "Liste de numéros", "Number list name": "Nom de la liste de numéros", "Numbers": "Nombres", + "October": "Octobre", "Office Hours Announcement": "Office Hours Announcement", "On weekdays": "Les jours de semaine", "Only incoming calls from listed numbers are allowed": "Seuls les appels entrants provenant des numéros listés sont autorisés", @@ -351,6 +365,7 @@ "Password confirm": "Password confirm", "Password is not strong enough": "Le mot de passe n'est pas assez fort", "Passwords must be equal": "Les mots de passe doivent être égaux", + "Period": "Period", "Phone model": "Modèle du poste", "Phone number": "Numéro de téléphone", "Pilot": "Pilote", @@ -448,6 +463,7 @@ "Send": "Envoyer", "Send Fax": "Envoyer un fax", "Sending fax completed successfully.": "Le Fax a été envoyé avec succès.", + "September": "Septembre", "Serial Ringing": "Sonnerie en série", "Session expired, please login again": "Session expired, please login again", "Set your Extension settings": "Définir les paramètres de votre extensions", diff --git a/src/i18n/it.json b/src/i18n/it.json index 8225acc0..177e8cb3 100644 --- a/src/i18n/it.json +++ b/src/i18n/it.json @@ -45,8 +45,10 @@ "An error occured while trying to send the fax. Please try again": "Si è verificato un errore durante l'invio del fax. Si prega di riprovare", "An error occured while trying to unassign the speed dial slot. Please try again": "Si è verificato un errore nella cancellazione della selezione rapida. Si prega di riprovare", "Apps": "Apps", + "April": "Aprile", "Assigned slot {slot}": "Slot assegnato: {slot}", "Attach voicemail to email notification": "Allega messaggio vocale all'email di notifica", + "August": "Agosto", "Auto Attendant": "Risponditore Automatico", "Block Incoming": "Blocca entranti", "Block Incoming/Outgoing": "Blocca entranti/uscenti", @@ -125,12 +127,15 @@ "Custom Announcement": "Custom Announcement", "Custom Announcements": "Custom Announcements", "Custom sound": "Audio personalizzato", + "Custom time set": "Custom time set", + "Custom time sets": "Custom time sets", "Customer Details": "Dettagli cliente", "Customer Phonebook": "Rubrica cliente", "Daily": "Giornaliero", "Dashboard": "Dashboard", "Data is in the clipboard": "I dati sono negli appunti", "Data loading error": "Errore nel caricamento dei dati", + "December": "Dicembre", "Default": "Predefinito", "Default sound": "Audio predefinito", "Default sound set for all seats and groups": "Set di suoni predefinito per tutte le postazioni e i gruppi", @@ -173,6 +178,7 @@ "End time": "End time", "English": "Italiano", "Enter a number to dial": "Inserisci un numero per chiamare", + "Entity belongs to admin": "Questa entità appartiene ad admin", "Expires": "Scade", "Extension": "Interno", "Extension Settings": "Impostazioni dell'Estensione", @@ -182,6 +188,7 @@ "Fax to mail and sendfax": "Fax to mail and sendfax", "Fax2Mail": "Fax2Mail", "Faxes": "Fax", + "February": "Febbraio", "File": "File", "File Type": "File Type", "Filter": "Filtra", @@ -248,7 +255,10 @@ "Input a valid phone number": "Inserire un numero di telefono valido", "Interval when the secret key is automatically renewed.": "Interval when the secret key is automatically renewed.", "Italian": "Italian", + "January": "Gennaio", "Join conference with name": "Partecipa alla conferenza con nome", + "July": "Luglio", + "June": "Giugno", "Lamp/Key": "Lampada/Tasto", "Lamps/Keys": "Lampade/Tasti", "Language": "Lingua", @@ -267,8 +277,10 @@ "Mail to Fax": "Mail to Fax", "Manager Secretary": "Segreteria", "Manager Secretary feature": "Manager Secretary feature", + "March": "Marzo", "Maximum allowed extension is {max}": "Maximum allowed extension is {max}", "Maximum calls in queue": "Numero massimo di chiamate in coda", + "May": "Maggio", "Me": "Me", "Messages": "Messages", "Minimum allowed extension is {min}": "Minimum allowed extension is {min}", @@ -320,10 +332,12 @@ "No speed dials found": "Nessuna impostazione di chiamata rapida", "Normal": "Normale", "Not modified yet": "Not modified yet", + "November": "Novembre", "Number": "Numero", "Number list": "Number list", "Number list name": "Number list name", "Numbers": "Numeri", + "October": "Ottobre", "Office Hours Announcement": "Office Hours Announcement", "On weekdays": "Nei giorni feriali", "Only incoming calls from listed numbers are allowed": "Solo ammesse solo chiamate dai numeri in elenco", @@ -343,7 +357,14 @@ "Password changed successfully": "Password changed successfully", "Password confirm": "Password confirm", "Password is not strong enough": "Password is not strong enough", - "Passwords must be equal": "Passwords must be equal", + "Password is not strong enough, add more digits": "Password is not strong enough, add more digits", + "Password is not strong enough, add more lowercase letters": "Password is not strong enough, add more lowercase letters", + "Password is not strong enough, add more special characters": "Password is not strong enough, add more special characters", + "Password is not strong enough, add more uppercase letters": "Password is not strong enough, add more uppercase letters", + "Password must be at least {max} characters long": "Password must be at least {max} characters long", + "Password must be at least {min} characters long": "Password must be at least {min} characters long", + "Passwords must be equal": "Le passwords devono essere identiche", + "Period": "Period", "Phone model": "Modello telefono", "Phone number": "Numero di telefono", "Pilot": "Pilota", @@ -441,6 +462,7 @@ "Send": "Invia", "Send Fax": "Invia fax", "Sending fax completed successfully.": "Fax inviato correttamente.", + "September": "Settembre", "Serial Ringing": "Chiamata in sequenza", "Session expired, please login again": "Session expired, please login again", "Set your fax settings": "Set your fax settings", diff --git a/src/pages/CscPageCf.vue b/src/pages/CscPageCf.vue index daf1dfda..cc466c20 100644 --- a/src/pages/CscPageCf.vue +++ b/src/pages/CscPageCf.vue @@ -90,16 +90,12 @@ </template> <script> import CscCfGroup from 'components/call-forwarding/CscCfGroup' -import { - mapActions, - mapState, - mapGetters -} from 'vuex' import CscPopupMenuItem from 'components/CscPopupMenuItem' import CscPopupMenu from 'components/CscPopupMenu' import CscSpinner from 'components/CscSpinner' import CscCfGroupItemPrimaryNumber from 'components/call-forwarding/CscCfGroupItemPrimaryNumber' import CscPageSticky from 'components/CscPageSticky' +import { mapActions, mapGetters, mapState } from 'vuex' export default { name: 'CscPageCf', components: { diff --git a/src/pages/CscPagePbxGroupDetails.vue b/src/pages/CscPagePbxGroupDetails.vue index d1c4e181..341a3413 100644 --- a/src/pages/CscPagePbxGroupDetails.vue +++ b/src/pages/CscPagePbxGroupDetails.vue @@ -242,6 +242,7 @@ <csc-call-forward-details v-else :id="id" + :key="id" /> </csc-page-sticky-tabs> </template> @@ -373,6 +374,13 @@ export default { } }, watch: { + async $route (to) { + if (this.id !== to.params.id) { + this.id = to.params.id + this.selectGroup(this.id) + await this.loadMappingsFull(this.id) + } + }, groupSelected () { this.changes = this.getGroupData() this.soundSet = this.getSoundSetByGroupId(this.groupSelected.id) @@ -385,9 +393,9 @@ export default { } } }, - mounted () { + async mounted () { this.selectGroup(this.id) - this.loadMappingsFull(this.id) + await this.loadMappingsFull(this.id) }, beforeUnmount () { this.resetSelectedGroup() diff --git a/src/pages/CscPagePbxSeatDetails.vue b/src/pages/CscPagePbxSeatDetails.vue index f959af00..baf1b288 100644 --- a/src/pages/CscPagePbxSeatDetails.vue +++ b/src/pages/CscPagePbxSeatDetails.vue @@ -297,6 +297,7 @@ <csc-call-forward-details v-else :id="id" + :key="id" /> </csc-page-sticky-tabs> </template> @@ -392,7 +393,14 @@ export default { 'getCurrentCli', 'getIntraPbx', 'getSeatUpdateToastMessage', - 'isSeatLoading' + 'isSeatLoading', + 'isSeatMapByIdEmpty', + 'getAnnouncementCfu', + 'getAnnouncementCallSetup', + 'getAnnouncementToCallee', + 'getIgnoreCfWhenHunting', + 'getCstaClient', + 'getCstaController' ]), ...mapGetters('pbx', [ 'getExtensionHint', @@ -499,6 +507,12 @@ export default { } }, watch: { + async $route (to) { + if (this.id !== to.params.id) { + this.id = to.params.id + this.selectSeat(this.id) + } + }, seatSelected () { this.soundSet = this.getSoundSetBySeatId(this.seatSelected.id) this.loadPreferences(this.seatSelected.id).then((preferences) => { @@ -546,7 +560,11 @@ export default { } }, async mounted () { - this.selectSeat(this.id) + if (this.isSeatMapByIdEmpty) { + await this.loadSeatListItems() + } + + this.selectSeat(this.$route.params.id) await this.loadAnnouncements() // await this.getNcosLevelsSubscriber() await this.getNcosSetSubscriber() @@ -564,6 +582,7 @@ export default { 'setIntraPbx', 'setMusicOnHold', 'setSeatSoundSet', + 'loadSeatListItems', 'loadPreferences', 'setCli', 'setNcosSet', diff --git a/src/store/call-forwarding/actions.js b/src/store/call-forwarding/actions.js index 30f236c1..222c7dc8 100644 --- a/src/store/call-forwarding/actions.js +++ b/src/store/call-forwarding/actions.js @@ -19,14 +19,17 @@ import { cfUpdateTimeSetWeekdays } from 'src/api/call-forwarding' import { - v4 -} from 'uuid' -import { + get, + getList, patchReplace, patchReplaceFull, - post, put, get, getList + post, + put } from 'src/api/common' import _ from 'lodash' +import { i18n } from 'src/boot/i18n' +import { showGlobalError, showGlobalWarning } from 'src/helpers/ui' +import { v4 } from 'uuid' const DEFAULT_RING_TIMEOUT = 60 const DEFAULT_PRIORITY = 0 @@ -44,19 +47,16 @@ function createDefaultDestination (destination, defaultAnnouncementId) { return payload } -export async function loadMappingsFull ({ dispatch, commit, rootGetters }, subscriberId) { +export async function loadMappingsFull ({ dispatch, commit, rootGetters }, id) { dispatch('wait/start', WAIT_IDENTIFIER, { root: true }) - let res = null - if (subscriberId) { - res = await cfLoadMappingsFull(subscriberId) - } else { - res = await cfLoadMappingsFull(rootGetters['user/getSubscriberId']) - } + const subscriberId = id || rootGetters['user/getSubscriberId'] + const mappingData = await cfLoadMappingsFull(subscriberId) + commit('dataSucceeded', { - mappings: res[0], - destinationSets: res[1].items, - sourceSets: res[2].items, - timeSets: res[3].items + mappings: mappingData[0], + destinationSets: mappingData[1].items, + sourceSets: mappingData[2].items, + timeSets: mappingData[3].items }) dispatch('wait/end', WAIT_IDENTIFIER, { root: true }) } @@ -116,7 +116,19 @@ export async function deleteMapping ({ dispatch, commit, state, rootGetters }, p fieldPath: payload.type, value: updatedMappings }) - await cfDeleteDestinationSet(payload.destinationset_id) + + try { + await cfDeleteDestinationSet(payload.destinationset_id) + } catch (e) { + if (e.code === 404 && e.message === 'Entity \'cfdestinationset\' not found.') { + // This happens when CF was set by Admin therefore current + // csc user doesn't have rights to delete the entity + showGlobalWarning(i18n.global.tc('Entity belongs to admin')) + } else { + showGlobalError(e.message) + } + } + const destinationSets = await cfLoadDestinationSets() commit('dataSucceeded', { mappings: patchRes, @@ -141,8 +153,8 @@ export async function toggleMapping ({ dispatch, commit, state, rootGetters }, p dispatch('wait/end', WAIT_IDENTIFIER, { root: true }) } -export async function updateDestination ({ dispatch, commit, state, rootGetters }, payload) { - dispatch('wait/start', WAIT_IDENTIFIER, { root: true }) +export async function updateDestination ({ dispatch, commit, state }, payload) { + dispatch('wait/start', 'csc-cf-destination-set-update', { root: true }) const destinations = _.cloneDeep(state.destinationSetMap[payload.destinationSetId].destinations) destinations[payload.destinationIndex].destination = payload.destination await patchReplace({ @@ -155,7 +167,7 @@ export async function updateDestination ({ dispatch, commit, state, rootGetters commit('dataSucceeded', { destinationSets: destinationSets.items }) - dispatch('wait/end', WAIT_IDENTIFIER, { root: true }) + dispatch('wait/end', 'csc-cf-destination-set-update', { root: true }) } export async function addDestination ({ dispatch, commit, state, rootGetters }, payload) { @@ -191,8 +203,8 @@ export async function rewriteDestination ({ dispatch, commit, state, rootGetters } } -export async function removeDestination ({ dispatch, commit, state, rootGetters }, payload) { - dispatch('wait/start', WAIT_IDENTIFIER, { root: true }) +export async function removeDestination ({ dispatch, commit, state }, payload) { + dispatch('wait/start', 'csc-cf-destination-set-remove', { root: true }) const destinations = _.cloneDeep(state.destinationSetMap[payload.destinationSetId].destinations) const updatedDestinations = destinations.reduce(($updatedDestinations, value, index) => { if (index !== payload.destinationIndex) { @@ -210,19 +222,23 @@ export async function removeDestination ({ dispatch, commit, state, rootGetters commit('dataSucceeded', { destinationSets: destinationSets.items }) - dispatch('wait/end', WAIT_IDENTIFIER, { root: true }) + dispatch('wait/end', 'csc-cf-destination-set-remove', { root: true }) } -export async function updateDestinationTimeout ({ dispatch, commit, state, rootGetters }, payload) { +export async function updateDestinationTimeout ({ dispatch, commit, state }, payload) { dispatch('wait/start', WAIT_IDENTIFIER, { root: true }) const destinations = _.cloneDeep(state.destinationSetMap[payload.destinationSetId].destinations) destinations[payload.destinationIndex].timeout = payload.destinationTimeout - await patchReplace({ - resource: 'cfdestinationsets', - resourceId: payload.destinationSetId, - fieldPath: 'destinations', - value: destinations - }) + try { + await patchReplace({ + resource: 'cfdestinationsets', + resourceId: payload.destinationSetId, + fieldPath: 'destinations', + value: destinations + }) + } catch (e) { + showGlobalError(e.message) + } const destinationSets = await cfLoadDestinationSets() commit('dataSucceeded', { destinationSets: destinationSets.items @@ -230,7 +246,7 @@ export async function updateDestinationTimeout ({ dispatch, commit, state, rootG dispatch('wait/end', WAIT_IDENTIFIER, { root: true }) } -export async function loadSourceSets ({ dispatch, commit, rootGetters }) { +export async function loadSourceSets ({ dispatch, commit }) { dispatch('wait/start', 'csc-cf-sourcesets', { root: true }) const sourceSets = await cfLoadSourceSets() commit('dataSucceeded', { @@ -261,7 +277,7 @@ export async function createSourceSet ({ dispatch, commit, rootGetters, state }, } } -export async function updateSourceSet ({ dispatch, commit, rootGetters, state }, payload) { +export async function updateSourceSet ({ dispatch, commit, rootGetters }, payload) { try { dispatch('wait/start', 'csc-cf-source-set-create', { root: true }) await cfUpdateSourceSet(rootGetters['user/getSubscriberId'], payload) @@ -269,6 +285,14 @@ export async function updateSourceSet ({ dispatch, commit, rootGetters, state }, commit('dataSucceeded', { sourceSets: sourceSets.items }) + } catch (e) { + if (e.code === 404 && e.message === 'Entity \'sourceset\' not found.') { + // This happens when CF was set by Admin therefore current + // csc user doesn't have rights to delete the entity + showGlobalWarning(i18n.global.tc('Entity belongs to admin')) + } else { + showGlobalError(e.message) + } } finally { dispatch('wait/end', 'csc-cf-source-set-create', { root: true }) } @@ -292,6 +316,8 @@ export async function deleteSourceSet ({ dispatch, commit, rootGetters, state }, mappings: updatedMappings, sourceSets: sourceSets.items }) + } catch (e) { + showGlobalError(e.message) } finally { dispatch('wait/end', 'csc-cf-source-set-create', { root: true }) } @@ -355,14 +381,19 @@ export async function createTimeSetDate ({ dispatch, commit, rootGetters, state dispatch('wait/end', 'csc-cf-time-set-create', { root: true }) } -export async function updateTimeSetDate ({ dispatch, commit, rootGetters, state }, payload) { +export async function updateTimeSetDate ({ dispatch, commit }, payload) { dispatch('wait/start', 'csc-cf-time-set-create', { root: true }) - await cfUpdateTimeSetDate(payload.id, payload.date) - const timeSets = await cfLoadTimeSets() - commit('dataSucceeded', { - timeSets: timeSets.items - }) - dispatch('wait/end', 'csc-cf-time-set-create', { root: true }) + try { + await cfUpdateTimeSetDate(payload.id, payload.date) + const timeSets = await cfLoadTimeSets() + commit('dataSucceeded', { + timeSets: timeSets.items + }) + } catch (e) { + showGlobalError(e.message) + } finally { + dispatch('wait/end', 'csc-cf-time-set-create', { root: true }) + } } export async function deleteTimeSet ({ dispatch, commit, rootGetters, state }, payload) { @@ -376,7 +407,17 @@ export async function deleteTimeSet ({ dispatch, commit, rootGetters, state }, p fieldPath: payload.mapping.type, value: updatedMapping }) - await cfDeleteTimeSet(payload.id) + try { + await cfDeleteTimeSet(payload.id) + } catch (e) { + if (e.code === 404 && e.message === 'Entity \'cftimeset\' not found.') { + // This happens when CF was set by Admin therefore current + // csc user doesn't have rights to delete the entity + showGlobalWarning(i18n.global.tc('Entity belongs to admin')) + } else { + showGlobalError(e.message) + } + } const timeSets = await cfLoadTimeSets() commit('dataSucceeded', { mappings: updatedMappings, @@ -416,6 +457,8 @@ export async function doNotRingPrimaryNumber ({ commit, rootGetters, state }, pa } export async function updateRingTimeout ({ commit, rootGetters, state }, payload) { + // eslint-disable-next-line no-console + console.debug('aaa') const updatedMappings = await patchReplaceFull({ resource: 'cfmappings', resourceId: (payload.subscriberId) ? payload.subscriberId : rootGetters['user/getSubscriberId'], @@ -446,9 +489,20 @@ export async function createTimeSetDateRange ({ dispatch, commit, rootGetters, s dispatch('wait/end', 'csc-cf-time-set-create', { root: true }) } -export async function updateTimeSetDateRange ({ dispatch, commit, rootGetters, state }, payload) { +export async function updateTimeSetDateRange ({ dispatch, commit }, payload) { dispatch('wait/start', 'csc-cf-time-set-create', { root: true }) - await cfUpdateTimeSetDateRange(payload.id, payload.date) + try { + await cfUpdateTimeSetDateRange(payload.id, payload.date) + } catch (e) { + if (e.code === 404 && e.message === 'Entity \'timeset\' not found.') { + // This happens when CF was set by Admin therefore current + // csc user doesn't have rights to delete the entity + showGlobalWarning(i18n.global.tc('Entity belongs to admin')) + } else { + showGlobalError(e.message) + } + } + const timeSets = await cfLoadTimeSets() commit('dataSucceeded', { timeSets: timeSets.items @@ -475,9 +529,20 @@ export async function createTimeSetWeekdays ({ dispatch, commit, rootGetters, st dispatch('wait/end', 'csc-cf-time-set-create', { root: true }) } -export async function updateTimeSetWeekdays ({ dispatch, commit, rootGetters, state }, payload) { +export async function updateTimeSetWeekdays ({ dispatch, commit }, payload) { dispatch('wait/start', 'csc-cf-time-set-create', { root: true }) - await cfUpdateTimeSetWeekdays(payload.id, payload.weekdays) + try { + await cfUpdateTimeSetWeekdays(payload.id, payload.weekdays) + } catch (e) { + if (e.code === 404 && e.message === 'Entity \'timeset\' not found.') { + // This happens when CF was set by Admin therefore current + // csc user doesn't have rights to delete the entity + showGlobalWarning(i18n.global.tc('Entity belongs to admin')) + } else { + showGlobalError(e.message) + } + } + const timeSets = await cfLoadTimeSets() commit('dataSucceeded', { timeSets: timeSets.items @@ -499,7 +564,7 @@ export async function createOfficeHours ({ dispatch, commit, rootGetters, state if (payload.id) { await cfDeleteTimeSet(payload.id) } - const timeSets = await cfLoadTimeSets(rootGetters['user/getSubscriberId']) + const timeSets = await cfLoadTimeSets() commit('dataSucceeded', { mappings: updatedMappings, timeSets: timeSets.items @@ -509,8 +574,13 @@ export async function createOfficeHours ({ dispatch, commit, rootGetters, state export async function updateOfficeHours ({ dispatch, commit, rootGetters, state }, payload) { dispatch('wait/start', 'csc-cf-time-set-create', { root: true }) - await cfUpdateOfficeHours(payload.id, payload.times) - const timeSets = await cfLoadTimeSets(rootGetters['user/getSubscriberId']) + try { + await cfUpdateOfficeHours(payload.id, payload.times) + } catch (e) { + showGlobalError(e.message) + } + + const timeSets = await cfLoadTimeSets() commit('dataSucceeded', { timeSets: timeSets.items }) @@ -543,15 +613,20 @@ export async function getAnnouncementById ({ dispatch, commit, rootGetters, stat } } -export async function updateAnnouncement ({ dispatch, commit, rootGetters, state }, payload) { - const destinations = _.cloneDeep(state.destinationSetMap[payload.destinationSetId].destinations) - destinations[payload.destinationIndex].announcement_id = payload.announcementId - await patchReplace({ - resource: 'cfdestinationsets', - resourceId: payload.destinationSetId, - fieldPath: 'destinations', - value: destinations - }) +export async function updateAnnouncement ({ dispatch, commit, state }, payload) { + try { + const destinations = _.cloneDeep(state.destinationSetMap[payload.destinationSetId].destinations) + destinations[payload.destinationIndex].announcement_id = payload.announcementId + await patchReplace({ + resource: 'cfdestinationsets', + resourceId: payload.destinationSetId, + fieldPath: 'destinations', + value: destinations + }) + } catch (e) { + showGlobalError(e.message) + } + const destinationSets = await cfLoadDestinationSets() commit('dataSucceeded', { destinationSets: destinationSets.items diff --git a/src/store/call-forwarding/mutations.js b/src/store/call-forwarding/mutations.js index 3fe37504..b09fa72e 100644 --- a/src/store/call-forwarding/mutations.js +++ b/src/store/call-forwarding/mutations.js @@ -6,6 +6,7 @@ export function dataSucceeded (state, res) { destinationSetMap[destinationSet.id] = destinationSet }) state.destinationSetMap = destinationSetMap + state.destinationSets = res.destinationSets } if (res.sourceSets) { const sourceSetMap = {} diff --git a/src/store/pbx-seats.js b/src/store/pbx-seats.js index a7987cd2..84ed29cf 100644 --- a/src/store/pbx-seats.js +++ b/src/store/pbx-seats.js @@ -56,6 +56,9 @@ export default { isSeatListEmpty (state) { return state.seatListItems.length && state.seatListItems.length === 0 }, + isSeatMapByIdEmpty (state) { + return Object.keys(state.seatMapById).length === 0 + }, isSeatListRequesting (state) { return state.seatListState === RequestState.requesting }, diff --git a/test/jest/utils/index.js b/test/jest/utils/index.js index 552b6554..7a440284 100755 --- a/test/jest/utils/index.js +++ b/test/jest/utils/index.js @@ -2,8 +2,8 @@ import { createLocalVue, shallowMount } from 'test-utils' import Vuex from 'vuex' -import VueRouter from 'vue-router' -import Quasar, { Cookies } from 'quasar' +import * as VueRouter from 'vue-router' +import { Cookies, Quasar } from 'quasar' const mockSsrContext = () => { return { @@ -46,10 +46,10 @@ export const mountQuasar = (component, options = {}) => { } // mock vue-i18n - const $t = () => {} - const $tc = () => {} - const $n = () => {} - const $d = () => {} + const $t = () => { } + const $tc = () => { } + const $n = () => { } + const $d = () => { } return shallowMount(component, { localVue: localVue,