diff --git a/.gitignore b/.gitignore index 907c91f7b..652f563a3 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,8 @@ examples/*/*.lock /target prisma*.rs +playwright-report + /sdserver_data .spacedrive dev.db-journal diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 0a384195e..4f2ed4bb0 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -18,6 +18,7 @@ "@sd/client": "workspace:*", "@sd/interface": "workspace:*", "@sd/ui": "workspace:*", + "@tanstack/react-query": "^4.24.4", "@tauri-apps/api": "1.2.0", "react": "^18.2.0", "react-dom": "^18.2.0" diff --git a/apps/desktop/src/App.tsx b/apps/desktop/src/App.tsx index 04e979687..92c63dad1 100644 --- a/apps/desktop/src/App.tsx +++ b/apps/desktop/src/App.tsx @@ -1,13 +1,13 @@ import { loggerLink } from '@rspc/client'; import { tauriLink } from '@rspc/tauri'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { dialog, invoke, os, shell } from '@tauri-apps/api'; import { listen } from '@tauri-apps/api/event'; import { convertFileSrc } from '@tauri-apps/api/tauri'; import { useEffect } from 'react'; -import { getDebugState, hooks, queryClient } from '@sd/client'; +import { getDebugState, hooks } from '@sd/client'; import SpacedriveInterface, { OperatingSystem, Platform, PlatformProvider } from '@sd/interface'; -import { KeybindEvent } from '@sd/interface'; -import { ErrorPage } from '@sd/interface'; +import { KeybindEvent, ErrorPage } from '@sd/interface'; import '@sd/ui/style'; const client = hooks.createClient({ @@ -65,6 +65,8 @@ const platform: Platform = { openPath: (path) => shell.open(path) }; +const queryClient = new QueryClient(); + export default function App() { useEffect(() => { // This tells Tauri to show the current window because it's finished loading @@ -86,9 +88,12 @@ export default function App() { } return ( + // @ts-expect-error: Just a version mismatch - + + + ); diff --git a/apps/mobile/src/App.tsx b/apps/mobile/src/App.tsx index 81ddcf4b6..c3138b00a 100644 --- a/apps/mobile/src/App.tsx +++ b/apps/mobile/src/App.tsx @@ -1,6 +1,7 @@ import { BottomSheetModalProvider } from '@gorhom/bottom-sheet'; import { DefaultTheme, NavigationContainer, Theme } from '@react-navigation/native'; import { loggerLink } from '@rspc/client'; +import { QueryClient } from '@tanstack/react-query'; import dayjs from 'dayjs'; import advancedFormat from 'dayjs/plugin/advancedFormat'; import duration from 'dayjs/plugin/duration'; @@ -17,7 +18,6 @@ import { ClientContextProvider, LibraryContextProvider, getDebugState, - queryClient, rspc, useClientContext, useInvalidateQuery @@ -95,12 +95,15 @@ const client = rspc.createClient({ ] }); +const queryClient = new QueryClient(); + export default function App() { useEffect(() => { SplashScreen.hideAsync(); }, []); return ( + // @ts-expect-error: Version mismatch diff --git a/apps/mobile/src/components/dialog/CreateLibraryDialog.tsx b/apps/mobile/src/components/dialog/CreateLibraryDialog.tsx index b71768502..8604154d1 100644 --- a/apps/mobile/src/components/dialog/CreateLibraryDialog.tsx +++ b/apps/mobile/src/components/dialog/CreateLibraryDialog.tsx @@ -1,5 +1,6 @@ +import { useQueryClient } from '@tanstack/react-query'; import { useState } from 'react'; -import { queryClient, useBridgeMutation } from '@sd/client'; +import { useBridgeMutation } from '@sd/client'; import { Input } from '~/components/form/Input'; import Dialog from '~/components/layout/Dialog'; import { currentLibraryStore } from '~/utils/nav'; @@ -12,6 +13,7 @@ type Props = { // TODO: Move to a Modal component const CreateLibraryDialog = ({ children, onSubmit, disableBackdropClose }: Props) => { + const queryClient = useQueryClient(); const [libName, setLibName] = useState(''); const [isOpen, setIsOpen] = useState(false); diff --git a/apps/mobile/src/components/explorer/sections/FavoriteButton.tsx b/apps/mobile/src/components/explorer/sections/FavoriteButton.tsx index d3353a0cc..6ed18f47f 100644 --- a/apps/mobile/src/components/explorer/sections/FavoriteButton.tsx +++ b/apps/mobile/src/components/explorer/sections/FavoriteButton.tsx @@ -1,7 +1,8 @@ import { Heart } from 'phosphor-react-native'; import { useState } from 'react'; import { Pressable, PressableProps } from 'react-native'; -import { Object as SDObject, queryClient, useLibraryMutation } from '@sd/client'; +import { Object as SDObject, useLibraryMutation } from '@sd/client'; +import { useQueryClient } from '@tanstack/react-query'; type Props = { data: SDObject; @@ -9,6 +10,7 @@ type Props = { }; const FavoriteButton = (props: Props) => { + const queryClient = useQueryClient(); const [favorite, setFavorite] = useState(props.data.favorite); const { mutate: toggleFavorite, isLoading } = useLibraryMutation('files.setFavorite', { diff --git a/apps/mobile/src/components/modal/confirm-modals/DeleteLibraryModal.tsx b/apps/mobile/src/components/modal/confirm-modals/DeleteLibraryModal.tsx index 26a5f64ca..b7f04b7c8 100644 --- a/apps/mobile/src/components/modal/confirm-modals/DeleteLibraryModal.tsx +++ b/apps/mobile/src/components/modal/confirm-modals/DeleteLibraryModal.tsx @@ -1,6 +1,7 @@ +import { useQueryClient } from '@tanstack/react-query'; +import { useBridgeMutation } from '@sd/client'; import { useRef } from 'react'; -import { queryClient, useBridgeMutation } from '@sd/client'; -import { ConfirmModal, ModalRef } from '~/components/layout/Modal'; +import { ModalRef, ConfirmModal } from '~/components/layout/Modal'; type Props = { libraryUuid: string; @@ -9,6 +10,7 @@ type Props = { }; const DeleteLibraryModal = ({ trigger, onSubmit, libraryUuid }: Props) => { + const queryClient = useQueryClient(); const modalRef = useRef(null); const { mutate: deleteLibrary, isLoading: deleteLibLoading } = useBridgeMutation( diff --git a/apps/mobile/src/components/modal/tag/CreateTagModal.tsx b/apps/mobile/src/components/modal/tag/CreateTagModal.tsx index 17c6aa5bb..aca5ec983 100644 --- a/apps/mobile/src/components/modal/tag/CreateTagModal.tsx +++ b/apps/mobile/src/components/modal/tag/CreateTagModal.tsx @@ -1,15 +1,17 @@ import { forwardRef, useEffect, useState } from 'react'; import { Pressable, Text, View } from 'react-native'; import ColorPicker from 'react-native-wheel-color-picker'; -import { queryClient, useLibraryMutation } from '@sd/client'; +import { useLibraryMutation } from '@sd/client'; import { FadeInAnimation } from '~/components/animation/layout'; import { Input } from '~/components/form/Input'; import { Modal, ModalRef } from '~/components/layout/Modal'; import { Button } from '~/components/primitive/Button'; import useForwardedRef from '~/hooks/useForwardedRef'; import { tw, twStyle } from '~/lib/tailwind'; +import { useQueryClient } from '@tanstack/react-query'; const CreateTagModal = forwardRef((_, ref) => { + const queryClient = useQueryClient(); const modalRef = useForwardedRef(ref); const [tagName, setTagName] = useState(''); diff --git a/apps/mobile/src/components/modal/tag/UpdateTagModal.tsx b/apps/mobile/src/components/modal/tag/UpdateTagModal.tsx index 3cf50ac1d..703fe4967 100644 --- a/apps/mobile/src/components/modal/tag/UpdateTagModal.tsx +++ b/apps/mobile/src/components/modal/tag/UpdateTagModal.tsx @@ -1,6 +1,6 @@ import { forwardRef, useEffect, useState } from 'react'; -import { ColorValue, Pressable, Text, View } from 'react-native'; -import { Tag, queryClient, useLibraryMutation } from '@sd/client'; +import { Pressable, Text, View } from 'react-native'; +import { Tag, useLibraryMutation } from '@sd/client'; import { FadeInAnimation } from '~/components/animation/layout'; import ColorPicker from '~/components/form/ColorPicker'; import { Input } from '~/components/form/Input'; @@ -8,6 +8,7 @@ import { Modal, ModalRef } from '~/components/layout/Modal'; import { Button } from '~/components/primitive/Button'; import useForwardedRef from '~/hooks/useForwardedRef'; import { tw, twStyle } from '~/lib/tailwind'; +import { useQueryClient } from '@tanstack/react-query'; type Props = { tag: Tag; @@ -15,6 +16,7 @@ type Props = { }; const UpdateTagModal = forwardRef((props, ref) => { + const queryClient = useQueryClient(); const modalRef = useForwardedRef(ref); const [tagName, setTagName] = useState(props.tag.name!); diff --git a/apps/web/package.json b/apps/web/package.json index e94d515eb..7fd03b7b0 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -6,6 +6,7 @@ "dev": "vite", "build": "vite build", "preview": "vite preview", + "test": "VITE_SD_DEMO_MODE=true playwright test", "typecheck": "tsc -b" }, "dependencies": { @@ -18,6 +19,7 @@ "react-dom": "^18.2.0" }, "devDependencies": { + "@playwright/test": "^1.30.0", "@sd/config": "workspace:*", "@sd/ui": "workspace:*", "@types/react": "^18.0.21", diff --git a/apps/web/playwright.config.ts b/apps/web/playwright.config.ts new file mode 100644 index 000000000..221c95d16 --- /dev/null +++ b/apps/web/playwright.config.ts @@ -0,0 +1,60 @@ +import { defineConfig, devices } from '@playwright/test'; + +export default defineConfig({ + testDir: './tests', + timeout: 30 * 1000, + expect: { + timeout: 5000 + }, + fullyParallel: true, + forbidOnly: !!process.env.CI, + retries: process.env.CI ? 2 : 0, + workers: process.env.CI ? 1 : undefined, + reporter: 'html', + webServer: { + command: 'pnpm build && pnpm preview', + port: 4173 + }, + use: { + actionTimeout: 0, + trace: 'on-first-retry' + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] } + } + + // { + // name: 'firefox', + // use: { ...devices['Desktop Firefox'] } + // }, + + // { + // name: 'webkit', + // use: { ...devices['Desktop Safari'] } + // } + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { channel: 'chrome' }, + // }, + ] +}); diff --git a/apps/web/screenshots/overview-dark.png b/apps/web/screenshots/overview-dark.png new file mode 100644 index 000000000..91b0a3b20 Binary files /dev/null and b/apps/web/screenshots/overview-dark.png differ diff --git a/apps/web/screenshots/overview-light.png b/apps/web/screenshots/overview-light.png new file mode 100644 index 000000000..4d3f6c5db Binary files /dev/null and b/apps/web/screenshots/overview-light.png differ diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx index 6919cf8eb..18ac2b387 100644 --- a/apps/web/src/App.tsx +++ b/apps/web/src/App.tsx @@ -1,7 +1,9 @@ import { createWSClient, loggerLink, wsLink } from '@rspc/client'; +import { QueryClient, QueryClientProvider, hydrate } from '@tanstack/react-query'; import { useEffect } from 'react'; -import { getDebugState, hooks, queryClient } from '@sd/client'; +import { getDebugState, hooks } from '@sd/client'; import SpacedriveInterface, { Platform, PlatformProvider } from '@sd/interface'; +import demoData from './demoData.json'; globalThis.isDev = import.meta.env.DEV; @@ -34,17 +36,38 @@ const platform: Platform = { locationLocalId )}/${encodeURIComponent(filePathId)}`, openLink: (url) => window.open(url, '_blank')?.focus(), - demoMode: true + demoMode: import.meta.env.VITE_SD_DEMO_MODE === 'true' }; +const queryClient = new QueryClient({ + defaultOptions: { + queries: import.meta.env.VITE_SD_DEMO_MODE + ? { + refetchOnWindowFocus: false, + staleTime: Infinity, + cacheTime: Infinity, + networkMode: 'offlineFirst', + enabled: false + } + : undefined + // TODO: Mutations can't be globally disable which is annoying! + } +}); + function App() { useEffect(() => window.parent.postMessage('spacedrive-hello', '*'), []); + if (import.meta.env.VITE_SD_DEMO_MODE === 'true') { + hydrate(queryClient, demoData); + } + return (
- + + +
diff --git a/apps/web/src/demoData.json b/apps/web/src/demoData.json new file mode 100644 index 000000000..4bf298eb5 --- /dev/null +++ b/apps/web/src/demoData.json @@ -0,0 +1,182 @@ +{ + "mutations": [], + "queries": [ + { + "state": { + "data": [ + { + "uuid": "dc1c41b9-65c6-4a9d-a418-79e628b3ac59", + "config": { "version": "0.1.0", "name": "My Library", "description": "" } + } + ], + "dataUpdateCount": 2, + "dataUpdatedAt": 1675912735380, + "error": null, + "errorUpdateCount": 0, + "errorUpdatedAt": 0, + "fetchFailureCount": 0, + "fetchFailureReason": null, + "fetchMeta": {}, + "isInvalidated": false, + "status": "success", + "fetchStatus": "fetching" + }, + "queryKey": ["library.list"], + "queryHash": "[\"library.list\"]" + }, + { + "state": { + "data": "macOS", + "dataUpdateCount": 0, + "dataUpdatedAt": 1675912734876, + "error": null, + "errorUpdateCount": 0, + "errorUpdatedAt": 0, + "fetchFailureCount": 0, + "fetchFailureReason": null, + "fetchMeta": null, + "isInvalidated": false, + "status": "success", + "fetchStatus": "idle" + }, + "queryKey": ["_tauri", "platform"], + "queryHash": "[\"_tauri\",\"platform\"]" + }, + { + "state": { + "data": [], + "dataUpdateCount": 1, + "dataUpdatedAt": 1675912735051, + "error": null, + "errorUpdateCount": 0, + "errorUpdatedAt": 0, + "fetchFailureCount": 0, + "fetchFailureReason": null, + "fetchMeta": {}, + "isInvalidated": false, + "status": "success", + "fetchStatus": "fetching" + }, + "queryKey": [ + "locations.list", + { "library_id": "dc1c41b9-65c6-4a9d-a418-79e628b3ac59", "arg": null } + ], + "queryHash": "[\"locations.list\",{\"arg\":null,\"library_id\":\"dc1c41b9-65c6-4a9d-a418-79e628b3ac59\"}]" + }, + { + "state": { + "data": [], + "dataUpdateCount": 1, + "dataUpdatedAt": 1675912735057, + "error": null, + "errorUpdateCount": 0, + "errorUpdatedAt": 0, + "fetchFailureCount": 0, + "fetchFailureReason": null, + "fetchMeta": {}, + "isInvalidated": false, + "status": "success", + "fetchStatus": "fetching" + }, + "queryKey": [ + "tags.list", + { "library_id": "dc1c41b9-65c6-4a9d-a418-79e628b3ac59", "arg": null } + ], + "queryHash": "[\"tags.list\",{\"arg\":null,\"library_id\":\"dc1c41b9-65c6-4a9d-a418-79e628b3ac59\"}]" + }, + { + "state": { + "data": false, + "dataUpdateCount": 1, + "dataUpdatedAt": 1675912735057, + "error": null, + "errorUpdateCount": 0, + "errorUpdatedAt": 0, + "fetchFailureCount": 0, + "fetchFailureReason": null, + "fetchMeta": {}, + "isInvalidated": false, + "status": "success", + "fetchStatus": "fetching" + }, + "queryKey": [ + "jobs.isRunning", + { "library_id": "dc1c41b9-65c6-4a9d-a418-79e628b3ac59", "arg": null } + ], + "queryHash": "[\"jobs.isRunning\",{\"arg\":null,\"library_id\":\"dc1c41b9-65c6-4a9d-a418-79e628b3ac59\"}]" + }, + { + "state": { + "data": { "version": "0.1.0", "commit": "07401ac0" }, + "dataUpdateCount": 1, + "dataUpdatedAt": 1675912735057, + "error": null, + "errorUpdateCount": 0, + "errorUpdatedAt": 0, + "fetchFailureCount": 0, + "fetchFailureReason": null, + "fetchMeta": {}, + "isInvalidated": false, + "status": "success", + "fetchStatus": "fetching" + }, + "queryKey": ["buildInfo"], + "queryHash": "[\"buildInfo\"]" + }, + { + "state": { + "data": { + "version": "0.1.0", + "id": "afa03a65-861e-489e-918b-dac0252fe40c", + "name": "Oscars-MBP-2.lan", + "p2p_port": null, + "data_path": "/Users/oscar/Desktop/sd-ui-testing/sdserver_data" + }, + "dataUpdateCount": 1, + "dataUpdatedAt": 1675912735057, + "error": null, + "errorUpdateCount": 0, + "errorUpdatedAt": 0, + "fetchFailureCount": 0, + "fetchFailureReason": null, + "fetchMeta": {}, + "isInvalidated": false, + "status": "success", + "fetchStatus": "fetching" + }, + "queryKey": ["nodeState"], + "queryHash": "[\"nodeState\"]" + }, + { + "state": { + "data": { + "id": 1, + "date_captured": "2023-02-09T03:18:55.378+00:00", + "total_object_count": 0, + "library_db_size": "128", + "total_bytes_used": "0", + "total_bytes_capacity": "994662584320", + "total_unique_bytes": "0", + "total_bytes_free": "170520260608", + "preview_media_bytes": "0" + }, + "dataUpdateCount": 1, + "dataUpdatedAt": 1675912735381, + "error": null, + "errorUpdateCount": 0, + "errorUpdatedAt": 0, + "fetchFailureCount": 0, + "fetchFailureReason": null, + "fetchMeta": {}, + "isInvalidated": false, + "status": "success", + "fetchStatus": "fetching" + }, + "queryKey": [ + "library.getStatistics", + { "library_id": "dc1c41b9-65c6-4a9d-a418-79e628b3ac59", "arg": null } + ], + "queryHash": "[\"library.getStatistics\",{\"arg\":null,\"library_id\":\"dc1c41b9-65c6-4a9d-a418-79e628b3ac59\"}]" + } + ] +} diff --git a/apps/web/src/index.tsx b/apps/web/src/index.tsx index d965b4ff7..200fbbcae 100644 --- a/apps/web/src/index.tsx +++ b/apps/web/src/index.tsx @@ -2,6 +2,7 @@ import React, { Suspense } from 'react'; import ReactDOM from 'react-dom/client'; import '@sd/ui/style'; +import '~/patches'; // THIS MUST GO BEFORE importing the App import '~/patches'; import App from './App'; diff --git a/apps/web/tests/screenshots.test.ts b/apps/web/tests/screenshots.test.ts new file mode 100644 index 000000000..46e423b22 --- /dev/null +++ b/apps/web/tests/screenshots.test.ts @@ -0,0 +1,13 @@ +import { test } from '@playwright/test'; + +test('dark screenshot', async ({ page }) => { + await page.emulateMedia({ colorScheme: 'dark' }); + await page.goto('/'); + await page.screenshot({ path: 'screenshots/overview-dark.png', fullPage: true }); +}); + +test('light screenshot', async ({ page }) => { + await page.emulateMedia({ colorScheme: 'light' }); + await page.goto('/'); + await page.screenshot({ path: 'screenshots/overview-light.png', fullPage: true }); +}); diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json index 3f7f1295b..e45eb13df 100644 --- a/apps/web/tsconfig.json +++ b/apps/web/tsconfig.json @@ -4,7 +4,7 @@ "rootDir": "src", "declarationDir": "dist" }, - "include": ["src"], + "include": ["src", "src/demoData.json"], "references": [ { "path": "../../packages/interface" diff --git a/packages/client/src/rspc.ts b/packages/client/src/rspc.ts index 54a2bba0a..e2450ed72 100644 --- a/packages/client/src/rspc.ts +++ b/packages/client/src/rspc.ts @@ -1,6 +1,5 @@ import { ProcedureDef } from '@rspc/client'; import { internal_createReactHooksFactory } from '@rspc/react'; -import { QueryClient } from '@tanstack/react-query'; import { LibraryArgs, Procedures } from './core'; import { currentLibraryCache } from './hooks'; import { normiCustomHooks } from './normi'; @@ -70,7 +69,6 @@ const libraryHooks = hooks.createHooks< } }); -export const queryClient = new QueryClient(); export const rspc = hooks.createHooks(); export const useBridgeQuery = nonLibraryHooks.useQuery; diff --git a/packages/interface/src/App.tsx b/packages/interface/src/App.tsx index 6da5b55f8..12f12ecfd 100644 --- a/packages/interface/src/App.tsx +++ b/packages/interface/src/App.tsx @@ -4,15 +4,15 @@ import { init } from '@sentry/browser'; import '@fontsource/inter/variable.css'; -import { QueryClientProvider, defaultContext } from '@tanstack/react-query'; +import { defaultContext, QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import dayjs from 'dayjs'; import advancedFormat from 'dayjs/plugin/advancedFormat'; import duration from 'dayjs/plugin/duration'; import relativeTime from 'dayjs/plugin/relativeTime'; import { ErrorBoundary } from 'react-error-boundary'; -import { MemoryRouter } from 'react-router-dom'; -import { queryClient, useDebugState } from '@sd/client'; +import { BrowserRouter, MemoryRouter } from 'react-router-dom'; +import { useDebugState } from '@sd/client'; import { Dialogs } from '@sd/ui'; import { AppRouter } from './AppRouter'; import { ErrorFallback } from './ErrorFallback'; @@ -29,16 +29,15 @@ init({ integrations: [new HttpContextIntegration(), new DedupeIntegration()] }); -export default function SpacedriveInterface() { +export default function SpacedriveInterface({ router }: { router: 'memory' | 'browser' }) { + const Router = router === 'memory' ? MemoryRouter : BrowserRouter; return ( - - - - - - - + + + + + ); } diff --git a/packages/interface/src/components/layout/Sidebar.tsx b/packages/interface/src/components/layout/Sidebar.tsx index 6f40a27c0..83c3a02f7 100644 --- a/packages/interface/src/components/layout/Sidebar.tsx +++ b/packages/interface/src/components/layout/Sidebar.tsx @@ -1,3 +1,4 @@ +import { useQueryClient } from '@tanstack/react-query'; import clsx from 'clsx'; import { ArchiveBox, @@ -229,6 +230,7 @@ function IsRunningJob() { } function DebugPanel() { + const queryClient = useQueryClient(); const buildInfo = useBridgeQuery(['buildInfo']); const nodeState = useBridgeQuery(['nodeState']); const debugState = useDebugState(); @@ -289,6 +291,18 @@ function DebugPanel() { Enabled +
+ +
{/* {platform.showDevtools && ( =14'} + hasBin: true + dependencies: + '@types/node': 18.11.18 + playwright-core: 1.30.0 + dev: true + /@pmmmwh/react-refresh-webpack-plugin/0.5.10_ohj47mxwagpoxvu7nhhwxzphqm: resolution: {integrity: sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==} engines: {node: '>= 10.13'} @@ -7639,6 +7652,24 @@ packages: react-dom: 18.2.0_react@18.2.0 use-sync-external-store: 1.2.0_react@18.2.0 + /@tanstack/react-query/4.24.4_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-RpaS/3T/a3pHuZJbIAzAYRu+1nkp+/enr9hfRXDS/mojwx567UiMksoqW4wUFWlwIvWTXyhot2nbIipTKEg55Q==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-native: '*' + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + dependencies: + '@tanstack/query-core': 4.24.4 + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + use-sync-external-store: 1.2.0_react@18.2.0 + dev: false + /@tanstack/react-query/4.24.4_tj3nonr5gneraukzjkxpsiy7yu: resolution: {integrity: sha512-RpaS/3T/a3pHuZJbIAzAYRu+1nkp+/enr9hfRXDS/mojwx567UiMksoqW4wUFWlwIvWTXyhot2nbIipTKEg55Q==} peerDependencies: @@ -8394,7 +8425,7 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.19.6_@babel+core@7.20.12 magic-string: 0.26.7 react-refresh: 0.14.0 - vite: 4.0.4_@types+node@18.11.18 + vite: 4.0.4_sass@1.57.1 transitivePeerDependencies: - supports-color @@ -16686,6 +16717,12 @@ packages: dependencies: find-up: 3.0.0 + /playwright-core/1.30.0: + resolution: {integrity: sha512-7AnRmTCf+GVYhHbLJsGUtskWTE33SwMZkybJ0v6rqR1boxq2x36U7p1vDRV7HO2IwTZgmycracLxPEJI49wu4g==} + engines: {node: '>=14'} + hasBin: true + dev: true + /plist/3.0.6: resolution: {integrity: sha512-WiIVYyrp8TD4w8yCvyeIr+lkmrGRd5u0VbRnU+tP/aRLxP/YadJUYOMZJ/6hIa3oUyVCsycXvtNRgd5XBJIbiA==} engines: {node: '>=6'} @@ -21023,7 +21060,7 @@ packages: dependencies: '@rollup/pluginutils': 5.0.2 '@svgr/core': 6.5.1 - vite: 4.0.4_@types+node@18.11.18 + vite: 4.0.4_sass@1.57.1 transitivePeerDependencies: - rollup - supports-color @@ -21119,6 +21156,7 @@ packages: rollup: 3.10.0 optionalDependencies: fsevents: 2.3.2 + dev: true /vite/4.0.4_ovmyjmuuyckt3r3gpaexj2onji: resolution: {integrity: sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==} @@ -21186,7 +21224,6 @@ packages: sass: 1.57.1 optionalDependencies: fsevents: 2.3.2 - dev: true /vlq/1.0.1: resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==}