feat: Add assistant filter support to documents page (#10697)

This PR introduces support for an assistant filter on the documents page.

- Moved the existing assistant filter functionality to a standalone, reusable component.
- Updated the documents page and responses page to use the component
This commit is contained in:
Pranav
2025-01-15 21:41:07 -08:00
committed by GitHub
parent 54d629d171
commit 793b1f85f6
4 changed files with 99 additions and 51 deletions

View File

@@ -6,11 +6,12 @@ class CaptainDocument extends ApiClient {
super('captain/documents', { accountScoped: true });
}
get({ page = 1, searchKey } = {}) {
get({ page = 1, searchKey, assistantId } = {}) {
return axios.get(this.url, {
params: {
page,
searchKey,
assistant_id: assistantId,
},
});
}

View File

@@ -0,0 +1,68 @@
<script setup>
import { computed, ref } from 'vue';
import { useMapGetter } from 'dashboard/composables/store';
import { useI18n } from 'vue-i18n';
import { OnClickOutside } from '@vueuse/components';
import Button from 'dashboard/components-next/button/Button.vue';
import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.vue';
const props = defineProps({
assistantId: {
type: [String, Number],
required: true,
},
});
const emit = defineEmits(['update']);
const { t } = useI18n();
const isFilterOpen = ref(false);
const assistants = useMapGetter('captainAssistants/getRecords');
const assistantOptions = computed(() => [
{
label: t(`CAPTAIN.RESPONSES.FILTER.ALL_ASSISTANTS`),
value: 'all',
action: 'filter',
},
...assistants.value.map(assistant => ({
value: assistant.id,
label: assistant.name,
action: 'filter',
})),
]);
const selectedAssistantLabel = computed(() => {
const assistant = assistantOptions.value.find(
option => option.value === props.assistantId
);
return t('CAPTAIN.RESPONSES.FILTER.ASSISTANT', {
selected: assistant ? assistant.label : '',
});
});
const handleAssistantFilterChange = ({ value }) => {
isFilterOpen.value = false;
emit('update', value);
};
</script>
<template>
<OnClickOutside @trigger="isFilterOpen = false">
<Button
:label="selectedAssistantLabel"
icon="i-lucide-chevron-down"
size="sm"
color="slate"
trailing-icon
class="max-w-48"
@click="isFilterOpen = !isFilterOpen"
/>
<DropdownMenu
v-if="isFilterOpen"
:menu-items="assistantOptions"
class="mt-2"
@action="handleAssistantFilterChange"
/>
</OnClickOutside>
</template>

View File

@@ -7,7 +7,8 @@ import DocumentCard from 'dashboard/components-next/captain/assistant/DocumentCa
import PageLayout from 'dashboard/components-next/captain/PageLayout.vue';
import Spinner from 'dashboard/components-next/spinner/Spinner.vue';
import RelatedResponses from 'dashboard/components-next/captain/pageComponents/document/RelatedResponses.vue';
import CreateDocumentDialog from '../../../../components-next/captain/pageComponents/document/CreateDocumentDialog.vue';
import CreateDocumentDialog from 'dashboard/components-next/captain/pageComponents/document/CreateDocumentDialog.vue';
import AssistantSelector from 'dashboard/components-next/captain/pageComponents/AssistantSelector.vue';
const store = useStore();
const uiFlags = useMapGetter('captainDocuments/getUIFlags');
@@ -15,6 +16,7 @@ const documents = useMapGetter('captainDocuments/getRecords');
const assistants = useMapGetter('captainAssistants/getRecords');
const isFetching = computed(() => uiFlags.value.fetchingList);
const documentsMeta = useMapGetter('captainDocuments/getMeta');
const selectedAssistant = ref('all');
const selectedDocument = ref(null);
const deleteDocumentDialog = ref(null);
@@ -60,7 +62,17 @@ const handleAction = ({ action, id }) => {
};
const fetchDocuments = (page = 1) => {
store.dispatch('captainDocuments/get', { page });
const filterParams = { page };
if (selectedAssistant.value !== 'all') {
filterParams.assistantId = selectedAssistant.value;
}
store.dispatch('captainDocuments/get', filterParams);
};
const handleAssistantFilterChange = assistant => {
selectedAssistant.value = assistant;
fetchDocuments();
};
const onPageChange = page => fetchDocuments(page);
@@ -83,6 +95,12 @@ onMounted(() => {
@update:current-page="onPageChange"
@click="handleCreateDocument"
>
<div v-if="!isFetching" class="mb-4 -mt-3 flex gap-3">
<AssistantSelector
:assistant-id="selectedAssistant"
@update="handleAssistantFilterChange"
/>
</div>
<div
v-if="isFetching"
class="flex items-center justify-center py-10 text-n-slate-11"

View File

@@ -9,6 +9,7 @@ import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.v
import DeleteDialog from 'dashboard/components-next/captain/pageComponents/DeleteDialog.vue';
import PageLayout from 'dashboard/components-next/captain/PageLayout.vue';
import AssistantSelector from 'dashboard/components-next/captain/pageComponents/AssistantSelector.vue';
import ResponseCard from 'dashboard/components-next/captain/assistant/ResponseCard.vue';
import Spinner from 'dashboard/components-next/spinner/Spinner.vue';
import CreateResponseDialog from 'dashboard/components-next/captain/pageComponents/response/CreateResponseDialog.vue';
@@ -30,7 +31,6 @@ const { t } = useI18n();
const createDialog = ref(null);
const isStatusFilterOpen = ref(false);
const isAssistantFilterOpen = ref(false);
const statusOptions = computed(() =>
['all', 'pending', 'approved'].map(key => ({
@@ -49,29 +49,6 @@ const selectedStatusLabel = computed(() => {
});
});
const assistants = useMapGetter('captainAssistants/getRecords');
const assistantOptions = computed(() => [
{
label: t(`CAPTAIN.RESPONSES.FILTER.ALL_ASSISTANTS`),
value: 'all',
action: 'filter',
},
...assistants.value.map(assistant => ({
value: assistant.id,
label: assistant.name,
action: 'filter',
})),
]);
const selectedAssistantLabel = computed(() => {
const assistant = assistantOptions.value.find(
option => option.value === selectedAssistant.value
);
return t('CAPTAIN.RESPONSES.FILTER.ASSISTANT', {
selected: assistant ? assistant.label : '',
});
});
const handleDelete = () => {
deleteDialog.value.dialogRef.open();
};
@@ -122,14 +99,14 @@ const handleCreateClose = () => {
};
const fetchResponses = (page = 1) => {
const filterParams = {};
const filterParams = { page };
if (selectedStatus.value !== 'all') {
filterParams.status = selectedStatus.value;
}
if (selectedAssistant.value !== 'all') {
filterParams.assistantId = selectedAssistant.value;
}
store.dispatch('captainResponses/get', { page, ...filterParams });
store.dispatch('captainResponses/get', page);
};
const onPageChange = page => fetchResponses(page);
@@ -140,9 +117,8 @@ const handleStatusFilterChange = ({ value }) => {
fetchResponses();
};
const handleAssistantFilterChange = ({ value }) => {
selectedAssistant.value = value;
isAssistantFilterOpen.value = false;
const handleAssistantFilterChange = assistant => {
selectedAssistant.value = assistant;
fetchResponses();
};
@@ -181,25 +157,10 @@ onMounted(() => {
@action="handleStatusFilterChange"
/>
</OnClickOutside>
<OnClickOutside @trigger="isAssistantFilterOpen = false">
<Button
:label="selectedAssistantLabel"
icon="i-lucide-chevron-down"
size="sm"
color="slate"
trailing-icon
class="max-w-48"
@click="isAssistantFilterOpen = !isAssistantFilterOpen"
/>
<DropdownMenu
v-if="isAssistantFilterOpen"
:menu-items="assistantOptions"
class="mt-2"
@action="handleAssistantFilterChange"
/>
</OnClickOutside>
<AssistantSelector
:assistant-id="selectedAssistant"
@update="handleAssistantFilterChange"
/>
</div>
<div
v-if="isFetching"