mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-01 11:37:58 +00:00
# Pull Request Template ## Description This PR includes: 1. Ensuring dropdowns always stay within the screen, with auto top/bottom/left/right positioning. 2. Fixing the dropdown truncation issue. 3. Removing the display of IDs from dropdowns. 4. Increasing the width of the inbox limit input field. 5. Updating the position of the **Update** button in the agent assignment edit page. ## Type of change - [x] Bug fix (non-breaking change which fixes an issue) ## How Has This Been Tested? ### Loom video https://www.loom.com/share/f20afc854edc42fab69a003f347d089b?sid=5e5f45f3-5950-46ff-b25c-0d1894daaede ## 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
178 lines
5.0 KiB
Vue
178 lines
5.0 KiB
Vue
<script setup>
|
|
import { computed } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import Button from 'dashboard/components-next/button/Button.vue';
|
|
import Spinner from 'dashboard/components-next/spinner/Spinner.vue';
|
|
import AddDataDropdown from 'dashboard/components-next/AssignmentPolicy/components/AddDataDropdown.vue';
|
|
|
|
const props = defineProps({
|
|
inboxList: {
|
|
type: Array,
|
|
default: () => [],
|
|
},
|
|
isFetching: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
});
|
|
|
|
const emit = defineEmits(['delete', 'add', 'update']);
|
|
|
|
const inboxCapacityLimits = defineModel('inboxCapacityLimits', {
|
|
type: Array,
|
|
default: () => [],
|
|
});
|
|
|
|
const { t } = useI18n();
|
|
|
|
const BASE_KEY = 'ASSIGNMENT_POLICY.AGENT_CAPACITY_POLICY';
|
|
const DEFAULT_CONVERSATION_LIMIT = 10;
|
|
const MIN_CONVERSATION_LIMIT = 1;
|
|
const MAX_CONVERSATION_LIMIT = 100000;
|
|
|
|
const selectedInboxIds = computed(
|
|
() => new Set(inboxCapacityLimits.value.map(limit => limit.inboxId))
|
|
);
|
|
|
|
const availableInboxes = computed(() =>
|
|
props.inboxList.filter(
|
|
inbox => inbox && !selectedInboxIds.value.has(inbox.id)
|
|
)
|
|
);
|
|
|
|
const isLimitValid = limit => {
|
|
return (
|
|
limit.conversationLimit >= MIN_CONVERSATION_LIMIT &&
|
|
limit.conversationLimit <= MAX_CONVERSATION_LIMIT
|
|
);
|
|
};
|
|
|
|
const inboxMap = computed(
|
|
() => new Map(props.inboxList.map(inbox => [inbox.id, inbox]))
|
|
);
|
|
|
|
const handleAddInbox = inbox => {
|
|
emit('add', {
|
|
inboxId: inbox.id,
|
|
conversationLimit: DEFAULT_CONVERSATION_LIMIT,
|
|
});
|
|
};
|
|
|
|
const handleRemoveLimit = limitId => {
|
|
emit('delete', limitId);
|
|
};
|
|
|
|
const handleLimitChange = limit => {
|
|
if (isLimitValid(limit)) {
|
|
emit('update', limit);
|
|
}
|
|
};
|
|
|
|
const getInboxName = inboxId => {
|
|
return inboxMap.value.get(inboxId)?.name || '';
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div class="py-4 flex-col flex gap-3">
|
|
<div class="flex items-center w-full gap-8 justify-between pt-1 pb-3">
|
|
<label class="text-sm font-medium text-n-slate-12">
|
|
{{ t(`${BASE_KEY}.FORM.INBOX_CAPACITY_LIMIT.LABEL`) }}
|
|
</label>
|
|
|
|
<AddDataDropdown
|
|
:label="t(`${BASE_KEY}.FORM.INBOX_CAPACITY_LIMIT.ADD_BUTTON`)"
|
|
:search-placeholder="
|
|
t(`${BASE_KEY}.FORM.INBOX_CAPACITY_LIMIT.FIELD.SELECT_INBOX`)
|
|
"
|
|
:items="availableInboxes"
|
|
@add="handleAddInbox"
|
|
/>
|
|
</div>
|
|
|
|
<div
|
|
v-if="isFetching"
|
|
class="flex items-center justify-center py-3 w-full text-n-slate-11"
|
|
>
|
|
<Spinner />
|
|
</div>
|
|
|
|
<div
|
|
v-else-if="!inboxCapacityLimits.length"
|
|
class="custom-dashed-border flex items-center justify-center py-6 w-full"
|
|
>
|
|
<span class="text-sm text-n-slate-11">
|
|
{{ t(`${BASE_KEY}.FORM.INBOX_CAPACITY_LIMIT.EMPTY_STATE`) }}
|
|
</span>
|
|
</div>
|
|
|
|
<div v-else class="flex-col flex gap-3">
|
|
<div
|
|
v-for="(limit, index) in inboxCapacityLimits"
|
|
:key="limit.id || `temp-${index}`"
|
|
class="flex flex-col xs:flex-row items-stretch gap-3"
|
|
>
|
|
<div
|
|
class="flex items-center rounded-lg outline-1 outline cursor-not-allowed text-n-slate-11 outline-n-weak py-2.5 px-3 text-sm w-full min-w-0"
|
|
:title="getInboxName(limit.inboxId)"
|
|
>
|
|
<span class="truncate min-w-0">
|
|
{{ getInboxName(limit.inboxId) }}
|
|
</span>
|
|
</div>
|
|
|
|
<div class="flex items-center gap-3 w-full xs:w-auto">
|
|
<div
|
|
class="py-2.5 px-3 rounded-lg gap-2 outline outline-1 flex-1 xs:flex-shrink-0 flex items-center min-w-0"
|
|
:class="[
|
|
!isLimitValid(limit) ? 'outline-n-ruby-8' : 'outline-n-weak',
|
|
]"
|
|
>
|
|
<label
|
|
class="text-sm text-n-slate-12 ltr:pr-2 rtl:pl-2 truncate min-w-0 flex-shrink"
|
|
:title="
|
|
t(
|
|
`${BASE_KEY}.FORM.INBOX_CAPACITY_LIMIT.FIELD.MAX_CONVERSATIONS`
|
|
)
|
|
"
|
|
>
|
|
{{
|
|
t(
|
|
`${BASE_KEY}.FORM.INBOX_CAPACITY_LIMIT.FIELD.MAX_CONVERSATIONS`
|
|
)
|
|
}}
|
|
</label>
|
|
|
|
<div class="h-5 w-px bg-n-weak" />
|
|
|
|
<input
|
|
v-model.number="limit.conversationLimit"
|
|
type="number"
|
|
:min="MIN_CONVERSATION_LIMIT"
|
|
:max="MAX_CONVERSATION_LIMIT"
|
|
class="reset-base bg-transparent focus:outline-none min-w-16 w-24 text-sm flex-shrink-0"
|
|
:class="[
|
|
!isLimitValid(limit)
|
|
? 'placeholder:text-n-ruby-9 !text-n-ruby-9'
|
|
: 'placeholder:text-n-slate-10 text-n-slate-12',
|
|
]"
|
|
:placeholder="
|
|
t(`${BASE_KEY}.FORM.INBOX_CAPACITY_LIMIT.FIELD.SET_LIMIT`)
|
|
"
|
|
@blur="handleLimitChange(limit)"
|
|
/>
|
|
</div>
|
|
|
|
<Button
|
|
type="button"
|
|
slate
|
|
icon="i-lucide-trash"
|
|
class="flex-shrink-0"
|
|
@click="handleRemoveLimit(limit.id)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|