From b2f8a14acbfc993b81772afe9e89a91aa11214b4 Mon Sep 17 00:00:00 2001 From: Szedann <65607498+Szedann@users.noreply.github.com> Date: Wed, 20 Aug 2025 14:08:06 +0200 Subject: [PATCH] feat: browser --- apps/oneclient/frontend/src/bindings.gen.ts | 21 +---- .../src/routes/app/cluster/browser/index.tsx | 79 +++++++++++++++++-- .../frontend/src/routes/app/cluster/route.tsx | 1 + 3 files changed, 75 insertions(+), 26 deletions(-) diff --git a/apps/oneclient/frontend/src/bindings.gen.ts b/apps/oneclient/frontend/src/bindings.gen.ts index 3bda344c..db2c583c 100644 --- a/apps/oneclient/frontend/src/bindings.gen.ts +++ b/apps/oneclient/frontend/src/bindings.gen.ts @@ -230,25 +230,14 @@ export type VersionType = */ "old_beta" -<<<<<<< HEAD -const ARGS_MAP = { 'folders':'{"openCluster":["folder_name"],"fromCluster":["folder_name"]}', 'events':'{"ingress":["event"],"process":["event"],"message":["event"]}', 'oneclient':'{"getClustersGroupedByMajor":[],"openDevTools":[]}', 'core':'{"getWorlds":["id"],"launchCluster":["id","uuid"],"getDefaultUser":["fallback"],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"],"getClusterById":["id"],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"],"getProfileOrDefault":["name"],"updateClusterProfile":["name","profile"],"writeSettings":["setting"],"updateClusterById":["id","request"],"getMultiplePackages":["provider","slugs"],"removeCluster":["id"],"getUser":["uuid"],"getGlobalProfile":[],"openMsaLogin":[],"getPackageBody":["provider","body"],"getLogByName":["id","name"],"getLoadersForVersion":["mc_version"],"searchPackages":["provider","query"],"readSettings":[],"removeUser":["uuid"],"getClusters":[],"getGameVersions":[],"getUsers":[],"getPackage":["provider","slug"],"getUsersFromAuthor":["provider","author"],"getScreenshots":["id"],"getLogs":["id"],"setDefaultUser":["uuid"],"createCluster":["options"]}' } -export type Router = { 'events': { ingress: (event: IngressPayload) => Promise, -message: (event: MessagePayload) => Promise, -process: (event: ProcessPayload) => Promise }, -'folders': { fromCluster: (folderName: string) => Promise, +const ARGS_MAP = { 'core':'{"getPackageBody":["provider","body"],"getLogByName":["id","name"],"getClusters":[],"updateClusterProfile":["name","profile"],"getPackage":["provider","slug"],"getClusterById":["id"],"getGameVersions":[],"getUsers":[],"setDefaultUser":["uuid"],"openMsaLogin":[],"removeCluster":["id"],"getScreenshots":["id"],"removeUser":["uuid"],"searchPackages":["provider","query"],"getUsersFromAuthor":["provider","author"],"launchCluster":["id","uuid"],"getLogs":["id"],"updateClusterById":["id","request"],"getLoadersForVersion":["mc_version"],"getUser":["uuid"],"getProfileOrDefault":["name"],"fetchMinecraftProfile":["uuid"],"getWorlds":["id"],"writeSettings":["setting"],"getDefaultUser":["fallback"],"readSettings":[],"getGlobalProfile":[],"getMultiplePackages":["provider","slugs"],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"],"createCluster":["options"]}', 'folders':'{"fromCluster":["folder_name"],"openCluster":["folder_name"]}', 'events':'{"message":["event"],"ingress":["event"],"process":["event"]}', 'oneclient':'{"getClustersGroupedByMajor":[],"openDevTools":[]}' } +export type Router = { 'folders': { fromCluster: (folderName: string) => Promise, openCluster: (folderName: string) => Promise }, 'oneclient': { openDevTools: () => Promise, getClustersGroupedByMajor: () => Promise> }, -======= -const ARGS_MAP = { 'oneclient':'{"openDevTools":[],"getClustersGroupedByMajor":[]}', 'events':'{"message":["event"],"process":["event"],"ingress":["event"]}', 'core':'{"getLoadersForVersion":["mc_version"],"writeSettings":["setting"],"getLogs":["id"],"getWorlds":["id"],"getClusterById":["id"],"launchCluster":["id","uuid"],"getPackage":["provider","slug"],"getGlobalProfile":[],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"],"readSettings":[],"updateClusterById":["id","request"],"getUser":["uuid"],"getPackageBody":["provider","body"],"fetchMinecraftProfile":["uuid"],"createCluster":["options"],"updateClusterProfile":["name","profile"],"getScreenshots":["id"],"removeUser":["uuid"],"getDefaultUser":["fallback"],"openMsaLogin":[],"getGameVersions":[],"setDefaultUser":["uuid"],"getUsersFromAuthor":["provider","author"],"removeCluster":["id"],"getLogByName":["id","name"],"getProfileOrDefault":["name"],"getClusters":[],"getMultiplePackages":["provider","slugs"],"getUsers":[],"searchPackages":["provider","query"],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"]}', 'folders':'{"openCluster":["folder_name"],"fromCluster":["folder_name"]}' } -export type Router = { 'events': { ingress: (event: IngressPayload) => Promise, +'events': { ingress: (event: IngressPayload) => Promise, message: (event: MessagePayload) => Promise, process: (event: ProcessPayload) => Promise }, -'oneclient': { openDevTools: () => Promise, -getClustersGroupedByMajor: () => Promise> }, -'folders': { fromCluster: (folderName: string) => Promise, -openCluster: (folderName: string) => Promise }, ->>>>>>> 04cd2183d01fa465f38ac0b802c81eb344a7ecf9 'core': { getClusters: () => Promise, getClusterById: (id: number) => Promise, removeCluster: (id: number) => Promise, @@ -278,12 +267,8 @@ getPackageBody: (provider: Provider, body: ManagedPackageBody) => Promise Promise, getPackageVersions: (provider: Provider, slug: string, mcVersion: string | null, loader: GameLoader | null, offset: number, limit: number) => Promise>, downloadPackage: (provider: Provider, packageId: string, versionId: string, clusterId: number, skipCompatibility: boolean | null) => Promise, -<<<<<<< HEAD -getUsersFromAuthor: (provider: Provider, author: PackageAuthor) => Promise } }; -======= getUsersFromAuthor: (provider: Provider, author: PackageAuthor) => Promise, fetchMinecraftProfile: (uuid: string) => Promise } }; ->>>>>>> 04cd2183d01fa465f38ac0b802c81eb344a7ecf9 export type { InferCommandOutput } diff --git a/apps/oneclient/frontend/src/routes/app/cluster/browser/index.tsx b/apps/oneclient/frontend/src/routes/app/cluster/browser/index.tsx index fbae86d5..0331c368 100644 --- a/apps/oneclient/frontend/src/routes/app/cluster/browser/index.tsx +++ b/apps/oneclient/frontend/src/routes/app/cluster/browser/index.tsx @@ -1,23 +1,29 @@ -import type { PackageType, Provider } from '@/bindings.gen'; +import type { Filters, PackageCategories, PackageType, Provider } from '@/bindings.gen'; +import { LoaderSuspense } from '@/components'; +import { PackageGrid } from '@/components/PackageItem'; +import { bindings } from '@/main'; import { browserCategories, categoryNameFromId } from '@/utils/browser'; +import { useCommandSuspense, usePagination } from '@onelauncher/common'; import { Dropdown, Show, TextField } from '@onelauncher/common/components'; import { createFileRoute } from '@tanstack/react-router'; import { SearchMdIcon } from '@untitled-theme/icons-react'; -import { useMemo } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; interface BrowserSearchRouteSearchParams { query?: string; packageType: PackageType; categories: Array; + page: number; } export const Route = createFileRoute('/app/cluster/browser/')({ component: RouteComponent, validateSearch: (search): BrowserSearchRouteSearchParams => { return { - query: search.query as string, + query: (search.query ?? '') as string, packageType: search.packageType as PackageType, - categories: search.categories as Array, + categories: (search.categories ?? []) as Array, + page: Number(search.page ?? 0), }; }, }); @@ -39,6 +45,9 @@ function RouteComponent() {
+ + +
@@ -54,17 +63,18 @@ function BrowserCategories() { const search = Route.useSearch(); const { categories, packageType } = search; const navigate = Route.useNavigate(); + const navRef = useRef(navigate); const switchCategory = useMemo(() => (category: string) => { const newCategories = categories.includes(category) ? categories.filter(element => element !== category) : [...categories, category]; - navigate({ + navRef.current({ search: { ...search, categories: newCategories, }, }); - }, []); + }, [search, categories]); return (
@@ -97,6 +107,7 @@ function BrowserToolbar() { const setQuery = (query: string) => { navigate({ search: { ...search, query } }); }; + const [searchBar, setSearchBar] = useState(query); return (
@@ -120,7 +131,7 @@ function BrowserToolbar() { } - // onChange={e => setQuery(e.currentTarget.value)} + onChange={e => setSearchBar(e.currentTarget.value)} onKeyDown={(e) => { if (e.key !== 'Enter') return; @@ -128,9 +139,61 @@ function BrowserToolbar() { setQuery(e.currentTarget.value); }} placeholder="Search for content" - value={query} + value={searchBar} />
); } + +interface SearchQuery { + query: string | null; + offset: number | null; + limit: number; + sort: 'Relevance' | 'Downloads' | 'Newest' | 'Updated' | null; + filters: Filters | null; +} + +const itemsPerPage = 25; + +function SearchResult() { + const search = Route.useSearch(); + const { cluster } = Route.useRouteContext(); + const navigate = Route.useNavigate(); + const navRef = useRef(navigate); + const query = useMemo(() => ({ + query: search.query ?? null, + offset: (search.page - 1) * itemsPerPage, + limit: itemsPerPage, + sort: 'Relevance', + filters: { + game_versions: [cluster.mc_version], + categories: { [categoryNameFromId[search.packageType]]: search.categories } as PackageCategories, + loaders: [cluster.mc_loader], + package_type: search.packageType, + }, + }), [cluster, search]); + const results = useCommandSuspense(['searchPackages', search], () => bindings.core.searchPackages( + search.provider, + query, + )); + const pagination = usePagination({ + itemsPerPage: query.limit, + itemsCount: results.data.total, + }); + const paginationRef = useRef(pagination); + useEffect(() => { + navRef.current({ search: prev => ({ ...prev, page: pagination.page }) }); + }, [pagination.page]); + useEffect(() => { + paginationRef.current.reset(); + }, [pagination.totalPages]); + return ( +
+
+ +
+ +
+ ); +} diff --git a/apps/oneclient/frontend/src/routes/app/cluster/route.tsx b/apps/oneclient/frontend/src/routes/app/cluster/route.tsx index 948cdb2c..2fbffa42 100644 --- a/apps/oneclient/frontend/src/routes/app/cluster/route.tsx +++ b/apps/oneclient/frontend/src/routes/app/cluster/route.tsx @@ -67,6 +67,7 @@ function RouteComponent() { Overview Logs + Browser