diff --git a/crm/api/doc.py b/crm/api/doc.py index 16e6b2ef..1369a952 100644 --- a/crm/api/doc.py +++ b/crm/api/doc.py @@ -11,6 +11,7 @@ from pypika import Criterion from crm.api.views import get_views from crm.fcrm.doctype.crm_form_script.crm_form_script import get_form_script +from crm.utils import get_dynamic_linked_docs, get_linked_docs @frappe.whitelist() @@ -676,6 +677,7 @@ def remove_assignments(doctype, name, assignees, ignore_permissions=False): ignore_permissions=ignore_permissions, ) + @frappe.whitelist() def get_assigned_users(doctype, name, default_assigned_to=None): assigned_users = frappe.get_all( @@ -744,3 +746,98 @@ def getCounts(d, doctype): "FCRM Note", filters={"reference_doctype": doctype, "reference_docname": d.get("name")} ) return d + + +@frappe.whitelist() +def get_linked_docs_of_document(doctype, docname): + doc = frappe.get_doc(doctype, docname) + linked_docs = get_linked_docs(doc) + dynamic_linked_docs = get_dynamic_linked_docs(doc) + + linked_docs.extend(dynamic_linked_docs) + linked_docs = list({doc["reference_docname"]: doc for doc in linked_docs}.values()) + + docs_data = [] + for doc in linked_docs: + data = frappe.get_doc(doc["reference_doctype"], doc["reference_docname"]) + title = data.get("title") + if data.doctype == "CRM Call Log": + title = f"Call from {data.get('from')} to {data.get('to')}" + + if data.doctype == "CRM Deal": + title = data.get("organization") + + docs_data.append( + { + "doc": data.doctype, + "title": title or data.get("name"), + "reference_docname": doc["reference_docname"], + "reference_doctype": doc["reference_doctype"], + } + ) + return docs_data + + +def remove_doc_link(doctype, docname): + linked_doc_data = frappe.get_doc(doctype, docname) + linked_doc_data.update( + { + "reference_doctype": None, + "reference_docname": None, + } + ) + linked_doc_data.save(ignore_permissions=True) + + +def remove_contact_link(doctype, docname): + linked_doc_data = frappe.get_doc(doctype, docname) + linked_doc_data.update( + { + "contact": None, + "contacts": [], + } + ) + linked_doc_data.save(ignore_permissions=True) + + +@frappe.whitelist() +def remove_linked_doc_reference(items, remove_contact=None, delete=False): + if isinstance(items, str): + items = frappe.parse_json(items) + + for item in items: + if remove_contact: + remove_contact_link(item["doctype"], item["docname"]) + else: + remove_doc_link(item["doctype"], item["docname"]) + + if delete: + frappe.delete_doc(item["doctype"], item["docname"]) + + return "success" + + +@frappe.whitelist() +def delete_bulk_docs(doctype, items, delete_linked=False): + from frappe.desk.reportview import delete_bulk + + items = frappe.parse_json(items) + for doc in items: + linked_docs = get_linked_docs_of_document(doctype, doc) + for linked_doc in linked_docs: + remove_linked_doc_reference( + [ + { + "doctype": linked_doc["reference_doctype"], + "docname": linked_doc["reference_docname"], + } + ], + remove_contact=doctype == "Contact", + delete=delete_linked, + ) + + if len(items) > 10: + frappe.enqueue("frappe.desk.reportview.delete_bulk", doctype=doctype, items=items) + else: + delete_bulk(doctype, items) + return "success" diff --git a/crm/fcrm/doctype/crm_invitation/crm_invitation.py b/crm/fcrm/doctype/crm_invitation/crm_invitation.py index 965bf4d7..b7184d68 100644 --- a/crm/fcrm/doctype/crm_invitation/crm_invitation.py +++ b/crm/fcrm/doctype/crm_invitation/crm_invitation.py @@ -44,6 +44,10 @@ class CRMInvitation(Document): user = self.create_user_if_not_exists() user.append_roles(self.role) + if self.role == "System Manager": + user.append_roles("Sales Manager", "Sales User") + elif self.role == "Sales Manager": + user.append_roles("Sales User") if self.role == "Sales User": self.update_module_in_user(user, "FCRM") user.save(ignore_permissions=True) diff --git a/crm/locale/main.pot b/crm/locale/main.pot index cd121a1b..ab01579c 100644 --- a/crm/locale/main.pot +++ b/crm/locale/main.pot @@ -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-06-22 09:36+0000\n" -"PO-Revision-Date: 2025-06-22 09:36+0000\n" +"POT-Creation-Date: 2025-06-29 09:36+0000\n" +"PO-Revision-Date: 2025-06-29 09:36+0000\n" "Last-Translator: shariq@frappe.io\n" "Language-Team: shariq@frappe.io\n" "MIME-Version: 1.0\n" @@ -20,28 +20,28 @@ msgstr "" msgid " (New)" msgstr "" -#: frontend/src/components/Modals/TaskModal.vue:95 -#: frontend/src/components/Telephony/TaskPanel.vue:67 +#: frontend/src/components/Modals/TaskModal.vue:99 +#: frontend/src/components/Telephony/TaskPanel.vue:70 msgid "01/04/2024 11:30 PM" msgstr "" -#: frontend/src/utils/index.js:170 +#: frontend/src/utils/index.js:171 msgid "1 hour ago" msgstr "" -#: frontend/src/utils/index.js:166 +#: frontend/src/utils/index.js:167 msgid "1 minute ago" msgstr "" -#: frontend/src/utils/index.js:184 +#: frontend/src/utils/index.js:185 msgid "1 month ago" msgstr "" -#: frontend/src/utils/index.js:180 +#: frontend/src/utils/index.js:181 msgid "1 week ago" msgstr "" -#: frontend/src/utils/index.js:188 +#: frontend/src/utils/index.js:189 msgid "1 year ago" msgstr "" @@ -115,7 +115,8 @@ msgstr "" msgid "SHORTCUTS" msgstr "" -#: frontend/src/components/Modals/EmailTemplateModal.vue:67 +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:98 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:98 msgid "

Dear {{ lead_name }},

\\n\\n

This is a reminder for the payment of {{ grand_total }}.

\\n\\n

Thanks,

\\n

Frappé

" msgstr "" @@ -196,12 +197,16 @@ msgstr "" msgid "Actions" msgstr "" -#: frontend/src/pages/Deal.vue:552 frontend/src/pages/Lead.vue:541 +#: frontend/src/pages/Deal.vue:563 frontend/src/pages/Lead.vue:556 #: frontend/src/pages/MobileDeal.vue:443 frontend/src/pages/MobileLead.vue:344 msgid "Activity" msgstr "" -#: frontend/src/components/Settings/EmailAccountList.vue:9 +#: frontend/src/components/Modals/AddExistingUserModal.vue:53 +msgid "Add" +msgstr "" + +#: frontend/src/components/Settings/EmailAccountList.vue:19 msgid "Add Account" msgstr "" @@ -210,6 +215,11 @@ msgstr "" msgid "Add Column" msgstr "" +#: frontend/src/components/Modals/AddExistingUserModal.vue:4 +#: frontend/src/components/Settings/Users.vue:21 +msgid "Add Existing User" +msgstr "" + #: frontend/src/components/Controls/GridFieldsEditorModal.vue:58 #: frontend/src/components/FieldLayoutEditor.vue:173 #: frontend/src/components/Kanban/KanbanSettings.vue:84 @@ -252,6 +262,10 @@ msgstr "" msgid "Add description..." msgstr "" +#: frontend/src/components/Modals/AddExistingUserModal.vue:12 +msgid "Add existing system users to this CRM. Assign them a role to grant access with their current credentials." +msgstr "" + #: frontend/src/components/ViewControls.vue:104 msgid "Add filter" msgstr "" @@ -278,15 +292,30 @@ msgstr "" msgid "Add to Holidays" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:428 +#: frontend/src/components/Layouts/AppSidebar.vue:422 msgid "Add your first comment" msgstr "" +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:11 +msgid "Add, edit, and manage email templates for various CRM communications" +msgstr "" + #. Label of the address (Link) field in DocType 'CRM Organization' #: crm/fcrm/doctype/crm_organization/crm_organization.json msgid "Address" msgstr "" +#: frontend/src/components/Modals/AddExistingUserModal.vue:92 +#: frontend/src/components/Settings/InviteUserPage.vue:172 +#: frontend/src/components/Settings/InviteUserPage.vue:179 +#: frontend/src/components/Settings/Users.vue:86 +#: frontend/src/components/Settings/Users.vue:126 +#: frontend/src/components/Settings/Users.vue:184 +#: frontend/src/components/Settings/Users.vue:244 +#: frontend/src/components/Settings/Users.vue:247 +msgid "Admin" +msgstr "" + #: crm/integrations/twilio/twilio_handler.py:144 msgid "Agent is unavailable to take the call, please call after some time." msgstr "" @@ -300,14 +329,16 @@ msgstr "" #: crm/fcrm/doctype/crm_lead_source/crm_lead_source.json #: crm/fcrm/doctype/crm_lead_status/crm_lead_status.json #: crm/fcrm/doctype/fcrm_settings/fcrm_settings.json +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:76 +#: frontend/src/components/Settings/Users.vue:85 msgid "All" msgstr "" #. Label of the amount (Currency) field in DocType 'CRM Products' #: crm/fcrm/doctype/crm_products/crm_products.json -#: frontend/src/pages/Contact.vue:583 frontend/src/pages/MobileContact.vue:558 +#: frontend/src/pages/Contact.vue:573 frontend/src/pages/MobileContact.vue:558 #: frontend/src/pages/MobileOrganization.vue:460 -#: frontend/src/pages/Organization.vue:492 +#: frontend/src/pages/Organization.vue:484 msgid "Amount" msgstr "" @@ -348,11 +379,11 @@ msgstr "" msgid "Annual Revenue should be a number" msgstr "" -#: frontend/src/components/Settings/GeneralSettings.vue:49 +#: frontend/src/components/Settings/GeneralSettings.vue:64 msgid "Appears in the left sidebar. Recommended size is 32x32 px in PNG or SVG" msgstr "" -#: frontend/src/components/Settings/GeneralSettings.vue:84 +#: frontend/src/components/Settings/GeneralSettings.vue:99 msgid "Appears next to the title in your browser tab. Recommended size is 32x32 px in PNG or ICO" msgstr "" @@ -379,12 +410,11 @@ msgstr "" msgid "Are you sure you want to delete this attachment?" msgstr "" -#: frontend/src/pages/Contact.vue:310 frontend/src/pages/MobileContact.vue:282 +#: frontend/src/pages/MobileContact.vue:282 msgid "Are you sure you want to delete this contact?" msgstr "" #: frontend/src/pages/MobileOrganization.vue:267 -#: frontend/src/pages/Organization.vue:302 msgid "Are you sure you want to delete this organization?" msgstr "" @@ -392,6 +422,10 @@ msgstr "" msgid "Are you sure you want to delete this task?" msgstr "" +#: frontend/src/components/DeleteLinkedDocModal.vue:230 +msgid "Are you sure you want to delete {0} linked item(s)?" +msgstr "" + #: frontend/src/composables/frappecloud.js:24 msgid "Are you sure you want to login to your Frappe Cloud dashboard?" msgstr "" @@ -400,7 +434,11 @@ msgstr "" msgid "Are you sure you want to reset 'Create Quotation from CRM Deal' Form Script?" msgstr "" -#: frontend/src/components/ListBulkActions.vue:181 +#: frontend/src/components/DeleteLinkedDocModal.vue:243 +msgid "Are you sure you want to unlink {0} linked item(s)?" +msgstr "" + +#: frontend/src/components/ListBulkActions.vue:184 #: frontend/src/components/Modals/AssignmentModal.vue:5 msgid "Assign To" msgstr "" @@ -424,11 +462,11 @@ msgstr "" msgid "Assignment Rule" msgstr "" -#: frontend/src/components/ListBulkActions.vue:149 +#: frontend/src/components/ListBulkActions.vue:152 msgid "Assignment cleared successfully" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:571 +#: frontend/src/components/Layouts/AppSidebar.vue:565 msgid "Assignment rule" msgstr "" @@ -441,11 +479,11 @@ msgstr "" msgid "Attach" msgstr "" -#: frontend/src/pages/Deal.vue:133 frontend/src/pages/Lead.vue:183 +#: frontend/src/pages/Deal.vue:125 frontend/src/pages/Lead.vue:180 msgid "Attach a file" msgstr "" -#: frontend/src/pages/Deal.vue:587 frontend/src/pages/Lead.vue:576 +#: frontend/src/pages/Deal.vue:598 frontend/src/pages/Lead.vue:591 #: frontend/src/pages/MobileDeal.vue:479 frontend/src/pages/MobileLead.vue:380 msgid "Attachments" msgstr "" @@ -462,6 +500,7 @@ msgid "BCC" msgstr "" #: frontend/src/components/FilesUploader/FilesUploader.vue:31 +#: frontend/src/components/Settings/EmailAdd.vue:79 #: frontend/src/components/Settings/EmailEdit.vue:67 msgid "Back" msgstr "" @@ -479,8 +518,8 @@ msgstr "" msgid "Between" msgstr "" -#: frontend/src/components/Settings/GeneralSettings.vue:19 -msgid "Brand Name" +#: frontend/src/components/Settings/GeneralSettings.vue:34 +msgid "Brand name" msgstr "" #. Label of the branding_tab (Tab Break) field in DocType 'FCRM Settings' @@ -520,7 +559,6 @@ msgstr "" #. Name of a DocType #: crm/fcrm/doctype/crm_deal/crm_deal.json -#: frontend/src/components/Modals/EmailTemplateModal.vue:34 msgid "CRM Deal" msgstr "" @@ -682,7 +720,7 @@ msgstr "" msgid "Call duration in seconds" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:545 +#: frontend/src/components/Layouts/AppSidebar.vue:539 msgid "Call log" msgstr "" @@ -690,7 +728,7 @@ msgstr "" msgid "Call using {0}" msgstr "" -#: frontend/src/components/Modals/NoteModal.vue:43 +#: frontend/src/components/Modals/NoteModal.vue:30 #: frontend/src/components/Modals/TaskModal.vue:43 msgid "Call with John Doe" msgstr "" @@ -709,7 +747,7 @@ msgstr "" msgid "Calling..." msgstr "" -#: frontend/src/pages/Deal.vue:572 frontend/src/pages/Lead.vue:561 +#: frontend/src/pages/Deal.vue:583 frontend/src/pages/Lead.vue:576 #: frontend/src/pages/MobileDeal.vue:463 frontend/src/pages/MobileLead.vue:364 msgid "Calls" msgstr "" @@ -718,7 +756,9 @@ msgstr "" msgid "Camera" msgstr "" +#: frontend/src/components/BulkDeleteLinkedDocModal.vue:81 #: frontend/src/components/ColumnSettings.vue:132 +#: frontend/src/components/DeleteLinkedDocModal.vue:114 #: frontend/src/components/Modals/AssignmentModal.vue:9 #: frontend/src/components/Telephony/TwilioCallUI.vue:77 #: frontend/src/components/ViewControls.vue:56 @@ -733,6 +773,10 @@ msgstr "" msgid "Canceled" msgstr "" +#: frontend/src/components/Settings/Users.vue:124 +msgid "Cannot change role of user with Admin access" +msgstr "" + #: crm/fcrm/doctype/fcrm_settings/fcrm_settings.py:32 msgid "Cannot delete standard items {0}" msgstr "" @@ -741,23 +785,29 @@ msgstr "" msgid "Capture" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:550 +#: frontend/src/components/Layouts/AppSidebar.vue:544 msgid "Capturing leads" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:479 +#: frontend/src/components/Layouts/AppSidebar.vue:473 msgid "Change" msgstr "" +#: frontend/src/components/Modals/ChangePasswordModal.vue:2 +#: frontend/src/components/Settings/ProfileSettings.vue:65 +msgid "Change Password" +msgstr "" + #: frontend/src/components/Activities/TaskArea.vue:44 msgid "Change Status" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:470 -#: frontend/src/components/Layouts/AppSidebar.vue:478 +#: frontend/src/components/Layouts/AppSidebar.vue:464 +#: frontend/src/components/Layouts/AppSidebar.vue:472 msgid "Change deal status" msgstr "" +#: frontend/src/components/Settings/ProfileSettings.vue:26 #: frontend/src/pages/Contact.vue:41 frontend/src/pages/Lead.vue:101 #: frontend/src/pages/MobileContact.vue:34 #: frontend/src/pages/MobileOrganization.vue:37 @@ -765,7 +815,7 @@ msgstr "" msgid "Change image" msgstr "" -#: frontend/src/pages/Lead.vue:272 frontend/src/pages/Lead.vue:298 +#: frontend/src/pages/Lead.vue:279 frontend/src/pages/Lead.vue:305 #: frontend/src/pages/MobileLead.vue:122 frontend/src/pages/MobileLead.vue:149 msgid "Choose Existing" msgstr "" @@ -786,9 +836,9 @@ msgstr "" msgid "Clear" msgstr "" -#: frontend/src/components/ListBulkActions.vue:131 -#: frontend/src/components/ListBulkActions.vue:139 -#: frontend/src/components/ListBulkActions.vue:185 +#: frontend/src/components/ListBulkActions.vue:134 +#: frontend/src/components/ListBulkActions.vue:142 +#: frontend/src/components/ListBulkActions.vue:188 msgid "Clear Assignment" msgstr "" @@ -849,11 +899,11 @@ msgstr "" #: crm/fcrm/doctype/crm_notification/crm_notification.json #: frontend/src/components/CommentBox.vue:80 #: frontend/src/components/CommunicationArea.vue:19 -#: frontend/src/components/Layouts/AppSidebar.vue:568 +#: frontend/src/components/Layouts/AppSidebar.vue:562 msgid "Comment" msgstr "" -#: frontend/src/pages/Deal.vue:562 frontend/src/pages/Lead.vue:551 +#: frontend/src/pages/Deal.vue:573 frontend/src/pages/Lead.vue:566 #: frontend/src/pages/MobileDeal.vue:453 frontend/src/pages/MobileLead.vue:354 msgid "Comments" msgstr "" @@ -890,10 +940,32 @@ msgstr "" msgid "Condition" msgstr "" +#: frontend/src/components/Settings/GeneralSettings.vue:15 +msgid "Configure general settings for your CRM" +msgstr "" + +#: frontend/src/components/Settings/TelephonySettings.vue:17 +msgid "Configure telephony settings for your CRM" +msgstr "" + #: frontend/src/composables/frappecloud.js:29 msgid "Confirm" msgstr "" +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:250 +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:253 +msgid "Confirm Delete" +msgstr "" + +#: frontend/src/components/Modals/ChangePasswordModal.vue:18 +msgid "Confirm Password" +msgstr "" + +#: frontend/src/components/Settings/Users.vue:225 +#: frontend/src/components/Settings/Users.vue:228 +msgid "Confirm Remove" +msgstr "" + #: frontend/src/pages/Welcome.vue:35 msgid "Connect your email" msgstr "" @@ -902,8 +974,8 @@ msgstr "" #. Label of the contact (Link) field in DocType 'CRM Deal' #: crm/fcrm/doctype/crm_contacts/crm_contacts.json #: crm/fcrm/doctype/crm_deal/crm_deal.json -#: frontend/src/components/Layouts/AppSidebar.vue:541 -#: frontend/src/pages/Lead.vue:294 frontend/src/pages/MobileLead.vue:145 +#: frontend/src/components/Layouts/AppSidebar.vue:535 +#: frontend/src/pages/Lead.vue:301 frontend/src/pages/MobileLead.vue:145 msgid "Contact" msgstr "" @@ -919,11 +991,11 @@ msgstr "" msgid "Contact Us" msgstr "" -#: frontend/src/pages/Deal.vue:666 frontend/src/pages/MobileDeal.vue:557 +#: frontend/src/pages/Deal.vue:677 frontend/src/pages/MobileDeal.vue:557 msgid "Contact added" msgstr "" -#: frontend/src/pages/Deal.vue:656 frontend/src/pages/MobileDeal.vue:547 +#: frontend/src/pages/Deal.vue:667 frontend/src/pages/MobileDeal.vue:547 msgid "Contact already added" msgstr "" @@ -935,12 +1007,12 @@ msgstr "" msgid "Contact not found" msgstr "" -#: frontend/src/pages/Deal.vue:677 frontend/src/pages/MobileDeal.vue:568 +#: frontend/src/pages/Deal.vue:688 frontend/src/pages/MobileDeal.vue:568 msgid "Contact removed" msgstr "" -#: frontend/src/pages/Contact.vue:508 frontend/src/pages/Contact.vue:521 -#: frontend/src/pages/Contact.vue:534 frontend/src/pages/Contact.vue:544 +#: frontend/src/pages/Contact.vue:498 frontend/src/pages/Contact.vue:511 +#: frontend/src/pages/Contact.vue:524 frontend/src/pages/Contact.vue:534 #: frontend/src/pages/MobileContact.vue:483 #: frontend/src/pages/MobileContact.vue:496 #: frontend/src/pages/MobileContact.vue:509 @@ -953,38 +1025,48 @@ msgstr "" #. Label of a shortcut in the Frappe CRM Workspace #: crm/fcrm/doctype/crm_deal/crm_deal.json #: crm/fcrm/workspace/frappe_crm/frappe_crm.json -#: frontend/src/pages/Contact.vue:261 frontend/src/pages/MobileContact.vue:233 +#: frontend/src/pages/Contact.vue:268 frontend/src/pages/MobileContact.vue:233 #: frontend/src/pages/MobileOrganization.vue:340 msgid "Contacts" msgstr "" #. Label of the content (Text Editor) field in DocType 'FCRM Note' #: crm/fcrm/doctype/fcrm_note/fcrm_note.json -#: frontend/src/components/Modals/EmailTemplateModal.vue:61 -#: frontend/src/components/Modals/EmailTemplateModal.vue:74 -#: frontend/src/components/Modals/NoteModal.vue:47 +#: frontend/src/components/Modals/NoteModal.vue:34 +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:92 +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:105 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:92 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:105 msgid "Content" msgstr "" -#: frontend/src/components/Modals/EmailTemplateModal.vue:51 +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:81 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:81 msgid "Content Type" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:369 -#: frontend/src/components/ListBulkActions.vue:70 -#: frontend/src/pages/Lead.vue:228 frontend/src/pages/MobileLead.vue:61 +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:163 +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:167 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:165 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:169 +msgid "Content is required" +msgstr "" + +#: frontend/src/components/Layouts/AppSidebar.vue:363 +#: frontend/src/components/ListBulkActions.vue:88 +#: frontend/src/pages/Lead.vue:235 frontend/src/pages/MobileLead.vue:61 #: frontend/src/pages/MobileLead.vue:108 msgid "Convert" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:360 -#: frontend/src/components/Layouts/AppSidebar.vue:368 +#: frontend/src/components/Layouts/AppSidebar.vue:354 +#: frontend/src/components/Layouts/AppSidebar.vue:362 msgid "Convert lead to deal" msgstr "" -#: frontend/src/components/ListBulkActions.vue:62 -#: frontend/src/components/ListBulkActions.vue:192 -#: frontend/src/pages/Lead.vue:52 frontend/src/pages/Lead.vue:239 +#: frontend/src/components/ListBulkActions.vue:80 +#: frontend/src/components/ListBulkActions.vue:195 +#: frontend/src/pages/Lead.vue:52 frontend/src/pages/Lead.vue:246 #: frontend/src/pages/MobileLead.vue:104 msgid "Convert to Deal" msgstr "" @@ -994,11 +1076,11 @@ msgstr "" msgid "Converted" msgstr "" -#: frontend/src/components/ListBulkActions.vue:78 +#: frontend/src/components/ListBulkActions.vue:96 msgid "Converted successfully" msgstr "" -#: frontend/src/utils/index.js:342 +#: frontend/src/utils/index.js:343 msgid "Copied to clipboard" msgstr "" @@ -1007,16 +1089,17 @@ msgstr "" #: frontend/src/components/Modals/ContactModal.vue:41 #: frontend/src/components/Modals/CreateDocumentModal.vue:92 #: frontend/src/components/Modals/DealModal.vue:67 -#: frontend/src/components/Modals/EmailTemplateModal.vue:9 +#: frontend/src/components/Modals/EmailTemplateSelectorModal.vue:20 #: frontend/src/components/Modals/LeadModal.vue:38 #: frontend/src/components/Modals/NoteModal.vue:6 #: frontend/src/components/Modals/OrganizationModal.vue:42 -#: frontend/src/components/Modals/TaskModal.vue:6 +#: frontend/src/components/Modals/TaskModal.vue:8 #: frontend/src/components/Modals/ViewModal.vue:16 +#: frontend/src/components/Settings/EmailAdd.vue:85 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:19 #: frontend/src/pages/CallLogs.vue:11 frontend/src/pages/Contacts.vue:13 #: 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/Deals.vue:236 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:60 frontend/src/pages/Tasks.vue:11 @@ -1034,16 +1117,12 @@ msgstr "" msgid "Create Deal" msgstr "" -#: frontend/src/components/Modals/EmailTemplateModal.vue:5 -msgid "Create Email Template" -msgstr "" - #: frontend/src/components/Modals/LeadModal.vue:8 msgid "Create Lead" msgstr "" #: frontend/src/components/Controls/Link.vue:48 -#: frontend/src/components/Modals/EmailTemplateSelectorModal.vue:55 +#: frontend/src/components/Modals/EmailTemplateSelectorModal.vue:69 #: frontend/src/components/Modals/WhatsappTemplateSelectorModal.vue:45 #: frontend/src/components/SidePanelLayout.vue:140 msgid "Create New" @@ -1055,7 +1134,7 @@ msgid "Create Note" msgstr "" #: frontend/src/components/Activities/Activities.vue:398 -#: frontend/src/components/Modals/TaskModal.vue:15 +#: frontend/src/components/Modals/TaskModal.vue:18 msgid "Create Task" msgstr "" @@ -1074,15 +1153,15 @@ msgstr "" msgid "Create lead" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:338 +#: frontend/src/components/Layouts/AppSidebar.vue:332 msgid "Create your first lead" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:408 +#: frontend/src/components/Layouts/AppSidebar.vue:402 msgid "Create your first note" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:388 +#: frontend/src/components/Layouts/AppSidebar.vue:382 msgid "Create your first task" msgstr "" @@ -1093,31 +1172,31 @@ msgstr "" msgid "Currency" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:580 +#: frontend/src/components/Layouts/AppSidebar.vue:574 msgid "Custom actions" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:530 +#: frontend/src/components/Layouts/AppSidebar.vue:524 msgid "Custom branding" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:579 +#: frontend/src/components/Layouts/AppSidebar.vue:573 msgid "Custom fields" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:582 +#: frontend/src/components/Layouts/AppSidebar.vue:576 msgid "Custom list actions" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:581 +#: frontend/src/components/Layouts/AppSidebar.vue:575 msgid "Custom statuses" msgstr "" -#: frontend/src/pages/Deal.vue:457 +#: frontend/src/pages/Deal.vue:464 msgid "Customer created successfully" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:576 +#: frontend/src/components/Layouts/AppSidebar.vue:570 msgid "Customization" msgstr "" @@ -1126,8 +1205,8 @@ msgid "Customize quick filters" msgstr "" #: frontend/src/components/Activities/DataFields.vue:6 -#: frontend/src/components/Layouts/AppSidebar.vue:569 -#: frontend/src/pages/Deal.vue:567 frontend/src/pages/Lead.vue:556 +#: frontend/src/components/Layouts/AppSidebar.vue:563 +#: frontend/src/pages/Deal.vue:578 frontend/src/pages/Lead.vue:571 #: frontend/src/pages/MobileDeal.vue:458 frontend/src/pages/MobileLead.vue:359 msgid "Data" msgstr "" @@ -1142,7 +1221,12 @@ msgstr "" msgid "Date" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:540 +#: frontend/src/components/Layouts/AppSidebar.vue:534 +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:54 +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:62 +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:78 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:54 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:62 #: frontend/src/components/Telephony/ExotelCallUI.vue:205 #: frontend/src/pages/Tasks.vue:129 msgid "Deal" @@ -1168,25 +1252,26 @@ msgstr "" msgid "Deal Value" msgstr "" -#: frontend/src/pages/Contact.vue:604 frontend/src/pages/MobileContact.vue:579 +#: frontend/src/pages/Contact.vue:594 frontend/src/pages/MobileContact.vue:579 #: frontend/src/pages/MobileOrganization.vue:481 -#: frontend/src/pages/Organization.vue:513 +#: frontend/src/pages/Organization.vue:505 msgid "Deal owner" msgstr "" -#: frontend/src/pages/Deal.vue:493 frontend/src/pages/MobileDeal.vue:378 +#: frontend/src/pages/Deal.vue:504 frontend/src/pages/MobileDeal.vue:378 msgid "Deal updated" msgstr "" #. Label of a shortcut in the Frappe CRM Workspace #: crm/fcrm/workspace/frappe_crm/frappe_crm.json -#: frontend/src/pages/Deal.vue:512 frontend/src/pages/MobileContact.vue:310 +#: frontend/src/pages/Deal.vue:523 frontend/src/pages/MobileContact.vue:310 #: frontend/src/pages/MobileDeal.vue:397 #: frontend/src/pages/MobileOrganization.vue:334 msgid "Deals" msgstr "" -#: frontend/src/components/Modals/EmailTemplateModal.vue:84 +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:115 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:115 msgid "Dear {{ lead_name }}, \\n\\nThis is a reminder for the payment of {{ grand_total }}. \\n\\nThanks, \\nFrappé" msgstr "" @@ -1230,7 +1315,7 @@ msgstr "" msgid "Default Service Level Agreement already exists for {0}" msgstr "" -#: frontend/src/components/Settings/TelephonySettings.vue:29 +#: frontend/src/components/Settings/TelephonySettings.vue:44 msgid "Default calling medium for logged in user" msgstr "" @@ -1238,11 +1323,11 @@ msgstr "" msgid "Default calling medium set successfully to {0}" msgstr "" -#: frontend/src/components/Settings/TelephonySettings.vue:278 +#: frontend/src/components/Settings/TelephonySettings.vue:280 msgid "Default calling medium updated successfully" msgstr "" -#: frontend/src/components/Settings/TelephonySettings.vue:22 +#: frontend/src/components/Settings/TelephonySettings.vue:37 msgid "Default medium" msgstr "" @@ -1255,21 +1340,27 @@ msgstr "" #: frontend/src/components/Activities/NoteArea.vue:12 #: frontend/src/components/Activities/TaskArea.vue:55 #: frontend/src/components/Activities/TaskArea.vue:63 +#: frontend/src/components/BulkDeleteLinkedDocModal.vue:8 +#: frontend/src/components/BulkDeleteLinkedDocModal.vue:48 +#: frontend/src/components/BulkDeleteLinkedDocModal.vue:73 +#: frontend/src/components/BulkDeleteLinkedDocModal.vue:121 #: frontend/src/components/Controls/Grid.vue:316 +#: frontend/src/components/DeleteLinkedDocModal.vue:10 +#: frontend/src/components/DeleteLinkedDocModal.vue:89 #: frontend/src/components/Kanban/KanbanView.vue:225 -#: frontend/src/components/ListBulkActions.vue:92 -#: frontend/src/components/ListBulkActions.vue:100 -#: frontend/src/components/ListBulkActions.vue:174 +#: frontend/src/components/ListBulkActions.vue:177 +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:235 +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:238 #: frontend/src/components/ViewControls.vue:1161 #: frontend/src/components/ViewControls.vue:1172 -#: frontend/src/pages/Contact.vue:105 frontend/src/pages/Contact.vue:313 -#: frontend/src/pages/MobileContact.vue:81 +#: frontend/src/pages/Contact.vue:105 frontend/src/pages/Deal.vue:132 +#: frontend/src/pages/Lead.vue:189 frontend/src/pages/MobileContact.vue:81 #: frontend/src/pages/MobileContact.vue:285 #: frontend/src/pages/MobileDeal.vue:528 #: frontend/src/pages/MobileOrganization.vue:72 #: frontend/src/pages/MobileOrganization.vue:270 #: frontend/src/pages/Notes.vue:40 frontend/src/pages/Organization.vue:83 -#: frontend/src/pages/Organization.vue:305 frontend/src/pages/Tasks.vue:368 +#: frontend/src/pages/Tasks.vue:369 msgid "Delete" msgstr "" @@ -1286,22 +1377,41 @@ msgstr "" msgid "Delete View" msgstr "" +#: frontend/src/components/DeleteLinkedDocModal.vue:65 +msgid "Delete all" +msgstr "" + #: frontend/src/components/Activities/AttachmentArea.vue:60 #: frontend/src/components/Activities/AttachmentArea.vue:131 msgid "Delete attachment" msgstr "" -#: frontend/src/pages/Contact.vue:309 frontend/src/pages/MobileContact.vue:281 +#: frontend/src/pages/MobileContact.vue:281 msgid "Delete contact" msgstr "" +#: frontend/src/components/DeleteLinkedDocModal.vue:229 +msgid "Delete linked item" +msgstr "" + +#: frontend/src/components/DeleteLinkedDocModal.vue:11 +msgid "Delete or unlink linked documents" +msgstr "" + +#: frontend/src/components/DeleteLinkedDocModal.vue:23 +msgid "Delete or unlink these linked documents before deleting this document" +msgstr "" + #: frontend/src/pages/MobileOrganization.vue:266 -#: frontend/src/pages/Organization.vue:301 msgid "Delete organization" msgstr "" -#: frontend/src/components/ListBulkActions.vue:109 -msgid "Deleted successfully" +#: frontend/src/components/DeleteLinkedDocModal.vue:66 +msgid "Delete {0} item(s)" +msgstr "" + +#: frontend/src/components/BulkDeleteLinkedDocModal.vue:28 +msgid "Delete {0} items" msgstr "" #. Label of the description (Text Editor) field in DocType 'CRM Holiday' @@ -1310,7 +1420,7 @@ msgstr "" #: crm/fcrm/doctype/crm_holiday/crm_holiday.json #: crm/fcrm/doctype/crm_product/crm_product.json #: crm/fcrm/doctype/crm_task/crm_task.json -#: frontend/src/components/Modals/TaskModal.vue:48 +#: frontend/src/components/Modals/TaskModal.vue:49 msgid "Description" msgstr "" @@ -1368,10 +1478,6 @@ msgstr "" msgid "DocType" msgstr "" -#: frontend/src/components/Modals/EmailTemplateModal.vue:32 -msgid "Doctype" -msgstr "" - #. Label of the dt (Link) field in DocType 'CRM Fields Layout' #: crm/fcrm/doctype/crm_fields_layout/crm_fields_layout.json msgid "Document Type" @@ -1418,6 +1524,9 @@ msgid "Due Date" msgstr "" #: frontend/src/components/Modals/ViewModal.vue:15 +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:225 +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:228 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:19 #: frontend/src/components/ViewControls.vue:1113 msgid "Duplicate" msgstr "" @@ -1426,6 +1535,10 @@ msgstr "" msgid "Duplicate View" msgstr "" +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:10 +msgid "Duplicate template" +msgstr "" + #. Label of the duration (Duration) field in DocType 'CRM Call Log' #. Label of the duration (Duration) field in DocType 'CRM Status Change Log' #: crm/fcrm/doctype/crm_call_log/crm_call_log.json @@ -1433,8 +1546,8 @@ msgstr "" msgid "Duration" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:593 -#: frontend/src/components/Settings/Settings.vue:130 +#: frontend/src/components/Layouts/AppSidebar.vue:587 +#: frontend/src/components/Settings/Settings.vue:135 msgid "ERPNext" msgstr "" @@ -1443,14 +1556,6 @@ msgstr "" msgid "ERPNext CRM Settings" msgstr "" -#: frontend/src/components/Settings/ERPNextSettings.vue:4 -msgid "ERPNext Settings" -msgstr "" - -#: frontend/src/components/Settings/ERPNextSettings.vue:5 -msgid "ERPNext Settings updated" -msgstr "" - #. Label of the section_break_oubd (Section Break) field in DocType 'ERPNext #. CRM Settings' #: crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.json @@ -1471,10 +1576,18 @@ msgstr "" msgid "ERPNext is not integrated with the CRM" msgstr "" +#: frontend/src/components/Settings/ERPNextSettings.vue:4 +msgid "ERPNext settings" +msgstr "" + +#: frontend/src/components/Settings/ERPNextSettings.vue:5 +msgid "ERPNext settings updated" +msgstr "" + #: frontend/src/components/FieldLayout/Field.vue:91 #: frontend/src/components/FieldLayoutEditor.vue:319 #: frontend/src/components/FieldLayoutEditor.vue:345 -#: frontend/src/components/ListBulkActions.vue:167 +#: frontend/src/components/ListBulkActions.vue:170 #: frontend/src/components/ViewControls.vue:1131 msgid "Edit" msgstr "" @@ -1523,11 +1636,6 @@ msgstr "" msgid "Edit note" msgstr "" -#: frontend/src/components/Settings/ProfileSettings.vue:19 -#: frontend/src/components/Settings/ProfileSettings.vue:23 -msgid "Edit profile photo" -msgstr "" - #: frontend/src/components/Modals/CallLogDetailModal.vue:24 msgid "Edit task" msgstr "" @@ -1543,16 +1651,15 @@ msgstr "" #: crm/fcrm/doctype/crm_contacts/crm_contacts.json #: crm/fcrm/doctype/crm_deal/crm_deal.json #: crm/fcrm/doctype/crm_invitation/crm_invitation.json -#: crm/fcrm/doctype/crm_lead/crm_lead.json frontend/src/pages/Contact.vue:594 +#: crm/fcrm/doctype/crm_lead/crm_lead.json frontend/src/pages/Contact.vue:584 #: frontend/src/pages/MobileContact.vue:569 #: frontend/src/pages/MobileOrganization.vue:471 #: frontend/src/pages/MobileOrganization.vue:499 -#: frontend/src/pages/Organization.vue:503 -#: frontend/src/pages/Organization.vue:531 +#: frontend/src/pages/Organization.vue:495 +#: frontend/src/pages/Organization.vue:523 msgid "Email" msgstr "" -#: frontend/src/components/Settings/EmailAccountList.vue:6 #: frontend/src/components/Settings/Settings.vue:107 msgid "Email Accounts" msgstr "" @@ -1567,6 +1674,7 @@ msgid "Email Sent At" msgstr "" #: frontend/src/components/Modals/EmailTemplateSelectorModal.vue:4 +#: frontend/src/components/Settings/Settings.vue:113 msgid "Email Templates" msgstr "" @@ -1578,7 +1686,11 @@ msgstr "" msgid "Email account updated successfully" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:567 +#: frontend/src/components/Settings/EmailAccountList.vue:7 +msgid "Email accounts" +msgstr "" + +#: frontend/src/components/Layouts/AppSidebar.vue:561 msgid "Email communication" msgstr "" @@ -1586,11 +1698,15 @@ msgstr "" msgid "Email from Lead" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:546 +#: frontend/src/components/Layouts/AppSidebar.vue:540 msgid "Email template" msgstr "" -#: frontend/src/pages/Deal.vue:557 frontend/src/pages/Lead.vue:546 +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:7 +msgid "Email templates" +msgstr "" + +#: frontend/src/pages/Deal.vue:568 frontend/src/pages/Lead.vue:561 #: frontend/src/pages/MobileDeal.vue:448 frontend/src/pages/MobileLead.vue:349 msgid "Emails" msgstr "" @@ -1634,7 +1750,9 @@ msgstr "" #: crm/fcrm/doctype/crm_service_level_agreement/crm_service_level_agreement.json #: crm/fcrm/doctype/crm_twilio_settings/crm_twilio_settings.json #: crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.json -#: frontend/src/components/Modals/EmailTemplateModal.vue:92 +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:33 +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:85 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:33 msgid "Enabled" msgstr "" @@ -1650,7 +1768,7 @@ msgstr "" msgid "End Time" msgstr "" -#: frontend/src/components/FieldLayout/Field.vue:330 +#: frontend/src/components/FieldLayout/Field.vue:334 msgid "Enter {0}" msgstr "" @@ -1664,7 +1782,7 @@ msgstr "" msgid "Equals" msgstr "" -#: frontend/src/pages/Lead.vue:666 +#: frontend/src/pages/Lead.vue:685 msgid "Error converting to deal: {0}" msgstr "" @@ -1672,7 +1790,7 @@ msgstr "" msgid "Error updating deal" msgstr "" -#: frontend/src/pages/Deal.vue:497 +#: frontend/src/pages/Deal.vue:508 msgid "Error updating deal: {0}" msgstr "" @@ -1680,7 +1798,7 @@ msgstr "" msgid "Error updating document" msgstr "" -#: frontend/src/pages/Lead.vue:486 +#: frontend/src/pages/Lead.vue:501 msgid "Error updating lead" msgstr "" @@ -1707,9 +1825,9 @@ msgstr "" #. Agent' #: crm/fcrm/doctype/crm_call_log/crm_call_log.json #: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json -#: frontend/src/components/Layouts/AppSidebar.vue:591 -#: frontend/src/components/Settings/TelephonySettings.vue:26 -#: frontend/src/components/Settings/TelephonySettings.vue:48 +#: frontend/src/components/Layouts/AppSidebar.vue:585 +#: frontend/src/components/Settings/TelephonySettings.vue:41 +#: frontend/src/components/Settings/TelephonySettings.vue:63 msgid "Exotel" msgstr "" @@ -1730,11 +1848,11 @@ msgstr "" msgid "Exotel Number {0} is not valid" msgstr "" -#: frontend/src/components/Settings/TelephonySettings.vue:291 +#: frontend/src/components/Settings/TelephonySettings.vue:293 msgid "Exotel is not enabled" msgstr "" -#: frontend/src/components/Settings/TelephonySettings.vue:138 +#: frontend/src/components/Settings/TelephonySettings.vue:140 msgid "Exotel settings updated successfully" msgstr "" @@ -1779,6 +1897,10 @@ msgstr "" msgid "Failed" msgstr "" +#: frontend/src/components/Modals/AddExistingUserModal.vue:109 +msgid "Failed to add users" +msgstr "" + #: crm/integrations/twilio/api.py:130 msgid "Failed to capture Twilio recording" msgstr "" @@ -1787,10 +1909,22 @@ msgstr "" msgid "Failed to create email account, Invalid credentials" msgstr "" +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:182 +msgid "Failed to create template" +msgstr "" + +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:217 +msgid "Failed to delete template" +msgstr "" + #: frontend/src/data/script.js:110 msgid "Failed to load form controller: {0}" msgstr "" +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:246 +msgid "Failed to rename template" +msgstr "" + #: crm/integrations/twilio/api.py:152 msgid "Failed to update Twilio call status" msgstr "" @@ -1799,9 +1933,22 @@ msgstr "" msgid "Failed to update email account, Invalid credentials" msgstr "" +#: frontend/src/components/Modals/ChangePasswordModal.vue:95 +msgid "Failed to update password" +msgstr "" + +#: frontend/src/components/Settings/ProfileSettings.vue:151 +msgid "Failed to update profile" +msgstr "" + +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:212 +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:202 +msgid "Failed to update template" +msgstr "" + #. Label of the favicon (Attach) field in DocType 'FCRM Settings' #: crm/fcrm/doctype/fcrm_settings/fcrm_settings.json -#: frontend/src/components/Settings/GeneralSettings.vue:62 +#: frontend/src/components/Settings/GeneralSettings.vue:77 msgid "Favicon" msgstr "" @@ -1879,9 +2026,16 @@ msgid "First Response Time" msgstr "" #: frontend/src/components/Filter.vue:131 +#: frontend/src/components/Settings/ProfileSettings.vue:78 msgid "First name" msgstr "" +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:51 +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:84 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:51 +msgid "For" +msgstr "" + #. Option for the 'Apply To' (Select) field in DocType 'CRM Form Script' #: crm/fcrm/doctype/crm_form_script/crm_form_script.json msgid "Form" @@ -1896,7 +2050,7 @@ msgstr "" msgid "Frappe CRM" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:597 +#: frontend/src/components/Layouts/AppSidebar.vue:591 msgid "Frappe CRM mobile" msgstr "" @@ -1949,8 +2103,8 @@ msgstr "" msgid "Gender" msgstr "" -#: frontend/src/components/Settings/GeneralSettings.vue:4 -#: frontend/src/components/Settings/Settings.vue:95 +#: frontend/src/components/Settings/GeneralSettings.vue:6 +#: frontend/src/components/Settings/Settings.vue:89 msgid "General" msgstr "" @@ -1958,7 +2112,7 @@ msgstr "" msgid "GitHub Repository" msgstr "" -#: frontend/src/pages/Deal.vue:117 frontend/src/pages/Lead.vue:167 +#: frontend/src/pages/Deal.vue:112 frontend/src/pages/Lead.vue:165 msgid "Go to website" msgstr "" @@ -2000,6 +2154,10 @@ msgstr "" msgid "Hide" msgstr "" +#: frontend/src/components/Controls/Password.vue:19 +msgid "Hide Password" +msgstr "" + #: frontend/src/components/Activities/CallArea.vue:74 msgid "Hide Recording" msgstr "" @@ -2042,8 +2200,8 @@ msgstr "" msgid "Holidays" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:531 -#: frontend/src/components/Settings/GeneralSettings.vue:97 +#: frontend/src/components/Layouts/AppSidebar.vue:525 +#: frontend/src/components/Settings/GeneralSettings.vue:112 msgid "Home actions" msgstr "" @@ -2143,7 +2301,7 @@ msgstr "" msgid "Initiating call..." msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:587 +#: frontend/src/components/Layouts/AppSidebar.vue:581 msgid "Integration" msgstr "" @@ -2151,13 +2309,13 @@ msgstr "" msgid "Integration Not Enabled" msgstr "" -#: frontend/src/components/Settings/Settings.vue:115 +#: frontend/src/components/Settings/Settings.vue:120 msgctxt "FCRM" msgid "Integrations" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:518 -#: frontend/src/components/Layouts/AppSidebar.vue:521 +#: frontend/src/components/Layouts/AppSidebar.vue:512 +#: frontend/src/components/Layouts/AppSidebar.vue:515 msgid "Introduction" msgstr "" @@ -2182,23 +2340,31 @@ msgstr "" msgid "Invalid email ID" msgstr "" -#: frontend/src/components/Settings/Settings.vue:101 -msgid "Invite Members" +#: frontend/src/components/Settings/Users.vue:25 +msgid "Invite New User" msgstr "" -#: frontend/src/components/Settings/InviteMemberPage.vue:30 +#: frontend/src/components/Settings/Settings.vue:101 +msgid "Invite User" +msgstr "" + +#: frontend/src/components/Settings/InviteUserPage.vue:56 msgid "Invite as" msgstr "" -#: frontend/src/components/Settings/InviteMemberPage.vue:9 +#: frontend/src/components/Settings/InviteUserPage.vue:29 msgid "Invite by email" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:532 -msgid "Invite members" +#: frontend/src/components/Layouts/AppSidebar.vue:526 +msgid "Invite users" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:348 +#: frontend/src/components/Settings/InviteUserPage.vue:10 +msgid "Invite users to access CRM. Specify their roles to control access and permissions" +msgstr "" + +#: frontend/src/components/Layouts/AppSidebar.vue:342 msgid "Invite your team" msgstr "" @@ -2269,7 +2435,7 @@ msgstr "" #: frontend/src/components/Filter.vue:75 frontend/src/components/Filter.vue:108 #: frontend/src/components/Modals/AssignmentModal.vue:35 -#: frontend/src/components/Modals/TaskModal.vue:75 +#: frontend/src/components/Modals/TaskModal.vue:76 #: frontend/src/components/Telephony/TaskPanel.vue:47 msgid "John Doe" msgstr "" @@ -2342,14 +2508,18 @@ msgstr "" msgid "Last Year" msgstr "" -#: frontend/src/pages/Contact.vue:609 frontend/src/pages/MobileContact.vue:584 +#: frontend/src/pages/Contact.vue:599 frontend/src/pages/MobileContact.vue:584 #: frontend/src/pages/MobileOrganization.vue:486 #: frontend/src/pages/MobileOrganization.vue:514 -#: frontend/src/pages/Organization.vue:518 -#: frontend/src/pages/Organization.vue:546 +#: frontend/src/pages/Organization.vue:510 +#: frontend/src/pages/Organization.vue:538 msgid "Last modified" msgstr "" +#: frontend/src/components/Settings/ProfileSettings.vue:83 +msgid "Last name" +msgstr "" + #. Label of the layout (Code) field in DocType 'CRM Fields Layout' #: crm/fcrm/doctype/crm_fields_layout/crm_fields_layout.json msgid "Layout" @@ -2357,7 +2527,10 @@ msgstr "" #. Label of the lead (Link) field in DocType 'CRM Deal' #: crm/fcrm/doctype/crm_deal/crm_deal.json -#: frontend/src/components/Layouts/AppSidebar.vue:539 +#: frontend/src/components/Layouts/AppSidebar.vue:533 +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:58 +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:77 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:58 #: frontend/src/components/Telephony/ExotelCallUI.vue:205 #: frontend/src/pages/Tasks.vue:130 msgid "Lead" @@ -2392,13 +2565,13 @@ msgstr "" msgid "Lead Statuses" msgstr "" -#: frontend/src/pages/Lead.vue:482 frontend/src/pages/MobileLead.vue:279 +#: frontend/src/pages/Lead.vue:497 frontend/src/pages/MobileLead.vue:279 msgid "Lead updated successfully" msgstr "" #. Label of a shortcut in the Frappe CRM Workspace #: crm/fcrm/workspace/frappe_crm/frappe_crm.json -#: frontend/src/pages/Lead.vue:501 frontend/src/pages/MobileLead.vue:298 +#: frontend/src/pages/Lead.vue:516 frontend/src/pages/MobileLead.vue:298 msgid "Leads" msgstr "" @@ -2448,6 +2621,8 @@ msgid "Load Default Columns" msgstr "" #: frontend/src/components/Kanban/KanbanView.vue:139 +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:142 +#: frontend/src/components/Settings/Users.vue:155 msgid "Load More" msgstr "" @@ -2470,7 +2645,7 @@ msgstr "" #. Label of the brand_logo (Attach) field in DocType 'FCRM Settings' #: crm/fcrm/doctype/fcrm_settings/fcrm_settings.json -#: frontend/src/components/Settings/GeneralSettings.vue:27 +#: frontend/src/components/Settings/GeneralSettings.vue:42 msgid "Logo" msgstr "" @@ -2526,9 +2701,22 @@ msgstr "" msgid "Make {0} as default calling medium" msgstr "" -#: frontend/src/components/Settings/InviteMemberPage.vue:33 -#: frontend/src/components/Settings/InviteMemberPage.vue:120 -msgid "Manager Access" +#: frontend/src/components/Settings/Users.vue:11 +msgid "Manage CRM users by adding or inviting them, and assign roles to control their access and permissions" +msgstr "" + +#: frontend/src/components/Settings/EmailAccountList.vue:11 +msgid "Manage your email accounts to send and receive emails directly from CRM. You can add multiple accounts and set one as default for incoming and outgoing emails." +msgstr "" + +#: frontend/src/components/Modals/AddExistingUserModal.vue:91 +#: frontend/src/components/Settings/InviteUserPage.vue:171 +#: frontend/src/components/Settings/InviteUserPage.vue:178 +#: frontend/src/components/Settings/Users.vue:87 +#: frontend/src/components/Settings/Users.vue:185 +#: frontend/src/components/Settings/Users.vue:256 +#: frontend/src/components/Settings/Users.vue:259 +msgid "Manager" msgstr "" #: frontend/src/data/document.js:31 @@ -2546,7 +2734,7 @@ msgstr "" msgid "Mark all as read" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:536 +#: frontend/src/components/Layouts/AppSidebar.vue:530 msgid "Masters" msgstr "" @@ -2599,13 +2787,13 @@ msgstr "" msgid "Mobile Number Missing" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:600 +#: frontend/src/components/Layouts/AppSidebar.vue:594 msgid "Mobile app installation" msgstr "" -#: frontend/src/pages/Contact.vue:599 frontend/src/pages/MobileContact.vue:574 +#: frontend/src/pages/Contact.vue:589 frontend/src/pages/MobileContact.vue:574 #: frontend/src/pages/MobileOrganization.vue:476 -#: frontend/src/pages/Organization.vue:508 +#: frontend/src/pages/Organization.vue:500 msgid "Mobile no" msgstr "" @@ -2640,13 +2828,19 @@ msgstr "" #. Label of the brand_name (Data) field in DocType 'FCRM Settings' #: 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/Settings/EmailTemplate/EditEmailTemplate.vue:42 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42 #: frontend/src/components/ViewControls.vue:779 #: frontend/src/pages/MobileOrganization.vue:494 -#: frontend/src/pages/Organization.vue:526 +#: frontend/src/pages/Organization.vue:518 msgid "Name" msgstr "" +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:155 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:157 +msgid "Name is required" +msgstr "" + #. Label of the naming_series (Select) field in DocType 'CRM Deal' #. Label of the naming_series (Select) field in DocType 'CRM Product' #: crm/fcrm/doctype/crm_deal/crm_deal.json @@ -2667,6 +2861,8 @@ msgid "Net Total" msgstr "" #: frontend/src/components/Activities/ActivityHeader.vue:82 +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:19 +#: frontend/src/components/Settings/Users.vue:30 msgid "New" msgstr "" @@ -2708,6 +2904,10 @@ msgstr "" msgid "New Organization" msgstr "" +#: frontend/src/components/Modals/ChangePasswordModal.vue:6 +msgid "New Password" +msgstr "" + #: frontend/src/components/FieldLayoutEditor.vue:203 #: frontend/src/components/SidePanelLayoutEditor.vue:133 msgid "New Section" @@ -2728,14 +2928,18 @@ msgstr "" msgid "New WhatsApp Message" msgstr "" -#: frontend/src/pages/Lead.vue:310 frontend/src/pages/MobileLead.vue:162 +#: frontend/src/pages/Lead.vue:317 frontend/src/pages/MobileLead.vue:162 msgid "New contact will be created based on the person's details" msgstr "" -#: frontend/src/pages/Lead.vue:285 frontend/src/pages/MobileLead.vue:136 +#: frontend/src/pages/Lead.vue:292 frontend/src/pages/MobileLead.vue:136 msgid "New organization will be created based on the data in details section" msgstr "" +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:10 +msgid "New template" +msgstr "" + #: frontend/src/components/Modals/CreateDocumentModal.vue:88 msgid "New {0}" msgstr "" @@ -2793,15 +2997,19 @@ msgstr "" msgid "No contacts added" msgstr "" -#: frontend/src/pages/Deal.vue:108 frontend/src/pages/Lead.vue:158 +#: frontend/src/pages/Deal.vue:105 frontend/src/pages/Lead.vue:156 msgid "No email set" msgstr "" +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:48 +msgid "No email templates found" +msgstr "" + #: frontend/src/components/FieldLayoutEditor.vue:92 msgid "No label" msgstr "" -#: frontend/src/pages/Deal.vue:716 +#: frontend/src/pages/Deal.vue:727 msgid "No mobile number set" msgstr "" @@ -2810,29 +3018,34 @@ msgstr "" msgid "No new notifications" msgstr "" -#: frontend/src/pages/Lead.vue:142 +#: frontend/src/pages/Lead.vue:141 msgid "No phone number set" msgstr "" -#: frontend/src/pages/Deal.vue:711 +#: frontend/src/pages/Deal.vue:722 msgid "No primary contact set" msgstr "" #: frontend/src/components/Controls/MultiSelectEmailInput.vue:72 +#: frontend/src/components/Controls/MultiSelectUserInput.vue:72 msgid "No results found" msgstr "" -#: frontend/src/components/Modals/EmailTemplateSelectorModal.vue:52 +#: frontend/src/components/Modals/EmailTemplateSelectorModal.vue:66 #: frontend/src/components/Modals/WhatsappTemplateSelectorModal.vue:42 msgid "No templates found" msgstr "" +#: frontend/src/components/Settings/Users.vue:57 +msgid "No users found" +msgstr "" + #: frontend/src/pages/MobileOrganization.vue:287 -#: frontend/src/pages/Organization.vue:326 +#: frontend/src/pages/Organization.vue:318 msgid "No website found" msgstr "" -#: frontend/src/pages/Deal.vue:124 frontend/src/pages/Lead.vue:174 +#: frontend/src/pages/Deal.vue:118 frontend/src/pages/Lead.vue:171 msgid "No website set" msgstr "" @@ -2842,8 +3055,7 @@ msgstr "" #: frontend/src/pages/CallLogs.vue:56 frontend/src/pages/Contact.vue:164 #: 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:153 +#: frontend/src/pages/Leads.vue:261 frontend/src/pages/MobileContact.vue:153 #: frontend/src/pages/MobileOrganization.vue:142 #: frontend/src/pages/Notes.vue:92 frontend/src/pages/Organization.vue:156 #: frontend/src/pages/Organizations.vue:59 frontend/src/pages/Tasks.vue:184 @@ -2892,9 +3104,9 @@ msgstr "" #: frontend/src/components/Modals/DataFieldsModal.vue:10 #: frontend/src/components/Modals/QuickEntryModal.vue:10 #: frontend/src/components/Modals/SidePanelModal.vue:10 -#: frontend/src/components/Settings/GeneralSettings.vue:7 -#: frontend/src/components/Settings/SettingsPage.vue:9 -#: frontend/src/components/Settings/TelephonySettings.vue:9 +#: frontend/src/components/Settings/GeneralSettings.vue:9 +#: frontend/src/components/Settings/SettingsPage.vue:11 +#: frontend/src/components/Settings/TelephonySettings.vue:11 msgid "Not Saved" msgstr "" @@ -2914,18 +3126,18 @@ msgstr "" msgid "Not allowed to set primary contact for Deal" msgstr "" -#: frontend/src/pages/Contact.vue:252 frontend/src/pages/Deal.vue:442 -#: frontend/src/pages/Lead.vue:449 frontend/src/pages/Organization.vue:237 +#: frontend/src/pages/Contact.vue:259 frontend/src/pages/Deal.vue:449 +#: frontend/src/pages/Lead.vue:464 frontend/src/pages/Organization.vue:247 msgid "Not permitted" msgstr "" #. Label of the note (Link) field in DocType 'CRM Call Log' #: crm/fcrm/doctype/crm_call_log/crm_call_log.json -#: frontend/src/components/Layouts/AppSidebar.vue:543 +#: frontend/src/components/Layouts/AppSidebar.vue:537 msgid "Note" msgstr "" -#: frontend/src/pages/Deal.vue:582 frontend/src/pages/Lead.vue:571 +#: frontend/src/pages/Deal.vue:593 frontend/src/pages/Lead.vue:586 #: frontend/src/pages/MobileDeal.vue:474 frontend/src/pages/MobileLead.vue:375 msgid "Notes" msgstr "" @@ -2935,7 +3147,7 @@ msgid "Notes View" msgstr "" #: frontend/src/components/Activities/EmailArea.vue:13 -#: frontend/src/components/Layouts/AppSidebar.vue:572 +#: frontend/src/components/Layouts/AppSidebar.vue:566 msgid "Notification" msgstr "" @@ -2973,7 +3185,7 @@ msgstr "" msgid "Old Parent" msgstr "" -#: frontend/src/utils/index.js:448 +#: frontend/src/utils/index.js:449 msgid "Only image files are allowed" msgstr "" @@ -2982,12 +3194,12 @@ msgstr "" msgid "Only one {0} can be set as primary." msgstr "" -#: frontend/src/components/Modals/NoteModal.vue:25 +#: frontend/src/components/Modals/NoteModal.vue:18 #: frontend/src/components/Modals/TaskModal.vue:25 msgid "Open Deal" msgstr "" -#: frontend/src/components/Modals/NoteModal.vue:26 +#: frontend/src/components/Modals/NoteModal.vue:19 #: frontend/src/components/Modals/TaskModal.vue:26 msgid "Open Lead" msgstr "" @@ -3027,14 +3239,14 @@ msgstr "" #. Label of the organization (Data) field in DocType 'CRM Lead' #: crm/fcrm/doctype/crm_deal/crm_deal.json #: crm/fcrm/doctype/crm_lead/crm_lead.json -#: frontend/src/components/Layouts/AppSidebar.vue:542 -#: frontend/src/pages/Contact.vue:578 frontend/src/pages/Lead.vue:268 +#: frontend/src/components/Layouts/AppSidebar.vue:536 +#: frontend/src/pages/Contact.vue:568 frontend/src/pages/Lead.vue:275 #: frontend/src/pages/MobileContact.vue:553 #: frontend/src/pages/MobileLead.vue:118 #: frontend/src/pages/MobileOrganization.vue:455 #: frontend/src/pages/MobileOrganization.vue:509 -#: frontend/src/pages/Organization.vue:487 -#: frontend/src/pages/Organization.vue:541 +#: frontend/src/pages/Organization.vue:479 +#: frontend/src/pages/Organization.vue:533 msgid "Organization" msgstr "" @@ -3064,11 +3276,11 @@ msgstr "" #. Label of a shortcut in the Frappe CRM Workspace #: crm/fcrm/workspace/frappe_crm/frappe_crm.json #: frontend/src/pages/MobileOrganization.vue:211 -#: frontend/src/pages/Organization.vue:246 +#: frontend/src/pages/Organization.vue:256 msgid "Organizations" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:564 +#: frontend/src/components/Layouts/AppSidebar.vue:558 msgid "Other features" msgstr "" @@ -3108,12 +3320,18 @@ msgstr "" msgid "Password is required" msgstr "" -#: frontend/src/components/Modals/EmailTemplateModal.vue:23 -#: frontend/src/components/Modals/EmailTemplateSelectorModal.vue:11 +#: frontend/src/components/Modals/ChangePasswordModal.vue:88 +msgid "Password updated successfully" +msgstr "" + +#: frontend/src/components/Modals/EmailTemplateSelectorModal.vue:13 +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:41 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:41 msgid "Payment Reminder" msgstr "" -#: frontend/src/components/Modals/EmailTemplateModal.vue:43 +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:72 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:72 msgid "Payment Reminder from Frappé - (#{{ name }})" msgstr "" @@ -3122,7 +3340,7 @@ msgstr "" msgid "Pending" msgstr "" -#: frontend/src/components/Settings/InviteMemberPage.vue:43 +#: frontend/src/components/Settings/InviteUserPage.vue:66 msgid "Pending Invites" msgstr "" @@ -3142,7 +3360,7 @@ msgstr "" #: crm/fcrm/doctype/crm_lead/crm_lead.json #: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json #: frontend/src/pages/MobileOrganization.vue:504 -#: frontend/src/pages/Organization.vue:536 +#: frontend/src/pages/Organization.vue:528 msgid "Phone" msgstr "" @@ -3164,7 +3382,7 @@ msgstr "" msgid "Pinned Views" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:560 +#: frontend/src/components/Layouts/AppSidebar.vue:554 msgid "Pinned view" msgstr "" @@ -3172,7 +3390,7 @@ msgstr "" msgid "Playback speed" msgstr "" -#: frontend/src/components/Settings/EmailAccountList.vue:34 +#: frontend/src/components/Settings/EmailAccountList.vue:42 msgid "Please add an email account to continue." msgstr "" @@ -3184,11 +3402,11 @@ msgstr "" msgid "Please enter a valid URL" msgstr "" -#: frontend/src/pages/Lead.vue:637 frontend/src/pages/MobileLead.vue:437 +#: frontend/src/pages/Lead.vue:656 frontend/src/pages/MobileLead.vue:437 msgid "Please select an existing contact" msgstr "" -#: frontend/src/pages/Lead.vue:642 frontend/src/pages/MobileLead.vue:442 +#: frontend/src/pages/Lead.vue:661 frontend/src/pages/MobileLead.vue:442 msgid "Please select an existing organization" msgstr "" @@ -3207,7 +3425,7 @@ msgstr "" msgid "Primary" msgstr "" -#: frontend/src/pages/Deal.vue:688 frontend/src/pages/MobileDeal.vue:579 +#: frontend/src/pages/Deal.vue:699 frontend/src/pages/MobileDeal.vue:579 msgid "Primary contact set" msgstr "" @@ -3261,12 +3479,12 @@ msgstr "" msgid "Products" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:529 -#: frontend/src/components/Settings/Settings.vue:85 +#: frontend/src/components/Layouts/AppSidebar.vue:523 +#: frontend/src/components/Settings/Settings.vue:79 msgid "Profile" msgstr "" -#: frontend/src/components/Settings/ProfileSettings.vue:130 +#: frontend/src/components/Settings/ProfileSettings.vue:147 msgid "Profile updated successfully" msgstr "" @@ -3279,7 +3497,7 @@ msgstr "" msgid "Public Views" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:559 +#: frontend/src/components/Layouts/AppSidebar.vue:553 msgid "Public view" msgstr "" @@ -3307,7 +3525,7 @@ msgstr "" msgid "Quick Filters updated successfully" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:583 +#: frontend/src/components/Layouts/AppSidebar.vue:577 msgid "Quick entry layout" msgstr "" @@ -3371,16 +3589,13 @@ msgstr "" msgid "Refresh" msgstr "" -#: frontend/src/components/Settings/InviteMemberPage.vue:32 -#: frontend/src/components/Settings/InviteMemberPage.vue:119 -msgid "Regular Access" -msgstr "" - #: frontend/src/components/Telephony/TwilioCallUI.vue:104 msgid "Reject" msgstr "" -#: frontend/src/pages/Deal.vue:637 +#: frontend/src/components/Settings/Users.vue:210 +#: frontend/src/components/Settings/Users.vue:213 +#: frontend/src/pages/Deal.vue:648 msgid "Remove" msgstr "" @@ -3396,6 +3611,7 @@ msgstr "" msgid "Remove column" msgstr "" +#: frontend/src/components/Settings/ProfileSettings.vue:32 #: frontend/src/pages/Contact.vue:47 frontend/src/pages/Lead.vue:107 #: frontend/src/pages/MobileContact.vue:40 #: frontend/src/pages/MobileOrganization.vue:43 @@ -3485,7 +3701,8 @@ msgstr "" msgid "Retake" msgstr "" -#: frontend/src/components/Modals/EmailTemplateModal.vue:54 +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:84 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:84 msgid "Rich Text" msgstr "" @@ -3506,6 +3723,7 @@ msgstr "" #. Label of the role (Select) field in DocType 'CRM Invitation' #: crm/fcrm/doctype/crm_invitation/crm_invitation.json +#: frontend/src/components/Modals/AddExistingUserModal.vue:44 msgid "Role" msgstr "" @@ -3606,6 +3824,13 @@ msgstr "" #: crm/fcrm/doctype/crm_territory/crm_territory.json #: crm/fcrm/doctype/crm_view_settings/crm_view_settings.json #: crm/fcrm/doctype/fcrm_note/fcrm_note.json +#: frontend/src/components/Modals/AddExistingUserModal.vue:90 +#: frontend/src/components/Settings/InviteUserPage.vue:170 +#: frontend/src/components/Settings/InviteUserPage.vue:177 +#: frontend/src/components/Settings/Users.vue:88 +#: frontend/src/components/Settings/Users.vue:186 +#: frontend/src/components/Settings/Users.vue:268 +#: frontend/src/components/Settings/Users.vue:271 msgid "Sales User" msgstr "" @@ -3631,7 +3856,6 @@ msgstr "" #: frontend/src/components/Modals/DataFieldsModal.vue:26 #: frontend/src/components/Modals/QuickEntryModal.vue:26 #: frontend/src/components/Modals/SidePanelModal.vue:26 -#: frontend/src/components/Settings/ProfileSettings.vue:35 #: frontend/src/components/Telephony/ExotelCallUI.vue:231 #: frontend/src/components/ViewControls.vue:123 msgid "Save" @@ -3647,7 +3871,7 @@ msgstr "" msgid "Saved Views" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:558 +#: frontend/src/components/Layouts/AppSidebar.vue:552 msgid "Saved view" msgstr "" @@ -3660,11 +3884,19 @@ msgstr "" msgid "Script" msgstr "" +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:64 +msgid "Search template" +msgstr "" + +#: frontend/src/components/Settings/Users.vue:73 +msgid "Search user" +msgstr "" + #: frontend/src/components/FieldLayoutEditor.vue:342 msgid "Section" msgstr "" -#: frontend/src/components/FieldLayout/Field.vue:328 +#: frontend/src/components/FieldLayout/Field.vue:332 msgid "Select {0}" msgstr "" @@ -3672,26 +3904,26 @@ msgstr "" msgid "Send" msgstr "" -#: frontend/src/components/Settings/InviteMemberPage.vue:82 +#: frontend/src/components/Settings/InviteUserPage.vue:18 msgid "Send Invites" msgstr "" -#: frontend/src/components/Settings/InviteMemberPage.vue:4 -msgid "Send Invites To" -msgstr "" - #: frontend/src/components/Activities/ActivityHeader.vue:66 msgid "Send Template" msgstr "" -#: frontend/src/pages/Deal.vue:101 frontend/src/pages/Lead.vue:151 +#: frontend/src/pages/Deal.vue:99 frontend/src/pages/Lead.vue:150 msgid "Send an email" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:449 +#: frontend/src/components/Layouts/AppSidebar.vue:443 msgid "Send email" msgstr "" +#: frontend/src/components/Settings/InviteUserPage.vue:6 +msgid "Send invites to" +msgstr "" + #. Option for the 'Type' (Select) field in DocType 'CRM Dropdown Item' #: crm/fcrm/doctype/crm_dropdown_item/crm_dropdown_item.json msgid "Separator" @@ -3702,7 +3934,7 @@ msgstr "" msgid "Series" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:570 +#: frontend/src/components/Layouts/AppSidebar.vue:564 msgid "Service level agreement" msgstr "" @@ -3718,7 +3950,7 @@ msgstr "" msgid "Set an organization" msgstr "" -#: frontend/src/pages/Deal.vue:645 frontend/src/pages/MobileDeal.vue:536 +#: frontend/src/pages/Deal.vue:656 frontend/src/pages/MobileDeal.vue:536 msgid "Set as Primary Contact" msgstr "" @@ -3730,7 +3962,7 @@ msgstr "" msgid "Set first name" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:522 +#: frontend/src/components/Layouts/AppSidebar.vue:516 msgid "Setting up" msgstr "" @@ -3776,9 +4008,9 @@ msgstr "" #. Label of the defaults_tab (Tab Break) field in DocType 'FCRM Settings' #: crm/fcrm/doctype/fcrm_settings/fcrm_settings.json -#: frontend/src/components/Layouts/AppSidebar.vue:526 +#: frontend/src/components/Layouts/AppSidebar.vue:520 #: frontend/src/components/Settings/Settings.vue:11 -#: frontend/src/components/Settings/Settings.vue:81 +#: frontend/src/components/Settings/Settings.vue:75 msgid "Settings" msgstr "" @@ -3786,7 +4018,7 @@ msgstr "" msgid "Setup Email" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:327 +#: frontend/src/components/Layouts/AppSidebar.vue:322 msgid "Setup your password" msgstr "" @@ -3794,6 +4026,10 @@ msgstr "" msgid "Show" msgstr "" +#: frontend/src/components/Controls/Password.vue:19 +msgid "Show Password" +msgstr "" + #: frontend/src/components/FieldLayoutEditor.vue:360 msgid "Show border" msgstr "" @@ -3890,10 +4126,10 @@ msgstr "" #: crm/fcrm/doctype/crm_invitation/crm_invitation.json #: crm/fcrm/doctype/crm_lead/crm_lead.json #: crm/fcrm/doctype/crm_lead_status/crm_lead_status.json -#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:589 +#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:579 #: frontend/src/pages/MobileContact.vue:564 #: frontend/src/pages/MobileOrganization.vue:466 -#: frontend/src/pages/Organization.vue:498 +#: frontend/src/pages/Organization.vue:490 msgid "Status" msgstr "" @@ -3914,11 +4150,17 @@ msgstr "" msgid "Subdomain" msgstr "" -#: frontend/src/components/Modals/EmailTemplateModal.vue:42 +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:71 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:71 msgid "Subject" msgstr "" -#: frontend/src/components/Modals/EmailTemplateSelectorModal.vue:31 +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:159 +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:161 +msgid "Subject is required" +msgstr "" + +#: frontend/src/components/Modals/EmailTemplateSelectorModal.vue:45 msgid "Subject: {0}" msgstr "" @@ -3942,6 +4184,7 @@ msgid "Sync your contacts,email and calenders" msgstr "" #. Name of a role +#. Option for the 'Role' (Select) field in DocType 'CRM Invitation' #: crm/fcrm/doctype/crm_exotel_settings/crm_exotel_settings.json #: crm/fcrm/doctype/crm_fields_layout/crm_fields_layout.json #: crm/fcrm/doctype/crm_global_settings/crm_global_settings.json @@ -3965,11 +4208,11 @@ msgstr "" #. Option for the 'Type' (Select) field in DocType 'CRM Notification' #: crm/fcrm/doctype/crm_notification/crm_notification.json -#: frontend/src/components/Layouts/AppSidebar.vue:544 +#: frontend/src/components/Layouts/AppSidebar.vue:538 msgid "Task" msgstr "" -#: frontend/src/pages/Deal.vue:577 frontend/src/pages/Lead.vue:566 +#: frontend/src/pages/Deal.vue:588 frontend/src/pages/Lead.vue:581 #: frontend/src/pages/MobileDeal.vue:469 frontend/src/pages/MobileLead.vue:370 msgid "Tasks" msgstr "" @@ -3978,7 +4221,7 @@ msgstr "" msgid "Telegram Channel" msgstr "" -#: frontend/src/components/Settings/Settings.vue:118 +#: frontend/src/components/Settings/Settings.vue:123 msgid "Telephony" msgstr "" @@ -3987,8 +4230,36 @@ msgstr "" msgid "Telephony Medium" msgstr "" -#: frontend/src/components/Settings/TelephonySettings.vue:6 -msgid "Telephony Settings" +#: frontend/src/components/Settings/TelephonySettings.vue:8 +msgid "Telephony settings" +msgstr "" + +#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:178 +msgid "Template created successfully" +msgstr "" + +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:214 +msgid "Template deleted successfully" +msgstr "" + +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:198 +msgid "Template disabled successfully" +msgstr "" + +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:197 +msgid "Template enabled successfully" +msgstr "" + +#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:83 +msgid "Template name" +msgstr "" + +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:243 +msgid "Template renamed successfully" +msgstr "" + +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:208 +msgid "Template updated successfully" msgstr "" #. Label of a shortcut in the Frappe CRM Workspace @@ -4048,6 +4319,14 @@ msgstr "" msgid "This section is not editable" msgstr "" +#: frontend/src/components/BulkDeleteLinkedDocModal.vue:59 +msgid "This will delete selected items and items linked to it, are you sure?" +msgstr "" + +#: frontend/src/components/BulkDeleteLinkedDocModal.vue:62 +msgid "This will delete selected items and unlink linked items to it, are you sure?" +msgstr "" + #: crm/fcrm/doctype/fcrm_settings/fcrm_settings.js:9 msgid "This will restore (if not exist) all the default statuses, custom fields and layouts. Delete & Restore will delete default layouts and then restore them." msgstr "" @@ -4067,7 +4346,7 @@ msgstr "" #. Label of the title (Data) field in DocType 'FCRM Note' #: crm/fcrm/doctype/crm_task/crm_task.json #: crm/fcrm/doctype/fcrm_note/fcrm_note.json -#: frontend/src/components/Modals/NoteModal.vue:41 +#: frontend/src/components/Modals/NoteModal.vue:30 #: frontend/src/components/Modals/TaskModal.vue:41 msgid "Title" msgstr "" @@ -4119,8 +4398,8 @@ msgstr "" msgid "Tomorrow" msgstr "" -#: frontend/src/components/Modals/NoteModal.vue:56 -#: frontend/src/components/Modals/TaskModal.vue:58 +#: frontend/src/components/Modals/NoteModal.vue:37 +#: frontend/src/components/Modals/TaskModal.vue:59 msgid "Took a call with John Doe and discussed the new project." msgstr "" @@ -4161,9 +4440,9 @@ msgstr "" #. Agent' #: crm/fcrm/doctype/crm_call_log/crm_call_log.json #: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json -#: frontend/src/components/Layouts/AppSidebar.vue:590 -#: frontend/src/components/Settings/TelephonySettings.vue:25 -#: frontend/src/components/Settings/TelephonySettings.vue:35 +#: frontend/src/components/Layouts/AppSidebar.vue:584 +#: frontend/src/components/Settings/TelephonySettings.vue:40 +#: frontend/src/components/Settings/TelephonySettings.vue:50 msgid "Twilio" msgstr "" @@ -4177,11 +4456,11 @@ msgstr "" msgid "Twilio Number" msgstr "" -#: frontend/src/components/Settings/TelephonySettings.vue:287 +#: frontend/src/components/Settings/TelephonySettings.vue:289 msgid "Twilio is not enabled" msgstr "" -#: frontend/src/components/Settings/TelephonySettings.vue:123 +#: frontend/src/components/Settings/TelephonySettings.vue:125 msgid "Twilio settings updated successfully" msgstr "" @@ -4201,7 +4480,8 @@ msgid "Type" msgstr "" #: frontend/src/components/Controls/MultiSelectEmailInput.vue:73 -msgid "Type an email address to add" +#: frontend/src/components/Controls/MultiSelectUserInput.vue:73 +msgid "Type an email address to invite" msgstr "" #: frontend/src/components/Activities/WhatsAppBox.vue:85 @@ -4221,6 +4501,30 @@ msgstr "" msgid "Unknown" msgstr "" +#: frontend/src/components/BulkDeleteLinkedDocModal.vue:132 +msgid "Unlink" +msgstr "" + +#: frontend/src/components/DeleteLinkedDocModal.vue:77 +msgid "Unlink all" +msgstr "" + +#: frontend/src/components/BulkDeleteLinkedDocModal.vue:73 +msgid "Unlink and delete" +msgstr "" + +#: frontend/src/components/BulkDeleteLinkedDocModal.vue:35 +msgid "Unlink and delete {0} items" +msgstr "" + +#: frontend/src/components/DeleteLinkedDocModal.vue:242 +msgid "Unlink linked item" +msgstr "" + +#: frontend/src/components/DeleteLinkedDocModal.vue:78 +msgid "Unlink {0} item(s)" +msgstr "" + #: frontend/src/components/ViewControls.vue:1138 msgid "Unpin View" msgstr "" @@ -4240,13 +4544,14 @@ msgstr "" #: frontend/src/components/ColumnSettings.vue:138 #: frontend/src/components/Modals/AssignmentModal.vue:17 -#: frontend/src/components/Modals/EmailTemplateModal.vue:9 +#: frontend/src/components/Modals/ChangePasswordModal.vue:45 #: frontend/src/components/Modals/NoteModal.vue:6 -#: frontend/src/components/Modals/TaskModal.vue:6 -#: frontend/src/components/Settings/GeneralSettings.vue:113 -#: frontend/src/components/Settings/ProfileSettings.vue:71 -#: frontend/src/components/Settings/SettingsPage.vue:31 -#: frontend/src/components/Settings/TelephonySettings.vue:70 +#: frontend/src/components/Modals/TaskModal.vue:8 +#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:17 +#: frontend/src/components/Settings/GeneralSettings.vue:21 +#: frontend/src/components/Settings/ProfileSettings.vue:95 +#: frontend/src/components/Settings/SettingsPage.vue:20 +#: frontend/src/components/Settings/TelephonySettings.vue:23 #: frontend/src/components/Telephony/ExotelCallUI.vue:219 #: frontend/src/components/ViewControls.vue:980 msgid "Update" @@ -4282,6 +4587,7 @@ msgstr "" msgid "Upload Video" msgstr "" +#: frontend/src/components/Settings/ProfileSettings.vue:27 #: frontend/src/pages/Contact.vue:42 frontend/src/pages/Lead.vue:102 #: frontend/src/pages/MobileContact.vue:35 #: frontend/src/pages/MobileOrganization.vue:38 @@ -4301,6 +4607,20 @@ msgstr "" msgid "User Name" msgstr "" +#: frontend/src/components/Settings/Users.vue:301 +msgid "User {0} has been removed" +msgstr "" + +#: frontend/src/components/Modals/AddExistingUserModal.vue:20 +#: frontend/src/components/Settings/Settings.vue:95 +#: frontend/src/components/Settings/Users.vue:7 +msgid "Users" +msgstr "" + +#: frontend/src/components/Modals/AddExistingUserModal.vue:103 +msgid "Users added successfully" +msgstr "" + #. Label of the section_break_nevd (Section Break) field in DocType 'CRM #. Service Level Agreement' #: crm/fcrm/doctype/crm_service_level_agreement/crm_service_level_agreement.json @@ -4315,11 +4635,11 @@ msgstr "" msgid "View Name" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:555 +#: frontend/src/components/Layouts/AppSidebar.vue:549 msgid "Views" msgstr "" -#: frontend/src/components/Layouts/AppSidebar.vue:552 +#: frontend/src/components/Layouts/AppSidebar.vue:546 msgid "Web form" msgstr "" @@ -4363,9 +4683,9 @@ msgstr "" #. Option for the 'Type' (Select) field in DocType 'CRM Notification' #: crm/fcrm/doctype/crm_notification/crm_notification.json -#: frontend/src/components/Layouts/AppSidebar.vue:592 -#: frontend/src/components/Settings/Settings.vue:124 -#: frontend/src/pages/Deal.vue:592 frontend/src/pages/Lead.vue:581 +#: frontend/src/components/Layouts/AppSidebar.vue:586 +#: frontend/src/components/Settings/Settings.vue:129 +#: frontend/src/pages/Deal.vue:603 frontend/src/pages/Lead.vue:596 #: frontend/src/pages/MobileDeal.vue:484 frontend/src/pages/MobileLead.vue:385 msgid "WhatsApp" msgstr "" @@ -4485,7 +4805,8 @@ msgstr "" msgid "cyan" msgstr "" -#: frontend/src/components/Controls/MultiSelectEmailInput.vue:256 +#: frontend/src/components/Controls/MultiSelectEmailInput.vue:268 +#: frontend/src/components/Controls/MultiSelectUserInput.vue:242 msgid "email already exists" msgstr "" @@ -4516,75 +4837,77 @@ msgstr "" msgid "has reached out" msgstr "" +#: frontend/src/components/Settings/EmailAdd.vue:36 #: frontend/src/components/Settings/EmailEdit.vue:25 msgid "here" msgstr "" -#: frontend/src/utils/index.js:144 +#: frontend/src/utils/index.js:145 msgid "in 1 hour" msgstr "" -#: frontend/src/utils/index.js:140 +#: frontend/src/utils/index.js:141 msgid "in 1 minute" msgstr "" -#: frontend/src/utils/index.js:158 +#: frontend/src/utils/index.js:159 msgid "in 1 year" msgstr "" -#: frontend/src/utils/index.js:110 +#: frontend/src/utils/index.js:111 msgid "in {0} M" msgstr "" -#: frontend/src/utils/index.js:106 +#: frontend/src/utils/index.js:107 msgid "in {0} d" msgstr "" -#: frontend/src/utils/index.js:152 +#: frontend/src/utils/index.js:153 msgid "in {0} days" msgstr "" -#: frontend/src/utils/index.js:100 +#: frontend/src/utils/index.js:101 msgid "in {0} h" msgstr "" -#: frontend/src/utils/index.js:146 +#: frontend/src/utils/index.js:147 msgid "in {0} hours" msgstr "" -#: frontend/src/utils/index.js:98 +#: frontend/src/utils/index.js:99 msgid "in {0} m" msgstr "" -#: frontend/src/utils/index.js:142 +#: frontend/src/utils/index.js:143 msgid "in {0} minutes" msgstr "" -#: frontend/src/utils/index.js:156 +#: frontend/src/utils/index.js:157 msgid "in {0} months" msgstr "" -#: frontend/src/utils/index.js:108 +#: frontend/src/utils/index.js:109 msgid "in {0} w" msgstr "" -#: frontend/src/utils/index.js:154 +#: frontend/src/utils/index.js:155 msgid "in {0} weeks" msgstr "" -#: frontend/src/utils/index.js:112 +#: frontend/src/utils/index.js:113 msgid "in {0} y" msgstr "" -#: frontend/src/utils/index.js:160 +#: frontend/src/utils/index.js:161 msgid "in {0} years" msgstr "" -#: frontend/src/components/Settings/InviteMemberPage.vue:17 +#: frontend/src/components/Modals/AddExistingUserModal.vue:28 +#: frontend/src/components/Settings/InviteUserPage.vue:37 msgid "john@doe.com" msgstr "" -#: frontend/src/utils/index.js:138 frontend/src/utils/index.js:164 +#: frontend/src/utils/index.js:139 frontend/src/utils/index.js:165 msgid "just now" msgstr "" @@ -4593,7 +4916,7 @@ msgstr "" msgid "kanban" msgstr "" -#: crm/api/doc.py:39 crm/api/doc.py:157 crm/api/doc.py:502 +#: crm/api/doc.py:40 crm/api/doc.py:158 crm/api/doc.py:503 msgid "label" msgstr "" @@ -4611,7 +4934,7 @@ msgstr "" msgid "next" msgstr "" -#: frontend/src/utils/index.js:96 frontend/src/utils/index.js:116 +#: frontend/src/utils/index.js:97 frontend/src/utils/index.js:117 msgid "now" msgstr "" @@ -4671,7 +4994,7 @@ msgstr "" msgid "to" msgstr "" -#: frontend/src/utils/index.js:104 frontend/src/utils/index.js:150 +#: frontend/src/utils/index.js:105 frontend/src/utils/index.js:151 msgid "tomorrow" msgstr "" @@ -4689,11 +5012,11 @@ msgstr "" msgid "yellow" msgstr "" -#: frontend/src/utils/index.js:176 +#: frontend/src/utils/index.js:177 msgid "yesterday" msgstr "" -#: frontend/src/utils/index.js:128 +#: frontend/src/utils/index.js:129 msgid "{0} M" msgstr "" @@ -4701,23 +5024,27 @@ msgstr "" msgid "{0} assigned a {1} {2} to you" msgstr "" -#: frontend/src/utils/index.js:124 +#: frontend/src/utils/index.js:125 msgid "{0} d" msgstr "" -#: frontend/src/utils/index.js:178 +#: frontend/src/utils/index.js:179 msgid "{0} days ago" msgstr "" -#: frontend/src/utils/index.js:120 +#: frontend/src/utils/index.js:121 msgid "{0} h" msgstr "" -#: frontend/src/utils/index.js:172 +#: frontend/src/components/Settings/Users.vue:291 +msgid "{0} has been granted {1} access" +msgstr "" + +#: frontend/src/utils/index.js:173 msgid "{0} hours ago" msgstr "" -#: frontend/src/pages/Deal.vue:505 frontend/src/pages/Lead.vue:494 +#: frontend/src/pages/Deal.vue:516 frontend/src/pages/Lead.vue:509 #: frontend/src/pages/MobileDeal.vue:390 frontend/src/pages/MobileLead.vue:291 msgid "{0} is a required field" msgstr "" @@ -4725,35 +5052,36 @@ msgstr "" #: frontend/src/components/EmailEditor.vue:29 #: frontend/src/components/EmailEditor.vue:64 #: frontend/src/components/EmailEditor.vue:77 -#: frontend/src/components/Settings/InviteMemberPage.vue:21 +#: frontend/src/components/Modals/AddExistingUserModal.vue:36 +#: frontend/src/components/Settings/InviteUserPage.vue:41 msgid "{0} is an invalid email address" msgstr "" -#: frontend/src/utils/index.js:118 +#: frontend/src/utils/index.js:119 msgid "{0} m" msgstr "" -#: frontend/src/utils/index.js:168 +#: frontend/src/utils/index.js:169 msgid "{0} minutes ago" msgstr "" -#: frontend/src/utils/index.js:186 +#: frontend/src/utils/index.js:187 msgid "{0} months ago" msgstr "" -#: frontend/src/utils/index.js:126 +#: frontend/src/utils/index.js:127 msgid "{0} w" msgstr "" -#: frontend/src/utils/index.js:182 +#: frontend/src/utils/index.js:183 msgid "{0} weeks ago" msgstr "" -#: frontend/src/utils/index.js:130 +#: frontend/src/utils/index.js:131 msgid "{0} y" msgstr "" -#: frontend/src/utils/index.js:190 +#: frontend/src/utils/index.js:191 msgid "{0} years ago" msgstr "" diff --git a/crm/utils/__init__.py b/crm/utils/__init__.py index cd4a4ff8..9b954859 100644 --- a/crm/utils/__init__.py +++ b/crm/utils/__init__.py @@ -1,7 +1,10 @@ +from frappe import frappe import phonenumbers from frappe.utils import floor from phonenumbers import NumberParseException from phonenumbers import PhoneNumberFormat as PNF +from frappe.model.docstatus import DocStatus +from frappe.model.dynamic_links import get_dynamic_link_map def parse_phone_number(phone_number, default_country="IN"): @@ -93,3 +96,129 @@ def seconds_to_duration(seconds): return f"{seconds}s" else: return "0s" + +# Extracted from frappe core frappe/model/delete_doc.py/check_if_doc_is_linked +def get_linked_docs(doc, method="Delete"): + from frappe.model.rename_doc import get_link_fields + + link_fields = get_link_fields(doc.doctype) + ignored_doctypes = set() + + if method == "Cancel" and (doc_ignore_flags := doc.get("ignore_linked_doctypes")): + ignored_doctypes.update(doc_ignore_flags) + if method == "Delete": + ignored_doctypes.update(frappe.get_hooks("ignore_links_on_delete")) + + docs = [] + + for lf in link_fields: + link_dt, link_field, issingle = lf["parent"], lf["fieldname"], lf["issingle"] + if link_dt in ignored_doctypes or (link_field == "amended_from" and method == "Cancel"): + continue + + try: + meta = frappe.get_meta(link_dt) + except frappe.DoesNotExistError: + frappe.clear_last_message() + # This mostly happens when app do not remove their customizations, we shouldn't + # prevent link checks from failing in those cases + continue + + if issingle: + if frappe.db.get_single_value(link_dt, link_field) == doc.name: + docs.append({"doc": doc.name, "link_dt": link_dt, "link_field": link_field}) + continue + + fields = ["name", "docstatus"] + + if meta.istable: + fields.extend(["parent", "parenttype"]) + + for item in frappe.db.get_values(link_dt, {link_field: doc.name}, fields, as_dict=True): + # available only in child table cases + item_parent = getattr(item, "parent", None) + linked_parent_doctype = item.parenttype if item_parent else link_dt + + if linked_parent_doctype in ignored_doctypes: + continue + + if method != "Delete" and (method != "Cancel" or not DocStatus(item.docstatus).is_submitted()): + # don't raise exception if not + # linked to a non-cancelled doc when deleting or to a submitted doc when cancelling + continue + elif link_dt == doc.doctype and (item_parent or item.name) == doc.name: + # don't raise exception if not + # linked to same item or doc having same name as the item + continue + else: + reference_docname = item_parent or item.name + docs.append( + { + "doc": doc.name, + "reference_doctype": linked_parent_doctype, + "reference_docname": reference_docname, + } + ) + return docs + +# Extracted from frappe core frappe/model/delete_doc.py/check_if_doc_is_dynamically_linked +def get_dynamic_linked_docs(doc, method="Delete"): + docs = [] + for df in get_dynamic_link_map().get(doc.doctype, []): + ignore_linked_doctypes = doc.get("ignore_linked_doctypes") or [] + + if df.parent in frappe.get_hooks("ignore_links_on_delete") or ( + df.parent in ignore_linked_doctypes and method == "Cancel" + ): + # don't check for communication and todo! + continue + + meta = frappe.get_meta(df.parent) + if meta.issingle: + # dynamic link in single doc + refdoc = frappe.db.get_singles_dict(df.parent) + if ( + refdoc.get(df.options) == doc.doctype + and refdoc.get(df.fieldname) == doc.name + and ( + # linked to an non-cancelled doc when deleting + (method == "Delete" and not DocStatus(refdoc.docstatus).is_cancelled()) + # linked to a submitted doc when cancelling + or (method == "Cancel" and DocStatus(refdoc.docstatus).is_submitted()) + ) + ): + docs.append({"doc": doc.name, "reference_doctype": df.parent, "reference_docname": df.parent}) + else: + # dynamic link in table + df["table"] = ", `parent`, `parenttype`, `idx`" if meta.istable else "" + for refdoc in frappe.db.sql( + """select `name`, `docstatus` {table} from `tab{parent}` where + `{options}`=%s and `{fieldname}`=%s""".format(**df), + (doc.doctype, doc.name), + as_dict=True, + ): + # linked to an non-cancelled doc when deleting + # or linked to a submitted doc when cancelling + if (method == "Delete" and not DocStatus(refdoc.docstatus).is_cancelled()) or ( + method == "Cancel" and DocStatus(refdoc.docstatus).is_submitted() + ): + reference_doctype = refdoc.parenttype if meta.istable else df.parent + reference_docname = refdoc.parent if meta.istable else refdoc.name + + if reference_doctype in frappe.get_hooks("ignore_links_on_delete") or ( + reference_doctype in ignore_linked_doctypes and method == "Cancel" + ): + # don't check for communication and todo! + continue + + at_position = f"at Row: {refdoc.idx}" if meta.istable else "" + + docs.append( + { + "doc": doc.name, + "reference_doctype": reference_doctype, + "reference_docname": reference_docname, + "at_position": at_position, + } + ) + return docs diff --git a/frappe-ui b/frappe-ui index 883bb643..424288f7 160000 --- a/frappe-ui +++ b/frappe-ui @@ -1 +1 @@ -Subproject commit 883bb643d1e662d6467925927e347dd28376960f +Subproject commit 424288f77af4779dd3bb71dc3d278fc627f95179 diff --git a/frontend/components.d.ts b/frontend/components.d.ts index 6a8cbbaf..d4d287e4 100644 --- a/frontend/components.d.ts +++ b/frontend/components.d.ts @@ -31,6 +31,7 @@ declare module 'vue' { Autocomplete: typeof import('./src/components/frappe-ui/Autocomplete.vue')['default'] AvatarIcon: typeof import('./src/components/Icons/AvatarIcon.vue')['default'] BrandLogo: typeof import('./src/components/BrandLogo.vue')['default'] + BulkDeleteLinkedDocModal: typeof import('./src/components/BulkDeleteLinkedDocModal.vue')['default'] CalendarIcon: typeof import('./src/components/Icons/CalendarIcon.vue')['default'] CallArea: typeof import('./src/components/Activities/CallArea.vue')['default'] CallLogDetailModal: typeof import('./src/components/Modals/CallLogDetailModal.vue')['default'] @@ -66,6 +67,7 @@ declare module 'vue' { DealsIcon: typeof import('./src/components/Icons/DealsIcon.vue')['default'] DealsListView: typeof import('./src/components/ListViews/DealsListView.vue')['default'] DeclinedCallIcon: typeof import('./src/components/Icons/DeclinedCallIcon.vue')['default'] + DeleteLinkedDocModal: typeof import('./src/components/DeleteLinkedDocModal.vue')['default'] DesendingIcon: typeof import('./src/components/Icons/DesendingIcon.vue')['default'] DesktopLayout: typeof import('./src/components/Layouts/DesktopLayout.vue')['default'] DetailsIcon: typeof import('./src/components/Icons/DetailsIcon.vue')['default'] @@ -79,6 +81,7 @@ declare module 'vue' { DropdownItem: typeof import('./src/components/DropdownItem.vue')['default'] DuplicateIcon: typeof import('./src/components/Icons/DuplicateIcon.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'] EditValueModal: typeof import('./src/components/Modals/EditValueModal.vue')['default'] Email2Icon: typeof import('./src/components/Icons/Email2Icon.vue')['default'] @@ -93,7 +96,10 @@ declare module 'vue' { 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'] + EmailTemplateIcon: typeof import('./src/components/Icons/EmailTemplateIcon.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'] EmailTemplateSelectorModal: typeof import('./src/components/Modals/EmailTemplateSelectorModal.vue')['default'] EmailTemplatesListView: typeof import('./src/components/ListViews/EmailTemplatesListView.vue')['default'] ERPNextIcon: typeof import('./src/components/Icons/ERPNextIcon.vue')['default'] @@ -149,14 +155,18 @@ declare module 'vue' { LeadsListView: typeof import('./src/components/ListViews/LeadsListView.vue')['default'] LightningIcon: typeof import('./src/components/Icons/LightningIcon.vue')['default'] Link: typeof import('./src/components/Controls/Link.vue')['default'] + LinkedDocsListView: typeof import('./src/components/ListViews/LinkedDocsListView.vue')['default'] LinkIcon: typeof import('./src/components/Icons/LinkIcon.vue')['default'] ListBulkActions: typeof import('./src/components/ListBulkActions.vue')['default'] ListIcon: typeof import('./src/components/Icons/ListIcon.vue')['default'] ListRows: typeof import('./src/components/ListViews/ListRows.vue')['default'] LoadingIndicator: typeof import('./src/components/Icons/LoadingIndicator.vue')['default'] + LucideCalendar: typeof import('~icons/lucide/calendar')['default'] LucideInfo: typeof import('~icons/lucide/info')['default'] + LucideMoreHorizontal: typeof import('~icons/lucide/more-horizontal')['default'] LucidePlus: typeof import('~icons/lucide/plus')['default'] LucideSearch: typeof import('~icons/lucide/search')['default'] + LucideX: typeof import('~icons/lucide/x')['default'] MarkAsDoneIcon: typeof import('./src/components/Icons/MarkAsDoneIcon.vue')['default'] MaximizeIcon: typeof import('./src/components/Icons/MaximizeIcon.vue')['default'] MenuIcon: typeof import('./src/components/Icons/MenuIcon.vue')['default'] @@ -172,6 +182,7 @@ declare module 'vue' { MultiSelectUserInput: typeof import('./src/components/Controls/MultiSelectUserInput.vue')['default'] MuteIcon: typeof import('./src/components/Icons/MuteIcon.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'] NoteIcon: typeof import('./src/components/Icons/NoteIcon.vue')['default'] NoteModal: typeof import('./src/components/Modals/NoteModal.vue')['default'] diff --git a/frontend/package.json b/frontend/package.json index 51a6ff41..1f359a5c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,7 +13,7 @@ "@tiptap/extension-paragraph": "^2.12.0", "@twilio/voice-sdk": "^2.10.2", "@vueuse/integrations": "^10.3.0", - "frappe-ui": "^0.1.156", + "frappe-ui": "^0.1.162", "gemoji": "^8.1.0", "lodash": "^4.17.21", "mime": "^4.0.1", diff --git a/frontend/src/components/Activities/AllModals.vue b/frontend/src/components/Activities/AllModals.vue index e4f7498b..ec58b6ee 100644 --- a/frontend/src/components/Activities/AllModals.vue +++ b/frontend/src/components/Activities/AllModals.vue @@ -19,6 +19,7 @@ v-if="showCallLogModal" v-model="showCallLogModal" :data="callLog" + :referenceDoc="referenceDoc" :options="{ afterInsert: () => activities.reload() }" /> @@ -87,10 +88,12 @@ function showNote(n) { // Call Logs const showCallLogModal = ref(false) const callLog = ref({}) +const referenceDoc = ref({}) function createCallLog() { let doctype = props.doctype let docname = props.doc.data?.name + referenceDoc.value = { ...props.doc.data } callLog.value = { reference_doctype: doctype, reference_docname: docname, diff --git a/frontend/src/components/BulkDeleteLinkedDocModal.vue b/frontend/src/components/BulkDeleteLinkedDocModal.vue new file mode 100644 index 00000000..b27273b5 --- /dev/null +++ b/frontend/src/components/BulkDeleteLinkedDocModal.vue @@ -0,0 +1,154 @@ + + + diff --git a/frontend/src/components/DeleteLinkedDocModal.vue b/frontend/src/components/DeleteLinkedDocModal.vue new file mode 100644 index 00000000..64a24128 --- /dev/null +++ b/frontend/src/components/DeleteLinkedDocModal.vue @@ -0,0 +1,265 @@ + + + diff --git a/frontend/src/components/EmailEditor.vue b/frontend/src/components/EmailEditor.vue index a13acdab..ca468ecc 100644 --- a/frontend/src/components/EmailEditor.vue +++ b/frontend/src/components/EmailEditor.vue @@ -150,7 +150,7 @@ @click="showEmailTemplateSelectorModal = true" > @@ -176,7 +176,7 @@ diff --git a/frontend/src/components/ListViews/LinkedDocsListView.vue b/frontend/src/components/ListViews/LinkedDocsListView.vue new file mode 100644 index 00000000..2687f5ea --- /dev/null +++ b/frontend/src/components/ListViews/LinkedDocsListView.vue @@ -0,0 +1,139 @@ + + + diff --git a/frontend/src/components/Modals/AddressModal.vue b/frontend/src/components/Modals/AddressModal.vue index e7c4543f..444490c4 100644 --- a/frontend/src/components/Modals/AddressModal.vue +++ b/frontend/src/components/Modals/AddressModal.vue @@ -84,7 +84,10 @@ const error = ref(null) const title = ref(null) const editMode = ref(false) -const { document: _address } = useDocument('Address', props.address || '') +const { document: _address, triggerOnBeforeCreate } = useDocument( + 'Address', + props.address || '', +) const dialogOptions = computed(() => { let title = !editMode.value @@ -95,8 +98,7 @@ const dialogOptions = computed(() => { { label: editMode.value ? __('Save') : __('Create'), variant: 'solid', - onClick: () => - editMode.value ? updateAddress() : createAddress.submit(), + onClick: () => (editMode.value ? updateAddress() : createAddress()), }, ] @@ -133,16 +135,22 @@ async function updateAddress() { await _address.save.submit(null, callBacks) } -const createAddress = createResource({ +async function createAddress() { + loading.value = true + error.value = null + + await triggerOnBeforeCreate?.() + + await _createAddress.submit({ + doc: { + doctype: 'Address', + ..._address.doc, + }, + }) +} + +const _createAddress = createResource({ url: 'frappe.client.insert', - makeParams() { - return { - doc: { - doctype: 'Address', - ..._address.doc, - }, - } - }, onSuccess(doc) { loading.value = false if (doc.name) { diff --git a/frontend/src/components/Modals/CallLogModal.vue b/frontend/src/components/Modals/CallLogModal.vue index 8ab881cd..1c90541f 100644 --- a/frontend/src/components/Modals/CallLogModal.vue +++ b/frontend/src/components/Modals/CallLogModal.vue @@ -69,6 +69,10 @@ const props = defineProps({ type: Object, default: () => ({}), }, + referenceDoc: { + type: Object, + default: () => ({}), + }, options: { type: Object, default: { @@ -85,7 +89,7 @@ const loading = ref(false) const error = ref(null) const editMode = ref(false) -const { document: callLog } = useDocument( +const { document: callLog, triggerOnBeforeCreate } = useDocument( 'CRM Call Log', props.data?.name || '', ) @@ -97,8 +101,7 @@ const dialogOptions = computed(() => { { label: editMode.value ? __('Save') : __('Create'), variant: 'solid', - onClick: () => - editMode.value ? updateCallLog() : createCallLog.submit(), + onClick: () => (editMode.value ? updateCallLog() : createCallLog()), }, ] @@ -135,18 +138,21 @@ async function updateCallLog() { await callLog.save.submit(null, callBacks) } -const createCallLog = createResource({ +async function createCallLog() { + Object.assign(callLog.doc, { + doctype: 'CRM Call Log', + id: getRandom(6), + telephony_medium: 'Manual', + }) + + await triggerOnBeforeCreate?.(props.referenceDoc) + await _createCallLog.submit({ + doc: callLog.doc, + }) +} + +const _createCallLog = createResource({ url: 'frappe.client.insert', - makeParams() { - return { - doc: { - doctype: 'CRM Call Log', - id: getRandom(6), - telephony_medium: 'Manual', - ...callLog.doc, - }, - } - }, onSuccess(doc) { loading.value = false if (doc.name) { diff --git a/frontend/src/components/Modals/ContactModal.vue b/frontend/src/components/Modals/ContactModal.vue index 25a0c022..4578ca35 100644 --- a/frontend/src/components/Modals/ContactModal.vue +++ b/frontend/src/components/Modals/ContactModal.vue @@ -86,7 +86,7 @@ const show = defineModel() const loading = ref(false) -const { document: _contact } = useDocument('Contact') +const { document: _contact, triggerOnBeforeCreate } = useDocument('Contact') async function createContact() { if (_contact.doc.email_id) { @@ -99,6 +99,8 @@ async function createContact() { delete _contact.doc.mobile_no } + await triggerOnBeforeCreate?.() + const doc = await call('frappe.client.insert', { doc: { doctype: 'Contact', diff --git a/frontend/src/components/Modals/CreateDocumentModal.vue b/frontend/src/components/Modals/CreateDocumentModal.vue index be5bbf01..0a2933a7 100644 --- a/frontend/src/components/Modals/CreateDocumentModal.vue +++ b/frontend/src/components/Modals/CreateDocumentModal.vue @@ -27,7 +27,7 @@
- +
@@ -51,6 +51,7 @@ import FieldLayout from '@/components/FieldLayout/FieldLayout.vue' import EditIcon from '@/components/Icons/EditIcon.vue' import { usersStore } from '@/stores/users' +import { useDocument } from '@/data/document' import { isMobileView } from '@/composables/settings' import { showQuickEntryModal, quickEntryProps } from '@/composables/modals' import { FeatherIcon, createResource, ErrorMessage, call } from 'frappe-ui' @@ -76,7 +77,7 @@ const show = defineModel() const loading = ref(false) const error = ref(null) -let _data = ref({}) +const { document: _data, triggerOnBeforeCreate } = useDocument(props.doctype) const dialogOptions = computed(() => { let doctype = props.doctype @@ -109,12 +110,14 @@ async function create() { loading.value = true error.value = null + await triggerOnBeforeCreate?.() + let doc = await call( 'frappe.client.insert', { doc: { doctype: props.doctype, - ..._data.value, + ..._data.doc, }, }, { @@ -138,7 +141,7 @@ watch( if (!value) return nextTick(() => { - _data.value = { ...props.data } + _data.doc = { ...props.data } }) }, ) diff --git a/frontend/src/components/Modals/DealModal.vue b/frontend/src/components/Modals/DealModal.vue index 8bf9498b..7ccb128f 100644 --- a/frontend/src/components/Modals/DealModal.vue +++ b/frontend/src/components/Modals/DealModal.vue @@ -98,7 +98,11 @@ const show = defineModel() const router = useRouter() const error = ref(null) -const { document: deal, triggerOnChange } = useDocument('CRM Deal') +const { + document: deal, + triggerOnChange, + triggerOnBeforeCreate, +} = useDocument('CRM Deal') const hasOrganizationSections = ref(true) const hasContactSections = ref(true) @@ -175,7 +179,7 @@ const dealStatuses = computed(() => { return statuses }) -function createDeal() { +async function createDeal() { if (deal.doc.website && !deal.doc.website.startsWith('http')) { deal.doc.website = 'https://' + deal.doc.website } @@ -186,6 +190,8 @@ function createDeal() { deal.doc['mobile_no'] = null } else deal.doc['contact'] = null + await triggerOnBeforeCreate?.() + createResource({ url: 'crm.fcrm.doctype.crm_deal.crm_deal.create_deal', params: { args: deal.doc }, diff --git a/frontend/src/components/Modals/EmailTemplateModal.vue b/frontend/src/components/Modals/EmailTemplateModal.vue deleted file mode 100644 index 15f27d46..00000000 --- a/frontend/src/components/Modals/EmailTemplateModal.vue +++ /dev/null @@ -1,239 +0,0 @@ - - - diff --git a/frontend/src/components/Modals/EmailTemplateSelectorModal.vue b/frontend/src/components/Modals/EmailTemplateSelectorModal.vue index a4fd820b..4f52e719 100644 --- a/frontend/src/components/Modals/EmailTemplateSelectorModal.vue +++ b/frontend/src/components/Modals/EmailTemplateSelectorModal.vue @@ -4,19 +4,33 @@ :options="{ title: __('Email Templates'), size: '4xl' }" > - diff --git a/frontend/src/components/Settings/EmailTemplate/EmailTemplatePage.vue b/frontend/src/components/Settings/EmailTemplate/EmailTemplatePage.vue new file mode 100644 index 00000000..c148a6dc --- /dev/null +++ b/frontend/src/components/Settings/EmailTemplate/EmailTemplatePage.vue @@ -0,0 +1,55 @@ + + + diff --git a/frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue b/frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue new file mode 100644 index 00000000..7fdb2972 --- /dev/null +++ b/frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue @@ -0,0 +1,265 @@ + + diff --git a/frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue b/frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue new file mode 100644 index 00000000..16e645a7 --- /dev/null +++ b/frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue @@ -0,0 +1,195 @@ + + diff --git a/frontend/src/components/Settings/Settings.vue b/frontend/src/components/Settings/Settings.vue index e4662770..8a8b4744 100644 --- a/frontend/src/components/Settings/Settings.vue +++ b/frontend/src/components/Settings/Settings.vue @@ -45,12 +45,14 @@ import WhatsAppIcon from '@/components/Icons/WhatsAppIcon.vue' import ERPNextIcon from '@/components/Icons/ERPNextIcon.vue' import PhoneIcon from '@/components/Icons/PhoneIcon.vue' import Email2Icon from '@/components/Icons/Email2Icon.vue' +import EmailTemplateIcon from '@/components/Icons/EmailTemplateIcon.vue' import Users from '@/components/Settings/Users.vue' import GeneralSettings from '@/components/Settings/GeneralSettings.vue' import InviteUserPage from '@/components/Settings/InviteUserPage.vue' import ProfileSettings from '@/components/Settings/ProfileSettings.vue' import WhatsAppSettings from '@/components/Settings/WhatsAppSettings.vue' import ERPNextSettings from '@/components/Settings/ERPNextSettings.vue' +import EmailTemplatePage from '@/components/Settings/EmailTemplate/EmailTemplatePage.vue' import TelephonySettings from '@/components/Settings/TelephonySettings.vue' import EmailConfig from '@/components/Settings/EmailConfig.vue' import SidebarLink from '@/components/SidebarLink.vue' @@ -107,6 +109,11 @@ const tabs = computed(() => { component: markRaw(EmailConfig), condition: () => isManager(), }, + { + label: __('Email Templates'), + icon: EmailTemplateIcon, + component: markRaw(EmailTemplatePage), + }, ], }, { diff --git a/frontend/src/components/Settings/Users.vue b/frontend/src/components/Settings/Users.vue index 0d4670ed..ad23658c 100644 --- a/frontend/src/components/Settings/Users.vue +++ b/frontend/src/components/Settings/Users.vue @@ -1,7 +1,7 @@ diff --git a/frontend/src/pages/Organization.vue b/frontend/src/pages/Organization.vue index a339e75d..ab4239ab 100644 --- a/frontend/src/pages/Organization.vue +++ b/frontend/src/pages/Organization.vue @@ -83,7 +83,7 @@ :label="__('Delete')" theme="red" size="sm" - @click="deleteOrganization" + @click="deleteOrganization()" > diff --git a/frontend/src/router.js b/frontend/src/router.js index e5665630..93e4743f 100644 --- a/frontend/src/router.js +++ b/frontend/src/router.js @@ -79,18 +79,6 @@ const routes = [ name: 'Call Logs', component: () => import('@/pages/CallLogs.vue'), }, - { - alias: '/email-templates', - path: '/email-templates/view/:viewType?', - name: 'Email Templates', - component: () => import('@/pages/EmailTemplates.vue'), - }, - { - path: '/email-templates/:emailTemplateId', - name: 'Email Template', - component: () => import('@/pages/EmailTemplate.vue'), - props: true, - }, { path: '/welcome', name: 'Welcome', diff --git a/frontend/src/utils/index.js b/frontend/src/utils/index.js index f2633b2f..c337907e 100644 --- a/frontend/src/utils/index.js +++ b/frontend/src/utils/index.js @@ -1,9 +1,10 @@ +import LucideCheck from '~icons/lucide/check' import TaskStatusIcon from '@/components/Icons/TaskStatusIcon.vue' import TaskPriorityIcon from '@/components/Icons/TaskPriorityIcon.vue' import { usersStore } from '@/stores/users' import { gemoji } from 'gemoji' import { getMeta } from '@/stores/meta' -import { toast, dayjsLocal, dayjs, getConfig } from 'frappe-ui' +import { toast, dayjsLocal, dayjs, getConfig, FeatherIcon } from 'frappe-ui' import { h } from 'vue' export function formatTime(seconds) { @@ -465,3 +466,66 @@ export function runSequentially(functions) { return promise.then(() => fn()) }, Promise.resolve()) } + +export function DropdownOption({ + active, + option, + theme, + icon, + onClick, + selected, +}) { + return h( + 'button', + { + class: [ + active ? 'bg-surface-gray-2' : 'text-ink-gray-8', + 'group flex w-full justify-between items-center rounded-md px-2 py-2 text-sm', + theme == 'danger' ? 'text-ink-red-3 hover:bg-ink-red-1' : '', + ], + onClick: !selected ? onClick : null, + }, + [ + h('div', { class: 'flex gap-2' }, [ + icon + ? h(FeatherIcon, { + name: icon, + class: ['h-4 w-4 shrink-0'], + 'aria-hidden': true, + }) + : null, + h('span', { class: 'whitespace-nowrap' }, option), + ]), + selected + ? h(LucideCheck, { + class: ['h-4 w-4 shrink-0 text-ink-gray-7'], + 'aria-hidden': true, + }) + : null, + ], + ) +} + +export function TemplateOption({ active, option, theme, icon, onClick }) { + return h( + 'button', + { + class: [ + active ? 'bg-surface-gray-2 text-ink-gray-8' : 'text-ink-gray-7', + 'group flex w-full gap-2 items-center rounded-md px-2 py-2 text-sm', + theme == '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), + ], + ) +} diff --git a/frontend/vite.config.js b/frontend/vite.config.js index f4de2403..97d2b193 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -2,11 +2,72 @@ import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import vueJsx from '@vitejs/plugin-vue-jsx' import path from 'path' +import fs from 'fs' import frappeui from 'frappe-ui/vite' import { VitePWA } from 'vite-plugin-pwa' +function appPath(app) { + const root = path.resolve(__dirname, '../..') // points to apps + const frontendPaths = [ + // Standard frontend structure: appname/frontend/src + path.join(root, app, 'frontend', 'src'), + // Desk-based apps: appname/desk/src + path.join(root, app, 'desk', 'src'), + // Alternative frontend structures + path.join(root, app, 'client', 'src'), + path.join(root, app, 'ui', 'src'), + // Direct src structure: appname/src + path.join(root, app, 'src'), + ] + return frontendPaths.find((srcPath) => fs.existsSync(srcPath)) || null +} + +function hasApp(app) { + return fs.existsSync(appPath(app)) +} + +// List of frontend apps used in this project +let apps = [] + +const alias = [ + // Default "@" for this app + { + find: '@', + replacement: path.resolve(__dirname, 'src'), + }, + + // App-specific aliases like @helpdesk, @hrms, etc. + ...apps.map((app) => + hasApp(app) + ? { find: `@${app}`, replacement: appPath(app) } + : { find: `@${app}`, replacement: `virtual:${app}` }, + ), +] + +const defineFlags = Object.fromEntries( + apps.map((app) => [ + `__HAS_${app.toUpperCase()}__`, + JSON.stringify(hasApp(app)), + ]), +) + +const virtualStubPlugin = { + name: 'virtual-empty-modules', + resolveId(id) { + if (id.startsWith('virtual:')) return '\0' + id + }, + load(id) { + if (id.startsWith('\0virtual:')) { + return 'export default {}; export const missing = true;' + } + }, +} + +console.log('Generated app aliases:', alias) + // https://vitejs.dev/config/ export default defineConfig({ + define: defineFlags, plugins: [ frappeui({ frappeProxy: true, @@ -60,12 +121,9 @@ export default defineConfig({ ], }, }), + virtualStubPlugin, ], - resolve: { - alias: { - '@': path.resolve(__dirname, 'src'), - }, - }, + resolve: { alias }, optimizeDeps: { include: [ 'feather-icons', diff --git a/yarn.lock b/yarn.lock index 7a442893..ed8ede6e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2570,10 +2570,10 @@ fraction.js@^4.3.7: resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7" integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== -frappe-ui@^0.1.156: - version "0.1.156" - resolved "https://registry.yarnpkg.com/frappe-ui/-/frappe-ui-0.1.156.tgz#1a476aec80b0e0f72470f9dc3990bb023b2ebb09" - integrity sha512-JsIODLL7YYFhKSYfWJJ9M1+VMmj8M0xZ1D5M7Cx0c+OWg5Qm0xda1592Tr+om1a7u0zWcfjuQnW9mHN1lW5HIA== +frappe-ui@^0.1.162: + version "0.1.162" + resolved "https://registry.yarnpkg.com/frappe-ui/-/frappe-ui-0.1.162.tgz#01a2f06e9db70b1bce6e0b0f2089a9cc1cb8dd51" + integrity sha512-LdlEQ1I8oMj2TAmx0FGuJl+AwQ6/jqtwEy3lei3mH6SVArfGnoVDqLm8aeJTwAB6KUjgCj+ffWe6vN7HmZXIcg== dependencies: "@floating-ui/vue" "^1.1.6" "@headlessui/vue" "^1.7.14"