From 3ce9c6d7de6e63c8c96b6f8102aa63285cefc25c Mon Sep 17 00:00:00 2001 From: tdgao Date: Fri, 14 Aug 2026 12:55:45 -0600 Subject: [PATCH] feat: hook up excludes modpack --- .../search/SearchDependsOnFilter.vue | 36 +++++++------ .../components/search/SearchFilterControl.vue | 50 ++++++++++++++++--- packages/ui/src/locales/en-US/index.json | 3 ++ 3 files changed, 64 insertions(+), 25 deletions(-) diff --git a/packages/ui/src/components/search/SearchDependsOnFilter.vue b/packages/ui/src/components/search/SearchDependsOnFilter.vue index 20e75ea2b6..5e0e145fed 100644 --- a/packages/ui/src/components/search/SearchDependsOnFilter.vue +++ b/packages/ui/src/components/search/SearchDependsOnFilter.vue @@ -186,14 +186,14 @@ const dependencyProjectIds = computed(() => [ ), ]) const pendingProjectId = ref() -const excludedProjectIds = ref(new Set()) - -watch(dependencyProjectIds, (projectIds) => { - const selectedProjectIds = new Set(projectIds) - excludedProjectIds.value = new Set( - [...excludedProjectIds.value].filter((projectId) => selectedProjectIds.has(projectId)), - ) -}) +const excludedProjectIds = computed( + () => + new Set( + selectedFilters.value + .filter((filter) => filter.type === FILTER_TYPE_ID && filter.negative) + .map((filter) => parseDependencyProjectFilterOption(filter.option).projectId), + ), +) const { data: dependentProjects } = useQuery({ queryKey: computed(() => [ @@ -226,7 +226,9 @@ const selectedProjectId = computed(() => ? parseDependencyProjectFilterOption(selectedDependencyFilter.value.option).projectId : undefined, ) -const showSelectedProject = computed(() => Boolean(selectedProjectId.value && selectedProject.value)) +const showSelectedProject = computed(() => + Boolean(selectedProjectId.value && selectedProject.value), +) const dependencyTypes = computed(() => selectedDependencyFilter.value @@ -294,19 +296,15 @@ function removeIncludedProject(projectId: string) { filter.type !== FILTER_TYPE_ID || parseDependencyProjectFilterOption(filter.option).projectId !== projectId, ) - const nextExcludedProjectIds = new Set(excludedProjectIds.value) - nextExcludedProjectIds.delete(projectId) - excludedProjectIds.value = nextExcludedProjectIds } function toggleProjectExcluded(projectId: string) { - const nextExcludedProjectIds = new Set(excludedProjectIds.value) - if (nextExcludedProjectIds.has(projectId)) { - nextExcludedProjectIds.delete(projectId) - } else { - nextExcludedProjectIds.add(projectId) - } - excludedProjectIds.value = nextExcludedProjectIds + selectedFilters.value = selectedFilters.value.map((filter) => + filter.type === FILTER_TYPE_ID && + parseDependencyProjectFilterOption(filter.option).projectId === projectId + ? { ...filter, negative: !filter.negative } + : filter, + ) } function resetDraftDependencyTypes() { diff --git a/packages/ui/src/components/search/SearchFilterControl.vue b/packages/ui/src/components/search/SearchFilterControl.vue index 8c3329ad66..9d5b6c0e84 100644 --- a/packages/ui/src/components/search/SearchFilterControl.vue +++ b/packages/ui/src/components/search/SearchFilterControl.vue @@ -12,9 +12,16 @@ {{ formatMessage(includedProjectsMessage, { - projects: selectedIncludedProjectItems - .map((item) => dependentProjectNames.get(item.option) ?? item.option) - .join(', '), + projects: formatProjectNames(selectedIncludedProjectItems), + }) + }} + + + + + {{ + formatMessage(excludedProjectsMessage, { + projects: formatProjectNames(selectedExcludedProjectItems), }) }} @@ -86,6 +93,10 @@ const includedProjectsMessage = defineMessage({ id: 'search.filter.included_projects', defaultMessage: 'Includes: {projects}', }) +const excludedProjectsMessage = defineMessage({ + id: 'search.filter.excluded_projects', + defaultMessage: 'Excludes: {projects}', +}) type Item = { type: string @@ -172,7 +183,16 @@ const items: ComputedRef = computed(() => { const selectedItems = computed(() => items.value.filter((x) => !x.provided)) const selectedIncludedProjectItems = computed(() => props.projectType === 'modpack' - ? selectedItems.value.filter((item) => item.type === 'compatible_dependency_project_ids') + ? selectedItems.value.filter( + (item) => item.type === 'compatible_dependency_project_ids' && !item.negative, + ) + : [], +) +const selectedExcludedProjectItems = computed(() => + props.projectType === 'modpack' + ? selectedItems.value.filter( + (item) => item.type === 'compatible_dependency_project_ids' && item.negative, + ) : [], ) const otherSelectedItems = computed(() => @@ -181,9 +201,21 @@ const otherSelectedItems = computed(() => : selectedItems.value, ) const selectedTagCount = computed( - () => otherSelectedItems.value.length + (selectedIncludedProjectItems.value.length > 0 ? 1 : 0), + () => + otherSelectedItems.value.length + + (selectedIncludedProjectItems.value.length > 0 ? 1 : 0) + + (selectedExcludedProjectItems.value.length > 0 ? 1 : 0), ) +function formatProjectNames(items: Item[]) { + return items + .map((item) => { + const projectId = parseDependencyProjectFilterOption(item.option).projectId + return dependentProjectNames.value.get(projectId) ?? projectId + }) + .join(', ') +} + function removeFilter(filter: Item) { selectedFilters.value = selectedFilters.value.filter( (x) => x.type !== filter.type || x.option !== filter.option, @@ -192,7 +224,13 @@ function removeFilter(filter: Item) { function removeIncludedProjectFilters() { selectedFilters.value = selectedFilters.value.filter( - (filter) => filter.type !== 'compatible_dependency_project_ids', + (filter) => filter.type !== 'compatible_dependency_project_ids' || filter.negative, + ) +} + +function removeExcludedProjectFilters() { + selectedFilters.value = selectedFilters.value.filter( + (filter) => filter.type !== 'compatible_dependency_project_ids' || !filter.negative, ) } diff --git a/packages/ui/src/locales/en-US/index.json b/packages/ui/src/locales/en-US/index.json index 2887d65d68..e26579cecf 100644 --- a/packages/ui/src/locales/en-US/index.json +++ b/packages/ui/src/locales/en-US/index.json @@ -4049,6 +4049,9 @@ "search.filter.dependent_project.search_placeholder": { "defaultMessage": "Search for a project..." }, + "search.filter.excluded_projects": { + "defaultMessage": "Excludes: {projects}" + }, "search.filter.included_content.exclude": { "defaultMessage": "Exclude" },