feat: Create/Edit & List page for email template & implemented delete from list
(cherry picked from commit cd7bab918448e914516b43536d346068bbdfe659)
This commit is contained in:
parent
b932130bb2
commit
b799e8dbb4
5
frontend/components.d.ts
vendored
5
frontend/components.d.ts
vendored
@ -79,6 +79,7 @@ declare module 'vue' {
|
|||||||
DropdownItem: typeof import('./src/components/DropdownItem.vue')['default']
|
DropdownItem: typeof import('./src/components/DropdownItem.vue')['default']
|
||||||
DuplicateIcon: typeof import('./src/components/Icons/DuplicateIcon.vue')['default']
|
DuplicateIcon: typeof import('./src/components/Icons/DuplicateIcon.vue')['default']
|
||||||
DurationIcon: typeof import('./src/components/Icons/DurationIcon.vue')['default']
|
DurationIcon: typeof import('./src/components/Icons/DurationIcon.vue')['default']
|
||||||
|
EditEmailTemplate: typeof import('./src/components/Settings/EmailTemplate/EditEmailTemplate.vue')['default']
|
||||||
EditIcon: typeof import('./src/components/Icons/EditIcon.vue')['default']
|
EditIcon: typeof import('./src/components/Icons/EditIcon.vue')['default']
|
||||||
EditValueModal: typeof import('./src/components/Modals/EditValueModal.vue')['default']
|
EditValueModal: typeof import('./src/components/Modals/EditValueModal.vue')['default']
|
||||||
Email2Icon: typeof import('./src/components/Icons/Email2Icon.vue')['default']
|
Email2Icon: typeof import('./src/components/Icons/Email2Icon.vue')['default']
|
||||||
@ -94,6 +95,7 @@ declare module 'vue' {
|
|||||||
EmailIcon: typeof import('./src/components/Icons/EmailIcon.vue')['default']
|
EmailIcon: typeof import('./src/components/Icons/EmailIcon.vue')['default']
|
||||||
EmailProviderIcon: typeof import('./src/components/Settings/EmailProviderIcon.vue')['default']
|
EmailProviderIcon: typeof import('./src/components/Settings/EmailProviderIcon.vue')['default']
|
||||||
EmailTemplateModal: typeof import('./src/components/Modals/EmailTemplateModal.vue')['default']
|
EmailTemplateModal: typeof import('./src/components/Modals/EmailTemplateModal.vue')['default']
|
||||||
|
EmailTemplatePage: typeof import('./src/components/Settings/EmailTemplate/EmailTemplatePage.vue')['default']
|
||||||
EmailTemplates: typeof import('./src/components/Settings/EmailTemplate/EmailTemplates.vue')['default']
|
EmailTemplates: typeof import('./src/components/Settings/EmailTemplate/EmailTemplates.vue')['default']
|
||||||
EmailTemplateSelectorModal: typeof import('./src/components/Modals/EmailTemplateSelectorModal.vue')['default']
|
EmailTemplateSelectorModal: typeof import('./src/components/Modals/EmailTemplateSelectorModal.vue')['default']
|
||||||
EmailTemplatesListView: typeof import('./src/components/ListViews/EmailTemplatesListView.vue')['default']
|
EmailTemplatesListView: typeof import('./src/components/ListViews/EmailTemplatesListView.vue')['default']
|
||||||
@ -156,8 +158,10 @@ declare module 'vue' {
|
|||||||
ListRows: typeof import('./src/components/ListViews/ListRows.vue')['default']
|
ListRows: typeof import('./src/components/ListViews/ListRows.vue')['default']
|
||||||
LoadingIndicator: typeof import('./src/components/Icons/LoadingIndicator.vue')['default']
|
LoadingIndicator: typeof import('./src/components/Icons/LoadingIndicator.vue')['default']
|
||||||
LucideInfo: typeof import('~icons/lucide/info')['default']
|
LucideInfo: typeof import('~icons/lucide/info')['default']
|
||||||
|
LucideMoreHorizontal: typeof import('~icons/lucide/more-horizontal')['default']
|
||||||
LucidePlus: typeof import('~icons/lucide/plus')['default']
|
LucidePlus: typeof import('~icons/lucide/plus')['default']
|
||||||
LucideSearch: typeof import('~icons/lucide/search')['default']
|
LucideSearch: typeof import('~icons/lucide/search')['default']
|
||||||
|
LucideX: typeof import('~icons/lucide/x')['default']
|
||||||
MarkAsDoneIcon: typeof import('./src/components/Icons/MarkAsDoneIcon.vue')['default']
|
MarkAsDoneIcon: typeof import('./src/components/Icons/MarkAsDoneIcon.vue')['default']
|
||||||
MaximizeIcon: typeof import('./src/components/Icons/MaximizeIcon.vue')['default']
|
MaximizeIcon: typeof import('./src/components/Icons/MaximizeIcon.vue')['default']
|
||||||
MenuIcon: typeof import('./src/components/Icons/MenuIcon.vue')['default']
|
MenuIcon: typeof import('./src/components/Icons/MenuIcon.vue')['default']
|
||||||
@ -173,6 +177,7 @@ declare module 'vue' {
|
|||||||
MultiSelectUserInput: typeof import('./src/components/Controls/MultiSelectUserInput.vue')['default']
|
MultiSelectUserInput: typeof import('./src/components/Controls/MultiSelectUserInput.vue')['default']
|
||||||
MuteIcon: typeof import('./src/components/Icons/MuteIcon.vue')['default']
|
MuteIcon: typeof import('./src/components/Icons/MuteIcon.vue')['default']
|
||||||
NestedPopover: typeof import('./src/components/NestedPopover.vue')['default']
|
NestedPopover: typeof import('./src/components/NestedPopover.vue')['default']
|
||||||
|
NewEmailTemplate: typeof import('./src/components/Settings/EmailTemplate/NewEmailTemplate.vue')['default']
|
||||||
NoteArea: typeof import('./src/components/Activities/NoteArea.vue')['default']
|
NoteArea: typeof import('./src/components/Activities/NoteArea.vue')['default']
|
||||||
NoteIcon: typeof import('./src/components/Icons/NoteIcon.vue')['default']
|
NoteIcon: typeof import('./src/components/Icons/NoteIcon.vue')['default']
|
||||||
NoteModal: typeof import('./src/components/Modals/NoteModal.vue')['default']
|
NoteModal: typeof import('./src/components/Modals/NoteModal.vue')['default']
|
||||||
|
|||||||
@ -0,0 +1,3 @@
|
|||||||
|
<template>
|
||||||
|
Edit
|
||||||
|
</template>
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
<template>
|
||||||
|
<NewEmailTemplate v-if="step === 'new-template'" @updateStep="updateStep" />
|
||||||
|
<EmailTemplates
|
||||||
|
v-else-if="step === 'template-list'"
|
||||||
|
@updateStep="updateStep"
|
||||||
|
/>
|
||||||
|
<EditEmailTemplate
|
||||||
|
v-else-if="step === 'edit-template'"
|
||||||
|
:data="templateData"
|
||||||
|
@updateStep="updateStep"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import NewEmailTemplate from './NewEmailTemplate.vue'
|
||||||
|
import EditEmailTemplate from './EditEmailTemplate.vue'
|
||||||
|
import EmailTemplates from './EmailTemplates.vue'
|
||||||
|
import { createListResource } from 'frappe-ui'
|
||||||
|
import { provide, ref } from 'vue'
|
||||||
|
|
||||||
|
const step = ref('template-list')
|
||||||
|
const templateData = ref(null)
|
||||||
|
|
||||||
|
const templates = createListResource({
|
||||||
|
type: 'list',
|
||||||
|
doctype: 'Email Template',
|
||||||
|
cache: 'emailTemplates',
|
||||||
|
fields: [
|
||||||
|
'name',
|
||||||
|
'enabled',
|
||||||
|
'use_html',
|
||||||
|
'reference_doctype',
|
||||||
|
'subject',
|
||||||
|
'response',
|
||||||
|
'response_html',
|
||||||
|
'modified',
|
||||||
|
'owner',
|
||||||
|
],
|
||||||
|
auto: true,
|
||||||
|
filters: { reference_doctype: ['in', ['CRM Lead', 'CRM Deal']] },
|
||||||
|
orderBy: 'modified desc',
|
||||||
|
pageLength: 20,
|
||||||
|
})
|
||||||
|
|
||||||
|
provide('templates', templates)
|
||||||
|
|
||||||
|
function updateStep(newStep, data) {
|
||||||
|
step.value = newStep
|
||||||
|
templateData.value = data
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -15,7 +15,12 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex item-center space-x-2 w-3/12 justify-end">
|
<div class="flex item-center space-x-2 w-3/12 justify-end">
|
||||||
<Button :label="__('New')" icon-left="plus" variant="solid" />
|
<Button
|
||||||
|
:label="__('New')"
|
||||||
|
icon-left="plus"
|
||||||
|
variant="solid"
|
||||||
|
@click="emit('updateStep', 'new-template')"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -100,27 +105,15 @@
|
|||||||
@update:model-value="toggleEmailTemplate(template)"
|
@update:model-value="toggleEmailTemplate(template)"
|
||||||
/>
|
/>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
:options="[
|
:options="getDropdownOptions(template)"
|
||||||
{
|
|
||||||
label: __('Edit'),
|
|
||||||
icon: 'edit-2',
|
|
||||||
onClick: () => {},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: __('Duplicate'),
|
|
||||||
icon: 'copy',
|
|
||||||
onClick: () => {},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: __('Delete'),
|
|
||||||
icon: 'trash-2',
|
|
||||||
onClick: () => {},
|
|
||||||
},
|
|
||||||
]"
|
|
||||||
placement="right"
|
placement="right"
|
||||||
:button="{
|
:button="{
|
||||||
icon: 'more-horizontal',
|
icon: 'more-horizontal',
|
||||||
variant: 'ghost',
|
variant: 'ghost',
|
||||||
|
onblur: (e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
confirmDelete = false
|
||||||
|
},
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -148,34 +141,18 @@ import {
|
|||||||
TextInput,
|
TextInput,
|
||||||
FormControl,
|
FormControl,
|
||||||
Switch,
|
Switch,
|
||||||
createListResource,
|
|
||||||
Dropdown,
|
Dropdown,
|
||||||
|
FeatherIcon,
|
||||||
} from 'frappe-ui'
|
} from 'frappe-ui'
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed, inject, h } from 'vue'
|
||||||
|
|
||||||
const templates = createListResource({
|
const emit = defineEmits(['updateStep'])
|
||||||
type: 'list',
|
|
||||||
doctype: 'Email Template',
|
const templates = inject('templates')
|
||||||
cache: 'emailTemplates',
|
|
||||||
fields: [
|
|
||||||
'name',
|
|
||||||
'enabled',
|
|
||||||
'use_html',
|
|
||||||
'reference_doctype',
|
|
||||||
'subject',
|
|
||||||
'response',
|
|
||||||
'response_html',
|
|
||||||
'modified',
|
|
||||||
'owner',
|
|
||||||
],
|
|
||||||
auto: true,
|
|
||||||
filters: { reference_doctype: ['in', ['CRM Lead', 'CRM Deal']] },
|
|
||||||
orderBy: 'modified desc',
|
|
||||||
pageLength: 20,
|
|
||||||
})
|
|
||||||
|
|
||||||
const search = ref('')
|
const search = ref('')
|
||||||
const currentDoctype = ref('All')
|
const currentDoctype = ref('All')
|
||||||
|
const confirmDelete = ref(false)
|
||||||
|
|
||||||
const templatesList = computed(() => {
|
const templatesList = computed(() => {
|
||||||
let list = templates.data || []
|
let list = templates.data || []
|
||||||
@ -200,4 +177,89 @@ function toggleEmailTemplate(template) {
|
|||||||
enabled: template.enabled ? 1 : 0,
|
enabled: template.enabled ? 1 : 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deleteTemplate(template) {
|
||||||
|
confirmDelete.value = false
|
||||||
|
templates.delete.submit(template.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDropdownOptions(template) {
|
||||||
|
let options = [
|
||||||
|
{
|
||||||
|
label: __('Edit'),
|
||||||
|
component: (props) =>
|
||||||
|
TemplateOption({
|
||||||
|
option: __('Edit'),
|
||||||
|
icon: 'edit-2',
|
||||||
|
active: props.active,
|
||||||
|
onClick: () => {
|
||||||
|
emit('updateStep', 'edit-template', { ...template })
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __('Duplicate'),
|
||||||
|
component: (props) =>
|
||||||
|
TemplateOption({
|
||||||
|
option: __('Duplicate'),
|
||||||
|
icon: 'copy',
|
||||||
|
active: props.active,
|
||||||
|
onClick: () => {},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __('Delete'),
|
||||||
|
component: (props) =>
|
||||||
|
TemplateOption({
|
||||||
|
option: __('Delete'),
|
||||||
|
icon: 'trash-2',
|
||||||
|
active: props.active,
|
||||||
|
onClick: (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
confirmDelete.value = true
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
condition: () => !confirmDelete.value,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __('Confirm Delete'),
|
||||||
|
component: (props) =>
|
||||||
|
TemplateOption({
|
||||||
|
option: __('Confirm Delete'),
|
||||||
|
icon: 'trash-2',
|
||||||
|
active: props.active,
|
||||||
|
variant: 'danger',
|
||||||
|
onClick: () => deleteTemplate(template),
|
||||||
|
}),
|
||||||
|
condition: () => confirmDelete.value,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
return options.filter((option) => option.condition?.() || true)
|
||||||
|
}
|
||||||
|
|
||||||
|
function TemplateOption({ active, option, variant, icon, onClick }) {
|
||||||
|
return h(
|
||||||
|
'button',
|
||||||
|
{
|
||||||
|
class: [
|
||||||
|
active ? 'bg-surface-gray-2' : 'text-ink-gray-8',
|
||||||
|
'group flex w-full gap-2 items-center rounded-md px-2 py-2 text-sm',
|
||||||
|
variant == 'danger' ? 'text-ink-red-3 hover:bg-ink-red-1' : '',
|
||||||
|
],
|
||||||
|
onClick: onClick,
|
||||||
|
},
|
||||||
|
[
|
||||||
|
icon
|
||||||
|
? h(FeatherIcon, {
|
||||||
|
name: icon,
|
||||||
|
class: ['h-4 w-4 shrink-0'],
|
||||||
|
'aria-hidden': true,
|
||||||
|
})
|
||||||
|
: null,
|
||||||
|
h('span', { class: 'whitespace-nowrap' }, option),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
<template>New</template>
|
||||||
@ -51,7 +51,7 @@ import InviteUserPage from '@/components/Settings/InviteUserPage.vue'
|
|||||||
import ProfileSettings from '@/components/Settings/ProfileSettings.vue'
|
import ProfileSettings from '@/components/Settings/ProfileSettings.vue'
|
||||||
import WhatsAppSettings from '@/components/Settings/WhatsAppSettings.vue'
|
import WhatsAppSettings from '@/components/Settings/WhatsAppSettings.vue'
|
||||||
import ERPNextSettings from '@/components/Settings/ERPNextSettings.vue'
|
import ERPNextSettings from '@/components/Settings/ERPNextSettings.vue'
|
||||||
import EmailTemplates from '@/components/Settings/EmailTemplate/EmailTemplates.vue'
|
import EmailTemplatePage from '@/components/Settings/EmailTemplate/EmailTemplatePage.vue'
|
||||||
import TelephonySettings from '@/components/Settings/TelephonySettings.vue'
|
import TelephonySettings from '@/components/Settings/TelephonySettings.vue'
|
||||||
import EmailConfig from '@/components/Settings/EmailConfig.vue'
|
import EmailConfig from '@/components/Settings/EmailConfig.vue'
|
||||||
import SidebarLink from '@/components/SidebarLink.vue'
|
import SidebarLink from '@/components/SidebarLink.vue'
|
||||||
@ -111,7 +111,7 @@ const tabs = computed(() => {
|
|||||||
{
|
{
|
||||||
label: __('Email Templates'),
|
label: __('Email Templates'),
|
||||||
icon: Email2Icon,
|
icon: Email2Icon,
|
||||||
component: markRaw(EmailTemplates),
|
component: markRaw(EmailTemplatePage),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user