feat: Agent assignment policy index page with CRUD actions (#12373)
# Pull Request Template ## Description This PR incudes new Agent assignment policy index page with CRUD actions. Fixes https://linear.app/chatwoot/issue/CW-5570/feat-assignment-policy-index-page-with-actions ## Type of change - [x] New feature (non-breaking change which adds functionality) ## How Has This Been Tested? ### Loom https://www.loom.com/share/17ab5ceca4854f179628a3b53f347e5a?sid=cb64e881-57fd-4ae1-921b-7648653cca33 ### Screenshots **Light mode** <img width="1428" height="888" alt="image" src="https://github.com/user-attachments/assets/fdbb83e9-1f4f-4432-9e8a-4a8f1b810d31" /> **Dark mode** <img width="1428" height="888" alt="image" src="https://github.com/user-attachments/assets/f1fb38b9-1150-482c-ba62-3fe63ee1c7d4" /> <img width="726" height="495" alt="image" src="https://github.com/user-attachments/assets/90a6ad55-9ab6-4adb-93a7-2327f5f09c79" /> ## 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 - [ ] 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 <muhsinkeramam@gmail.com>
This commit is contained in:
@@ -23,7 +23,7 @@ defineProps({
|
||||
<div class="flex flex-col w-full h-full gap-8 font-inter">
|
||||
<slot name="header" />
|
||||
<!-- Added to render any templates that should be rendered before body -->
|
||||
<div>
|
||||
<main>
|
||||
<slot name="preBody" />
|
||||
<slot v-if="isLoading" name="loading">
|
||||
<woot-loading-state :message="loadingMessage" />
|
||||
@@ -37,6 +37,6 @@ defineProps({
|
||||
<slot v-else name="body" />
|
||||
<!-- Do not delete the slot below. It is required to render anything that is not defined in the above slots. -->
|
||||
<slot />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -11,7 +11,7 @@ const { t } = useI18n();
|
||||
|
||||
const agentAssignments = computed(() => [
|
||||
{
|
||||
key: 'assignment_policy',
|
||||
key: 'agent_assignment_policy_index',
|
||||
title: t('ASSIGNMENT_POLICY.INDEX.ASSIGNMENT_POLICY.TITLE'),
|
||||
description: t('ASSIGNMENT_POLICY.INDEX.ASSIGNMENT_POLICY.DESCRIPTION'),
|
||||
features: [
|
||||
|
||||
@@ -2,6 +2,7 @@ import { FEATURE_FLAGS } from '../../../../featureFlags';
|
||||
import { frontendURL } from '../../../../helper/URLHelper';
|
||||
import SettingsWrapper from '../SettingsWrapper.vue';
|
||||
import AssignmentPolicyIndex from './Index.vue';
|
||||
import AgentAssignmentIndex from './pages/AgentAssignmentIndexPage.vue';
|
||||
|
||||
export default {
|
||||
routes: [
|
||||
@@ -24,6 +25,15 @@ export default {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'assignment',
|
||||
name: 'agent_assignment_policy_index',
|
||||
component: AgentAssignmentIndex,
|
||||
meta: {
|
||||
featureFlag: FEATURE_FLAGS.ASSIGNMENT_V2,
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
<script setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useStore, useMapGetter } from 'dashboard/composables/store';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useAlert } from 'dashboard/composables';
|
||||
|
||||
import Breadcrumb from 'dashboard/components-next/breadcrumb/Breadcrumb.vue';
|
||||
import Button from 'dashboard/components-next/button/Button.vue';
|
||||
import SettingsLayout from 'dashboard/routes/dashboard/settings/SettingsLayout.vue';
|
||||
import AssignmentPolicyCard from 'dashboard/components-next/AssignmentPolicy/AssignmentPolicyCard/AssignmentPolicyCard.vue';
|
||||
import ConfirmDeletePolicyDialog from './components/ConfirmDeletePolicyDialog.vue';
|
||||
|
||||
const store = useStore();
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
|
||||
const agentAssignmentsPolicies = useMapGetter(
|
||||
'assignmentPolicies/getAssignmentPolicies'
|
||||
);
|
||||
const uiFlags = useMapGetter('assignmentPolicies/getUIFlags');
|
||||
const inboxUiFlags = useMapGetter('assignmentPolicies/getInboxUiFlags');
|
||||
|
||||
const confirmDeletePolicyDialogRef = ref(null);
|
||||
|
||||
const breadcrumbItems = computed(() => {
|
||||
const items = [
|
||||
{
|
||||
label: t('ASSIGNMENT_POLICY.INDEX.HEADER.TITLE'),
|
||||
routeName: 'assignment_policy_index',
|
||||
},
|
||||
{
|
||||
label: t('ASSIGNMENT_POLICY.AGENT_ASSIGNMENT_POLICY.INDEX.HEADER.TITLE'),
|
||||
},
|
||||
];
|
||||
return items;
|
||||
});
|
||||
|
||||
const handleBreadcrumbClick = item => {
|
||||
router.push({
|
||||
name: item.routeName,
|
||||
});
|
||||
};
|
||||
|
||||
const onClickCreatePolicy = () => {
|
||||
router.push({
|
||||
name: 'assignment_policy_create',
|
||||
});
|
||||
};
|
||||
|
||||
const handleFetchInboxes = id => {
|
||||
if (inboxUiFlags.value.isFetching) return;
|
||||
store.dispatch('assignmentPolicies/getInboxes', id);
|
||||
};
|
||||
|
||||
const handleDelete = id => {
|
||||
confirmDeletePolicyDialogRef.value.openDialog(id);
|
||||
};
|
||||
|
||||
const handleDeletePolicy = async policyId => {
|
||||
try {
|
||||
await store.dispatch('assignmentPolicies/delete', policyId);
|
||||
useAlert(
|
||||
t(
|
||||
'ASSIGNMENT_POLICY.AGENT_ASSIGNMENT_POLICY.DELETE_POLICY.SUCCESS_MESSAGE'
|
||||
)
|
||||
);
|
||||
confirmDeletePolicyDialogRef.value.closeDialog();
|
||||
} catch (error) {
|
||||
useAlert(
|
||||
t('ASSIGNMENT_POLICY.AGENT_ASSIGNMENT_POLICY.DELETE_POLICY.ERROR_MESSAGE')
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
store.dispatch('assignmentPolicies/get');
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SettingsLayout
|
||||
:is-loading="uiFlags.isFetching"
|
||||
:no-records-found="agentAssignmentsPolicies.length === 0"
|
||||
:no-records-message="
|
||||
$t('ASSIGNMENT_POLICY.AGENT_ASSIGNMENT_POLICY.INDEX.NO_RECORDS_FOUND')
|
||||
"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2 w-full justify-between">
|
||||
<Breadcrumb :items="breadcrumbItems" @click="handleBreadcrumbClick" />
|
||||
<Button icon="i-lucide-plus" md @click="onClickCreatePolicy">
|
||||
{{
|
||||
$t(
|
||||
'ASSIGNMENT_POLICY.AGENT_ASSIGNMENT_POLICY.INDEX.HEADER.CREATE_POLICY'
|
||||
)
|
||||
}}
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
<template #body>
|
||||
<div class="flex flex-col gap-4 pt-8">
|
||||
<AssignmentPolicyCard
|
||||
v-for="policy in agentAssignmentsPolicies"
|
||||
:key="policy.id"
|
||||
v-bind="policy"
|
||||
:is-fetching-inboxes="inboxUiFlags.isFetching"
|
||||
@fetch-inboxes="handleFetchInboxes"
|
||||
@delete="handleDelete"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<ConfirmDeletePolicyDialog
|
||||
ref="confirmDeletePolicyDialogRef"
|
||||
@delete="handleDeletePolicy"
|
||||
/>
|
||||
</SettingsLayout>
|
||||
</template>
|
||||
@@ -0,0 +1,50 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import Dialog from 'dashboard/components-next/dialog/Dialog.vue';
|
||||
|
||||
const emit = defineEmits(['delete']);
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const dialogRef = ref(null);
|
||||
const currentPolicyId = ref(null);
|
||||
|
||||
const openDialog = policyId => {
|
||||
currentPolicyId.value = policyId;
|
||||
dialogRef.value.open();
|
||||
};
|
||||
|
||||
const closeDialog = () => {
|
||||
dialogRef.value.close();
|
||||
};
|
||||
|
||||
const handleDialogConfirm = () => {
|
||||
emit('delete', currentPolicyId.value);
|
||||
};
|
||||
|
||||
defineExpose({ openDialog, closeDialog });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog
|
||||
ref="dialogRef"
|
||||
type="alert"
|
||||
:title="t('ASSIGNMENT_POLICY.AGENT_ASSIGNMENT_POLICY.DELETE_POLICY.TITLE')"
|
||||
:description="
|
||||
t('ASSIGNMENT_POLICY.AGENT_ASSIGNMENT_POLICY.DELETE_POLICY.DESCRIPTION')
|
||||
"
|
||||
:confirm-button-label="
|
||||
t(
|
||||
'ASSIGNMENT_POLICY.AGENT_ASSIGNMENT_POLICY.DELETE_POLICY.CONFIRM_BUTTON_LABEL'
|
||||
)
|
||||
"
|
||||
:cancel-button-label="
|
||||
t(
|
||||
'ASSIGNMENT_POLICY.AGENT_ASSIGNMENT_POLICY.DELETE_POLICY.CANCEL_BUTTON_LABEL'
|
||||
)
|
||||
"
|
||||
@confirm="handleDialogConfirm"
|
||||
/>
|
||||
</template>
|
||||
Reference in New Issue
Block a user