From c3ec1d4f8abbab7650bafda726dc0f4d6eb84340 Mon Sep 17 00:00:00 2001 From: Fayaz Ahmed <15716057+fayazara@users.noreply.github.com> Date: Tue, 25 Oct 2022 09:03:59 +0530 Subject: [PATCH] feat: Add the ability for the agents to execute a macro (#5698) Co-authored-by: Pranav Raj S --- app/javascript/dashboard/components/index.js | 10 +- .../components/widgets/FeatureToggle.vue | 25 ++++ .../helper/specs/macrosHelper.spec.js | 37 +++++- .../i18n/locale/en/conversation.json | 3 +- .../dashboard/i18n/locale/en/macros.json | 12 +- .../dashboard/mixins/specs/uiSettings.spec.js | 1 + app/javascript/dashboard/mixins/uiSettings.js | 13 +- .../dashboard/conversation/ContactPanel.vue | 15 +++ .../dashboard/conversation/Macros/List.vue | 75 +++++++++++ .../conversation/Macros/MacroItem.vue | 111 +++++++++++++++++ .../conversation/Macros/MacroPreview.vue | 116 ++++++++++++++++++ .../dashboard/settings/macros/macroHelper.js | 23 ++++ .../shared/assets/stylesheets/spacing.scss | 3 +- .../FluentIcon/dashboard-icons.json | 1 + 14 files changed, 431 insertions(+), 14 deletions(-) create mode 100644 app/javascript/dashboard/components/widgets/FeatureToggle.vue create mode 100644 app/javascript/dashboard/routes/dashboard/conversation/Macros/List.vue create mode 100644 app/javascript/dashboard/routes/dashboard/conversation/Macros/MacroItem.vue create mode 100644 app/javascript/dashboard/routes/dashboard/conversation/Macros/MacroPreview.vue diff --git a/app/javascript/dashboard/components/index.js b/app/javascript/dashboard/components/index.js index 5e58aa049..f5ce5d856 100644 --- a/app/javascript/dashboard/components/index.js +++ b/app/javascript/dashboard/components/index.js @@ -5,9 +5,12 @@ import Button from './ui/WootButton'; import Code from './Code'; import ColorPicker from './widgets/ColorPicker'; import ConfirmDeleteModal from './widgets/modal/ConfirmDeleteModal.vue'; +import ConfirmModal from './widgets/modal/ConfirmationModal.vue'; +import ContextMenu from './ui/ContextMenu.vue'; import DeleteModal from './widgets/modal/DeleteModal.vue'; import DropdownItem from 'shared/components/ui/dropdown/DropdownItem'; import DropdownMenu from 'shared/components/ui/dropdown/DropdownMenu'; +import FeatureToggle from './widgets/FeatureToggle'; import HorizontalBar from './widgets/chart/HorizontalBarChart'; import Input from './widgets/forms/Input.vue'; import Label from './ui/Label'; @@ -21,8 +24,6 @@ import SubmitButton from './buttons/FormSubmitButton'; import Tabs from './ui/Tabs/Tabs'; import TabsItem from './ui/Tabs/TabsItem'; import Thumbnail from './widgets/Thumbnail.vue'; -import ConfirmModal from './widgets/modal/ConfirmationModal.vue'; -import ContextMenu from './ui/ContextMenu.vue'; const WootUIKit = { AvatarUploader, @@ -31,9 +32,12 @@ const WootUIKit = { Code, ColorPicker, ConfirmDeleteModal, + ConfirmModal, + ContextMenu, DeleteModal, DropdownItem, DropdownMenu, + FeatureToggle, HorizontalBar, Input, Label, @@ -47,8 +51,6 @@ const WootUIKit = { Tabs, TabsItem, Thumbnail, - ConfirmModal, - ContextMenu, install(Vue) { const keys = Object.keys(this); keys.pop(); // remove 'install' from keys diff --git a/app/javascript/dashboard/components/widgets/FeatureToggle.vue b/app/javascript/dashboard/components/widgets/FeatureToggle.vue new file mode 100644 index 000000000..ec7759a9c --- /dev/null +++ b/app/javascript/dashboard/components/widgets/FeatureToggle.vue @@ -0,0 +1,25 @@ + + diff --git a/app/javascript/dashboard/helper/specs/macrosHelper.spec.js b/app/javascript/dashboard/helper/specs/macrosHelper.spec.js index 26c731aa8..649eff8c5 100644 --- a/app/javascript/dashboard/helper/specs/macrosHelper.spec.js +++ b/app/javascript/dashboard/helper/specs/macrosHelper.spec.js @@ -1,4 +1,11 @@ -import { emptyMacro } from '../../routes/dashboard/settings/macros/macroHelper'; +import { + emptyMacro, + resolveActionName, + resolveLabels, + resolveTeamIds, +} from '../../routes/dashboard/settings/macros/macroHelper'; +import { MACRO_ACTION_TYPES } from '../../routes/dashboard/settings/macros/constants'; +import { teams, labels } from './macrosFixtures'; describe('#emptyMacro', () => { const defaultMacro = { @@ -15,3 +22,31 @@ describe('#emptyMacro', () => { expect(emptyMacro).toEqual(defaultMacro); }); }); + +describe('#resolveActionName', () => { + it('resolve action name from key and return the correct label', () => { + expect(resolveActionName(MACRO_ACTION_TYPES[0].key)).toEqual( + MACRO_ACTION_TYPES[0].label + ); + expect(resolveActionName(MACRO_ACTION_TYPES[1].key)).toEqual( + MACRO_ACTION_TYPES[1].label + ); + expect(resolveActionName(MACRO_ACTION_TYPES[1].key)).not.toEqual( + MACRO_ACTION_TYPES[0].label + ); + }); +}); + +describe('#resolveTeamIds', () => { + it('resolves team names from ids, and returns a joined string', () => { + const resolvedTeams = '⚙️ sales team, 🤷‍♂️ fayaz'; + expect(resolveTeamIds(teams, [1, 2])).toEqual(resolvedTeams); + }); +}); + +describe('#resolveLabels', () => { + it('resolves labels names from ids and returns a joined string', () => { + const resolvedLabels = 'sales, billing'; + expect(resolveLabels(labels, ['sales', 'billing'])).toEqual(resolvedLabels); + }); +}); diff --git a/app/javascript/dashboard/i18n/locale/en/conversation.json b/app/javascript/dashboard/i18n/locale/en/conversation.json index 7c6fa76d5..771b5305f 100644 --- a/app/javascript/dashboard/i18n/locale/en/conversation.json +++ b/app/javascript/dashboard/i18n/locale/en/conversation.json @@ -208,7 +208,8 @@ "CONVERSATION_LABELS": "Conversation Labels", "CONVERSATION_INFO": "Conversation Information", "CONTACT_ATTRIBUTES": "Contact Attributes", - "PREVIOUS_CONVERSATION": "Previous Conversations" + "PREVIOUS_CONVERSATION": "Previous Conversations", + "MACROS": "Macros" } }, "CONVERSATION_CUSTOM_ATTRIBUTES": { diff --git a/app/javascript/dashboard/i18n/locale/en/macros.json b/app/javascript/dashboard/i18n/locale/en/macros.json index 132151241..28c4660aa 100644 --- a/app/javascript/dashboard/i18n/locale/en/macros.json +++ b/app/javascript/dashboard/i18n/locale/en/macros.json @@ -24,12 +24,7 @@ } }, "LIST": { - "TABLE_HEADER": [ - "Name", - "Created by", - "Last updated by", - "Visibility" - ], + "TABLE_HEADER": ["Name", "Created by", "Last updated by", "Visibility"], "404": "No macros found" }, "DELETE": { @@ -68,6 +63,11 @@ "DESCRIPTION": "This macro will be private to you and not be available to others." } } + }, + "EXECUTE": { + "BUTTON_TOOLTIP": "Execute", + "PREVIEW": "Preview Macro", + "EXECUTED_SUCCESSFULLY": "Macro executed successfully" } } } diff --git a/app/javascript/dashboard/mixins/specs/uiSettings.spec.js b/app/javascript/dashboard/mixins/specs/uiSettings.spec.js index 79c06939e..3613574ba 100644 --- a/app/javascript/dashboard/mixins/specs/uiSettings.spec.js +++ b/app/javascript/dashboard/mixins/specs/uiSettings.spec.js @@ -119,6 +119,7 @@ describe('uiSettingsMixin', () => { { name: 'conversation_info' }, { name: 'contact_attributes' }, { name: 'previous_conversation' }, + { name: 'macros' }, ]); }); }); diff --git a/app/javascript/dashboard/mixins/uiSettings.js b/app/javascript/dashboard/mixins/uiSettings.js index adc407eb3..e517d6961 100644 --- a/app/javascript/dashboard/mixins/uiSettings.js +++ b/app/javascript/dashboard/mixins/uiSettings.js @@ -1,6 +1,7 @@ import { mapGetters } from 'vuex'; export const DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER = [ { name: 'conversation_actions' }, + { name: 'macros' }, { name: 'conversation_info' }, { name: 'contact_attributes' }, { name: 'previous_conversation' }, @@ -30,7 +31,17 @@ export default { ...mapGetters({ uiSettings: 'getUISettings' }), conversationSidebarItemsOrder() { const { conversation_sidebar_items_order: itemsOrder } = this.uiSettings; - return itemsOrder || DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER; + // If the sidebar order is not set, use the default order. + if (!itemsOrder) { + return DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER; + } + // If the sidebar order doesn't have the new elements, then add them to the list. + DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER.forEach(item => { + if (!itemsOrder.find(i => i.name === item.name)) { + itemsOrder.push(item); + } + }); + return itemsOrder; }, contactSidebarItemsOrder() { const { contact_sidebar_items_order: itemsOrder } = this.uiSettings; diff --git a/app/javascript/dashboard/routes/dashboard/conversation/ContactPanel.vue b/app/javascript/dashboard/routes/dashboard/conversation/ContactPanel.vue index 4405ed2ad..4c20bfec2 100644 --- a/app/javascript/dashboard/routes/dashboard/conversation/ContactPanel.vue +++ b/app/javascript/dashboard/routes/dashboard/conversation/ContactPanel.vue @@ -93,6 +93,19 @@ /> + + + + + @@ -112,6 +125,7 @@ import CustomAttributes from './customAttributes/CustomAttributes.vue'; import CustomAttributeSelector from './customAttributes/CustomAttributeSelector.vue'; import draggable from 'vuedraggable'; import uiSettingsMixin from 'dashboard/mixins/uiSettings'; +import MacrosList from './Macros/List'; export default { components: { @@ -123,6 +137,7 @@ export default { CustomAttributeSelector, ConversationAction, draggable, + MacrosList, }, mixins: [alertMixin, uiSettingsMixin], props: { diff --git a/app/javascript/dashboard/routes/dashboard/conversation/Macros/List.vue b/app/javascript/dashboard/routes/dashboard/conversation/Macros/List.vue new file mode 100644 index 000000000..d16051ce7 --- /dev/null +++ b/app/javascript/dashboard/routes/dashboard/conversation/Macros/List.vue @@ -0,0 +1,75 @@ + + + diff --git a/app/javascript/dashboard/routes/dashboard/conversation/Macros/MacroItem.vue b/app/javascript/dashboard/routes/dashboard/conversation/Macros/MacroItem.vue new file mode 100644 index 000000000..c8cac6829 --- /dev/null +++ b/app/javascript/dashboard/routes/dashboard/conversation/Macros/MacroItem.vue @@ -0,0 +1,111 @@ + + + + + diff --git a/app/javascript/dashboard/routes/dashboard/conversation/Macros/MacroPreview.vue b/app/javascript/dashboard/routes/dashboard/conversation/Macros/MacroPreview.vue new file mode 100644 index 000000000..bf7d09cbd --- /dev/null +++ b/app/javascript/dashboard/routes/dashboard/conversation/Macros/MacroPreview.vue @@ -0,0 +1,116 @@ + + + + + diff --git a/app/javascript/dashboard/routes/dashboard/settings/macros/macroHelper.js b/app/javascript/dashboard/routes/dashboard/settings/macros/macroHelper.js index 134e0d943..584deeb5e 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/macros/macroHelper.js +++ b/app/javascript/dashboard/routes/dashboard/settings/macros/macroHelper.js @@ -1,3 +1,4 @@ +import { MACRO_ACTION_TYPES as macroActionTypes } from 'dashboard/routes/dashboard/settings/macros/constants.js'; export const emptyMacro = { name: '', actions: [ @@ -8,3 +9,25 @@ export const emptyMacro = { ], visibility: 'global', }; + +export const resolveActionName = key => { + return macroActionTypes.find(i => i.key === key).label; +}; + +export const resolveTeamIds = (teams, ids) => { + return ids + .map(id => { + const team = teams.find(i => i.id === id); + return team ? team.name : ''; + }) + .join(', '); +}; + +export const resolveLabels = (labels, ids) => { + return ids + .map(id => { + const label = labels.find(i => i.title === id); + return label ? label.title : ''; + }) + .join(', '); +}; diff --git a/app/javascript/shared/assets/stylesheets/spacing.scss b/app/javascript/shared/assets/stylesheets/spacing.scss index c556c65b8..7ef494a7a 100644 --- a/app/javascript/shared/assets/stylesheets/spacing.scss +++ b/app/javascript/shared/assets/stylesheets/spacing.scss @@ -16,9 +16,10 @@ --space-jumbo: 6.4rem; --space-mega: 10rem; --space-giga: 24rem; - + --space-minus-micro: -0.2rem; --space-minus-smaller: -0.4rem; + --space-minus-half: -0.5rem; --space-minus-small: -0.8rem; --space-minus-one: -1rem; --space-minus-slab: -1.2rem; diff --git a/app/javascript/shared/components/FluentIcon/dashboard-icons.json b/app/javascript/shared/components/FluentIcon/dashboard-icons.json index 5b6cda950..c08b66c77 100644 --- a/app/javascript/shared/components/FluentIcon/dashboard-icons.json +++ b/app/javascript/shared/components/FluentIcon/dashboard-icons.json @@ -119,6 +119,7 @@ "person-add-outline": "M17.5 12a5.5 5.5 0 1 1 0 11a5.5 5.5 0 0 1 0-11zm-5.477 2a6.47 6.47 0 0 0-.709 1.5H4.253a.749.749 0 0 0-.75.75v.577c0 .535.192 1.053.54 1.46c1.253 1.469 3.22 2.214 5.957 2.214c.597 0 1.157-.035 1.68-.106c.246.495.553.954.912 1.367c-.795.16-1.66.24-2.592.24c-3.146 0-5.532-.906-7.098-2.74a3.75 3.75 0 0 1-.898-2.435v-.578A2.249 2.249 0 0 1 4.253 14h7.77zm5.477 0l-.09.008a.5.5 0 0 0-.402.402L17 14.5V17h-2.496l-.09.008a.5.5 0 0 0-.402.402l-.008.09l.008.09a.5.5 0 0 0 .402.402l.09.008H17L17 20.5l.008.09a.5.5 0 0 0 .402.402l.09.008l.09-.008a.5.5 0 0 0 .402-.402L18 20.5V18h2.504l.09-.008a.5.5 0 0 0 .402-.402l.008-.09l-.008-.09a.5.5 0 0 0-.402-.402l-.09-.008H18L18 14.5l-.008-.09a.5.5 0 0 0-.402-.402L17.5 14zM10 2.005a5 5 0 1 1 0 10a5 5 0 0 1 0-10zm0 1.5a3.5 3.5 0 1 0 0 7a3.5 3.5 0 0 0 0-7z", "person-assign-outline": "M11.313 15.5a6.471 6.471 0 0 1 .709-1.5h-7.77a2.249 2.249 0 0 0-2.249 2.25v.577c0 .892.319 1.756.899 2.435c1.566 1.834 3.952 2.74 7.098 2.74c.931 0 1.796-.08 2.592-.24a6.51 6.51 0 0 1-.913-1.366c-.524.07-1.083.105-1.68.105c-2.737 0-4.703-.745-5.957-2.213a2.25 2.25 0 0 1-.539-1.461v-.578a.75.75 0 0 1 .75-.749h7.06ZM10 2.005a5 5 0 1 1 0 10a5 5 0 0 1 0-10Zm0 1.5a3.5 3.5 0 1 0 0 7a3.5 3.5 0 0 0 0-7ZM23 17.5a5.5 5.5 0 1 1-11 0a5.5 5.5 0 0 1 11 0Zm-4.647-2.853a.5.5 0 0 0-.707.707L19.293 17H15a.5.5 0 1 0 0 1h4.293l-1.647 1.647a.5.5 0 0 0 .707.707l2.5-2.5a.497.497 0 0 0 .147-.345V17.5a.498.498 0 0 0-.15-.357l-2.497-2.496Z", "person-outline": "M17.754 14a2.249 2.249 0 0 1 2.25 2.249v.575c0 .894-.32 1.76-.902 2.438-1.57 1.834-3.957 2.739-7.102 2.739-3.146 0-5.532-.905-7.098-2.74a3.75 3.75 0 0 1-.898-2.435v-.577a2.249 2.249 0 0 1 2.249-2.25h11.501Zm0 1.5H6.253a.749.749 0 0 0-.75.749v.577c0 .536.192 1.054.54 1.461 1.253 1.468 3.219 2.214 5.957 2.214s4.706-.746 5.962-2.214a2.25 2.25 0 0 0 .541-1.463v-.575a.749.749 0 0 0-.749-.75ZM12 2.004a5 5 0 1 1 0 10 5 5 0 0 1 0-10Zm0 1.5a3.5 3.5 0 1 0 0 7 3.5 3.5 0 0 0 0-7Z", + "play-circle-outline": "M2 12C2 6.477 6.477 2 12 2s10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12Zm8.856-3.845A1.25 1.25 0 0 0 9 9.248v5.504a1.25 1.25 0 0 0 1.856 1.093l5.757-3.189a.75.75 0 0 0 0-1.312l-5.757-3.189Z", "power-outline": "M8.204 4.82a.75.75 0 0 1 .634 1.36A7.51 7.51 0 0 0 4.5 12.991c0 4.148 3.358 7.51 7.499 7.51s7.499-3.362 7.499-7.51a7.51 7.51 0 0 0-4.323-6.804.75.75 0 1 1 .637-1.358 9.01 9.01 0 0 1 5.186 8.162c0 4.976-4.029 9.01-9 9.01C7.029 22 3 17.966 3 12.99a9.01 9.01 0 0 1 5.204-8.17ZM12 2.496a.75.75 0 0 1 .743.648l.007.102v7.5a.75.75 0 0 1-1.493.102l-.007-.102v-7.5a.75.75 0 0 1 .75-.75Z", "quote-outline": "M7.5 6a2.5 2.5 0 0 1 2.495 2.336l.005.206c-.01 3.555-1.24 6.614-3.705 9.223a.75.75 0 1 1-1.09-1.03c1.64-1.737 2.66-3.674 3.077-5.859A2.5 2.5 0 1 1 7.5 6Zm9 0a2.5 2.5 0 0 1 2.495 2.336l.005.206c-.01 3.56-1.238 6.614-3.705 9.223a.75.75 0 1 1-1.09-1.03c1.643-1.738 2.662-3.672 3.078-5.859A2.5 2.5 0 1 1 16.5 6Zm-9 1.5a1 1 0 1 0 .993 1.117l.007-.124a1 1 0 0 0-1-.993Zm9 0a1 1 0 1 0 .993 1.117l.007-.124a1 1 0 0 0-1-.993Z", "resize-large-outline": "M6.25 4.5A1.75 1.75 0 0 0 4.5 6.25v1.5a.75.75 0 0 1-1.5 0v-1.5A3.25 3.25 0 0 1 6.25 3h1.5a.75.75 0 0 1 0 1.5h-1.5ZM19.5 6.25a1.75 1.75 0 0 0-1.75-1.75h-1.5a.75.75 0 0 1 0-1.5h1.5A3.25 3.25 0 0 1 21 6.25v1.5a.75.75 0 0 1-1.5 0v-1.5ZM19.5 17.75a1.75 1.75 0 0 1-1.75 1.75h-1.5a.75.75 0 0 0 0 1.5h1.5A3.25 3.25 0 0 0 21 17.75v-1.5a.75.75 0 0 0-1.5 0v1.5ZM4.5 17.75c0 .966.784 1.75 1.75 1.75h1.5a.75.75 0 0 1 0 1.5h-1.5A3.25 3.25 0 0 1 3 17.75v-1.5a.75.75 0 0 1 1.5 0v1.5ZM8.25 6A2.25 2.25 0 0 0 6 8.25v7.5A2.25 2.25 0 0 0 8.25 18h7.5A2.25 2.25 0 0 0 18 15.75v-7.5A2.25 2.25 0 0 0 15.75 6h-7.5ZM7.5 8.25a.75.75 0 0 1 .75-.75h7.5a.75.75 0 0 1 .75.75v7.5a.75.75 0 0 1-.75.75h-7.5a.75.75 0 0 1-.75-.75v-7.5Z",