From 9db18e4d12b157e9d3b2b0a7ddeb71170fccaf4f Mon Sep 17 00:00:00 2001 From: LynithDev <61880709+LynithDev@users.noreply.github.com> Date: Fri, 15 Aug 2025 19:16:21 +0200 Subject: [PATCH] feat: log viewer changes and fixes --- apps/oneclient/frontend/package.json | 1 + apps/oneclient/frontend/src/bindings.gen.ts | 14 +- .../frontend/src/components/LogViewer.tsx | 22 +-- apps/oneclient/frontend/src/routes/__root.tsx | 24 +++- .../frontend/src/routes/app/cluster/logs.tsx | 14 +- apps/oneclient/frontend/src/types/global.d.ts | 2 + apps/oneclient/frontend/tsconfig.json | 2 +- packages/web_common/src/components/Button.tsx | 1 + .../web_common/src/components/Dropdown.tsx | 19 ++- packages/web_common/src/hooks/useCommand.ts | 53 +++++--- packages/web_common/src/utils/error.ts | 23 ++++ packages/web_common/src/utils/index.ts | 1 + pnpm-lock.yaml | 126 ++++++++++++++++++ pnpm-workspace.yaml | 1 + 14 files changed, 247 insertions(+), 56 deletions(-) create mode 100644 packages/web_common/src/utils/error.ts diff --git a/apps/oneclient/frontend/package.json b/apps/oneclient/frontend/package.json index f46e29b7..3d5bfa9d 100644 --- a/apps/oneclient/frontend/package.json +++ b/apps/oneclient/frontend/package.json @@ -16,6 +16,7 @@ "@onelauncher/common": "workspace:*", "@tailwindcss/vite": "catalog:", "@tanstack/match-sorter-utils": "catalog:", + "@tanstack/react-devtools": "catalog:", "@tanstack/react-query": "catalog:", "@tanstack/react-query-devtools": "catalog:", "@tanstack/react-router": "catalog:", diff --git a/apps/oneclient/frontend/src/bindings.gen.ts b/apps/oneclient/frontend/src/bindings.gen.ts index a5d1b1ab..8ab8bfaa 100644 --- a/apps/oneclient/frontend/src/bindings.gen.ts +++ b/apps/oneclient/frontend/src/bindings.gen.ts @@ -228,8 +228,13 @@ export type VersionType = */ "old_beta" -const ARGS_MAP = { 'oneclient':'{"openDevTools":[],"getClustersGroupedByMajor":[]}', 'core':'{"getScreenshots":["id"],"updateClusterById":["id","request"],"getPackageBody":["provider","body"],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"],"launchCluster":["id","uuid"],"getClusters":[],"getLoadersForVersion":["mc_version"],"getUser":["uuid"],"getGameVersions":[],"getDefaultUser":["fallback"],"getUsersFromAuthor":["provider","author"],"getProfileOrDefault":["name"],"removeCluster":["id"],"getUsers":[],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"],"getMultiplePackages":["provider","slugs"],"getLogs":["id"],"getWorlds":["id"],"setDefaultUser":["uuid"],"removeUser":["uuid"],"openMsaLogin":[],"getPackage":["provider","slug"],"writeSettings":["setting"],"createCluster":["options"],"readSettings":[],"getLogByName":["id","name"],"updateClusterProfile":["name","profile"],"getClusterById":["id"],"searchPackages":["provider","query"],"getGlobalProfile":[]}', 'events':'{"process":["event"],"ingress":["event"],"message":["event"]}', 'folders':'{"openCluster":["folder_name"],"fromCluster":["folder_name"]}' } -export type Router = { 'core': { getClusters: () => Promise, +const ARGS_MAP = { 'folders':'{"openCluster":["folder_name"],"fromCluster":["folder_name"]}', 'oneclient':'{"getClustersGroupedByMajor":[],"openDevTools":[]}', 'events':'{"process":["event"],"ingress":["event"],"message":["event"]}', 'core':'{"openMsaLogin":[],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"],"getMultiplePackages":["provider","slugs"],"getGlobalProfile":[],"getLogByName":["id","name"],"getLogs":["id"],"getClusterById":["id"],"getLoadersForVersion":["mc_version"],"getDefaultUser":["fallback"],"getWorlds":["id"],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"],"getUsersFromAuthor":["provider","author"],"getProfileOrDefault":["name"],"updateClusterProfile":["name","profile"],"getUser":["uuid"],"launchCluster":["id","uuid"],"getPackageBody":["provider","body"],"readSettings":[],"getGameVersions":[],"searchPackages":["provider","query"],"getUsers":[],"removeUser":["uuid"],"createCluster":["options"],"writeSettings":["setting"],"getPackage":["provider","slug"],"setDefaultUser":["uuid"],"getScreenshots":["id"],"updateClusterById":["id","request"],"getClusters":[],"removeCluster":["id"]}' } +export type Router = { 'oneclient': { openDevTools: () => Promise, +getClustersGroupedByMajor: () => Promise> }, +'events': { ingress: (event: IngressPayload) => Promise, +message: (event: MessagePayload) => Promise, +process: (event: ProcessPayload) => Promise }, +'core': { getClusters: () => Promise, getClusterById: (id: number) => Promise, removeCluster: (id: number) => Promise, createCluster: (options: CreateCluster) => Promise, @@ -259,11 +264,6 @@ getMultiplePackages: (provider: Provider, slugs: string[]) => Promise Promise>, downloadPackage: (provider: Provider, packageId: string, versionId: string, clusterId: number, skipCompatibility: boolean | null) => Promise, getUsersFromAuthor: (provider: Provider, author: PackageAuthor) => 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 } }; diff --git a/apps/oneclient/frontend/src/components/LogViewer.tsx b/apps/oneclient/frontend/src/components/LogViewer.tsx index 7821417e..a28f88c2 100644 --- a/apps/oneclient/frontend/src/components/LogViewer.tsx +++ b/apps/oneclient/frontend/src/components/LogViewer.tsx @@ -1,16 +1,18 @@ import { useVirtualizer } from '@tanstack/react-virtual'; import { OverlayScrollbarsComponent } from 'overlayscrollbars-react'; -import { useImperativeHandle, useRef, useState } from 'react'; +import { useImperativeHandle, useMemo, useState } from 'react'; import styles from './LogViewer.module.css'; export interface LogViewerProps { content: string; scrollRef: React.RefObject; + autoScroll?: boolean; ref?: React.RefObject; } export interface LogViewerRef { push: (line: string) => void; + // search: (query: string) => void; } const LINE_HEIGHT = 16; @@ -19,15 +21,16 @@ const REGEX_PATTERN = /\[((?:\S+ )?\d+:\d+:\d+(?:\.\d+)?)\] \[(.[^(\n\r/\u2028\u export function LogViewer({ content, scrollRef, + autoScroll = false, ref, }: LogViewerProps) { - const linesRef = useRef>(content.split('\n')); + const lines = useMemo>(() => content.split('\n'), [content]); // used to force re-render (and re-init of virtualizer hook) - const [lastUpdated, setLastUpdated] = useState(Date.now()); + const [_lastUpdated, setLastUpdated] = useState(Date.now()); const virtualizer = useVirtualizer({ - count: linesRef.current.length, + count: lines.length, estimateSize: () => LINE_HEIGHT, getScrollElement: () => scrollRef.current ?? null, paddingStart: 4, @@ -37,11 +40,14 @@ export function LogViewer({ }); useImperativeHandle(ref, () => ({ - push: (line: string) => { - linesRef.current.push(line); + push: (line) => { + const len = lines.push(line); setLastUpdated(Date.now()); + + if (autoScroll) + virtualizer.scrollToIndex(len - 1); }, - }), []); + }), [autoScroll, lines, virtualizer]); return (
( router.navigate({ to, ...options })} useHref={to => router.buildLocation({ to }).href} > +
- -
// ); } + +function DevTools() { + return ( + , + }, + { + name: 'Tanstack Router', + render: , + }, + ]} + /> + ); +} diff --git a/apps/oneclient/frontend/src/routes/app/cluster/logs.tsx b/apps/oneclient/frontend/src/routes/app/cluster/logs.tsx index 8a680b6f..074f5caa 100644 --- a/apps/oneclient/frontend/src/routes/app/cluster/logs.tsx +++ b/apps/oneclient/frontend/src/routes/app/cluster/logs.tsx @@ -1,11 +1,11 @@ import type { Key } from 'react-aria-components'; -import { SheetPage, useSheetPageContext } from '@/components'; +import { LoaderContainer, SheetPage, useSheetPageContext } from '@/components'; import { LogViewer } from '@/components/LogViewer'; import { bindings } from '@/main'; -import { useCommand, useCommandSuspense } from '@onelauncher/common'; +import { getMessageFromError, useCommand, useCommandSuspense } from '@onelauncher/common'; import { Dropdown } from '@onelauncher/common/components'; import { createFileRoute } from '@tanstack/react-router'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; export const Route = createFileRoute('/app/cluster/logs')({ component: RouteComponent, @@ -52,8 +52,8 @@ function LogContent({ const { cluster } = Route.useRouteContext(); // TODO: Fix cache - const { data: content } = useCommand( - ['getLogByName', cluster.id.toString(), fileName], + const { data: content, error, isLoading } = useCommand( + ['getLogByName', cluster.id, fileName], () => bindings.core.getLogByName(cluster.id, fileName), { gcTime: 1000 * 60 * 1, // 1 minute @@ -61,6 +61,8 @@ function LogContent({ ); return ( - content && + + + ); } diff --git a/apps/oneclient/frontend/src/types/global.d.ts b/apps/oneclient/frontend/src/types/global.d.ts index 871e7fd1..8e822a19 100644 --- a/apps/oneclient/frontend/src/types/global.d.ts +++ b/apps/oneclient/frontend/src/types/global.d.ts @@ -1,3 +1,4 @@ +import type { LauncherError } from '@/bindings.gen'; import type { bindings } from '@/main'; export type BindingCommands = (keyof typeof bindings.core) | (keyof typeof bindings.oneclient); @@ -5,5 +6,6 @@ export type BindingCommands = (keyof typeof bindings.core) | (keyof typeof bindi declare module '@onelauncher/common' { interface Register { commands: Array; + defaultError: LauncherError; } } diff --git a/apps/oneclient/frontend/tsconfig.json b/apps/oneclient/frontend/tsconfig.json index e442b494..2d4316bf 100644 --- a/apps/oneclient/frontend/tsconfig.json +++ b/apps/oneclient/frontend/tsconfig.json @@ -25,5 +25,5 @@ "skipLibCheck": true, "noUncheckedSideEffectImports": true }, - "include": ["**/*.ts", "**/*.tsx", "vite.config.ts"] + "include": ["**/*.ts", "**/*.tsx", "vite.config.ts", "../../../packages/web_common/src/utils/error.ts"] } diff --git a/packages/web_common/src/components/Button.tsx b/packages/web_common/src/components/Button.tsx index 1fefb9c7..8e8e6105 100644 --- a/packages/web_common/src/components/Button.tsx +++ b/packages/web_common/src/components/Button.tsx @@ -53,6 +53,7 @@ export function Button({ }: ButtonProps) { return ( (props: DropdownProps) { selectValue, triggerClassName, triggerContentClassName, + 'aria-label': ariaLabel, ...rest } = props; const styles = dropdownStyles({ minimal, className }); return ( - + {({ isOpen }) => ( <> - {label && {label}} + {label && {label}} - +
- + {children} diff --git a/packages/web_common/src/hooks/useCommand.ts b/packages/web_common/src/hooks/useCommand.ts index 0d65ea33..9aab92fa 100644 --- a/packages/web_common/src/hooks/useCommand.ts +++ b/packages/web_common/src/hooks/useCommand.ts @@ -1,18 +1,31 @@ /* eslint-disable query/exhaustive-deps -- False */ import type { UndefinedInitialDataOptions, UseMutationOptions, UseMutationResult, UseQueryResult, UseSuspenseQueryOptions, UseSuspenseQueryResult } from '@tanstack/react-query'; +import type { AppError } from '../utils/error'; import { useMutation, useQuery, useSuspenseQuery } from '@tanstack/react-query'; +import { isLauncherError } from '../utils/error'; // this gets overwritten by the consumer project export interface Register { - // commands + // commands: string[]; + // defaultError: Error; } -type RegisterConfig = Register extends { +type CommandKeys = Register extends { commands: infer Keys; } ? Keys : never; -type CommandCacheKey = RegisterConfig[number] | (string & {}); -type CommandCacheKeys = Array | [CommandCacheKey] | [false]; +type DefaultError = Register extends { + defaultError: infer Error; +} ? Error : never; + +type QueryKey = [CommandKeys[number], ...ReadonlyArray]; + +declare module '@tanstack/react-query' { + interface Register { + queryKey: QueryKey; + mutationKey: QueryKey; + } +} async function fetchCommand(command: () => Promise): Promise { try { @@ -21,40 +34,40 @@ async function fetchCommand(command: () => Promise): Promise { } // TODO: (lynith) handle errors better (requires modifications to TauRPC) catch (e) { - console.error(e); - if (e instanceof Error) + console.error('[fetch]', e); + if (isLauncherError(e)) return Promise.reject(e); else - return Promise.reject(new Error('Unknown error')); + return Promise.reject(e); } } -export function useCommand( - cacheKey: CommandCacheKeys, +export function useCommand( + cacheKey: TQueryKey, command: () => Promise, options?: Omit< - UndefinedInitialDataOptions, + UndefinedInitialDataOptions, 'queryKey' | 'queryFn' >, -): UseQueryResult { - return useQuery({ - queryKey: cacheKey[0] === false ? [] : Array.isArray(cacheKey) ? cacheKey : [cacheKey], +): UseQueryResult { + return useQuery({ + queryKey: cacheKey, queryFn: () => fetchCommand(command), enabled: true, ...options, }); } -export function useCommandSuspense( - cacheKey: CommandCacheKeys, +export function useCommandSuspense( + cacheKey: TQueryKey, command: () => Promise, options?: Omit< - UseSuspenseQueryOptions, + UseSuspenseQueryOptions, 'queryKey' | 'queryFn' >, -): UseSuspenseQueryResult { - return useSuspenseQuery({ - queryKey: cacheKey[0] === false ? [] : Array.isArray(cacheKey) ? cacheKey : [cacheKey], +): UseSuspenseQueryResult { + return useSuspenseQuery({ + queryKey: cacheKey, queryFn: () => fetchCommand(command), ...options, }); @@ -62,7 +75,7 @@ export function useCommandSuspense( export function useCommandMut< TData, - TError = Error, + TError = DefaultError, TVariables = void, TContext = unknown, >( diff --git a/packages/web_common/src/utils/error.ts b/packages/web_common/src/utils/error.ts new file mode 100644 index 00000000..d6ccb73d --- /dev/null +++ b/packages/web_common/src/utils/error.ts @@ -0,0 +1,23 @@ +export interface AppError { + data: string | AppError; + type: string; +} + +export function isLauncherError(error: unknown): error is TErr { + return typeof error === 'object' + && error !== null + && 'data' in error + && 'type' in error; +} + +export function getMessageFromError(error: T): string; +export function getMessageFromError(error: T | null | undefined): string | null; +export function getMessageFromError(error: AppError | null | undefined): string | null { + if (!error) + return null; + + if (typeof error.data === 'string') + return error.data; + + return getMessageFromError(error.data); +} diff --git a/packages/web_common/src/utils/index.ts b/packages/web_common/src/utils/index.ts index 67b87f0c..acdeae59 100644 --- a/packages/web_common/src/utils/index.ts +++ b/packages/web_common/src/utils/index.ts @@ -1,2 +1,3 @@ export * from './dev'; +export * from './error'; export * from './nativeExperience'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8fc21ce7..75dd339f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,6 +27,9 @@ catalogs: '@tanstack/match-sorter-utils': specifier: ^8.19.4 version: 8.19.4 + '@tanstack/react-devtools': + specifier: ^0.4.0 + version: 0.4.0 '@tanstack/react-query': specifier: ^5.66.5 version: 5.75.0 @@ -232,6 +235,9 @@ importers: '@tanstack/match-sorter-utils': specifier: 'catalog:' version: 8.19.4 + '@tanstack/react-devtools': + specifier: 'catalog:' + version: 0.4.0(@types/react-dom@19.1.3(@types/react@19.1.2))(@types/react@19.1.2)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(solid-js@1.9.6) '@tanstack/react-query': specifier: 'catalog:' version: 5.75.0(react@19.1.0) @@ -2480,6 +2486,26 @@ packages: resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} engines: {node: '>=18'} + '@solid-primitives/event-listener@2.4.3': + resolution: {integrity: sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg==} + peerDependencies: + solid-js: ^1.6.12 + + '@solid-primitives/keyboard@1.3.3': + resolution: {integrity: sha512-9dQHTTgLBqyAI7aavtO+HnpTVJgWQA1ghBSrmLtMu1SMxLPDuLfuNr+Tk5udb4AL4Ojg7h9JrKOGEEDqsJXWJA==} + peerDependencies: + solid-js: ^1.6.12 + + '@solid-primitives/rootless@1.5.2': + resolution: {integrity: sha512-9HULb0QAzL2r47CCad0M+NKFtQ+LrGGNHZfteX/ThdGvKIg2o2GYhBooZubTCd/RTu2l2+Nw4s+dEfiDGvdrrQ==} + peerDependencies: + solid-js: ^1.6.12 + + '@solid-primitives/utils@6.3.2': + resolution: {integrity: sha512-hZ/M/qr25QOCcwDPOHtGjxTD8w2mNyVAYvcfgwzBHq2RwNqHNdDNsMZYap20+ruRwW4A3Cdkczyoz0TSxLCAPQ==} + peerDependencies: + solid-js: ^1.6.12 + '@stylistic/eslint-plugin-js@4.2.0': resolution: {integrity: sha512-MiJr6wvyzMYl/wElmj8Jns8zH7Q1w8XoVtm+WM6yDaTrfxryMyb8n0CMxt82fo42RoLIfxAEtM6tmQVxqhk0/A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2658,6 +2684,22 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 + '@tanstack/devtools-event-bus@0.2.1': + resolution: {integrity: sha512-JMq3AmrQR2LH9P8Rcj1MTq8Iq/mPk/PyuqSw1L0hO2Wl8G1oz5ue31fS8u8lIgOCVR/mGdJah18p+Pj5OosRJA==} + engines: {node: '>=18'} + + '@tanstack/devtools-ui@0.3.0': + resolution: {integrity: sha512-lyP0eM6juIWn8zgI8xI32Lh86gCnjUyNePE9F7Bfgkv5taILmmJAHW5Mme4T2ufv7L8NLwOiBY/bZYnP4zev0w==} + engines: {node: '>=18'} + peerDependencies: + solid-js: '>=1.9.7' + + '@tanstack/devtools@0.4.0': + resolution: {integrity: sha512-3LrVUMI/s76XxYbygecOueXPrUf9gDc700iebQrBZ0ZvDmZDB/Umwa84gNx6NAxfQyI24lvB0IqQ8lp970oDSg==} + engines: {node: '>=18'} + peerDependencies: + solid-js: '>=1.9.7' + '@tanstack/eslint-config@0.1.0': resolution: {integrity: sha512-/lVsQmmezpqqbCFtaxGNkoSnQ/+H0PAHyHF37PGQ6ZBrF8RXktgazMdsD5SCaNT9oEnGCl274GCZ9sY80b50Sg==} engines: {node: '>=18'} @@ -2681,6 +2723,15 @@ packages: '@tanstack/query-devtools@5.74.7': resolution: {integrity: sha512-nSNlfuGdnHf4yB0S+BoNYOE1o3oAH093weAYZolIHfS2stulyA/gWfSk/9H4ZFk5mAAHb5vNqAeJOmbdcGPEQw==} + '@tanstack/react-devtools@0.4.0': + resolution: {integrity: sha512-QkN0WcbwKjYa107yEYOau+yhaay3XXwL2Ue+V0JxzaBOhvbnFI9tDzvIx7T1NZs8qEUgSjsqmMj/H81cISs2EA==} + engines: {node: '>=18'} + peerDependencies: + '@types/react': '>=16.8' + '@types/react-dom': '>=16.8' + react: '>=16.8' + react-dom: '>=16.8' + '@tanstack/react-query-devtools@5.75.0': resolution: {integrity: sha512-ogTsCCONHPq8opyeU/NJZlus8+g36KnK+cybC1cs0Knr8iO/wAYgnciz+3DVNq38kRflBb0iJhHkUexp/7WfcQ==} peerDependencies: @@ -5964,6 +6015,18 @@ packages: utf-8-validate: optional: true + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + xml-name-validator@5.0.0: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} @@ -8337,6 +8400,27 @@ snapshots: '@sindresorhus/merge-streams@4.0.0': {} + '@solid-primitives/event-listener@2.4.3(solid-js@1.9.6)': + dependencies: + '@solid-primitives/utils': 6.3.2(solid-js@1.9.6) + solid-js: 1.9.6 + + '@solid-primitives/keyboard@1.3.3(solid-js@1.9.6)': + dependencies: + '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.6) + '@solid-primitives/rootless': 1.5.2(solid-js@1.9.6) + '@solid-primitives/utils': 6.3.2(solid-js@1.9.6) + solid-js: 1.9.6 + + '@solid-primitives/rootless@1.5.2(solid-js@1.9.6)': + dependencies: + '@solid-primitives/utils': 6.3.2(solid-js@1.9.6) + solid-js: 1.9.6 + + '@solid-primitives/utils@6.3.2(solid-js@1.9.6)': + dependencies: + solid-js: 1.9.6 + '@stylistic/eslint-plugin-js@4.2.0(eslint@9.25.1(jiti@2.4.2))': dependencies: eslint: 9.25.1(jiti@2.4.2) @@ -8508,6 +8592,33 @@ snapshots: tailwindcss: 4.1.10 vite: 6.3.4(@types/node@22.16.5)(jiti@2.4.2)(lightningcss@1.30.1)(sass@1.80.3)(tsx@4.19.4)(yaml@2.8.0) + '@tanstack/devtools-event-bus@0.2.1': + dependencies: + ws: 8.18.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@tanstack/devtools-ui@0.3.0(csstype@3.1.3)(solid-js@1.9.6)': + dependencies: + goober: 2.1.16(csstype@3.1.3) + solid-js: 1.9.6 + transitivePeerDependencies: + - csstype + + '@tanstack/devtools@0.4.0(csstype@3.1.3)(solid-js@1.9.6)': + dependencies: + '@solid-primitives/keyboard': 1.3.3(solid-js@1.9.6) + '@tanstack/devtools-event-bus': 0.2.1 + '@tanstack/devtools-ui': 0.3.0(csstype@3.1.3)(solid-js@1.9.6) + clsx: 2.1.1 + goober: 2.1.16(csstype@3.1.3) + solid-js: 1.9.6 + transitivePeerDependencies: + - bufferutil + - csstype + - utf-8-validate + '@tanstack/eslint-config@0.1.0(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3)': dependencies: '@eslint/js': 9.25.1 @@ -8541,6 +8652,19 @@ snapshots: '@tanstack/query-devtools@5.74.7': {} + '@tanstack/react-devtools@0.4.0(@types/react-dom@19.1.3(@types/react@19.1.2))(@types/react@19.1.2)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(solid-js@1.9.6)': + dependencies: + '@tanstack/devtools': 0.4.0(csstype@3.1.3)(solid-js@1.9.6) + '@types/react': 19.1.2 + '@types/react-dom': 19.1.3(@types/react@19.1.2) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + transitivePeerDependencies: + - bufferutil + - csstype + - solid-js + - utf-8-validate + '@tanstack/react-query-devtools@5.75.0(@tanstack/react-query@5.75.0(react@19.1.0))(react@19.1.0)': dependencies: '@tanstack/query-devtools': 5.74.7 @@ -12439,6 +12563,8 @@ snapshots: ws@8.18.0: optional: true + ws@8.18.3: {} + xml-name-validator@5.0.0: optional: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 54eedc00..87c122f5 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -61,6 +61,7 @@ catalog: '@tanstack/react-table': ^8.21.2 '@tanstack/router-plugin': ^1.114.3 '@tanstack/react-virtual': ^3.13.12 + '@tanstack/react-devtools': ^0.4.0 # tauri taurpc: ^1.8.1