MT#64383 Migrate Dialog Components

* Migrate:
  - CscDialog.vue
  - CscRemoveDialog.vue
  - CscRetrievePasswordDialog.vue
* Add docs about remove dialog logic

Change-Id: I10015ba50f2c13292fdd2cc4ca7ffe0fcb4938d5
mr26.2
Debora Crescenzo 4 months ago
parent 93ec8dbbdd
commit fd5dcf0b4e

@ -0,0 +1,59 @@
# Remove Dialog Usage
`CscRemoveDialog` is currently used in two different ways in the codebase. Both work and can render the same UI, but are used in different contexts.
- If there is any type of interaction with the state, use the ref-based pattern.
- If the delete button can build the dialog message and action immediately without changes in the state, use the Quasar plugin pattern.
## Ref-based mounted dialog
Example: `src/pages/CscPagePbxDevices.vue`
Reference:
- `src/pages/CscPagePbxDevices.vue`
In this pattern, the dialog is mounted in the page template and the page keeps a ref to it.
```vue
<csc-remove-dialog
ref="removeDialog"
:title="$t('Remove device')"
:message="getDeviceRemoveDialogMessage"
@remove="removeDevice(deviceRemoving.id)"
@cancel="closeDeviceRemovalDialog"
/>
```
```js
openDeviceRemovalDialog (deviceId) {
if (this.$refs.removeDialog) {
this.deviceRemovalRequesting(deviceId)
this.$refs.removeDialog.show()
}
}
```
## Quasar plugin dialog
Example: `src/pages/CscPageCallRecording.vue`
Reference:
- `src/pages/CscPageCallRecording.vue`
In this pattern, the dialog is created on demand through Quasar's dialog plugin.
```js
confirmRowDeletion (rowId) {
this.$q.dialog({
component: CscRemoveDialog,
componentProps: {
title: this.$t('Delete recording'),
message: this.$t('You are about to delete recording #{id}', { id: rowId })
}
}).onOk(() => {
this.deleteRecord(rowId)
})
}
```

@ -1,6 +1,6 @@
<template>
<q-dialog
ref="dialog"
ref="dialogRef"
v-bind="$attrs"
>
<q-card
@ -55,30 +55,38 @@
</q-dialog>
</template>
<script>
export default {
name: 'CscDialog',
props: {
title: {
type: String,
required: true
},
titleIcon: {
type: String,
default: undefined
},
titleIconColor: {
type: String,
default: 'primary'
}
<script setup>
import { ref } from 'vue'
defineOptions({ name: 'CscDialog' })
defineProps({
title: {
type: String,
required: true
},
methods: {
show () {
this.$refs.dialog.show()
},
hide () {
this.$refs.dialog.hide()
}
titleIcon: {
type: String,
default: undefined
},
titleIconColor: {
type: String,
default: 'primary'
}
})
const dialogRef = ref(null)
const show = () => {
dialogRef.value?.show()
}
const hide = () => {
dialogRef.value?.hide()
}
defineExpose({
show,
hide
})
</script>

@ -27,50 +27,46 @@
</csc-dialog>
</template>
<script>
<script setup>
import CscDialog from 'components/CscDialog'
export default {
name: 'CscRemoveDialog',
components: {
CscDialog
},
props: {
title: {
type: String,
default: ''
},
titleIcon: {
type: String,
default: ''
},
message: {
type: String,
default: ''
},
opened: {
type: Boolean,
default: false
}
import { ref } from 'vue'
defineOptions({ name: 'CscRemoveDialog' })
defineProps({
title: {
type: String,
default: ''
},
emits: ['ok', 'remove', 'cancel'],
data () {
return {
}
titleIcon: {
type: String,
default: ''
},
methods: {
show () {
this.$refs.dialogComp.show()
},
hide () {
this.$refs.dialogComp.hide()
},
remove () {
this.$emit('remove')
this.$emit('ok')
}
message: {
type: String,
default: ''
}
})
const emit = defineEmits(['ok', 'remove'])
const dialogComp = ref(null)
const show = () => {
dialogComp.value?.show()
}
const hide = () => {
dialogComp.value?.hide()
}
</script>
<style lang="sass" rel="stylesheet/sass">
</style>
const remove = () => {
emit('remove')
emit('ok')
}
defineExpose({
show,
hide
})
</script>

@ -1,10 +1,10 @@
<template>
<csc-dialog
:value="value"
:model-value="modelValue"
title-icon="vpn_key"
:title="$t('Forgot password?')"
@input="$emit('input')"
@hide="resetForm()"
@update:model-value="emit('update:modelValue', $event)"
@hide="resetForm"
>
<template
#content
@ -43,80 +43,57 @@
color="primary"
:label="$t('Send')"
:loading="newPasswordRequesting"
:disable="!username || username.length < 1 || newPasswordRequesting"
:disable="!username || newPasswordRequesting"
@click="submit()"
/>
</template>
</csc-dialog>
</template>
<script>
import useValidate from '@vuelidate/core'
<script setup>
import { useVuelidate } from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import { appConfig } from 'boot/appConfig'
import CscDialog from 'components/CscDialog'
import { mapActions, mapState } from 'vuex'
export default {
name: 'CscRetrievePasswordDialog',
components: {
CscDialog
},
props: {
value: {
type: Boolean,
default: false
}
},
emits: ['input', 'close'],
data () {
return {
v$: useValidate(),
username: ''
}
},
validations: {
username: {
required
}
},
computed: {
...mapState('user', [
'newPasswordRequesting'
])
},
methods: {
...mapActions('user', [
'resetPassword'
]),
async submit () {
this.v$.$touch()
if (!this.v$.$invalid) {
try {
const res = await this.resetPassword({
username: this.username,
domain: this.$appConfig.baseHttpUrl.replace(/(^\w+:|^)\/\//, '')
})
this.$q.notify({
position: 'top',
color: 'positive',
icon: 'check',
message: res.data.message
})
} catch (err) {
this.$q.notify({
position: 'top',
color: 'negative',
icon: 'error',
message: this.$t('There was an error, please retry later')
})
} finally {
this.$emit('close')
}
}
},
resetForm () {
this.v$.$reset()
this.username = ''
}
import { useActions, useState } from 'src/composables/useStore'
import { computed, ref } from 'vue'
defineOptions({ name: 'CscRetrievePasswordDialog' })
defineProps({
modelValue: {
type: Boolean,
default: false
}
})
const emit = defineEmits(['update:modelValue', 'close'])
const username = ref('')
const rules = computed(() => ({
username: {
required
}
}))
const v$ = useVuelidate(rules, { username })
const { newPasswordRequesting } = useState('user', ['newPasswordRequesting'])
const { resetPassword } = useActions('user', ['resetPassword'])
const submit = async () => {
v$.value.$touch()
if (!v$.value.$invalid) {
await resetPassword({
username: username.value,
domain: appConfig.baseHttpUrl.replace(/(^\w+:|^)\/\//, '')
})
emit('close')
resetForm()
}
}
const resetForm = () => {
v$.value.$reset()
username.value = ''
}
</script>

@ -43,6 +43,7 @@ import { LICENSES, PROFILE_ATTRIBUTE_MAP } from 'src/constants'
import { getSipInstanceId } from 'src/helpers/call-utils'
import { parseBlobToObject } from 'src/helpers/parse-blob-to-object'
import { qrPayload } from 'src/helpers/qr'
import { showGlobalError, showToast } from 'src/helpers/ui'
import { PATH_CHANGE_PASSWORD } from 'src/router/routes'
import { setLocal } from 'src/storage'
import { RequestState } from 'src/store/common'
@ -499,10 +500,15 @@ export default {
context.commit('subscriberUpdateSucceeded', subscriberData)
},
async resetPassword ({ commit }, data) {
commit('newPasswordRequesting', true)
const response = await resetPassword(data)
commit('newPasswordRequesting', false)
return response
try {
commit('newPasswordRequesting', true)
const res = await resetPassword(data)
showToast(res.data.message)
} catch (err) {
showGlobalError(i18n.global.t('There was an error, please retry later'))
} finally {
commit('newPasswordRequesting', false)
}
},
async recoverPassword ({ commit, dispatch, state, rootGetters }, data) {
commit('userPasswordRequesting')

Loading…
Cancel
Save