mirror of
https://github.com/directus/directus.git
synced 2026-02-17 17:02:11 -05:00
Add new advanced filters experience (#8570)
* Remove advanced filter sidebar detail So long, and thanks for all the fish. * Remove filter conversion logic * Start replacing/removing old skool filters * Add inline mode for usages in search bar * Make filter work in header bar * Emit empty string as null in filter * Move shared filter types to shared * Upgrade use-items * Fix manual sort on tabular * Cleanup styling in search bar usage * Tweak styling * Fix filtering issues * Update cards * Remove activeFilterCount from tabular * Update maps to work with new filters * Update calendar to new filter/sort structure * Fix activity module nav/search * Fix no-results message * Update file library filtering * Finalize user search * Allow filtering in drawer-collection * Handle cancelled responses semi-gracefully * Add loading start state timeout * Replace sort type in api * Last commit before redoing a bunch * Finish new visual style * Remove unused rounded prop from v-menu * Tweak sizing * Enough size tweaking for now * Count all filter operators instead of top * Fix archive casting * Fix api build * Add merge filters util * Split filter in user vs system * Fix export sidebar detail * Show field label on permissions configuration * Add migration for filter/sort * Use filters in insights
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<v-list large>
|
||||
<v-list-item clickable :active="!activeFilter" @click="clearNavFilter">
|
||||
<v-list-item clickable :active="!filterField" @click="clearNavFilter">
|
||||
<v-list-item-icon>
|
||||
<v-icon name="access_time" />
|
||||
</v-list-item-icon>
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
<v-list-item
|
||||
clickable
|
||||
:active="activeFilter && activeFilter.field === 'user' && activeFilter.value === currentUserID"
|
||||
:active="filterField === 'user' && filterValue === currentUserID"
|
||||
@click="setNavFilter('user', currentUserID)"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
<v-list-item
|
||||
clickable
|
||||
:active="activeFilter && activeFilter.field === 'action' && activeFilter.value === 'create'"
|
||||
:active="filterField === 'action' && filterValue === 'create'"
|
||||
@click="setNavFilter('action', 'create')"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
<v-list-item
|
||||
clickable
|
||||
:active="activeFilter && activeFilter.field === 'action' && activeFilter.value === 'update'"
|
||||
:active="filterField === 'action' && filterValue === 'update'"
|
||||
@click="setNavFilter('action', 'update')"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
<v-list-item
|
||||
clickable
|
||||
:active="activeFilter && activeFilter.field === 'action' && activeFilter.value === 'delete'"
|
||||
:active="filterField === 'action' && filterValue === 'delete'"
|
||||
@click="setNavFilter('action', 'delete')"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
<v-list-item
|
||||
clickable
|
||||
:active="activeFilter && activeFilter.field === 'action' && activeFilter.value === 'comment'"
|
||||
:active="filterField === 'action' && filterValue === 'comment'"
|
||||
@click="setNavFilter('action', 'comment')"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
@@ -78,7 +78,7 @@
|
||||
|
||||
<v-list-item
|
||||
clickable
|
||||
:active="activeFilter && activeFilter.field === 'action' && activeFilter.value === 'login'"
|
||||
:active="filterField === 'action' && filterValue === 'login'"
|
||||
@click="setNavFilter('action', 'login')"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
@@ -95,51 +95,37 @@
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { defineComponent, computed, PropType } from 'vue';
|
||||
import { useUserStore } from '@/stores/user';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { Filter } from '@directus/shared/types';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
filters: {
|
||||
type: Array as PropType<Filter[]>,
|
||||
required: true,
|
||||
filter: {
|
||||
type: Object as PropType<Filter>,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
emits: ['update:filters'],
|
||||
emits: ['update:filter'],
|
||||
setup(props, { emit }) {
|
||||
const { t } = useI18n();
|
||||
|
||||
const userStore = useUserStore();
|
||||
const currentUserID = computed(() => userStore.currentUser?.id);
|
||||
|
||||
const activeFilter = computed(() => {
|
||||
return props.filters.find((filter) => filter.locked === true);
|
||||
});
|
||||
const filterField = computed(() => Object.keys(props.filter ?? {})[0] ?? null);
|
||||
const filterValue = computed(() => Object.values(props.filter ?? {})[0]?._eq ?? null);
|
||||
|
||||
return { t, currentUserID, setNavFilter, clearNavFilter, activeFilter };
|
||||
return { t, currentUserID, setNavFilter, clearNavFilter, filterField, filterValue };
|
||||
|
||||
function setNavFilter(key: string, value: any) {
|
||||
emit('update:filters', [
|
||||
...props.filters.filter((filter) => {
|
||||
return filter.locked === false;
|
||||
}),
|
||||
{
|
||||
key: nanoid(),
|
||||
locked: true,
|
||||
field: key,
|
||||
operator: 'eq',
|
||||
value: value,
|
||||
emit('update:filter', {
|
||||
[key]: {
|
||||
_eq: value,
|
||||
},
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
function clearNavFilter() {
|
||||
emit(
|
||||
'update:filters',
|
||||
props.filters.filter((filter) => {
|
||||
return filter.locked === false;
|
||||
})
|
||||
);
|
||||
emit('update:filter', null);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
v-slot="{ layoutState }"
|
||||
v-model:layout-options="layoutOptions"
|
||||
v-model:layout-query="layoutQuery"
|
||||
v-model:filters="filters"
|
||||
v-model:search-query="searchQuery"
|
||||
:filter="mergeFilters"
|
||||
:filter-user="filter"
|
||||
:filter-system="roleFilter"
|
||||
:search="search"
|
||||
collection="directus_activity"
|
||||
>
|
||||
<private-view :title="t('activity_feed')">
|
||||
@@ -20,14 +22,26 @@
|
||||
</template>
|
||||
|
||||
<template #actions>
|
||||
<search-input v-model="searchQuery" />
|
||||
<search-input v-model="search" v-model:filter="filter" collection="directus_activity" />
|
||||
</template>
|
||||
|
||||
<template #navigation>
|
||||
<activity-navigation v-model:filters="filters" />
|
||||
<activity-navigation v-model:filter="roleFilter" />
|
||||
</template>
|
||||
|
||||
<component :is="`layout-${layout}`" v-bind="layoutState" class="layout" />
|
||||
<component :is="`layout-${layout}`" v-bind="layoutState" class="layout">
|
||||
<template #no-results>
|
||||
<v-info :title="t('no_results')" icon="search" center>
|
||||
{{ t('no_results_copy') }}
|
||||
</v-info>
|
||||
</template>
|
||||
|
||||
<template #no-items>
|
||||
<v-info :title="t('item_count', 0)" icon="access_time" center>
|
||||
{{ t('no_items_copy') }}
|
||||
</v-info>
|
||||
</template>
|
||||
</component>
|
||||
|
||||
<router-view name="detail" :primary-key="primaryKey" />
|
||||
|
||||
@@ -50,13 +64,14 @@ import { defineComponent, computed, ref } from 'vue';
|
||||
import ActivityNavigation from '../components/navigation.vue';
|
||||
import usePreset from '@/composables/use-preset';
|
||||
import { useLayout } from '@/composables/use-layout';
|
||||
import FilterSidebarDetail from '@/views/private/components/filter-sidebar-detail';
|
||||
import LayoutSidebarDetail from '@/views/private/components/layout-sidebar-detail';
|
||||
import SearchInput from '@/views/private/components/search-input';
|
||||
import { Filter } from '@directus/shared/types';
|
||||
import { mergeFilters } from '@directus/shared/utils';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ActivityCollection',
|
||||
components: { ActivityNavigation, FilterSidebarDetail, LayoutSidebarDetail, SearchInput },
|
||||
components: { ActivityNavigation, LayoutSidebarDetail, SearchInput },
|
||||
props: {
|
||||
primaryKey: {
|
||||
type: String,
|
||||
@@ -66,12 +81,25 @@ export default defineComponent({
|
||||
setup() {
|
||||
const { t } = useI18n();
|
||||
|
||||
const { layout, layoutOptions, layoutQuery, filters, searchQuery } = usePreset(ref('directus_activity'));
|
||||
const { layout, layoutOptions, layoutQuery, filter, search } = usePreset(ref('directus_activity'));
|
||||
const { breadcrumb } = useBreadcrumb();
|
||||
|
||||
const { layoutWrapper } = useLayout(layout);
|
||||
|
||||
return { t, breadcrumb, layout, layoutWrapper, layoutOptions, layoutQuery, searchQuery, filters };
|
||||
const roleFilter = ref<Filter | null>(null);
|
||||
|
||||
return {
|
||||
t,
|
||||
breadcrumb,
|
||||
layout,
|
||||
layoutWrapper,
|
||||
layoutOptions,
|
||||
layoutQuery,
|
||||
search,
|
||||
filter,
|
||||
roleFilter,
|
||||
mergeFilters,
|
||||
};
|
||||
|
||||
function useBreadcrumb() {
|
||||
const breadcrumb = computed(() => {
|
||||
|
||||
Reference in New Issue
Block a user