mirror of https://github.com/buster-so/buster.git
create persister
This commit is contained in:
parent
9b9b0f0bc5
commit
7e5344ccc6
|
@ -2,6 +2,7 @@
|
|||
"name": "@buster-app/web-tss",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev": "vite dev --port 3000",
|
||||
"dev:fast": "pnpm run build && pnpm run start",
|
||||
|
@ -61,14 +62,18 @@
|
|||
"@tailwindcss/vite": "^4.1.12",
|
||||
"@tanstack/db": "^0.1.3",
|
||||
"@tanstack/match-sorter-utils": "^8.19.4",
|
||||
"@tanstack/query-async-storage-persister": "^5.85.3",
|
||||
"@tanstack/query-db-collection": "0.1.1",
|
||||
"@tanstack/query-sync-storage-persister": "^5.85.3",
|
||||
"@tanstack/react-db": "0.1.3",
|
||||
"@tanstack/react-devtools": "^0.4.0",
|
||||
"@tanstack/react-form": "^1.19.2",
|
||||
"@tanstack/react-query": "^5.85.3",
|
||||
"@tanstack/react-query-devtools": "^5.85.3",
|
||||
"@tanstack/react-query-persist-client": "^5.85.3",
|
||||
"@tanstack/react-router": "^1.131.14",
|
||||
"@tanstack/react-router-devtools": "^1.131.14",
|
||||
"@tanstack/react-router-ssr-query": "^1.131.14",
|
||||
"@tanstack/react-router-with-query": "^1.130.17",
|
||||
"@tanstack/react-start": "^1.131.15",
|
||||
"@tanstack/react-store": "^0.7.3",
|
||||
|
|
|
@ -78,42 +78,39 @@ const topItems: ISidebarList = {
|
|||
const yourStuff: ISidebarGroup = {
|
||||
label: 'Your stuff',
|
||||
id: 'your-stuff',
|
||||
items: (
|
||||
[
|
||||
{
|
||||
label: 'Metrics',
|
||||
icon: <ASSET_ICONS.metrics />,
|
||||
route: { to: '/app/metrics' },
|
||||
id: '/app/metrics',
|
||||
preload: 'intent',
|
||||
preloadDelay: 1000,
|
||||
},
|
||||
{
|
||||
label: 'Dashboards',
|
||||
icon: <ASSET_ICONS.dashboards />,
|
||||
route: { to: '/app/dashboards' },
|
||||
id: '/app/dashboards/',
|
||||
preload: 'intent',
|
||||
preloadDelay: 1000,
|
||||
},
|
||||
{
|
||||
label: 'Collections',
|
||||
icon: <ASSET_ICONS.collections />,
|
||||
route: { to: '/app/collections' },
|
||||
id: '/app/collections/',
|
||||
preload: 'intent',
|
||||
preloadDelay: 1000,
|
||||
},
|
||||
{
|
||||
label: 'Reports',
|
||||
icon: <ASSET_ICONS.reports />,
|
||||
route: { to: '/app/reports' },
|
||||
id: '/app/reports/',
|
||||
preload: 'intent',
|
||||
show: process.env.NEXT_PUBLIC_ENABLE_REPORTS === 'true',
|
||||
},
|
||||
] satisfies (ISidebarItem & { show?: boolean })[]
|
||||
).filter((x) => x.show !== false),
|
||||
items: [
|
||||
{
|
||||
label: 'Metrics',
|
||||
icon: <ASSET_ICONS.metrics />,
|
||||
route: { to: '/app/metrics' },
|
||||
id: '/app/metrics',
|
||||
preload: 'intent',
|
||||
preloadDelay: 1000,
|
||||
},
|
||||
{
|
||||
label: 'Dashboards',
|
||||
icon: <ASSET_ICONS.dashboards />,
|
||||
route: { to: '/app/dashboards' },
|
||||
id: '/app/dashboards/',
|
||||
preload: 'intent',
|
||||
preloadDelay: 1000,
|
||||
},
|
||||
{
|
||||
label: 'Collections',
|
||||
icon: <ASSET_ICONS.collections />,
|
||||
route: { to: '/app/collections' },
|
||||
id: '/app/collections/',
|
||||
preload: 'intent',
|
||||
preloadDelay: 1000,
|
||||
},
|
||||
{
|
||||
label: 'Reports',
|
||||
icon: <ASSET_ICONS.reports />,
|
||||
route: { to: '/app/reports' },
|
||||
id: '/app/reports/',
|
||||
preload: 'intent',
|
||||
},
|
||||
] satisfies (ISidebarItem & { show?: boolean })[],
|
||||
};
|
||||
|
||||
const adminTools: ISidebarGroup = {
|
||||
|
@ -155,7 +152,10 @@ const tryGroup = (showInvitePeople: boolean): ISidebarGroup => ({
|
|||
id: 'leave-feedback',
|
||||
onClick: () => toggleContactSupportModal('feedback'),
|
||||
},
|
||||
].filter((x) => x.show !== false),
|
||||
].reduce((acc, { show, ...item }) => {
|
||||
if (show !== false) acc.push(item);
|
||||
return acc;
|
||||
}, [] as ISidebarItem[]),
|
||||
});
|
||||
|
||||
export const SidebarPrimary = React.memo(() => {
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import type { QueryClient } from '@tanstack/react-query';
|
||||
import type React from 'react';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { BusterStyleProvider } from './BusterStyles';
|
||||
import { QueryPersister } from './Query/QueryProvider';
|
||||
import {
|
||||
SupabaseContextProvider,
|
||||
type SupabaseContextType,
|
||||
} from './Supabase/SupabaseContextProvider';
|
||||
|
||||
// import type { UseSupabaseUserContextType } from '@/lib/supabase';
|
||||
// import { BusterAssetsProvider } from './Assets/BusterAssetsProvider';
|
||||
// import { AppLayoutProvider } from './BusterAppLayout';
|
||||
|
@ -21,15 +24,19 @@ import {
|
|||
// clearLog: false // clears the console per group of renders (default: false)
|
||||
// });
|
||||
|
||||
export const RootProviders: React.FC<PropsWithChildren<SupabaseContextType>> = ({
|
||||
type RootProvidersProps = PropsWithChildren<SupabaseContextType & { queryClient: QueryClient }>;
|
||||
|
||||
export const RootProviders: React.FC<RootProvidersProps> = ({
|
||||
children,
|
||||
user,
|
||||
accessToken,
|
||||
queryClient,
|
||||
}) => {
|
||||
return (
|
||||
<SupabaseContextProvider user={user} accessToken={accessToken}>
|
||||
<BusterStyleProvider>{children}</BusterStyleProvider>
|
||||
{/* <BusterReactQueryProvider>
|
||||
<QueryPersister queryClient={queryClient}>
|
||||
<SupabaseContextProvider user={user} accessToken={accessToken}>
|
||||
<BusterStyleProvider>{children}</BusterStyleProvider>
|
||||
{/* <BusterReactQueryProvider>
|
||||
<HydrationBoundary state={dehydrate(queryClient)}>
|
||||
<AppLayoutProvider>
|
||||
<BusterUserConfigProvider>
|
||||
|
@ -43,7 +50,8 @@ export const RootProviders: React.FC<PropsWithChildren<SupabaseContextType>> = (
|
|||
</AppLayoutProvider>
|
||||
</HydrationBoundary>
|
||||
</BusterReactQueryProvider> */}
|
||||
</SupabaseContextProvider>
|
||||
</SupabaseContextProvider>
|
||||
</QueryPersister>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import { isServer, type QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { PersistQueryClientProvider as TanstackPersistQueryClientProvider } from '@tanstack/react-query-persist-client';
|
||||
import React from 'react';
|
||||
import { persistOptions } from '@/integrations/tanstack-query/create-persister';
|
||||
import { userQueryKeys } from '../../api/query_keys/users';
|
||||
|
||||
export const QueryPersister = ({
|
||||
children,
|
||||
queryClient,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
queryClient: QueryClient;
|
||||
}) => {
|
||||
const [mounted, setMounted] = React.useState(false);
|
||||
|
||||
return (
|
||||
<TanstackPersistQueryClientProvider
|
||||
client={queryClient}
|
||||
persistOptions={persistOptions}
|
||||
onSuccess={() => {
|
||||
setMounted(true);
|
||||
}}
|
||||
>
|
||||
{mounted ? children : null}
|
||||
</TanstackPersistQueryClientProvider>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,60 @@
|
|||
import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister';
|
||||
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister';
|
||||
import { hashKey, isServer } from '@tanstack/react-query';
|
||||
import type { PersistQueryClientProviderProps } from '@tanstack/react-query-persist-client';
|
||||
import { dictionariesQueryKeys } from '@/api/query_keys/dictionaries';
|
||||
import { slackQueryKeys } from '@/api/query_keys/slack';
|
||||
import packageJson from '../../../package.json';
|
||||
|
||||
const buster = packageJson.version;
|
||||
export const PERSIST_TIME = 1000 * 60 * 60 * 24 * 3; // 3 days
|
||||
const PERSISTED_QUERIES = [slackQueryKeys.slackGetChannels.queryKey].map(hashKey);
|
||||
|
||||
export const PERMANENT_QUERIES = [
|
||||
dictionariesQueryKeys.getCurrencies.queryKey,
|
||||
dictionariesQueryKeys.colorPalettes.queryKey,
|
||||
].map(hashKey);
|
||||
|
||||
const ALL_PERSISTED_QUERIES = [...PERSISTED_QUERIES, ...PERMANENT_QUERIES];
|
||||
|
||||
const persisterAsync = createAsyncStoragePersister({
|
||||
key: 'buster-query-cache',
|
||||
storage: isServer ? undefined : window.localStorage,
|
||||
throttleTime: 1500, // 1.5 seconds,
|
||||
serialize: (client) => {
|
||||
/*
|
||||
* Make persisted queries appear stale on first load by setting the dataUpdatedAt to 1 (NOT 0)
|
||||
* This way the query will be refetched from the server when it is first mounted AND we
|
||||
* don't have to deal with the flash of stale data that would otherwise happen.
|
||||
*/
|
||||
for (const query of client.clientState.queries) {
|
||||
const isPermanentQuery = PERMANENT_QUERIES.includes(query.queryHash);
|
||||
if (!isPermanentQuery) {
|
||||
console.log('setting dataUpdatedAt to 1', query.queryHash);
|
||||
query.state.dataUpdatedAt = 1;
|
||||
}
|
||||
}
|
||||
return JSON.stringify(client);
|
||||
},
|
||||
});
|
||||
|
||||
export const persistOptions: PersistQueryClientProviderProps['persistOptions'] = {
|
||||
maxAge: PERSIST_TIME,
|
||||
dehydrateOptions: {
|
||||
shouldDehydrateQuery: (query) => {
|
||||
const isList =
|
||||
query.queryKey[1] === 'list' || query.queryKey[query.queryKey.length - 1] === 'list';
|
||||
|
||||
return isList || ALL_PERSISTED_QUERIES.includes(query.queryHash);
|
||||
},
|
||||
},
|
||||
hydrateOptions: {
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
initialDataUpdatedAt: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
buster,
|
||||
persister: persisterAsync,
|
||||
};
|
|
@ -1,6 +1,8 @@
|
|||
import type { User } from '@supabase/supabase-js';
|
||||
import type { QueryClient } from '@tanstack/react-query';
|
||||
import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client';
|
||||
import { createRouter as createTanstackRouter } from '@tanstack/react-router';
|
||||
import { setupRouterSsrQueryIntegration } from '@tanstack/react-router-ssr-query';
|
||||
import { routerWithQueryClient } from '@tanstack/react-router-with-query';
|
||||
import * as TanstackQuery from './integrations/tanstack-query/query-client';
|
||||
import { routeTree } from './routeTree.gen';
|
||||
|
@ -14,7 +16,7 @@ export interface AppRouterContext {
|
|||
export const createRouter = () => {
|
||||
const queryClient = TanstackQuery.getQueryClient();
|
||||
|
||||
return routerWithQueryClient(
|
||||
const router = routerWithQueryClient(
|
||||
createTanstackRouter({
|
||||
routeTree,
|
||||
context: { queryClient, user: null }, //context is defined in the root route
|
||||
|
@ -30,6 +32,15 @@ export const createRouter = () => {
|
|||
}),
|
||||
queryClient
|
||||
);
|
||||
|
||||
// setupRouterSsrQueryIntegration({
|
||||
// router,
|
||||
// queryClient,
|
||||
// // Disable auto-wrapping since we'll handle it ourselves
|
||||
// wrapQueryClient: false,
|
||||
// });
|
||||
|
||||
return router;
|
||||
};
|
||||
|
||||
// Register the router instance for type safety
|
||||
|
|
|
@ -10,16 +10,9 @@ import appCss from '../styles/styles.css?url';
|
|||
export const Route = createRootRouteWithContext<AppRouterContext>()({
|
||||
head: () => ({
|
||||
meta: [
|
||||
{
|
||||
charSet: 'utf-8',
|
||||
},
|
||||
{
|
||||
name: 'viewport',
|
||||
content: 'width=device-width, initial-scale=1',
|
||||
},
|
||||
{
|
||||
title: 'Buster',
|
||||
},
|
||||
{ charSet: 'utf-8' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
{ title: 'Buster' },
|
||||
],
|
||||
links: [{ rel: 'stylesheet', href: appCss }],
|
||||
}),
|
||||
|
@ -33,7 +26,7 @@ export const Route = createRootRouteWithContext<AppRouterContext>()({
|
|||
});
|
||||
|
||||
function RootDocument({ children }: { children: React.ReactNode }) {
|
||||
const { user, accessToken } = Route.useRouteContext();
|
||||
const { user, accessToken, queryClient } = Route.useRouteContext();
|
||||
|
||||
return (
|
||||
<html lang="en">
|
||||
|
@ -41,7 +34,7 @@ function RootDocument({ children }: { children: React.ReactNode }) {
|
|||
<HeadContent />
|
||||
</head>
|
||||
<body>
|
||||
<RootProviders user={user} accessToken={accessToken}>
|
||||
<RootProviders user={user} accessToken={accessToken} queryClient={queryClient}>
|
||||
{children}
|
||||
</RootProviders>
|
||||
<TanstackDevtools />
|
||||
|
|
398
pnpm-lock.yaml
398
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue