feat: implement dependent projects + members breakdown/filter (#6395)

* feat: implement dependent project breakdown

* implement dependent project type filter

* feat: show dependent on column if there are multiple projects selected

* feat: different tooltip for when both project version and dependent breakdowns are on

* feat: implement dependents query filter

* feat: add project icon to query filter

* fix: dont show dependent on column when project breakdown is selected

* feat: add org icon

* remove: dependent on project column and project version project column

* refactor: pnpm prepr

* fix: all project selection gets unselected when reload page

* pnpm prepr

* fix: still using old search formatter

* feat: implement projects in table click to link to project page

* feat: handle analytics values that dont have a dependent project as a "No dependent" row

* pnpm prepr

* feat: remove org icon for dependents projects and change unknown label

* feat: do not include unknown rows for showing top 8

* feat: separate out no dependents based on download reason

* fix: use compatible dependencies for query filter options

* feat: implement members breakdown/filter frontend (#6470)

* feat: add link to user in table

* fix: do not allow breakdowns to occur without shared stats

* pnpm prepr

* fix: i18n and passing params for formatter
This commit is contained in:
Truman Gao
2026-06-22 18:09:00 +00:00
committed by GitHub
parent 23edb2351d
commit 1f8b1bd2bb
46 changed files with 1710 additions and 254 deletions
@@ -414,9 +414,11 @@ export type DropdownFilterBarCategory = {
options: DropdownFilterBarItem[]
syntheticOptions?: DropdownFilterBarOption[]
searchable?: boolean
disableLocalOptionsFilter?: boolean
searchPlaceholder?: string
emptyOptionsLabel?: string
emptySearchLabel?: string
onSearchQueryChange?: (query: string) => void
submenuClass?: string
previewDropdownWidth?: string | number
previewDropdownMinWidth?: string | number
@@ -618,7 +620,7 @@ const filteredActiveCategoryOptions = computed(() => {
return []
}
if (!activeCategory.value.searchable) {
if (!activeCategory.value.searchable || activeCategory.value.disableLocalOptionsFilter) {
return activeCategory.value.options
}
@@ -1808,6 +1810,7 @@ watch(isAddMenuOpen, (isOpen) => {
})
watch(categorySearchQuery, () => {
activeCategory.value?.onSearchQueryChange?.(categorySearchQuery.value)
resetActiveCategoryOptionsScrollState()
initializeActiveCategoryOptionsOverlayScrollbars()
scheduleSubmenuPositionUpdate()
@@ -1816,6 +1819,7 @@ watch(categorySearchQuery, () => {
watch(activeCategoryKey, (categoryKey) => {
resetActiveCategoryOptionsScrollState()
if (categoryKey) {
activeCategory.value?.onSearchQueryChange?.(categorySearchQuery.value)
initializeActiveCategoryOptionsOverlayScrollbars()
} else {
destroyActiveCategoryOptionsOverlayScrollbars()
+1 -1
View File
@@ -44,7 +44,7 @@
<span
v-if="column.label || column.enableSorting"
class="inline-flex min-w-0 max-w-full items-center gap-1 font-semibold"
:class="`${sortColumn === column.key ? 'text-contrast' : ''}`"
:class="`${sortColumn === column.key ? 'text-contrast -mr-1' : ''}`"
>
<span class="min-w-0 truncate">{{ column.label ?? '' }}</span>
<template v-if="column.enableSorting">
+29
View File
@@ -823,3 +823,32 @@ function getParamValuesAsArray(x: LocationQueryValue | LocationQueryValue[]): st
return x.filter((x) => x !== null)
}
}
export function buildDependentsSearchFilters(
projectTypes: readonly ProjectType[],
dependencyProjectIds: readonly string[],
): string {
const parts: string[] = []
const mappedProjectTypes = projectTypes.map(mapProjectTypeToSearch)
if (mappedProjectTypes.length === 1) {
parts.push(`project_types = ${formatSearchFilterValue(mappedProjectTypes[0])}`)
} else if (mappedProjectTypes.length > 1) {
const quoted = mappedProjectTypes.map(formatSearchFilterValue).join(', ')
parts.push(`project_types IN [${quoted}]`)
}
const normalizedProjectIds = Array.from(
new Set(dependencyProjectIds.map((projectId) => projectId.trim()).filter(Boolean)),
)
if (normalizedProjectIds.length === 1) {
parts.push(
`compatible_dependency_project_ids = ${formatSearchFilterValue(normalizedProjectIds[0])}`,
)
} else if (normalizedProjectIds.length > 1) {
const quoted = normalizedProjectIds.map(formatSearchFilterValue).join(', ')
parts.push(`compatible_dependency_project_ids IN [${quoted}]`)
}
return parts.join(' AND ')
}