Merge branch 'main-hotfix' into mergify/bp/main-hotfix/pr-753

This commit is contained in:
Pratik Badhe 2025-04-22 14:33:16 +05:30 committed by GitHub
commit a921be33b3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 419 additions and 59 deletions

View File

@ -30,15 +30,7 @@ def get_contact(name):
if not len(contact):
frappe.throw(_("Contact not found"), frappe.DoesNotExistError)
contact = contact.pop()
contact["doctype"] = "Contact"
contact["email_ids"] = frappe.get_all(
"Contact Email", filters={"parent": name}, fields=["name", "email_id", "is_primary"]
)
contact["phone_nos"] = frappe.get_all(
"Contact Phone", filters={"parent": name}, fields=["name", "phone", "is_primary_mobile_no"]
)
return contact

99
crm/api/settings.py Normal file
View File

@ -0,0 +1,99 @@
import frappe
@frappe.whitelist()
def create_email_account(data):
service = data.get("service")
service_config = email_service_config.get(service)
if not service_config:
return "Service not supported"
try:
email_doc = frappe.get_doc(
{
"doctype": "Email Account",
"email_id": data.get("email_id"),
"email_account_name": data.get("email_account_name"),
"service": service,
"enable_incoming": data.get("enable_incoming"),
"enable_outgoing": data.get("enable_outgoing"),
"default_incoming": data.get("default_incoming"),
"default_outgoing": data.get("default_outgoing"),
"email_sync_option": "ALL",
"initial_sync_count": 100,
"create_contact": 1,
"track_email_status": 1,
"use_tls": 1,
"use_imap": 1,
"smtp_port": 587,
**service_config,
}
)
if service == "Frappe Mail":
email_doc.api_key = data.get("api_key")
email_doc.api_secret = data.get("api_secret")
email_doc.frappe_mail_site = data.get("frappe_mail_site")
email_doc.append_to = "CRM Lead"
else:
email_doc.append("imap_folder", {"append_to": "CRM Lead", "folder_name": "INBOX"})
email_doc.password = data.get("password")
# validate whether the credentials are correct
email_doc.get_incoming_server()
# if correct credentials, save the email account
email_doc.save()
except Exception as e:
frappe.throw(str(e))
email_service_config = {
"Frappe Mail": {
"domain": None,
"password": None,
"awaiting_password": 0,
"ascii_encode_password": 0,
"login_id_is_different": 0,
"login_id": None,
"use_imap": 0,
"use_ssl": 0,
"validate_ssl_certificate": 0,
"use_starttls": 0,
"email_server": None,
"incoming_port": 0,
"always_use_account_email_id_as_sender": 1,
"use_tls": 0,
"use_ssl_for_outgoing": 0,
"smtp_server": None,
"smtp_port": None,
"no_smtp_authentication": 0,
},
"GMail": {
"email_server": "imap.gmail.com",
"use_ssl": 1,
"smtp_server": "smtp.gmail.com",
},
"Outlook": {
"email_server": "imap-mail.outlook.com",
"use_ssl": 1,
"smtp_server": "smtp-mail.outlook.com",
},
"Sendgrid": {
"smtp_server": "smtp.sendgrid.net",
"smtp_port": 587,
},
"SparkPost": {
"smtp_server": "smtp.sparkpostmail.com",
},
"Yahoo": {
"email_server": "imap.mail.yahoo.com",
"use_ssl": 1,
"smtp_server": "smtp.mail.yahoo.com",
"smtp_port": 587,
},
"Yandex": {
"email_server": "imap.yandex.com",
"use_ssl": 1,
"smtp_server": "smtp.yandex.com",
"smtp_port": 587,
},
}

View File

@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Frappe CRM VERSION\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-04-13 09:36+0000\n"
"PO-Revision-Date: 2025-04-13 09:36+0000\n"
"POT-Creation-Date: 2025-04-20 09:35+0000\n"
"PO-Revision-Date: 2025-04-20 09:35+0000\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: shariq@frappe.io\n"
"MIME-Version: 1.0\n"
@ -16,7 +16,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.13.1\n"
#: frontend/src/components/ViewControls.vue:1206
#: frontend/src/components/ViewControls.vue:1219
msgid " (New)"
msgstr ""
@ -159,8 +159,8 @@ msgid "Account SID"
msgstr ""
#: frontend/src/components/CustomActions.vue:73
#: frontend/src/components/ViewControls.vue:669
#: frontend/src/components/ViewControls.vue:1098
#: frontend/src/components/ViewControls.vue:682
#: frontend/src/components/ViewControls.vue:1111
msgid "Actions"
msgstr ""
@ -933,13 +933,13 @@ msgstr ""
#: frontend/src/components/Modals/TaskModal.vue:8
#: frontend/src/components/Modals/ViewModal.vue:16
#: frontend/src/pages/CallLogs.vue:11 frontend/src/pages/Contacts.vue:13
#: frontend/src/pages/Contacts.vue:57 frontend/src/pages/Deals.vue:13
#: frontend/src/pages/Deals.vue:233 frontend/src/pages/EmailTemplates.vue:13
#: frontend/src/pages/EmailTemplates.vue:58 frontend/src/pages/Leads.vue:13
#: frontend/src/pages/Leads.vue:259 frontend/src/pages/Notes.vue:7
#: frontend/src/pages/Contacts.vue:60 frontend/src/pages/Deals.vue:13
#: frontend/src/pages/Deals.vue:236 frontend/src/pages/EmailTemplates.vue:13
#: frontend/src/pages/EmailTemplates.vue:61 frontend/src/pages/Leads.vue:13
#: frontend/src/pages/Leads.vue:262 frontend/src/pages/Notes.vue:7
#: frontend/src/pages/Notes.vue:93 frontend/src/pages/Organizations.vue:13
#: frontend/src/pages/Organizations.vue:57 frontend/src/pages/Tasks.vue:11
#: frontend/src/pages/Tasks.vue:182
#: frontend/src/pages/Organizations.vue:60 frontend/src/pages/Tasks.vue:11
#: frontend/src/pages/Tasks.vue:185
msgid "Create"
msgstr ""
@ -979,7 +979,7 @@ msgid "Create Task"
msgstr ""
#: frontend/src/components/Modals/ViewModal.vue:9
#: frontend/src/components/ViewControls.vue:673
#: frontend/src/components/ViewControls.vue:686
msgid "Create View"
msgstr ""
@ -1155,8 +1155,8 @@ msgstr ""
#: frontend/src/components/ListBulkActions.vue:96
#: frontend/src/components/ListBulkActions.vue:104
#: frontend/src/components/ListBulkActions.vue:186
#: frontend/src/components/ViewControls.vue:1150
#: frontend/src/components/ViewControls.vue:1161
#: frontend/src/components/ViewControls.vue:1163
#: frontend/src/components/ViewControls.vue:1174
#: frontend/src/pages/Contact.vue:105 frontend/src/pages/Contact.vue:320
#: frontend/src/pages/MobileContact.vue:81
#: frontend/src/pages/MobileContact.vue:295
@ -1164,7 +1164,7 @@ msgstr ""
#: frontend/src/pages/MobileOrganization.vue:72
#: frontend/src/pages/MobileOrganization.vue:289
#: frontend/src/pages/Notes.vue:40 frontend/src/pages/Organization.vue:83
#: frontend/src/pages/Organization.vue:327 frontend/src/pages/Tasks.vue:365
#: frontend/src/pages/Organization.vue:327 frontend/src/pages/Tasks.vue:368
msgid "Delete"
msgstr ""
@ -1176,8 +1176,8 @@ msgstr ""
msgid "Delete Task"
msgstr ""
#: frontend/src/components/ViewControls.vue:1146
#: frontend/src/components/ViewControls.vue:1154
#: frontend/src/components/ViewControls.vue:1159
#: frontend/src/components/ViewControls.vue:1167
msgid "Delete View"
msgstr ""
@ -1288,7 +1288,7 @@ msgid "Due Date"
msgstr ""
#: frontend/src/components/Modals/ViewModal.vue:15
#: frontend/src/components/ViewControls.vue:1102
#: frontend/src/components/ViewControls.vue:1115
msgid "Duplicate"
msgstr ""
@ -1345,7 +1345,7 @@ msgstr ""
#: frontend/src/components/FieldLayoutEditor.vue:319
#: frontend/src/components/FieldLayoutEditor.vue:345
#: frontend/src/components/ListBulkActions.vue:179
#: frontend/src/components/ViewControls.vue:1120
#: frontend/src/components/ViewControls.vue:1133
msgid "Edit"
msgstr ""
@ -1799,7 +1799,7 @@ msgstr ""
#. Label of the group_by_tab (Tab Break) field in DocType 'CRM View Settings'
#: crm/fcrm/doctype/crm_view_settings/crm_view_settings.json
#: frontend/src/components/ViewControls.vue:378
#: frontend/src/components/ViewControls.vue:597 frontend/src/utils/view.js:16
#: frontend/src/components/ViewControls.vue:610 frontend/src/utils/view.js:16
msgid "Group By"
msgstr ""
@ -2073,7 +2073,7 @@ msgstr ""
#. Label of the kanban_tab (Tab Break) field in DocType 'CRM View Settings'
#: crm/fcrm/doctype/crm_view_settings/crm_view_settings.json
#: frontend/src/components/ViewControls.vue:383
#: frontend/src/components/ViewControls.vue:586 frontend/src/utils/view.js:20
#: frontend/src/components/ViewControls.vue:599 frontend/src/utils/view.js:20
msgid "Kanban"
msgstr ""
@ -2229,7 +2229,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_form_script/crm_form_script.json
#: crm/fcrm/doctype/crm_view_settings/crm_view_settings.json
#: frontend/src/components/ViewControls.vue:373
#: frontend/src/components/ViewControls.vue:575 frontend/src/utils/view.js:12
#: frontend/src/components/ViewControls.vue:588 frontend/src/utils/view.js:12
msgid "List"
msgstr ""
@ -2279,18 +2279,18 @@ msgstr ""
msgid "Make Call"
msgstr ""
#: frontend/src/components/ViewControls.vue:1135
#: frontend/src/components/ViewControls.vue:1148
msgid "Make Private"
msgstr ""
#: frontend/src/components/ViewControls.vue:1135
#: frontend/src/components/ViewControls.vue:1148
msgid "Make Public"
msgstr ""
#: frontend/src/components/Activities/Activities.vue:792
#: frontend/src/components/Activities/ActivityHeader.vue:142
#: frontend/src/components/Activities/ActivityHeader.vue:185
#: frontend/src/pages/Deals.vue:509 frontend/src/pages/Leads.vue:532
#: frontend/src/pages/Deals.vue:512 frontend/src/pages/Leads.vue:535
msgid "Make a Call"
msgstr ""
@ -2433,7 +2433,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_dropdown_item/crm_dropdown_item.json
#: crm/fcrm/doctype/fcrm_settings/fcrm_settings.json
#: frontend/src/components/Modals/EmailTemplateModal.vue:24
#: frontend/src/components/ViewControls.vue:768
#: frontend/src/components/ViewControls.vue:781
#: frontend/src/pages/MobileOrganization.vue:527
#: frontend/src/pages/Organization.vue:562
msgid "Name"
@ -2478,7 +2478,7 @@ msgstr ""
#: frontend/src/components/Activities/ActivityHeader.vue:42
#: frontend/src/components/Activities/ActivityHeader.vue:148
#: frontend/src/pages/Deals.vue:515 frontend/src/pages/Leads.vue:538
#: frontend/src/pages/Deals.vue:518 frontend/src/pages/Leads.vue:541
msgid "New Note"
msgstr ""
@ -2498,7 +2498,7 @@ msgstr ""
#: frontend/src/components/Activities/ActivityHeader.vue:52
#: frontend/src/components/Activities/ActivityHeader.vue:153
#: frontend/src/pages/Deals.vue:520 frontend/src/pages/Leads.vue:543
#: frontend/src/pages/Deals.vue:523 frontend/src/pages/Leads.vue:546
msgid "New Task"
msgstr ""
@ -2601,13 +2601,13 @@ msgstr ""
msgid "No {0} Available"
msgstr ""
#: frontend/src/pages/CallLogs.vue:53 frontend/src/pages/Contact.vue:165
#: frontend/src/pages/Contacts.vue:56 frontend/src/pages/Deals.vue:232
#: frontend/src/pages/EmailTemplates.vue:57 frontend/src/pages/Leads.vue:258
#: frontend/src/pages/CallLogs.vue:56 frontend/src/pages/Contact.vue:165
#: frontend/src/pages/Contacts.vue:59 frontend/src/pages/Deals.vue:235
#: frontend/src/pages/EmailTemplates.vue:60 frontend/src/pages/Leads.vue:261
#: frontend/src/pages/MobileContact.vue:154
#: frontend/src/pages/MobileOrganization.vue:143
#: frontend/src/pages/Notes.vue:92 frontend/src/pages/Organization.vue:157
#: frontend/src/pages/Organizations.vue:56 frontend/src/pages/Tasks.vue:181
#: frontend/src/pages/Organizations.vue:59 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr ""
@ -2912,7 +2912,7 @@ msgstr ""
msgid "Phone Numbers"
msgstr ""
#: frontend/src/components/ViewControls.vue:1127
#: frontend/src/components/ViewControls.vue:1140
msgid "Pin View"
msgstr ""
@ -2921,7 +2921,7 @@ msgstr ""
msgid "Pinned"
msgstr ""
#: frontend/src/components/ViewControls.vue:663
#: frontend/src/components/ViewControls.vue:676
msgid "Pinned Views"
msgstr ""
@ -3004,7 +3004,7 @@ msgstr ""
msgid "Public"
msgstr ""
#: frontend/src/components/ViewControls.vue:658
#: frontend/src/components/ViewControls.vue:671
msgid "Public Views"
msgstr ""
@ -3027,7 +3027,7 @@ msgstr ""
msgid "Quick Filters"
msgstr ""
#: frontend/src/components/ViewControls.vue:719
#: frontend/src/components/ViewControls.vue:732
msgid "Quick Filters updated successfully"
msgstr ""
@ -3358,7 +3358,7 @@ msgstr ""
msgid "Save Changes"
msgstr ""
#: frontend/src/components/ViewControls.vue:653
#: frontend/src/components/ViewControls.vue:666
msgid "Saved Views"
msgstr ""
@ -3437,7 +3437,7 @@ msgstr ""
msgid "Set as Primary Contact"
msgstr ""
#: frontend/src/components/ViewControls.vue:1112
#: frontend/src/components/ViewControls.vue:1125
msgid "Set as default"
msgstr ""
@ -3512,7 +3512,7 @@ msgstr ""
msgid "Standard Form Scripts can not be modified, duplicate the Form Script instead."
msgstr ""
#: frontend/src/components/ViewControls.vue:620
#: frontend/src/components/ViewControls.vue:633
msgid "Standard Views"
msgstr ""
@ -3852,11 +3852,11 @@ msgstr ""
msgid "Unknown"
msgstr ""
#: frontend/src/components/ViewControls.vue:1127
#: frontend/src/components/ViewControls.vue:1140
msgid "Unpin View"
msgstr ""
#: frontend/src/components/ViewControls.vue:964
#: frontend/src/components/ViewControls.vue:977
msgid "Unsaved Changes"
msgstr ""
@ -3878,7 +3878,7 @@ msgstr ""
#: frontend/src/components/Settings/SettingsPage.vue:31
#: frontend/src/components/Settings/TelephonySettings.vue:70
#: frontend/src/components/Telephony/ExotelCallUI.vue:219
#: frontend/src/components/ViewControls.vue:969
#: frontend/src/components/ViewControls.vue:982
msgid "Update"
msgstr ""
@ -4051,7 +4051,7 @@ msgstr ""
msgid "You do not have mobile number set in your Telephony Agent"
msgstr ""
#: frontend/src/components/ViewControls.vue:965
#: frontend/src/components/ViewControls.vue:978
msgid "You have unsaved changes. Do you want to save them?"
msgstr ""

View File

@ -78,11 +78,17 @@ declare module 'vue' {
EditIcon: typeof import('./src/components/Icons/EditIcon.vue')['default']
EditValueModal: typeof import('./src/components/Modals/EditValueModal.vue')['default']
Email2Icon: typeof import('./src/components/Icons/Email2Icon.vue')['default']
EmailAccountCard: typeof import('./src/components/Settings/EmailAccountCard.vue')['default']
EmailAccountList: typeof import('./src/components/Settings/EmailAccountList.vue')['default']
EmailAdd: typeof import('./src/components/Settings/EmailAdd.vue')['default']
EmailArea: typeof import('./src/components/Activities/EmailArea.vue')['default']
EmailAtIcon: typeof import('./src/components/Icons/EmailAtIcon.vue')['default']
EmailConfig: typeof import('./src/components/Settings/EmailConfig.vue')['default']
EmailContent: typeof import('./src/components/Activities/EmailContent.vue')['default']
EmailEdit: typeof import('./src/components/Settings/EmailEdit.vue')['default']
EmailEditor: typeof import('./src/components/EmailEditor.vue')['default']
EmailIcon: typeof import('./src/components/Icons/EmailIcon.vue')['default']
EmailProviderIcon: typeof import('./src/components/Settings/EmailProviderIcon.vue')['default']
EmailTemplateModal: typeof import('./src/components/Modals/EmailTemplateModal.vue')['default']
EmailTemplateSelectorModal: typeof import('./src/components/Modals/EmailTemplateSelectorModal.vue')['default']
EmailTemplatesListView: typeof import('./src/components/ListViews/EmailTemplatesListView.vue')['default']

View File

@ -0,0 +1,4 @@
<svg width="44" height="44" viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.5714 44L31.4286 44C38.3716 44 44 38.3716 44 31.4286L44 12.5714C44 5.62842 38.3716 0 31.4286 0L12.5714 0C5.62842 0 0 5.62842 0 12.5714L0 31.4286C0 38.3716 5.62842 44 12.5714 44Z" fill="#0466DC"/>
<path d="M9.42859 12.5715V14.8972L12.5714 17.4587L18.5743 22.3458C19.5329 23.1315 20.7586 23.5715 22 23.5715C23.2414 23.5715 24.4672 23.1315 25.4257 22.3458L31.4286 17.443V28.2701H12.5714V21.5287L9.42859 18.9672V27.4844C9.42859 29.653 11.1886 31.413 13.3572 31.413H30.6429C32.8115 31.413 34.5715 29.653 34.5715 27.4844V12.5715H9.42859ZM23.4457 19.9101C22.6286 20.5701 21.3714 20.5701 20.57 19.9101L15.4157 15.7144H28.6L23.4457 19.9101Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 763 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -64,7 +64,7 @@ import LoadingIndicator from '@/components/Icons/LoadingIndicator.vue'
import { createToast } from '@/utils'
import { usersStore } from '@/stores/users'
import { isMobileView } from '@/composables/settings'
import { ref } from 'vue'
import { ref, watch } from 'vue'
const props = defineProps({
doctype: {
@ -114,4 +114,20 @@ const tabs = createResource({
function saveChanges() {
data.save.submit()
}
watch(
() => data.doc,
(newValue, oldValue) => {
if (!oldValue) return
if (newValue && oldValue) {
const isDirty =
JSON.stringify(newValue) !== JSON.stringify(data.originalDoc)
data.isDirty = isDirty
if (isDirty) {
data.save.loading = false
}
}
},
{ deep: true },
)
</script>

View File

@ -0,0 +1,27 @@
<template>
<div class="flex-1 p-8">
<div v-if="step === 'email-add'" class="h-full">
<EmailAdd @update:step="updateStep" />
</div>
<div v-else-if="step === 'email-list'" class="h-full">
<EmailAccountList @update:step="updateStep" />
</div>
<div v-else-if="step === 'email-edit'" class="h-full">
<EmailEdit :account-data="accountData" @update:step="updateStep" />
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import EmailAdd from "./EmailAdd.vue";
import EmailAccountList from "./EmailAccountList.vue";
import EmailEdit from "./EmailEdit.vue";
const step = ref("email-list");
const accountData = ref(null);
function updateStep(newStep, data) {
step.value = newStep;
accountData.value = data;
}
</script>

View File

@ -6,8 +6,8 @@
>
<template #body>
<div class="flex h-[calc(100vh_-_8rem)]">
<div class="flex w-52 shrink-0 flex-col bg-surface-gray-2 p-2">
<h1 class="mb-3 px-2 pt-2 text-lg font-semibold text-ink-gray-9">
<div class="flex flex-col p-2 w-52 shrink-0 bg-surface-gray-2">
<h1 class="px-2 pt-2 mb-3 text-lg font-semibold text-ink-gray-9">
{{ __('Settings') }}
</h1>
<div v-for="tab in tabs">
@ -34,7 +34,7 @@
</div>
</div>
<div
class="flex relative flex-1 flex-col overflow-y-auto bg-surface-modal"
class="relative flex flex-col flex-1 overflow-y-auto bg-surface-modal"
>
<Button
class="absolute right-5 top-5"
@ -53,12 +53,14 @@ import WhatsAppIcon from '@/components/Icons/WhatsAppIcon.vue'
import ERPNextIcon from '@/components/Icons/ERPNextIcon.vue'
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
import InviteIcon from '@/components/Icons/InviteIcon.vue'
import Email2Icon from '@/components/Icons/Email2Icon.vue'
import GeneralSettings from '@/components/Settings/GeneralSettings.vue'
import InviteMemberPage from '@/components/Settings/InviteMemberPage.vue'
import ProfileSettings from '@/components/Settings/ProfileSettings.vue'
import WhatsAppSettings from '@/components/Settings/WhatsAppSettings.vue'
import ERPNextSettings from '@/components/Settings/ERPNextSettings.vue'
import TelephonySettings from '@/components/Settings/TelephonySettings.vue'
import EmailConfig from '@/components/Settings/EmailConfig.vue'
import SidebarLink from '@/components/SidebarLink.vue'
import { usersStore } from '@/stores/users'
import {
@ -101,6 +103,12 @@ const tabs = computed(() => {
component: markRaw(InviteMemberPage),
condition: () => isManager(),
},
{
label: __('Email Accounts'),
icon: Email2Icon,
component: markRaw(EmailConfig),
condition: () => isManager(),
},
],
},
{

View File

@ -0,0 +1,179 @@
import { validateEmail } from '../../utils'
const LogoGmail = '/images/gmail.png'
const LogoOutlook = '/images/outlook.png'
const LogoSendgrid = '/images/sendgrid.png'
const LogoSparkpost = '/images/sparkpost.webp'
const LogoYahoo = '/images/yahoo.png'
const LogoYandex = '/images/yandex.png'
const LogoFrappeMail = '/images/frappe-mail.svg'
const fixedFields = [
{
label: 'Account Name',
name: 'email_account_name',
type: 'text',
placeholder: 'Support / Sales',
},
{
label: 'Email ID',
name: 'email_id',
type: 'email',
placeholder: 'johndoe@example.com',
},
]
export const incomingOutgoingFields = [
{
label: 'Enable Incoming',
name: 'enable_incoming',
type: 'checkbox',
description:
'If enabled, tickets can be created from the incoming emails on this account.',
},
{
label: 'Enable Outgoing',
name: 'enable_outgoing',
type: 'checkbox',
description: 'If enabled, outgoing emails can be sent from this account.',
},
{
label: 'Default Incoming',
name: 'default_incoming',
type: 'checkbox',
description:
'If enabled, all replies to your company (eg: replies@yourcomany.com) will come to this account. Note: Only one account can be default incoming.',
},
{
label: 'Default Outgoing',
name: 'default_outgoing',
type: 'checkbox',
description:
'If enabled, all outgoing emails will be sent from this account. Note: Only one account can be default outgoing.',
},
]
export const popularProviderFields = [
...fixedFields,
{
label: 'Password',
name: 'password',
type: 'password',
placeholder: '********',
},
]
export const customProviderFields = [
...fixedFields,
{
label: 'Frappe Mail Site',
name: 'frappe_mail_site',
type: 'text',
placeholder: 'https://frappemail.com',
},
{
label: 'API Key',
name: 'api_key',
type: 'text',
placeholder: '********',
},
{
label: 'API Secret',
name: 'api_secret',
type: 'password',
placeholder: '********',
},
]
export const services = [
{
name: 'GMail',
icon: LogoGmail,
info: `Setting up GMail requires you to enable two factor authentication
and app specific passwords. Read more`,
link: 'https://support.google.com/accounts/answer/185833',
custom: false,
},
{
name: 'Outlook',
icon: LogoOutlook,
info: `Setting up Outlook requires you to enable two factor authentication
and app specific passwords. Read more`,
link: 'https://support.microsoft.com/en-us/account-billing/how-to-get-and-use-app-passwords-5896ed9b-4263-e681-128a-a6f2979a7944',
custom: false,
},
{
name: 'Sendgrid',
icon: LogoSendgrid,
info: `Setting up Sendgrid requires you to enable two factor authentication
and app specific passwords. Read more `,
link: 'https://sendgrid.com/docs/ui/account-and-settings/two-factor-authentication/',
custom: false,
},
{
name: 'SparkPost',
icon: LogoSparkpost,
info: `Setting up SparkPost requires you to enable two factor authentication
and app specific passwords. Read more `,
link: 'https://support.sparkpost.com/docs/my-account-and-profile/enabling-two-factor-authentication',
custom: false,
},
{
name: 'Yahoo',
icon: LogoYahoo,
info: `Setting up Yahoo requires you to enable two factor authentication
and app specific passwords. Read more `,
link: 'https://help.yahoo.com/kb/SLN15241.html',
custom: false,
},
{
name: 'Yandex',
icon: LogoYandex,
info: `Setting up Yandex requires you to enable two factor authentication
and app specific passwords. Read more `,
link: 'https://yandex.com/support/id/authorization/app-passwords.html',
custom: false,
},
{
name: 'Frappe Mail',
icon: LogoFrappeMail,
info: `Setting up Frappe Mail requires you to have an API key and API Secret of your email account. Read more `,
link: 'https://github.com/frappe/mail',
custom: true,
},
]
export const emailIcon = {
GMail: LogoGmail,
Outlook: LogoOutlook,
Sendgrid: LogoSendgrid,
SparkPost: LogoSparkpost,
Yahoo: LogoYahoo,
Yandex: LogoYandex,
'Frappe Mail': LogoFrappeMail,
}
export function validateInputs(state, isCustom) {
if (!state.email_account_name) {
return 'Account name is required'
}
if (!state.email_id) {
return 'Email ID is required'
}
const validEmail = validateEmail(state.email_id)
if (!validEmail) {
return 'Invalid email ID'
}
if (!isCustom && !state.password) {
return 'Password is required'
}
if (isCustom) {
if (!state.api_key) {
return 'API Key is required'
}
if (!state.api_secret) {
return
}
}
return ''
}

View File

@ -168,7 +168,11 @@
</template>
</Tabs>
</div>
<ErrorPage v-else :errorTitle="errorTitle" :errorMessage="errorMessage" />
<ErrorPage
v-else-if="errorTitle"
:errorTitle="errorTitle"
:errorMessage="errorMessage"
/>
<AddressModal v-model="showAddressModal" v-model:address="_address" />
</template>

View File

@ -267,7 +267,11 @@
</div>
</Resizer>
</div>
<ErrorPage v-else :errorTitle="errorTitle" :errorMessage="errorMessage" />
<ErrorPage
v-else-if="errorTitle"
:errorTitle="errorTitle"
:errorMessage="errorMessage"
/>
<OrganizationModal
v-model="showOrganizationModal"
v-model:organization="_organization"

View File

@ -191,7 +191,11 @@
</div>
</Resizer>
</div>
<ErrorPage v-else :errorTitle="errorTitle" :errorMessage="errorMessage" />
<ErrorPage
v-else-if="errorTitle"
:errorTitle="errorTitle"
:errorMessage="errorMessage"
/>
<Dialog
v-model="showConvertToDealModal"
:options="{

View File

@ -160,7 +160,11 @@
</template>
</Tabs>
</div>
<ErrorPage v-else :errorTitle="errorTitle" :errorMessage="errorMessage" />
<ErrorPage
v-else-if="errorTitle"
:errorTitle="errorTitle"
:errorMessage="errorMessage"
/>
<QuickEntryModal
v-if="showQuickEntryModal"
v-model="showQuickEntryModal"

13
frontend/src/types.ts Normal file
View File

@ -0,0 +1,13 @@
export interface EmailAccount {
email_account_name: string
email_id: string
service: string
api_key?: string
api_secret?: string
password?: string
frappe_mail_site?: string
enable_outgoing?: boolean
enable_incoming?: boolean
default_outgoing?: boolean
default_incoming?: boolean
}