mirror of
https://github.com/modrinth/code.git
synced 2026-07-31 13:16:38 +00:00
fix: make search use v3 everywhere (#6840)
This commit is contained in:
@@ -73,6 +73,30 @@ export class LabrinthProjectsV3Module extends AbstractModule {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Search projects (v3)
|
||||
*
|
||||
* @param params - Search parameters
|
||||
* @returns Promise resolving to v3 search results
|
||||
*/
|
||||
public async search(
|
||||
params: Labrinth.Search.SearchParams,
|
||||
options?: {
|
||||
headers?: Record<string, string>
|
||||
},
|
||||
): Promise<Labrinth.Search.v3.SearchResults> {
|
||||
return this.client.request<Labrinth.Search.v3.SearchResults>(`/search`, {
|
||||
api: 'labrinth',
|
||||
version: 3,
|
||||
method: 'GET',
|
||||
headers: options?.headers,
|
||||
params: {
|
||||
...params,
|
||||
facets: params.facets ? JSON.stringify(params.facets) : undefined,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a project (v3)
|
||||
*
|
||||
|
||||
@@ -1750,6 +1750,17 @@ export namespace Labrinth {
|
||||
}
|
||||
|
||||
export namespace Search {
|
||||
export type SearchParams = {
|
||||
query?: string
|
||||
offset?: string | number
|
||||
index?: string
|
||||
limit?: string | number
|
||||
new_filters?: string
|
||||
facets?: string[][]
|
||||
filters?: string
|
||||
version?: string
|
||||
}
|
||||
|
||||
export namespace v2 {
|
||||
export interface ResultSearchProject {
|
||||
project_id: string
|
||||
@@ -1812,7 +1823,9 @@ export namespace Labrinth {
|
||||
featured_gallery: string | null
|
||||
color: number | null
|
||||
loaders: string[]
|
||||
project_loader_fields?: Record<string, unknown[]>
|
||||
project_loader_fields?: Record<string, unknown[]> & {
|
||||
environment?: Projects.v3.Environment[]
|
||||
}
|
||||
minecraft_server?: Projects.v3.MinecraftServer | null
|
||||
minecraft_java_server?: Projects.v3.MinecraftJavaServer | null
|
||||
minecraft_bedrock_server?: Projects.v3.MinecraftBedrockServer | null
|
||||
|
||||
@@ -250,9 +250,9 @@ pub struct SearchResultsV3 {
|
||||
pub struct SearchResultV3 {
|
||||
pub hits: Vec<serde_json::Value>,
|
||||
#[serde(default)]
|
||||
pub offset: u32,
|
||||
#[serde(default)]
|
||||
pub limit: u32,
|
||||
pub page: u32,
|
||||
#[serde(default, alias = "limit")]
|
||||
pub hits_per_page: u32,
|
||||
#[serde(default)]
|
||||
pub total_hits: u32,
|
||||
}
|
||||
|
||||
@@ -68,11 +68,7 @@
|
||||
class="smart-clickable:allow-pointer-events"
|
||||
/>
|
||||
</template>
|
||||
<ProjectCardEnvironment
|
||||
v-if="environment"
|
||||
:client-side="environment.clientSide"
|
||||
:server-side="environment.serverSide"
|
||||
/>
|
||||
<ProjectCardEnvironment v-if="environment" :environment="environment" />
|
||||
<ProjectCardTags
|
||||
v-if="tags"
|
||||
:tags="tags"
|
||||
@@ -168,11 +164,7 @@
|
||||
class="smart-clickable:allow-pointer-events"
|
||||
/>
|
||||
</template>
|
||||
<ProjectCardEnvironment
|
||||
v-if="environment"
|
||||
:client-side="environment.clientSide"
|
||||
:server-side="environment.serverSide"
|
||||
/>
|
||||
<ProjectCardEnvironment v-if="environment" :environment="environment" />
|
||||
<ProjectCardTags
|
||||
v-if="tags"
|
||||
:tags="tags"
|
||||
@@ -213,7 +205,7 @@ import ServerRegion from '../server/ServerRegion.vue'
|
||||
import ProjectCardAuthor from './ProjectCardAuthor.vue'
|
||||
import ProjectCardDate from './ProjectCardDate.vue'
|
||||
import ProjectCardEnvironment, {
|
||||
type ProjectCardEnvironmentProps,
|
||||
type ProjectCardEnvironmentValue,
|
||||
} from './ProjectCardEnvironment.vue'
|
||||
import ProjectCardStats from './ProjectCardStats.vue'
|
||||
import ProjectCardTags from './ProjectCardTags.vue'
|
||||
@@ -257,7 +249,7 @@ const props = defineProps<{
|
||||
isServerProject?: boolean
|
||||
banner?: string
|
||||
color?: string | number
|
||||
environment?: ProjectCardEnvironmentProps
|
||||
environment?: ProjectCardEnvironmentValue
|
||||
status?: ProjectStatus
|
||||
maxTags?: number
|
||||
}>()
|
||||
|
||||
@@ -1,18 +1,29 @@
|
||||
<script setup lang="ts">
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import { ClientIcon, GlobeIcon, ServerIcon } from '@modrinth/assets'
|
||||
import { ClientIcon, GlobeIcon, ServerIcon, UserIcon } from '@modrinth/assets'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { defineMessages, useVIntl } from '../../../composables'
|
||||
import { TagItem } from '../../base'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
export type ProjectCardEnvironmentProps = {
|
||||
export type LegacyProjectEnvironment = {
|
||||
clientSide: Labrinth.Projects.v2.Environment
|
||||
serverSide: Labrinth.Projects.v2.Environment
|
||||
}
|
||||
|
||||
defineProps<ProjectCardEnvironmentProps>()
|
||||
export type ProjectCardEnvironmentValue =
|
||||
| Labrinth.Projects.v3.Environment
|
||||
| LegacyProjectEnvironment
|
||||
|
||||
export type ProjectCardEnvironmentProps = {
|
||||
environment?: ProjectCardEnvironmentValue
|
||||
clientSide?: Labrinth.Projects.v2.Environment
|
||||
serverSide?: Labrinth.Projects.v2.Environment
|
||||
}
|
||||
|
||||
const props = defineProps<ProjectCardEnvironmentProps>()
|
||||
|
||||
const messages = defineMessages({
|
||||
clientOrServer: {
|
||||
@@ -31,36 +42,99 @@ const messages = defineMessages({
|
||||
id: 'project-card.environment.server',
|
||||
defaultMessage: 'Server',
|
||||
},
|
||||
singleplayer: {
|
||||
id: 'project-card.environment.singleplayer',
|
||||
defaultMessage: 'Singleplayer',
|
||||
},
|
||||
dedicatedServer: {
|
||||
id: 'project-card.environment.dedicated-server',
|
||||
defaultMessage: 'Dedicated server',
|
||||
},
|
||||
})
|
||||
|
||||
const displayEnvironment = computed(() => {
|
||||
const environment =
|
||||
props.environment ??
|
||||
(props.clientSide && props.serverSide
|
||||
? { clientSide: props.clientSide, serverSide: props.serverSide }
|
||||
: undefined)
|
||||
|
||||
if (typeof environment === 'string') {
|
||||
switch (environment) {
|
||||
case 'client_or_server':
|
||||
case 'client_or_server_prefers_both':
|
||||
return 'client-or-server'
|
||||
case 'client_and_server':
|
||||
return 'client-and-server'
|
||||
case 'client_only':
|
||||
case 'client_only_server_optional':
|
||||
return 'client'
|
||||
case 'server_only':
|
||||
case 'server_only_client_optional':
|
||||
return 'server'
|
||||
case 'singleplayer_only':
|
||||
return 'singleplayer'
|
||||
case 'dedicated_server_only':
|
||||
return 'dedicated-server'
|
||||
default:
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
if (!environment) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const { clientSide, serverSide } = environment
|
||||
|
||||
if (clientSide === 'optional' && serverSide === 'optional') {
|
||||
return 'client-or-server'
|
||||
}
|
||||
if (clientSide === 'required' && serverSide === 'required') {
|
||||
return 'client-and-server'
|
||||
}
|
||||
if (
|
||||
(clientSide === 'optional' || clientSide === 'required') &&
|
||||
(serverSide === 'optional' || serverSide === 'unsupported')
|
||||
) {
|
||||
return 'client'
|
||||
}
|
||||
if (
|
||||
(serverSide === 'optional' || serverSide === 'required') &&
|
||||
(clientSide === 'optional' || clientSide === 'unsupported')
|
||||
) {
|
||||
return 'server'
|
||||
}
|
||||
|
||||
return undefined
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TagItem class="empty:hidden">
|
||||
<template v-if="clientSide === 'optional' && serverSide === 'optional'">
|
||||
<template v-if="displayEnvironment === 'client-or-server'">
|
||||
<GlobeIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.clientOrServer) }}
|
||||
</template>
|
||||
<template v-else-if="clientSide === 'required' && serverSide === 'required'">
|
||||
<template v-else-if="displayEnvironment === 'client-and-server'">
|
||||
<GlobeIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.clientAndServer) }}
|
||||
</template>
|
||||
<template
|
||||
v-else-if="
|
||||
(clientSide === 'optional' || clientSide === 'required') &&
|
||||
(serverSide === 'optional' || serverSide === 'unsupported')
|
||||
"
|
||||
>
|
||||
<template v-else-if="displayEnvironment === 'client'">
|
||||
<ClientIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.client) }}
|
||||
</template>
|
||||
<template
|
||||
v-else-if="
|
||||
(serverSide === 'optional' || serverSide === 'required') &&
|
||||
(clientSide === 'optional' || clientSide === 'unsupported')
|
||||
"
|
||||
>
|
||||
<template v-else-if="displayEnvironment === 'server'">
|
||||
<ServerIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.server) }}
|
||||
</template>
|
||||
<template v-else-if="displayEnvironment === 'singleplayer'">
|
||||
<UserIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.singleplayer) }}
|
||||
</template>
|
||||
<template v-else-if="displayEnvironment === 'dedicated-server'">
|
||||
<ServerIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.dedicatedServer) }}
|
||||
</template>
|
||||
</TagItem>
|
||||
</template>
|
||||
|
||||
@@ -6,6 +6,7 @@ export type {
|
||||
Gamemode,
|
||||
GeneratorSettingsMode,
|
||||
LoaderVersionType,
|
||||
ModpackSearchResult,
|
||||
SetupType,
|
||||
} from '../../flows/creation-flow-modal/creation-flow-context'
|
||||
export { default as CreationFlowModal } from '../../flows/creation-flow-modal/index.vue'
|
||||
|
||||
@@ -66,6 +66,33 @@ const messages = defineMessages({
|
||||
defaultMessage: 'No results found for your query!',
|
||||
},
|
||||
})
|
||||
|
||||
function getLoaderFieldValues(
|
||||
result: Labrinth.Search.v3.ResultSearchProject,
|
||||
field: string,
|
||||
): string[] {
|
||||
return (result.project_loader_fields?.[field] ?? []).filter(
|
||||
(value): value is string => typeof value === 'string',
|
||||
)
|
||||
}
|
||||
|
||||
function getProjectCardTags(result: Labrinth.Search.v3.ResultSearchProject, displayOnly: boolean) {
|
||||
const tags = new Set(displayOnly ? result.display_categories : result.categories)
|
||||
|
||||
for (const loader of result.loaders) {
|
||||
if (loader !== 'mrpack') {
|
||||
tags.add(loader)
|
||||
}
|
||||
}
|
||||
|
||||
if (result.loaders.includes('mrpack')) {
|
||||
for (const loader of getLoaderFieldValues(result, 'mrpack_loaders')) {
|
||||
tags.add(loader)
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(tags)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -247,8 +274,8 @@ const messages = defineMessages({
|
||||
v-for="result in ctx.projectHits.value"
|
||||
:key="result.project_id"
|
||||
:link="ctx.getProjectLink(result)"
|
||||
:title="result.title"
|
||||
:icon-url="result.icon_url"
|
||||
:title="result.name"
|
||||
:icon-url="result.icon_url ?? undefined"
|
||||
:author="{
|
||||
name: result.organization == null ? result.author : result.organization,
|
||||
link:
|
||||
@@ -266,9 +293,9 @@ const messages = defineMessages({
|
||||
ctx.effectiveCurrentSortType.value.name === 'newest' ? 'published' : 'updated'
|
||||
"
|
||||
:downloads="result.downloads"
|
||||
:summary="result.description"
|
||||
:tags="result.display_categories"
|
||||
:all-tags="result.categories"
|
||||
:summary="result.summary"
|
||||
:tags="getProjectCardTags(result, true)"
|
||||
:all-tags="getProjectCardTags(result, false)"
|
||||
:deprioritized-tags="ctx.deprioritizedTags.value"
|
||||
:exclude-loaders="ctx.excludeLoaders.value"
|
||||
:followers="result.follows"
|
||||
@@ -276,10 +303,7 @@ const messages = defineMessages({
|
||||
:color="result.color ?? undefined"
|
||||
:environment="
|
||||
['mod', 'modpack'].includes(ctx.projectType.value)
|
||||
? {
|
||||
clientSide: result.client_side as Labrinth.Projects.v2.Environment,
|
||||
serverSide: result.server_side as Labrinth.Projects.v2.Environment,
|
||||
}
|
||||
? result.project_loader_fields?.environment?.[0]
|
||||
: undefined
|
||||
"
|
||||
:layout="ctx.effectiveLayout.value"
|
||||
|
||||
@@ -46,7 +46,7 @@ export interface BrowseManagerContext {
|
||||
clearSearch: () => void
|
||||
onFilterChange: () => void
|
||||
|
||||
getProjectLink: (result: Labrinth.Search.v2.ResultSearchProject) => string | RouteLocationRaw
|
||||
getProjectLink: (result: Labrinth.Search.v3.ResultSearchProject) => string | RouteLocationRaw
|
||||
getServerProjectLink: (
|
||||
result: Labrinth.Search.v3.ResultSearchProject,
|
||||
) => string | RouteLocationRaw
|
||||
@@ -57,7 +57,7 @@ export interface BrowseManagerContext {
|
||||
variant: 'app' | 'web'
|
||||
|
||||
getCardActions?: (
|
||||
result: Labrinth.Search.v2.ResultSearchProject | Labrinth.Search.v3.ResultSearchProject,
|
||||
result: Labrinth.Search.v3.ResultSearchProject,
|
||||
projectType: string,
|
||||
) => CardAction[]
|
||||
|
||||
@@ -85,13 +85,10 @@ export interface BrowseManagerContext {
|
||||
result: Labrinth.Search.v3.ResultSearchProject,
|
||||
) => ServerModpackContent | undefined
|
||||
|
||||
onProjectHover?: (result: Labrinth.Search.v2.ResultSearchProject) => void
|
||||
onProjectHover?: (result: Labrinth.Search.v3.ResultSearchProject) => void
|
||||
onServerProjectHover?: (result: Labrinth.Search.v3.ResultSearchProject) => void
|
||||
onProjectHoverEnd?: () => void
|
||||
onContextMenu?: (
|
||||
event: MouseEvent,
|
||||
result: Labrinth.Search.v2.ResultSearchProject | Labrinth.Search.v3.ResultSearchProject,
|
||||
) => void
|
||||
onContextMenu?: (event: MouseEvent, result: Labrinth.Search.v3.ResultSearchProject) => void
|
||||
offline?: Ref<boolean>
|
||||
|
||||
filtersMenuOpen?: Ref<boolean>
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { Component } from 'vue'
|
||||
import type { RouteLocationRaw } from 'vue-router'
|
||||
|
||||
export interface BrowseSearchResponse {
|
||||
projectHits: (Labrinth.Search.v2.ResultSearchProject & {
|
||||
projectHits: (Labrinth.Search.v3.ResultSearchProject & {
|
||||
installed?: boolean
|
||||
installing?: boolean
|
||||
})[]
|
||||
|
||||
@@ -2825,9 +2825,15 @@
|
||||
"project-card.environment.client-or-server": {
|
||||
"defaultMessage": "Client or server"
|
||||
},
|
||||
"project-card.environment.dedicated-server": {
|
||||
"defaultMessage": "Dedicated server"
|
||||
},
|
||||
"project-card.environment.server": {
|
||||
"defaultMessage": "Server"
|
||||
},
|
||||
"project-card.environment.singleplayer": {
|
||||
"defaultMessage": "Singleplayer"
|
||||
},
|
||||
"project-type.all": {
|
||||
"defaultMessage": "All"
|
||||
},
|
||||
|
||||
@@ -63,7 +63,7 @@ export const AllTypes: Story = {
|
||||
:followers="25000"
|
||||
date-updated="2023-06-01T00:00:00Z"
|
||||
:tags="['utility']"
|
||||
:environment="{ clientSide: 'unsupported', serverSide: 'required' }"
|
||||
environment="server_only"
|
||||
/>
|
||||
<ProjectCard
|
||||
link="/modpack/example-modpack"
|
||||
|
||||
Reference in New Issue
Block a user