diff --git a/app/javascript/dashboard/components-next/dropdown-menu/DropdownMenu.vue b/app/javascript/dashboard/components-next/dropdown-menu/DropdownMenu.vue index 111b9868e..6276dfec6 100644 --- a/app/javascript/dashboard/components-next/dropdown-menu/DropdownMenu.vue +++ b/app/javascript/dashboard/components-next/dropdown-menu/DropdownMenu.vue @@ -8,11 +8,15 @@ import Avatar from 'dashboard/components-next/avatar/Avatar.vue'; const props = defineProps({ menuItems: { type: Array, - required: true, + default: () => [], validator: value => { return value.every(item => item.action && item.value && item.label); }, }, + menuSections: { + type: Array, + default: () => [], + }, thumbnailSize: { type: Number, default: 20, @@ -42,19 +46,62 @@ const { t } = useI18n(); const searchInput = ref(null); const searchQuery = ref(''); -const filteredMenuItems = computed(() => { - if (!searchQuery.value) return props.menuItems; +const hasSections = computed(() => props.menuSections.length > 0); - return props.menuItems.filter(item => +const flattenedMenuItems = computed(() => { + if (!hasSections.value) { + return props.menuItems; + } + + return props.menuSections.flatMap(section => section.items || []); +}); + +const filteredMenuItems = computed(() => { + if (!searchQuery.value) return flattenedMenuItems.value; + + return flattenedMenuItems.value.filter(item => item.label.toLowerCase().includes(searchQuery.value.toLowerCase()) ); }); +const filteredMenuSections = computed(() => { + if (!hasSections.value) { + return []; + } + + if (!searchQuery.value) { + return props.menuSections; + } + + const query = searchQuery.value.toLowerCase(); + + return props.menuSections + .map(section => { + const filteredItems = (section.items || []).filter(item => + item.label.toLowerCase().includes(query) + ); + + return { + ...section, + items: filteredItems, + }; + }) + .filter(section => section.items.length > 0); +}); + const handleAction = item => { const { action, value, ...rest } = item; emit('action', { action, value, ...rest }); }; +const shouldShowEmptyState = computed(() => { + if (hasSections.value) { + return filteredMenuSections.value.length === 0; + } + + return filteredMenuItems.value.length === 0; +}); + onMounted(() => { if (searchInput.value && props.showSearch) { searchInput.value.focus(); @@ -64,54 +111,122 @@ onMounted(() => {