diff --git a/packages/ui/src/layouts/shared/content-tab/composables/content-filtering.ts b/packages/ui/src/layouts/shared/content-tab/composables/content-filtering.ts index 0e10446e54..5c534eb8e0 100644 --- a/packages/ui/src/layouts/shared/content-tab/composables/content-filtering.ts +++ b/packages/ui/src/layouts/shared/content-tab/composables/content-filtering.ts @@ -2,7 +2,7 @@ import { useSessionStorage } from '@vueuse/core' import type { Ref } from 'vue' import { computed, ref, watch } from 'vue' -import { useVIntl } from '#ui/composables/i18n' +import { defineMessages, useVIntl } from '#ui/composables/i18n' import { commonProjectTypeCategoryMessages, normalizeProjectType } from '#ui/utils/common-messages' import type { ClientWarningType, ContentItem } from '../types' @@ -33,6 +33,25 @@ export interface ContentFilterConfig { persistKey?: string } +const messages = defineMessages({ + updates: { + id: 'content.filter.updates', + defaultMessage: 'Updates', + }, + warnings: { + id: 'content.filter.warnings', + defaultMessage: 'Warnings', + }, + enabled: { + id: 'content.filter.enabled', + defaultMessage: 'Enabled', + }, + disabled: { + id: 'content.filter.disabled', + defaultMessage: 'Disabled', + }, +}) + export function useContentFilters(items: Ref, config?: ContentFilterConfig) { const { formatMessage } = useVIntl() @@ -40,6 +59,17 @@ export function useContentFilters(items: Ref, config?: ContentFil ? useSessionStorage(`content-filters:${config.persistKey}`, []) : ref([]) + const availableStatusFilters = computed>(() => { + const filters: Array<'enabled' | 'disabled'> = [] + if (items.value.some((m) => m.enabled)) { + filters.push('enabled') + } + if (items.value.some((m) => !m.enabled)) { + filters.push('disabled') + } + return filters + }) + const filterOptions = computed(() => { const options: ContentFilterOption[] = [] @@ -59,27 +89,48 @@ export function useContentFilters(items: Ref, config?: ContentFil } if (config?.showUpdateFilter && items.value.some((m) => m.has_update)) { - options.push({ id: 'updates', label: 'Updates' }) + options.push({ id: 'updates', label: formatMessage(messages.updates) }) } if (config?.showWarningsFilter && items.value.some((m) => getClientWarningType(m) !== null)) { - options.push({ id: 'warnings', label: 'Warnings' }) + options.push({ id: 'warnings', label: formatMessage(messages.warnings) }) } - if (items.value.some((m) => !m.enabled)) { - options.push({ id: 'disabled', label: 'Disabled' }) + for (const status of availableStatusFilters.value) { + options.push({ + id: status, + label: formatMessage(status === 'enabled' ? messages.enabled : messages.disabled), + }) } return options }) - watch(filterOptions, () => { - selectedFilters.value = selectedFilters.value.filter((f) => - filterOptions.value.some((opt) => opt.id === f), - ) - }) + watch( + filterOptions, + () => { + selectedFilters.value = selectedFilters.value.filter((f) => + filterOptions.value.some((opt) => opt.id === f), + ) + }, + { immediate: true }, + ) function toggleFilter(filterId: string) { + if (filterId === 'enabled' || filterId === 'disabled') { + const index = selectedFilters.value.indexOf(filterId) + const otherStatusFilter = filterId === 'enabled' ? 'disabled' : 'enabled' + if (index === -1) { + selectedFilters.value = [ + ...selectedFilters.value.filter((filter) => filter !== otherStatusFilter), + filterId, + ] + } else { + selectedFilters.value.splice(index, 1) + } + return + } + const index = selectedFilters.value.indexOf(filterId) if (index === -1) { selectedFilters.value.push(filterId) @@ -91,7 +142,7 @@ export function useContentFilters(items: Ref, config?: ContentFil function applyFilters(source: ContentItem[]): ContentItem[] { if (selectedFilters.value.length === 0) return source - const attributeFilters = new Set(['updates', 'disabled', 'warnings']) + const attributeFilters = new Set(['updates', 'enabled', 'disabled', 'warnings']) const typeFilters = selectedFilters.value.filter((f) => !attributeFilters.has(f)) const activeAttributes = selectedFilters.value.filter((f) => attributeFilters.has(f)) @@ -105,6 +156,7 @@ export function useContentFilters(items: Ref, config?: ContentFil for (const filter of activeAttributes) { if (filter === 'updates' && !item.has_update) return false + if (filter === 'enabled' && !item.enabled) return false if (filter === 'disabled' && item.enabled) return false if (filter === 'warnings' && getClientWarningType(item) === null) return false } diff --git a/packages/ui/src/locales/en-US/index.json b/packages/ui/src/locales/en-US/index.json index 2083686ccd..60397180ab 100644 --- a/packages/ui/src/locales/en-US/index.json +++ b/packages/ui/src/locales/en-US/index.json @@ -398,6 +398,18 @@ "content.diff-modal.updated-count": { "defaultMessage": "{count} updated" }, + "content.filter.disabled": { + "defaultMessage": "Disabled" + }, + "content.filter.enabled": { + "defaultMessage": "Enabled" + }, + "content.filter.updates": { + "defaultMessage": "Updates" + }, + "content.filter.warnings": { + "defaultMessage": "Warnings" + }, "content.inline-backup.backing-up": { "defaultMessage": "Creating backup..." },