diff --git a/app/builders/account_builder.rb b/app/builders/account_builder.rb index ff67eefc5..6f7980586 100644 --- a/app/builders/account_builder.rb +++ b/app/builders/account_builder.rb @@ -94,8 +94,8 @@ class AccountBuilder def blocked_domains domains = GlobalConfigService.load('BLOCKED_EMAIL_DOMAINS', '') - domains.split("\n").map(&:strip) if domains.present? + return [] if domains.blank? - [] + domains.split("\n").map(&:strip) end end diff --git a/app/javascript/dashboard/components/CustomAttribute.vue b/app/javascript/dashboard/components/CustomAttribute.vue index 4bf97320b..ee00c182d 100644 --- a/app/javascript/dashboard/components/CustomAttribute.vue +++ b/app/javascript/dashboard/components/CustomAttribute.vue @@ -331,10 +331,12 @@ export default { ::v-deep { .selector-wrap { @apply m-0 top-1; + .selector-name { @apply ml-0; } } + .name { @apply ml-0; } diff --git a/app/javascript/dashboard/components/widgets/WootWriter/FullEditor.vue b/app/javascript/dashboard/components/widgets/WootWriter/FullEditor.vue index ab4be9342..754182207 100644 --- a/app/javascript/dashboard/components/widgets/WootWriter/FullEditor.vue +++ b/app/javascript/dashboard/components/widgets/WootWriter/FullEditor.vue @@ -120,7 +120,6 @@ export default { if (fileUrl) { this.onImageUploadStart(fileUrl); } - useAlert(this.$t('HELP_CENTER.ARTICLE_EDITOR.IMAGE_UPLOAD.SUCCESS')); } catch (error) { useAlert(this.$t('HELP_CENTER.ARTICLE_EDITOR.IMAGE_UPLOAD.ERROR')); } @@ -173,6 +172,18 @@ export default { blur: () => { this.onBlur(); }, + paste: (view, event) => { + const data = event.clipboardData.files; + if (data.length > 0) { + data.forEach(file => { + // Check if the file is an image + if (file.type.includes('image')) { + this.uploadImageToStorage(file); + } + }); + event.preventDefault(); + } + }, }, }); }, diff --git a/app/javascript/dashboard/helper/featureHelper.js b/app/javascript/dashboard/helper/featureHelper.js index a7fa21616..b4d131ce4 100644 --- a/app/javascript/dashboard/helper/featureHelper.js +++ b/app/javascript/dashboard/helper/featureHelper.js @@ -9,6 +9,7 @@ const FEATURE_HELP_URLS = { custom_attributes: 'https://chwt.app/hc/custom-attributes', dashboard_apps: 'https://chwt.app/hc/dashboard-apps', help_center: 'https://chwt.app/hc/help-center', + inboxes: 'https://chwt.app/hc/inboxes', integrations: 'https://chwt.app/hc/integrations', labels: 'https://chwt.app/hc/labels', macros: 'https://chwt.app/hc/macros', diff --git a/app/javascript/dashboard/i18n/locale/en/attributesMgmt.json b/app/javascript/dashboard/i18n/locale/en/attributesMgmt.json index a2f7386dc..a83852fb8 100644 --- a/app/javascript/dashboard/i18n/locale/en/attributesMgmt.json +++ b/app/javascript/dashboard/i18n/locale/en/attributesMgmt.json @@ -3,7 +3,8 @@ "HEADER": "Custom Attributes", "HEADER_BTN_TXT": "Add Custom Attribute", "LOADING": "Fetching custom attributes", - "SIDEBAR_TXT": "

Custom Attributes

A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc.

For creating a Custom Attribute, just click on the Add Custom Attribute. You can also edit or delete an existing Custom Attribute by clicking on the Edit or Delete button.

", + "DESCRIPTION": "A custom attribute tracks additional details about your contacts or conversations—such as the subscription plan or the date of their first purchase. You can add different types of custom attributes, such as text, lists, or numbers, to capture the specific information you need.", + "LEARN_MORE": "Learn more about custom attributes", "ADD": { "TITLE": "Add Custom Attribute", "SUBMIT": "Create", @@ -91,7 +92,12 @@ "CONTACT": "Contact" }, "LIST": { - "TABLE_HEADER": ["Name", "Description", "Type", "Key"], + "TABLE_HEADER": [ + "Name", + "Description", + "Type", + "Key" + ], "BUTTONS": { "EDIT": "Edit", "DELETE": "Delete" diff --git a/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json index eec8ccde6..5bd1b6989 100644 --- a/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json @@ -1,7 +1,8 @@ { "INBOX_MGMT": { "HEADER": "Inboxes", - "SIDEBAR_TXT": "

Inbox

When you connect a website or a facebook Page to Chatwoot, it is called an Inbox. You can have unlimited inboxes in your Chatwoot account.

Click on Add Inbox to connect a website or a Facebook Page.

In the Dashboard, you can see all the conversations from all your inboxes in a single place and respond to them under the `Conversations` tab.

You can also see conversations specific to an inbox by clicking on the inbox name on the left pane of the dashboard.

", + "DESCRIPTION": "A channel is the mode of communication your customer chooses to interact with you. An inbox is where you manage interactions for a specific channel. It can include communications from various sources such as email, live chat, and social media.", + "LEARN_MORE": "Learn more about inboxes", "RECONNECTION_REQUIRED": "Your inbox is disconnected. You won't receive new messages until you reauthorize it.", "CLICK_TO_RECONNECT": "Click here to reconnect.", "LIST": { @@ -745,6 +746,18 @@ "MICROSOFT": "Microsoft", "GOOGLE": "Google", "OTHER_PROVIDERS": "Other Providers" + }, + "CHANNELS": { + "MESSENGER": "Messenger", + "WEB_WIDGET": "Website", + "TWITTER_PROFILE": "Twitter", + "TWILIO_SMS": "Twilio SMS", + "WHATSAPP": "WhatsApp", + "SMS": "SMS", + "EMAIL": "Email", + "TELEGRAM": "Telegram", + "LINE": "Line", + "API": "API Channel" } } } diff --git a/app/javascript/dashboard/routes/dashboard/settings/SettingsLayout.vue b/app/javascript/dashboard/routes/dashboard/settings/SettingsLayout.vue index 916f821ad..0e6a42fe8 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/SettingsLayout.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/SettingsLayout.vue @@ -22,17 +22,21 @@ defineProps({ diff --git a/app/javascript/dashboard/routes/dashboard/settings/attributes/AddAttribute.vue b/app/javascript/dashboard/routes/dashboard/settings/attributes/AddAttribute.vue index 1ff257b7e..33f9ab7a5 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/attributes/AddAttribute.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/attributes/AddAttribute.vue @@ -12,6 +12,12 @@ export default { type: Function, default: () => {}, }, + // Passes 0 or 1 based on the selected AttributeModel tab selected in the UI + // Needs a better data type, todo: refactor this component later + selectedAttributeModelTab: { + type: Number, + default: 0, + }, }, setup() { return { v$: useVuelidate() }; @@ -20,7 +26,10 @@ export default { return { displayName: '', description: '', - attributeModel: 0, + // Using the prop as default. There is no side effect here as the component + // is destroyed completely when the modal is closed. The prop doesn't change + // dynamically when the modal is active. + attributeModel: this.selectedAttributeModelTab || 0, attributeType: 0, attributeKey: '', regexPattern: null, @@ -280,13 +289,16 @@ export default { padding: 0 var(--space-small) var(--space-small) 0; font-family: monospace; } + .multiselect--wrap { margin-bottom: var(--space-normal); + .error-message { color: var(--r-400); font-size: var(--font-size-small); font-weight: var(--font-weight-normal); } + .invalid { ::v-deep { .multiselect__tags { @@ -295,13 +307,16 @@ export default { } } } + ::v-deep { .multiselect { margin-bottom: 0; } + .multiselect__content-wrapper { display: none; } + .multiselect--active .multiselect__tags { border-radius: var(--border-radius-normal); } diff --git a/app/javascript/dashboard/routes/dashboard/settings/attributes/CustomAttribute.vue b/app/javascript/dashboard/routes/dashboard/settings/attributes/CustomAttribute.vue index 5c234ec03..e5e85cdd1 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/attributes/CustomAttribute.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/attributes/CustomAttribute.vue @@ -1,195 +1,141 @@ -