From ca579bd62a3831c9813d3dd8ccc9840691cc5b68 Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Date: Fri, 12 Sep 2025 18:42:55 +0530 Subject: [PATCH] feat: Agent capacity policy Create/Edit pages (#12424) # Pull Request Template ## Description Fixes https://linear.app/chatwoot/issue/CW-5573/feat-createedit-agent-capacity-policy-page ## Type of change - [x] New feature (non-breaking change which adds functionality) ## How Has This Been Tested? ### Loom video https://www.loom.com/share/8de9e3c5d8824cd998d242636540dd18?sid=1314536f-c8d6-41fd-8139-cae9bf94f942 ### Screenshots **Light mode** image image **Dark mode** image image ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules --------- Co-authored-by: Muhsin Keloth --- .../components/AddDataDropdown.vue | 27 +- .../AssignmentPolicy/components/BaseInfo.vue | 3 +- .../AssignmentPolicy/components/DataTable.vue | 20 +- .../components/ExclusionRules.vue | 149 ++++++++ .../components/InboxCapacityLimits.vue | 163 +++++++++ .../story/AddDataDropdown.story.vue | 38 +- .../components/story/DataTable.story.vue | 27 +- .../components/story/ExclusionRules.story.vue | 67 ++++ .../story/InboxCapacityLimits.story.vue | 108 ++++++ .../Contacts/ContactLabels/ContactLabels.vue | 4 +- .../components-next/Label/LabelItem.vue | 3 +- .../dashboard/i18n/locale/en/settings.json | 86 +++++ .../assignmentPolicy.routes.js | 20 ++ .../pages/AgentCapacityCreatePage.vue | 87 +++++ .../pages/AgentCapacityEditPage.vue | 179 ++++++++++ .../components/AgentCapacityPolicyForm.vue | 214 ++++++++++++ .../store/modules/agentCapacityPolicies.js | 156 ++++++++- .../agentCapacityPolicies/actions.spec.js | 191 ++++++++++- .../specs/agentCapacityPolicies/fixtures.js | 126 ++++++- .../agentCapacityPolicies/mutations.spec.js | 324 +++++++++++++++++- .../dashboard/store/mutation-types.js | 6 + 21 files changed, 1965 insertions(+), 33 deletions(-) create mode 100644 app/javascript/dashboard/components-next/AssignmentPolicy/components/ExclusionRules.vue create mode 100644 app/javascript/dashboard/components-next/AssignmentPolicy/components/InboxCapacityLimits.vue create mode 100644 app/javascript/dashboard/components-next/AssignmentPolicy/components/story/ExclusionRules.story.vue create mode 100644 app/javascript/dashboard/components-next/AssignmentPolicy/components/story/InboxCapacityLimits.story.vue create mode 100644 app/javascript/dashboard/routes/dashboard/settings/assignmentPolicy/pages/AgentCapacityCreatePage.vue create mode 100644 app/javascript/dashboard/routes/dashboard/settings/assignmentPolicy/pages/AgentCapacityEditPage.vue create mode 100644 app/javascript/dashboard/routes/dashboard/settings/assignmentPolicy/pages/components/AgentCapacityPolicyForm.vue diff --git a/app/javascript/dashboard/components-next/AssignmentPolicy/components/AddDataDropdown.vue b/app/javascript/dashboard/components-next/AssignmentPolicy/components/AddDataDropdown.vue index c664d8929..7c98db791 100644 --- a/app/javascript/dashboard/components-next/AssignmentPolicy/components/AddDataDropdown.vue +++ b/app/javascript/dashboard/components-next/AssignmentPolicy/components/AddDataDropdown.vue @@ -4,6 +4,7 @@ import { useToggle } from '@vueuse/core'; import { vOnClickOutside } from '@vueuse/components'; import { picoSearch } from '@scmmishra/pico-search'; +import Avatar from 'next/avatar/Avatar.vue'; import Icon from 'dashboard/components-next/icon/Icon.vue'; import Button from 'dashboard/components-next/button/Button.vue'; import Input from 'dashboard/components-next/input/Input.vue'; @@ -36,8 +37,8 @@ const filteredItems = computed(() => { return picoSearch(props.items, query, ['name']); }); -const handleAdd = inbox => { - emit('add', inbox); +const handleAdd = item => { + emit('add', item); togglePopover(false); }; @@ -82,21 +83,35 @@ const handleClickOutside = () => {
+ +
- {{ item.name }} + {{ item.name || item.title }} { emit('validationChange', { isValid: isValid.value, + section: 'baseInfo', }); }, { immediate: true } @@ -108,7 +109,7 @@ watch(
-
+
+import Avatar from 'next/avatar/Avatar.vue'; import Icon from 'dashboard/components-next/icon/Icon.vue'; import Button from 'dashboard/components-next/button/Button.vue'; import Spinner from 'dashboard/components-next/spinner/Spinner.vue'; @@ -32,12 +33,14 @@ const handleDelete = itemId => { >
- - {{ emptyStateMessage }} - + + {{ emptyStateMessage }} + +
{ :icon="item.icon" class="size-4 text-n-slate-12 flex-shrink-0" /> - + {{ item.name }} diff --git a/app/javascript/dashboard/components-next/AssignmentPolicy/components/ExclusionRules.vue b/app/javascript/dashboard/components-next/AssignmentPolicy/components/ExclusionRules.vue new file mode 100644 index 000000000..5412675bd --- /dev/null +++ b/app/javascript/dashboard/components-next/AssignmentPolicy/components/ExclusionRules.vue @@ -0,0 +1,149 @@ + + + diff --git a/app/javascript/dashboard/components-next/AssignmentPolicy/components/InboxCapacityLimits.vue b/app/javascript/dashboard/components-next/AssignmentPolicy/components/InboxCapacityLimits.vue new file mode 100644 index 000000000..6a799005e --- /dev/null +++ b/app/javascript/dashboard/components-next/AssignmentPolicy/components/InboxCapacityLimits.vue @@ -0,0 +1,163 @@ + + + diff --git a/app/javascript/dashboard/components-next/AssignmentPolicy/components/story/AddDataDropdown.story.vue b/app/javascript/dashboard/components-next/AssignmentPolicy/components/story/AddDataDropdown.story.vue index 2ac4d8854..e69aa798f 100644 --- a/app/javascript/dashboard/components-next/AssignmentPolicy/components/story/AddDataDropdown.story.vue +++ b/app/javascript/dashboard/components-next/AssignmentPolicy/components/story/AddDataDropdown.story.vue @@ -34,6 +34,29 @@ const mockInboxes = [ }, ]; +const mockTags = [ + { + id: 1, + name: 'urgent', + color: '#ff4757', + }, + { + id: 2, + name: 'bug', + color: '#ff6b6b', + }, + { + id: 3, + name: 'feature-request', + color: '#4834d4', + }, + { + id: 4, + name: 'documentation', + color: '#26de81', + }, +]; + const handleAdd = item => { console.log('Add item:', item); }; @@ -42,9 +65,9 @@ const handleAdd = item => { diff --git a/app/javascript/dashboard/components-next/AssignmentPolicy/components/story/DataTable.story.vue b/app/javascript/dashboard/components-next/AssignmentPolicy/components/story/DataTable.story.vue index 912b1fdfc..a81a29976 100644 --- a/app/javascript/dashboard/components-next/AssignmentPolicy/components/story/DataTable.story.vue +++ b/app/javascript/dashboard/components-next/AssignmentPolicy/components/story/DataTable.story.vue @@ -22,6 +22,21 @@ const mockItems = [ }, ]; +const mockAgentList = [ + { + id: 1, + name: 'John Doe', + email: 'john.doe@example.com', + avatarUrl: 'https://i.pravatar.cc/150?img=1', + }, + { + id: 2, + name: 'Jane Smith', + email: 'jane.smith@example.com', + avatarUrl: 'https://i.pravatar.cc/150?img=2', + }, +]; + const handleDelete = itemId => { console.log('Delete item:', itemId); }; @@ -30,7 +45,7 @@ const handleDelete = itemId => {