mirror of
https://github.com/modrinth/code.git
synced 2026-08-27 18:14:49 +00:00
fix: servers misc fixes (#5475)
* fix: tags in project settings to have icons and ordered correctly * fix copy in project list layout settings * fix tag item in header navigation * adjust ping ranges * add handle click tag * fix: dont show offline in project page for draft status * move tags above creators in app * preload server project page on load and optimize queries * add server project card to organization page * fix minecraft_java_server label * pnpm prepr * have user option in project create modal be circle * feat: implement better mobile project page view * disable summary line clamp for servers * fix: unlink instance doesnt update instance * increase icon upload size * small fix on button size * improve how server ping info loads * remove unnecessary pings for instance page * fix order of computing dependency diff * remove linked_project_id from world, use name+address to match for managed world instead * pnpm prepr * hide duplicate worlds with same domain name in worlds list * add install content warning for server instance * increase summary max width * add handling for server projects for bulk editing links * implement include user unlisted projects in published modpack select * pnpm prepr * filter to only user unlisted status * add bad link warnings * fix modpack tags appearing in server * cargo fmt
This commit is contained in:
@@ -16,7 +16,8 @@
|
||||
<script lang="ts" setup>
|
||||
import { PackageIcon } from '@modrinth/assets'
|
||||
import { useDebounceFn } from '@vueuse/core'
|
||||
import { defineAsyncComponent, h, ref, watch } from 'vue'
|
||||
import Fuse from 'fuse.js'
|
||||
import { defineAsyncComponent, h, markRaw, ref, watch } from 'vue'
|
||||
|
||||
import { injectModrinthClient, injectNotificationManager } from '../../providers'
|
||||
import type { ComboboxOption } from '../base/Combobox.vue'
|
||||
@@ -57,6 +58,10 @@ const props = withDefaults(
|
||||
limit?: number
|
||||
/** Project IDs to exclude from results */
|
||||
excludeProjectIds?: string[]
|
||||
/** Include the user's own projects (including unlisted) in results via Fuse search */
|
||||
includeUserUnlistedProjects?: boolean
|
||||
/** User ID or username required when includeUserUnlistedProjects is true */
|
||||
userId?: string
|
||||
}>(),
|
||||
{
|
||||
placeholder: 'Select project',
|
||||
@@ -78,22 +83,67 @@ const searchResultsCache = ref<Map<string, SearchHit>>(new Map())
|
||||
|
||||
const { labrinth } = injectModrinthClient()
|
||||
|
||||
const userProjectHits = ref<SearchHit[]>([])
|
||||
const userProjectsFuse = ref<Fuse<SearchHit> | null>(null)
|
||||
|
||||
watch(
|
||||
() => props.includeUserUnlistedProjects && props.userId,
|
||||
async (shouldFetch) => {
|
||||
if (!shouldFetch || !props.userId) {
|
||||
userProjectHits.value = []
|
||||
userProjectsFuse.value = null
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const projects = await labrinth.users_v2.getProjects(props.userId)
|
||||
const projectTypeSet = props.projectTypes ? new Set(props.projectTypes) : null
|
||||
|
||||
userProjectHits.value = projects
|
||||
.filter((p) => !projectTypeSet || projectTypeSet.has(p.project_type as ProjectType))
|
||||
.filter((p) => p.status === 'unlisted')
|
||||
.map((p) => ({
|
||||
project_id: p.id,
|
||||
title: p.title,
|
||||
icon_url: p.icon_url ?? undefined,
|
||||
project_type: p.project_type,
|
||||
slug: p.slug,
|
||||
}))
|
||||
|
||||
for (const hit of userProjectHits.value) {
|
||||
searchResultsCache.value.set(hit.project_id, hit)
|
||||
}
|
||||
|
||||
userProjectsFuse.value = new Fuse(userProjectHits.value, {
|
||||
keys: ['title', 'slug'],
|
||||
threshold: 0.4,
|
||||
})
|
||||
} catch {
|
||||
userProjectHits.value = []
|
||||
userProjectsFuse.value = null
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
function hitToOption(hit: SearchHit): ComboboxOption<string> {
|
||||
return {
|
||||
label: hit.title,
|
||||
value: hit.project_id,
|
||||
icon: hit.icon_url
|
||||
? defineAsyncComponent(() =>
|
||||
Promise.resolve({
|
||||
setup: () => () =>
|
||||
h('img', {
|
||||
src: hit.icon_url,
|
||||
alt: hit.title,
|
||||
class: 'h-5 w-5 rounded',
|
||||
}),
|
||||
}),
|
||||
? markRaw(
|
||||
defineAsyncComponent(() =>
|
||||
Promise.resolve({
|
||||
setup: () => () =>
|
||||
h('img', {
|
||||
src: hit.icon_url,
|
||||
alt: hit.title,
|
||||
class: 'h-5 w-5 rounded',
|
||||
}),
|
||||
}),
|
||||
),
|
||||
)
|
||||
: PackageIcon,
|
||||
: markRaw(PackageIcon),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +210,11 @@ const search = async (query: string) => {
|
||||
facets: [[`project_id:${query.replace(/[^a-zA-Z0-9]/g, '')}`]],
|
||||
})
|
||||
|
||||
const allHits = [...resultsByProjectId.hits, ...results.hits]
|
||||
const userFuseHits: SearchHit[] = userProjectsFuse.value
|
||||
? userProjectsFuse.value.search(query).map((r) => r.item)
|
||||
: []
|
||||
|
||||
const allHits = [...userFuseHits, ...resultsByProjectId.hits, ...results.hits]
|
||||
const seenIds = new Set<string>()
|
||||
const excludeSet = new Set(props.excludeProjectIds ?? [])
|
||||
const uniqueHits: SearchHit[] = []
|
||||
@@ -169,7 +223,6 @@ const search = async (query: string) => {
|
||||
if (!seenIds.has(hit.project_id) && !excludeSet.has(hit.project_id)) {
|
||||
seenIds.add(hit.project_id)
|
||||
uniqueHits.push(hit)
|
||||
// Cache the hit for later lookup
|
||||
searchResultsCache.value.set(hit.project_id, hit)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user