AC: Can see a separate main menu item "Fax Settings" Can click the separate main menu item and land on a page "Fax Settings" (route=/user/fax-settings) Can enable/disable the feature Can change the name in fax header for outgoing fax Can add a new Destination (email, file type, outgoing, incoming, reports) Can edit a Destination (email, file type, outgoing, incoming, reports) Can remove a Destination Can toggle T38 (Fax over Internet) Can toggle ECM (Error Correction Mode) In addition there were changed "CscInputSavable" and "CscListMenuItem" components to provide better "disable state" possibility. Change-Id: I777dd718a6e676acd72f45c175296ce767449469pull/4/head
parent
efd518f95c
commit
e86d06d806
@ -0,0 +1,34 @@
|
||||
|
||||
import _ from 'lodash'
|
||||
import {
|
||||
get,
|
||||
patchReplaceFull
|
||||
} from './common'
|
||||
import { i18n } from 'src/boot/i18n'
|
||||
|
||||
export async function getFaxServerSettings (subscriberId) {
|
||||
const result = await get({
|
||||
path: `api/faxserversettings/${subscriberId}`
|
||||
})
|
||||
const settings = _.clone(result)
|
||||
delete settings._links
|
||||
return settings
|
||||
}
|
||||
|
||||
export async function setFaxServerField (options) {
|
||||
if (!['name', 'active', 'ecm', 't38', 'destinations'].includes(options.field)) {
|
||||
throw Error(`setFaxServerField: unknown field name ${options.field}`)
|
||||
}
|
||||
if (options.field === 'destinations') {
|
||||
// searching for duplicates
|
||||
const destinationsIds = options.value.map(d => d.destination)
|
||||
if ((new Set(destinationsIds)).size !== destinationsIds.length) {
|
||||
throw Error(i18n.t('faxSettings.destinationEmailExists'))
|
||||
}
|
||||
}
|
||||
return patchReplaceFull({
|
||||
path: `api/faxserversettings/${options.subscriberId}`,
|
||||
fieldPath: options.field,
|
||||
value: options.value
|
||||
})
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<csc-list-item
|
||||
icon="email"
|
||||
:odd="odd"
|
||||
:expanded="expanded"
|
||||
@toggle="toggle"
|
||||
>
|
||||
<template
|
||||
slot="title"
|
||||
>
|
||||
<csc-list-item-title>
|
||||
{{ $t('faxSettings.destinationItemTitle', {destination: destination.destination, filetype: destination.filetype}) }}
|
||||
</csc-list-item-title>
|
||||
<q-slide-transition>
|
||||
<csc-list-item-subtitle
|
||||
v-if="!expanded"
|
||||
>
|
||||
<q-icon
|
||||
size="16px"
|
||||
:name="destination.incoming ? 'call_received' : ' '"
|
||||
/>
|
||||
<q-icon
|
||||
size="16px"
|
||||
:name="destination.outgoing ? 'call_made' : ' '"
|
||||
/>
|
||||
<q-icon
|
||||
size="16px"
|
||||
:name="destination.status ? 'fas fa-file-alt' : ' '"
|
||||
/>
|
||||
</csc-list-item-subtitle>
|
||||
</q-slide-transition>
|
||||
</template>
|
||||
<template
|
||||
slot="menu"
|
||||
>
|
||||
<csc-list-menu-item
|
||||
:disable="loading"
|
||||
icon="delete"
|
||||
icon-color="negative"
|
||||
@click="deleteDestination"
|
||||
>
|
||||
{{ $t('buttons.remove') }}
|
||||
</csc-list-menu-item>
|
||||
</template>
|
||||
<template slot="body">
|
||||
<csc-fax2-mail-destination-form
|
||||
:is-add-new-mode="false"
|
||||
:initial-data="destination"
|
||||
:loading="loading"
|
||||
@update-property="updateProperty"
|
||||
/>
|
||||
</template>
|
||||
</csc-list-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CscListItem from 'components/CscListItem'
|
||||
import CscListItemTitle from 'components/CscListItemTitle'
|
||||
import CscListMenuItem from 'components/CscListMenuItem'
|
||||
import CscListItemSubtitle from 'components/CscListItemSubtitle'
|
||||
import CscFax2MailDestinationForm from 'components/pages/FaxSettings/CscFax2MailDestinationForm'
|
||||
|
||||
export default {
|
||||
name: 'CscFax2MailDestination',
|
||||
components: {
|
||||
CscFax2MailDestinationForm,
|
||||
CscListItemSubtitle,
|
||||
CscListMenuItem,
|
||||
CscListItemTitle,
|
||||
CscListItem
|
||||
},
|
||||
props: {
|
||||
destination: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
odd: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
expanded: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
deleteDestination () {
|
||||
if (this.$refs.listItem) {
|
||||
this.$refs.listItem.closePopoverMenu()
|
||||
}
|
||||
this.$emit('remove')
|
||||
},
|
||||
toggle () {
|
||||
if (this.expanded) {
|
||||
this.$emit('collapse')
|
||||
} else {
|
||||
this.$emit('expand')
|
||||
}
|
||||
},
|
||||
updateProperty () {
|
||||
this.$emit('update-property', ...arguments)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="row">
|
||||
<div
|
||||
class="col-xs-12 col-md-6"
|
||||
>
|
||||
<csc-input-saveable
|
||||
v-model="data.destination"
|
||||
icon="email"
|
||||
:label="$t('faxSettings.destinationEmail')"
|
||||
:disable="disabled"
|
||||
:readonly="loading"
|
||||
:error="$v.data.destination.$error"
|
||||
:error-message="destinationErrorMessage"
|
||||
:value-changed="!isAddNewMode && data.destination !== initialData.destination"
|
||||
@input="$v.data.destination.$touch"
|
||||
@keypress.space.prevent
|
||||
@keydown.space.prevent
|
||||
@keyup.space.prevent
|
||||
@undo="data.destination = initialData.destination"
|
||||
@save="updatePropertyData('destination')"
|
||||
/>
|
||||
<q-select
|
||||
v-model="data.filetype"
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
:disable="loading"
|
||||
:readonly="loading"
|
||||
:label="$t('faxSettings.fileType')"
|
||||
:options="fileTypeOptions"
|
||||
@input="updatePropertyData('filetype')"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="col-xs-12 col-md-6"
|
||||
>
|
||||
<q-toggle
|
||||
v-model="data.incoming"
|
||||
:label="$t('faxSettings.deliverIncomingFaxes')"
|
||||
:disable="loading"
|
||||
@input="updatePropertyData('incoming')"
|
||||
/>
|
||||
<q-toggle
|
||||
v-model="data.outgoing"
|
||||
:label="$t('faxSettings.deliverOutgoingFaxes')"
|
||||
:disable="loading"
|
||||
@input="updatePropertyData('outgoing')"
|
||||
/>
|
||||
<q-toggle
|
||||
v-model="data.status"
|
||||
:label="$t('faxSettings.receiveReports')"
|
||||
:disable="loading"
|
||||
@input="updatePropertyData('status')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="isAddNewMode"
|
||||
class="row justify-center"
|
||||
>
|
||||
<q-btn
|
||||
flat
|
||||
color="default"
|
||||
icon="clear"
|
||||
:disable="loading"
|
||||
:label="$t('buttons.cancel')"
|
||||
@click="cancel()"
|
||||
/>
|
||||
<q-btn
|
||||
flat
|
||||
color="primary"
|
||||
icon="person"
|
||||
:loading="loading"
|
||||
:disable="$v.data.$invalid || loading"
|
||||
:label="$t('faxSettings.createDestination')"
|
||||
@click="save()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { email, required } from 'vuelidate/lib/validators'
|
||||
import CscInputSaveable from 'components/form/CscInputSaveable'
|
||||
|
||||
export default {
|
||||
name: 'CscFax2MailDestinationForm',
|
||||
components: {
|
||||
CscInputSaveable
|
||||
},
|
||||
props: {
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
initialData: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
destination: '',
|
||||
filetype: 'TIFF',
|
||||
incoming: true,
|
||||
outgoing: true,
|
||||
status: true
|
||||
})
|
||||
},
|
||||
isAddNewMode: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
data: this.getDefaults()
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
data: {
|
||||
destination: {
|
||||
required,
|
||||
email
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
destinationErrorMessage () {
|
||||
if (!this.$v.data.destination.required) {
|
||||
return this.$t('validationErrors.fieldRequired', {
|
||||
field: this.$t('faxSettings.destinationEmail')
|
||||
})
|
||||
} else if (!this.$v.data.destination.email) {
|
||||
return this.$t('validationErrors.email')
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
fileTypeOptions () {
|
||||
return ['TIFF', 'PS', 'PDF', 'PDF14']
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getDefaults () {
|
||||
return { ...this.initialData }
|
||||
},
|
||||
cancel () {
|
||||
this.$emit('cancel')
|
||||
},
|
||||
save () {
|
||||
this.$emit('save', {
|
||||
...this.data
|
||||
})
|
||||
},
|
||||
reset () {
|
||||
this.data = this.getDefaults()
|
||||
this.$v.$reset()
|
||||
},
|
||||
updatePropertyData (propertyName) {
|
||||
this.$emit('update-property', {
|
||||
name: propertyName,
|
||||
value: this.data[propertyName]
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,276 @@
|
||||
<template>
|
||||
<csc-page
|
||||
class="q-pa-lg"
|
||||
>
|
||||
<q-list
|
||||
class="col col-xs-12 col-md-6"
|
||||
dense
|
||||
>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-toggle
|
||||
v-model="faxToMailSettings.active"
|
||||
:label="$t('faxSettings.active')"
|
||||
:disable="!dataLoaded"
|
||||
@input="setChangedData('active', !faxServerSettings.active)"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section
|
||||
side
|
||||
>
|
||||
<csc-spinner
|
||||
v-if="loadingFaxServerSettings"
|
||||
class="self-center"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<csc-input-saveable
|
||||
v-model.trim="faxToMailSettings.name"
|
||||
:label="$t('faxSettings.sendfaxHeaderName')"
|
||||
:disable="!dataLoaded"
|
||||
:loading="loadingFaxServerSettings"
|
||||
:value-changed="nameChanged"
|
||||
@save="setChangedData('name', faxToMailSettings.name)"
|
||||
@undo="restoreName"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-toggle
|
||||
v-model="faxToMailSettings.t38"
|
||||
:label="$t('faxSettings.T38')"
|
||||
:disable="!dataLoaded"
|
||||
@input="setChangedData('t38', !faxServerSettings.t38)"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section
|
||||
side
|
||||
>
|
||||
<csc-spinner
|
||||
v-if="loadingFaxServerSettings"
|
||||
class="self-center"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-toggle
|
||||
v-model="faxToMailSettings.ecm"
|
||||
:label="$t('faxSettings.ECM')"
|
||||
:disable="!dataLoaded"
|
||||
@input="setChangedData('ecm', !faxServerSettings.ecm)"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section
|
||||
side
|
||||
>
|
||||
<csc-spinner
|
||||
v-if="loadingFaxServerSettings"
|
||||
class="self-center"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item class="row">
|
||||
<div class="col">
|
||||
<span class="text-h6">Destinations:</span>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<csc-spinner
|
||||
v-if="loadingFaxServerSettings"
|
||||
/>
|
||||
</div>
|
||||
<div class="col text-right">
|
||||
<q-btn
|
||||
flat
|
||||
color="primary"
|
||||
icon="add"
|
||||
:disable="!dataLoaded || showAddNewDestination"
|
||||
@click="openAddNewDestination"
|
||||
>
|
||||
{{ $t('faxSettings.addDestination') }}
|
||||
</q-btn>
|
||||
</div>
|
||||
</q-item>
|
||||
</q-list>
|
||||
<q-separator />
|
||||
<div
|
||||
class="row justify-center q-mb-lg"
|
||||
>
|
||||
<q-list
|
||||
class="col-xs-12"
|
||||
>
|
||||
<q-item
|
||||
v-if="showAddNewDestination"
|
||||
class="row justify-center"
|
||||
>
|
||||
<csc-fax2-mail-destination-form
|
||||
v-if="showAddNewDestination"
|
||||
ref="addNewDestination"
|
||||
:loading="loadingFaxServerSettings"
|
||||
:is-add-new-mode="true"
|
||||
@save="addNewDestination"
|
||||
@cancel="closeAddNewDestination"
|
||||
/>
|
||||
</q-item>
|
||||
<q-item
|
||||
v-if="!hasDestinations"
|
||||
class="row justify-center"
|
||||
>
|
||||
{{ $t('faxSettings.noDestinationsCreatedYet') }}
|
||||
</q-item>
|
||||
<csc-fax2-mail-destination
|
||||
v-for="(destinationItem, index) in faxToMailSettings.destinations"
|
||||
:key="destinationItem.destination"
|
||||
:odd="(index % 2) === 0"
|
||||
:expanded="expandedDestinationId === destinationItem.destination"
|
||||
:destination="destinationItem"
|
||||
:loading="loadingFaxServerSettings"
|
||||
@collapse="expandedDestinationId = null"
|
||||
@expand="expandedDestinationId = destinationItem.destination"
|
||||
@remove="openDeleteDestinationDialog(destinationItem.destination)"
|
||||
@update-property="updateDestinationItemProperty(destinationItem.destination, ...arguments)"
|
||||
/>
|
||||
</q-list>
|
||||
</div>
|
||||
</csc-page>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import { mapState } from 'vuex'
|
||||
import CscInputSaveable from 'components/form/CscInputSaveable'
|
||||
import CscPage from 'components/CscPage'
|
||||
import CscSpinner from 'components/CscSpinner'
|
||||
import { mapWaitingActions, mapWaitingGetters } from 'vue-wait'
|
||||
import CscFax2MailDestinationForm from 'components/pages/FaxSettings/CscFax2MailDestinationForm'
|
||||
import CscFax2MailDestination from 'components/pages/FaxSettings/CscFax2MailDestination'
|
||||
import CscRemoveDialog from 'components/CscRemoveDialog'
|
||||
import { showGlobalError } from 'src/helpers/ui'
|
||||
export default {
|
||||
name: 'CscPageFaxSettings',
|
||||
components: {
|
||||
CscFax2MailDestination,
|
||||
CscFax2MailDestinationForm,
|
||||
CscSpinner,
|
||||
CscPage,
|
||||
CscInputSaveable
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
faxToMailSettings: {},
|
||||
showAddNewDestination: false,
|
||||
expandedDestinationId: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('fax', [
|
||||
'faxServerSettings',
|
||||
'faxServerSettingsInitialized'
|
||||
]),
|
||||
...mapWaitingGetters({
|
||||
loadingFaxServerSettings: 'loading faxServerSettings'
|
||||
}),
|
||||
dataLoaded () {
|
||||
return this.faxServerSettingsInitialized && !this.loadingFaxServerSettings
|
||||
},
|
||||
hasDestinations () {
|
||||
return this.faxToMailSettings?.destinations?.length
|
||||
},
|
||||
nameChanged () {
|
||||
return this.faxToMailSettings.name !== this.faxServerSettings.name
|
||||
}
|
||||
|
||||
},
|
||||
mounted () {
|
||||
this.loadFaxServerSettings()
|
||||
},
|
||||
methods: {
|
||||
...mapWaitingActions('fax', {
|
||||
loadFaxSettingsAction: 'loading faxServerSettings',
|
||||
fieldUpdateAction: 'loading faxServerSettings'
|
||||
}),
|
||||
async loadFaxServerSettings () {
|
||||
try {
|
||||
await this.loadFaxSettingsAction()
|
||||
this.updateDataFromStore()
|
||||
} catch (err) {
|
||||
showGlobalError(err?.message)
|
||||
}
|
||||
},
|
||||
updateDataFromStore () {
|
||||
this.faxToMailSettings = _.cloneDeep(this.faxServerSettings)
|
||||
},
|
||||
async setChangedData (field, value) {
|
||||
try {
|
||||
await this.fieldUpdateAction({ field, value })
|
||||
this.updateDataFromStore()
|
||||
} catch (err) {
|
||||
showGlobalError(err?.message)
|
||||
}
|
||||
},
|
||||
restoreName () {
|
||||
this.faxToMailSettings.name = this.faxServerSettings.name
|
||||
},
|
||||
async updateDestinations (destinationItems, beforeUpdateUI = () => {}) {
|
||||
try {
|
||||
await this.fieldUpdateAction({
|
||||
field: 'destinations',
|
||||
value: destinationItems
|
||||
})
|
||||
beforeUpdateUI()
|
||||
this.updateDataFromStore()
|
||||
} catch (err) {
|
||||
showGlobalError(err?.message)
|
||||
}
|
||||
},
|
||||
openAddNewDestination () {
|
||||
this.showAddNewDestination = true
|
||||
},
|
||||
closeAddNewDestination () {
|
||||
this.showAddNewDestination = false
|
||||
this.$refs.addNewDestination.reset()
|
||||
},
|
||||
addNewDestination (destination) {
|
||||
const destinationItems = [...this.faxToMailSettings.destinations, destination]
|
||||
|
||||
this.updateDestinations(destinationItems, () => {
|
||||
this.closeAddNewDestination()
|
||||
})
|
||||
},
|
||||
deleteDestination (destinationId) {
|
||||
const destinationItems = this.faxToMailSettings.destinations.filter(d => d.destination !== destinationId)
|
||||
this.fieldUpdateAction({
|
||||
field: 'destinations',
|
||||
value: destinationItems
|
||||
}).then(() => {
|
||||
if (this.expandedDestinationId === destinationId) {
|
||||
this.expandedDestinationId = null
|
||||
}
|
||||
this.updateDataFromStore()
|
||||
})
|
||||
},
|
||||
openDeleteDestinationDialog (destinationId) {
|
||||
this.$q.dialog({
|
||||
component: CscRemoveDialog,
|
||||
parent: this,
|
||||
title: this.$t('faxSettings.deleteDestinationTitle'),
|
||||
message: this.$t('faxSettings.deleteDestinationText', { destination: destinationId })
|
||||
}).onOk(() => {
|
||||
this.deleteDestination(destinationId)
|
||||
})
|
||||
},
|
||||
updateDestinationItemProperty (destinationId, data) {
|
||||
const destinationItems = _.cloneDeep(this.faxToMailSettings.destinations)
|
||||
const destinationItemIndex = destinationItems.findIndex(d => d.destination === destinationId)
|
||||
if (destinationItemIndex >= 0) {
|
||||
destinationItems[destinationItemIndex][data.name] = data.value
|
||||
}
|
||||
|
||||
this.updateDestinations(destinationItems)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,45 @@
|
||||
import _ from 'lodash'
|
||||
import {
|
||||
getFaxServerSettings,
|
||||
setFaxServerField
|
||||
} from '../api/fax'
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
faxServerSettingsInitialized: false,
|
||||
faxServerSettings: {}
|
||||
},
|
||||
getters: {
|
||||
subscriberId (state, getters, rootState, rootGetters) {
|
||||
return parseInt(rootGetters['user/getSubscriberId'])
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
settingsSucceeded (state, res) {
|
||||
if (_.has(res, 'faxServerSettings')) {
|
||||
state.faxServerSettings = res.faxServerSettings
|
||||
state.faxServerSettingsInitialized = true
|
||||
}
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
async loadFaxSettingsAction (context) {
|
||||
const faxServerSettings = await getFaxServerSettings(context.getters.subscriberId)
|
||||
context.commit('settingsSucceeded', {
|
||||
faxServerSettings
|
||||
})
|
||||
},
|
||||
async fieldUpdateAction (context, options) {
|
||||
const faxServerSettings = await setFaxServerField({
|
||||
subscriberId: context.getters.subscriberId,
|
||||
field: options.field,
|
||||
value: options.value
|
||||
})
|
||||
context.commit('settingsSucceeded', {
|
||||
faxServerSettings
|
||||
})
|
||||
context.commit('user/updateFaxActiveCapabilityState', faxServerSettings.active, { root: true })
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue