feat: log viewer changes and fixes
This commit is contained in:
parent
6d4e0fa850
commit
9db18e4d12
14 changed files with 247 additions and 56 deletions
|
|
@ -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:",
|
||||
|
|
|
|||
|
|
@ -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<ClusterModel[]>,
|
||||
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<void>,
|
||||
getClustersGroupedByMajor: () => Promise<Partial<{ [key in number]: ClusterModel[] }>> },
|
||||
'events': { ingress: (event: IngressPayload) => Promise<void>,
|
||||
message: (event: MessagePayload) => Promise<void>,
|
||||
process: (event: ProcessPayload) => Promise<void> },
|
||||
'core': { getClusters: () => Promise<ClusterModel[]>,
|
||||
getClusterById: (id: number) => Promise<ClusterModel | null>,
|
||||
removeCluster: (id: number) => Promise<null>,
|
||||
createCluster: (options: CreateCluster) => Promise<ClusterModel>,
|
||||
|
|
@ -259,11 +264,6 @@ getMultiplePackages: (provider: Provider, slugs: string[]) => Promise<ManagedPac
|
|||
getPackageVersions: (provider: Provider, slug: string, mcVersion: string | null, loader: GameLoader | null, offset: number, limit: number) => Promise<Paginated<ManagedVersion>>,
|
||||
downloadPackage: (provider: Provider, packageId: string, versionId: string, clusterId: number, skipCompatibility: boolean | null) => Promise<PackageModel>,
|
||||
getUsersFromAuthor: (provider: Provider, author: PackageAuthor) => Promise<ManagedUser[]> },
|
||||
'events': { ingress: (event: IngressPayload) => Promise<void>,
|
||||
message: (event: MessagePayload) => Promise<void>,
|
||||
process: (event: ProcessPayload) => Promise<void> },
|
||||
'oneclient': { openDevTools: () => Promise<void>,
|
||||
getClustersGroupedByMajor: () => Promise<Partial<{ [key in number]: ClusterModel[] }>> },
|
||||
'folders': { fromCluster: (folderName: string) => Promise<string>,
|
||||
openCluster: (folderName: string) => Promise<null> } };
|
||||
|
||||
|
|
|
|||
|
|
@ -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<HTMLElement | null>;
|
||||
autoScroll?: boolean;
|
||||
ref?: React.RefObject<LogViewerRef>;
|
||||
}
|
||||
|
||||
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<Array<string>>(content.split('\n'));
|
||||
const lines = useMemo<Array<string>>(() => 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 (
|
||||
<div
|
||||
|
|
@ -66,7 +72,7 @@ export function LogViewer({
|
|||
{virtualizer.getVirtualItems().map(virtualRow => (
|
||||
<LogLine
|
||||
key={virtualRow.key}
|
||||
line={linesRef.current[virtualRow.index]}
|
||||
line={lines[virtualRow.index]}
|
||||
style={{
|
||||
height: `${virtualRow.size}px`,
|
||||
transform: `translateY(${virtualRow.start}px)`,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import type { QueryClient } from '@tanstack/react-query';
|
||||
import type { NavigateOptions, ToOptions } from '@tanstack/react-router';
|
||||
import { TanStackDevtools } from '@tanstack/react-devtools';
|
||||
import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools';
|
||||
import { createRootRouteWithContext, Outlet, useRouter } from '@tanstack/react-router';
|
||||
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools';
|
||||
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools';
|
||||
import { RouterProvider } from 'react-aria-components';
|
||||
|
||||
interface AppRouterContext {
|
||||
|
|
@ -27,12 +29,28 @@ function RootRoute() {
|
|||
navigate={(to, options) => router.navigate({ to, ...options })}
|
||||
useHref={to => router.buildLocation({ to }).href}
|
||||
>
|
||||
<DevTools />
|
||||
<div className="h-screen flex flex-col overflow-hidden text-fg-primary">
|
||||
<Outlet />
|
||||
|
||||
<TanStackRouterDevtools />
|
||||
</div>
|
||||
</RouterProvider>
|
||||
// </AnimatedOutletProvider>
|
||||
);
|
||||
}
|
||||
|
||||
function DevTools() {
|
||||
return (
|
||||
<TanStackDevtools
|
||||
plugins={[
|
||||
{
|
||||
name: 'Tanstack Query',
|
||||
render: <ReactQueryDevtoolsPanel />,
|
||||
},
|
||||
{
|
||||
name: 'Tanstack Router',
|
||||
render: <TanStackRouterDevtoolsPanel />,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 && <LogViewer content={content} scrollRef={scrollRef} />
|
||||
<LoaderContainer loading={isLoading}>
|
||||
<LogViewer content={getMessageFromError(error) || content || 'Empty log file'} scrollRef={scrollRef} />
|
||||
</LoaderContainer>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<BindingCommands>;
|
||||
defaultError: LauncherError;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ export function Button({
|
|||
}: ButtonProps) {
|
||||
return (
|
||||
<AriaButton
|
||||
aria-label={props['aria-label'] ?? 'button'}
|
||||
className={buttonVariants({ color, size, className })}
|
||||
isDisabled={props.isDisabled}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -124,27 +124,24 @@ export function Dropdown<TValue extends object>(props: DropdownProps<TValue>) {
|
|||
selectValue,
|
||||
triggerClassName,
|
||||
triggerContentClassName,
|
||||
'aria-label': ariaLabel,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const styles = dropdownStyles({ minimal, className });
|
||||
|
||||
return (
|
||||
<AriaSelect {...rest} className={styles.root()}>
|
||||
<AriaSelect aria-label={ariaLabel ?? 'dropdown'} {...rest} className={styles.root()}>
|
||||
{({ isOpen }) => (
|
||||
<>
|
||||
{label && <AriaLabel className={labelClassName}>{label}</AriaLabel>}
|
||||
{label && <AriaLabel aria-label={label} className={labelClassName}>{label}</AriaLabel>}
|
||||
|
||||
<Button className={styles.trigger({ className: triggerClassName })} color="ghost">
|
||||
<div className={styles.triggerValueContent({ className: triggerContentClassName })}>
|
||||
{triggerTextPrefix && <span>{triggerTextPrefix}</span>}
|
||||
{selectValue
|
||||
? (
|
||||
<SelectValue>
|
||||
{selectValue}
|
||||
</SelectValue>
|
||||
)
|
||||
: <SelectValue />}
|
||||
<SelectValue>
|
||||
{selectValue}
|
||||
</SelectValue>
|
||||
</div>
|
||||
{
|
||||
isOpen
|
||||
|
|
@ -153,10 +150,10 @@ export function Dropdown<TValue extends object>(props: DropdownProps<TValue>) {
|
|||
}
|
||||
</Button>
|
||||
|
||||
<AriaPopover className={twMerge(styles.popover(), popoverClassName)}>
|
||||
<AriaPopover aria-label="dropdown menu" className={twMerge(styles.popover(), popoverClassName)}>
|
||||
<div className={styles.popoverContentWrapper()}>
|
||||
<OverlayScrollbarsComponent className={styles.overlayScrollbars()}>
|
||||
<AriaListBox className={styles.listBox()}>
|
||||
<AriaListBox aria-label="dropdown list" className={styles.listBox()}>
|
||||
{children}
|
||||
</AriaListBox>
|
||||
</OverlayScrollbarsComponent>
|
||||
|
|
|
|||
|
|
@ -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> | [CommandCacheKey] | [false];
|
||||
type DefaultError = Register extends {
|
||||
defaultError: infer Error;
|
||||
} ? Error : never;
|
||||
|
||||
type QueryKey = [CommandKeys[number], ...ReadonlyArray<unknown>];
|
||||
|
||||
declare module '@tanstack/react-query' {
|
||||
interface Register {
|
||||
queryKey: QueryKey;
|
||||
mutationKey: QueryKey;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchCommand<T>(command: () => Promise<T>): Promise<T> {
|
||||
try {
|
||||
|
|
@ -21,40 +34,40 @@ async function fetchCommand<T>(command: () => Promise<T>): Promise<T> {
|
|||
}
|
||||
// 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<TQueryFnData, TSelected = TQueryFnData>(
|
||||
cacheKey: CommandCacheKeys,
|
||||
export function useCommand<TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(
|
||||
cacheKey: TQueryKey,
|
||||
command: () => Promise<TQueryFnData>,
|
||||
options?: Omit<
|
||||
UndefinedInitialDataOptions<TQueryFnData, Error, TSelected, CommandCacheKeys | []>,
|
||||
UndefinedInitialDataOptions<TQueryFnData, TError, TData, TQueryKey>,
|
||||
'queryKey' | 'queryFn'
|
||||
>,
|
||||
): UseQueryResult<TSelected, Error> {
|
||||
return useQuery<TQueryFnData, Error, TSelected, CommandCacheKeys | []>({
|
||||
queryKey: cacheKey[0] === false ? [] : Array.isArray(cacheKey) ? cacheKey : [cacheKey],
|
||||
): UseQueryResult<TData, TError> {
|
||||
return useQuery<TQueryFnData, TError, TData, TQueryKey>({
|
||||
queryKey: cacheKey,
|
||||
queryFn: () => fetchCommand(command),
|
||||
enabled: true,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
export function useCommandSuspense<TQueryFnData, TSelected = TQueryFnData>(
|
||||
cacheKey: CommandCacheKeys,
|
||||
export function useCommandSuspense<TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(
|
||||
cacheKey: TQueryKey,
|
||||
command: () => Promise<TQueryFnData>,
|
||||
options?: Omit<
|
||||
UseSuspenseQueryOptions<TQueryFnData, Error, TSelected, CommandCacheKeys | []>,
|
||||
UseSuspenseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
|
||||
'queryKey' | 'queryFn'
|
||||
>,
|
||||
): UseSuspenseQueryResult<TSelected, Error> {
|
||||
return useSuspenseQuery<TQueryFnData, Error, TSelected, CommandCacheKeys | []>({
|
||||
queryKey: cacheKey[0] === false ? [] : Array.isArray(cacheKey) ? cacheKey : [cacheKey],
|
||||
): UseSuspenseQueryResult<TData, TError> {
|
||||
return useSuspenseQuery<TQueryFnData, TError, TData, TQueryKey>({
|
||||
queryKey: cacheKey,
|
||||
queryFn: () => fetchCommand(command),
|
||||
...options,
|
||||
});
|
||||
|
|
@ -62,7 +75,7 @@ export function useCommandSuspense<TQueryFnData, TSelected = TQueryFnData>(
|
|||
|
||||
export function useCommandMut<
|
||||
TData,
|
||||
TError = Error,
|
||||
TError = DefaultError,
|
||||
TVariables = void,
|
||||
TContext = unknown,
|
||||
>(
|
||||
|
|
|
|||
23
packages/web_common/src/utils/error.ts
Normal file
23
packages/web_common/src/utils/error.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
export interface AppError {
|
||||
data: string | AppError;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export function isLauncherError<TErr = AppError>(error: unknown): error is TErr {
|
||||
return typeof error === 'object'
|
||||
&& error !== null
|
||||
&& 'data' in error
|
||||
&& 'type' in error;
|
||||
}
|
||||
|
||||
export function getMessageFromError<T extends AppError>(error: T): string;
|
||||
export function getMessageFromError<T extends AppError>(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);
|
||||
}
|
||||
|
|
@ -1,2 +1,3 @@
|
|||
export * from './dev';
|
||||
export * from './error';
|
||||
export * from './nativeExperience';
|
||||
|
|
|
|||
126
pnpm-lock.yaml
generated
126
pnpm-lock.yaml
generated
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue