Rendering improvements, remove unused

This commit is contained in:
Jackson Harper 2024-08-13 13:29:57 +08:00
parent 742772fdb7
commit d51aed5b7c
12 changed files with 111 additions and 476 deletions

View file

@ -1,6 +1,7 @@
import Link from 'next/link'
import { useRouter } from 'next/router'
import { DEFAULT_HOME_PATH } from '../../../lib/navigations'
import { Box } from '../LayoutPrimitives'
export type OmnivoreLogoBaseProps = {
color?: string
href?: string
@ -9,13 +10,8 @@ export type OmnivoreLogoBaseProps = {
}
export function OmnivoreLogoBase(props: OmnivoreLogoBaseProps): JSX.Element {
const href = props.href || '/home'
const router = useRouter()
return (
<Link
passHref
href={href}
<Box
style={{
textDecoration: 'none',
display: 'flex',
@ -38,6 +34,6 @@ export function OmnivoreLogoBase(props: OmnivoreLogoBaseProps): JSX.Element {
aria-label="Omnivore logo"
>
{props.children}
</Link>
</Box>
)
}

View file

@ -8,8 +8,6 @@ import { Box, HStack, SpanBox, VStack } from '../../elements/LayoutPrimitives'
import { StyledText } from '../../elements/StyledText'
import { styled, theme } from '../../tokens/stitches.config'
import { SettingsLayout } from '../SettingsLayout'
import { usePersistedState } from '../../../lib/hooks/usePersistedState'
import { FeatureHelpBox } from '../../elements/FeatureHelpBox'
// Styles
export const Header = styled(Box, {
@ -26,8 +24,6 @@ type SettingsTableProps = {
createTitle?: string
createAction?: () => void
suggestionInfo: SuggestionInfo
children: React.ReactNode
}
@ -63,16 +59,6 @@ type MoreOptionsProps = {
onEdit?: () => void
}
type SuggestionInfo = {
title: string
message: string
docs: string
key: string
CTAText?: string
onClickCTA?: () => void
}
const MoreOptions = (props: MoreOptionsProps) => (
<Dropdown
align={'end'}
@ -294,11 +280,6 @@ const CreateButton = (props: CreateButtonProps): JSX.Element => {
}
export const SettingsTable = (props: SettingsTableProps): JSX.Element => {
const [showSuggestion, setShowSuggestion] = usePersistedState<boolean>({
key: props.suggestionInfo.key,
initialValue: !!props.suggestionInfo,
})
return (
<SettingsLayout>
<Toaster
@ -327,19 +308,6 @@ export const SettingsTable = (props: SettingsTableProps): JSX.Element => {
},
}}
>
{props.suggestionInfo && showSuggestion && (
<FeatureHelpBox
helpTitle={props.suggestionInfo.title}
helpMessage={props.suggestionInfo.message}
docsMessage={'Read the Docs'}
docsDestination={props.suggestionInfo.docs}
onDismiss={() => {
setShowSuggestion(false)
}}
helpCTAText={props.suggestionInfo.CTAText}
onClickCTA={props.suggestionInfo.onClickCTA}
/>
)}
<Box
css={{
width: '100%',

View file

@ -32,6 +32,7 @@
"@radix-ui/react-switch": "^1.0.1",
"@sentry/nextjs": "^7.42.0",
"@stitches/react": "^1.2.5",
"@tanstack/query-async-storage-persister": "^5.51.21",
"@tanstack/query-sync-storage-persister": "^5.51.21",
"@tanstack/react-query": "^5.51.21",
"@tanstack/react-query-persist-client": "^5.51.21",
@ -111,4 +112,4 @@
"volta": {
"extends": "../../package.json"
}
}
}

View file

@ -5,6 +5,7 @@ import type { AppProps } from 'next/app'
import { IdProvider } from '@radix-ui/react-id'
import { NextRouter, useRouter } from 'next/router'
import { ReactNode, useEffect, useState } from 'react'
import { HydrationBoundary } from '@tanstack/react-query'
import TopBarProgress from 'react-topbar-progress-indicator'
import {
KBarProvider,
@ -23,7 +24,7 @@ import { updateTheme } from '../lib/themeUpdater'
import { ThemeId } from '../components/tokens/stitches.config'
import { posthog } from 'posthog-js'
import { GoogleReCaptchaProvider } from '@google-recaptcha/react'
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister'
import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { persistQueryClient } from '@tanstack/react-query-persist-client'
import React from 'react'
@ -31,7 +32,7 @@ import React from 'react'
const queryClient = new QueryClient()
if (typeof window !== 'undefined') {
const localStoragePersister = createSyncStoragePersister({
const localStoragePersister = createAsyncStoragePersister({
storage: window.localStorage,
})
@ -44,7 +45,7 @@ if (typeof window !== 'undefined') {
shouldDehydrateQuery: ({ queryKey }) => {
// Don't cache the library items in local storage
const [firstKey] = queryKey
return firstKey !== 'library-items'
return firstKey !== 'library-items' && firstKey !== 'shortcuts'
},
},
})

View file

@ -120,21 +120,6 @@ export default function Api(): JSX.Element {
setExpiresAt(neverExpiresDate)
setAddModalOpen(true)
}}
suggestionInfo={{
title:
'Use API keys to Integrate Omnivore with other apps and services',
message:
'Create API keys to connect Omnivore to other apps such as Logseq and Obsidian or to query the API. Check out the integrations documentation for more info on connecting to Omnivore via the API.',
docs: 'https://docs.omnivore.app/integrations/api.html',
key: '--settings-apikeys-show-help',
CTAText: 'Create an API Key',
onClickCTA: () => {
onAdd()
setName('')
setExpiresAt(neverExpiresDate)
setAddModalOpen(true)
},
}}
>
{sortedApiKeys.length > 0 ? (
sortedApiKeys.map((apiKey, i) => {

View file

@ -76,17 +76,6 @@ export default function DiscoverFeedsSettings(): JSX.Element {
createAction={() => {
router.push('/settings/discover-feeds/add')
}}
suggestionInfo={{
title: 'Add RSS and Atom feeds to your Omnivore account',
message:
'When you add a new feed the last 24hrs of items, or at least one item will be added to your account. Feeds will be checked for updates every four hours, and new items will be added to your Following. You can also add feeds to your Library by checking the box below.',
docs: 'https://docs.omnivore.app/using/feeds.html',
key: '--settings-feeds-show-help',
CTAText: 'Add a feed',
onClickCTA: () => {
router.push('/settings/discover-feeds/add')
},
}}
>
{sortedFeeds.length === 0 ? (
<EmptySettingsRow text={isValidating ? '-' : 'No feeds subscribed'} />

View file

@ -80,9 +80,8 @@ function CopyTextButton(props: CopyTextButtonProps): JSX.Element {
export default function EmailsPage(): JSX.Element {
const { emailAddresses, revalidate, isValidating } =
useGetNewsletterEmailsQuery()
const [confirmDeleteEmailId, setConfirmDeleteEmailId] = useState<
undefined | string
>(undefined)
const [confirmDeleteEmailId, setConfirmDeleteEmailId] =
useState<undefined | string>(undefined)
applyStoredTheme()
@ -121,17 +120,6 @@ export default function EmailsPage(): JSX.Element {
headerTitle="Address"
createTitle="Create a new email address"
createAction={createEmail}
suggestionInfo={{
title: 'Subscribe to newsletters with an Omnivore Email Address',
message:
'Create an Omnivore email address and use it to subscribe to newsletters or send yourself documents. Newsletters and documents will be categorized and added to your library when we receive a message. View all received emails with the "Recently Received Emails" link at the bottom of this page.',
docs: 'https://docs.omnivore.app/using/inbox.html',
key: '--settings-emails-show-help',
CTAText: 'Create an email address',
onClickCTA: () => {
createEmail()
},
}}
>
{sortedEmailAddresses.length > 0 ? (
sortedEmailAddresses.map((email, i) => {

View file

@ -151,13 +151,11 @@ const ViewRecentEmailModal = (
export default function RecentEmails(): JSX.Element {
const { recentEmails, revalidate, isValidating } = useGetRecentEmailsQuery()
const [viewingEmailText, setViewingEmailText] = useState<
RecentEmail | undefined
>(undefined)
const [viewingEmailText, setViewingEmailText] =
useState<RecentEmail | undefined>(undefined)
const [viewingEmailHtml, setViewingEmailHtml] = useState<
RecentEmail | undefined
>(undefined)
const [viewingEmailHtml, setViewingEmailHtml] =
useState<RecentEmail | undefined>(undefined)
applyStoredTheme()
@ -170,14 +168,6 @@ export default function RecentEmails(): JSX.Element {
pageId="recent-emails"
pageInfoLink="https://docs.omnivore.app/using/inbox.html"
headerTitle="Recently Received Emails"
suggestionInfo={{
title:
'View original emails that have been recently received in your Omnivore inbox.',
message:
"Your 30 most recent emails are stored below. You can click on each email to view its original content or it's text content. If an email was not correctly classified as an article you can mark it as an article and it will be added to your library.",
docs: 'https://docs.omnivore.app/using/inbox.html',
key: '--settings-recent-emails-show-help',
}}
>
{sortedRecentEmails.length > 0 ? (
sortedRecentEmails.map((recentEmail: RecentEmail, i) => {

View file

@ -128,17 +128,6 @@ export default function Rss(): JSX.Element {
createAction={() => {
router.push('/settings/feeds/add')
}}
suggestionInfo={{
title: 'Add RSS and Atom feeds to your Omnivore account',
message:
'When you add a new feed the last 24hrs of items, or at least one item will be added to your account. Feeds will be checked for updates every four hours, and new items will be added to your Following. You can also add feeds to your Library by checking the box below.',
docs: 'https://docs.omnivore.app/using/feeds.html',
key: '--settings-feeds-show-help',
CTAText: 'Add a feed',
onClickCTA: () => {
router.push('/settings/feeds/add')
},
}}
>
{sortedSubscriptions.length === 0 ? (
<EmptySettingsRow text={isValidating ? '-' : 'No feeds subscribed'} />

View file

@ -10,6 +10,8 @@ import {
import { applyStoredTheme } from '../../lib/themeUpdater'
import { SettingsLayout } from '../../components/templates/SettingsLayout'
import { NavigationLayout } from '../../components/templates/NavigationLayout'
import { Toaster } from 'react-hot-toast'
import {
Box,
@ -38,185 +40,73 @@ import { useGetLabels } from '../../lib/networking/labels/useLabels'
import { useGetSavedSearches } from '../../lib/networking/savedsearches/useSavedSearches'
import {
Shortcut,
useGetShortcuts,
useResetShortcuts,
} from '../../lib/networking/shortcuts/useShortcuts'
import { ShortcutsTree } from '../../components/templates/ShortcutsTree'
import { TreeApi } from 'react-arborist'
type ListAction = 'RESET' | 'ADD_ITEM' | 'REMOVE_ITEM'
const SHORTCUTS_KEY = 'library-shortcuts'
export default function Shortcuts(): JSX.Element {
applyStoredTheme()
const [navMenuStyle, setNavMenuStyle] = usePersistedState<
'legacy' | 'shortcuts'
>({
key: 'library-nav-menu-style',
initialValue: 'legacy',
})
/**
* Use this function when you want to fix the "hydration" error in NextJS
* @param store
* @param callback
*/
export const useAsyncStore = <T, F>(
store: (callback: (state: T) => unknown) => unknown,
callback: (state: T) => F
) => {
const result = store(callback) as F
const [data, setData] = useState<F>()
const listReducer = (
state: { state: string; items: Shortcut[] },
action: {
type: ListAction
item?: Shortcut
useEffect(() => {
setData(typeof result === 'function' ? () => result : result)
}, [result])
return data
}
/**
* Use this function when you want to fix the "hydration" error in NextJS
* @param key
*/
export const useAsyncStoreValue = <K extends keyof ContextData>(key: K) => {
return useAsyncStore(yourContextNameHere, (state) => state[key])
}
function flattenShortcuts(shortcuts: Shortcut[]): string[] {
let result: string[] = []
for (const shortcut of shortcuts) {
if (shortcut.type !== 'folder') {
result.push(shortcut.id)
}
) => {
switch (action.type) {
case 'RESET': {
const itemStr = window['localStorage'].getItem(SHORTCUTS_KEY)
if (itemStr) {
try {
const parsed = JSON.parse(itemStr)
if (Array.isArray(parsed)) {
return { state: 'CURRENT', items: parsed as Shortcut[] }
}
} catch (err) {
console.log('error: ', err)
}
}
return { state: 'CURRENT', items: [] }
}
case 'ADD_ITEM': {
const item = action.item
if (!item) {
return state
}
const existing = state.items.find(
(existing) => existing.type == item.type && existing.id == item.id
)
if (existing) {
return state
}
state.items.push(item)
return { state: 'CURRENT', items: [...state.items] }
}
case 'REMOVE_ITEM': {
const item = action.item
if (!item) {
return state
}
const updated = state.items.filter((existing) => existing.id != item.id)
return { state: 'CURRENT', items: [...updated] }
}
default:
throw new Error('unknown action')
if (shortcut.children && shortcut.children?.length > 0) {
result = result.concat(flattenShortcuts(shortcut.children))
}
}
const [shortcuts, dispatchList] = useReducer(listReducer, {
state: 'INITIAL',
items: [],
})
return result
}
useEffect(() => {
try {
if (shortcuts.state == 'CURRENT') {
window['localStorage'].setItem(
SHORTCUTS_KEY,
JSON.stringify(shortcuts.items)
)
}
} catch (error) {
console.log('error": ', error)
export default function Shortcuts(): JSX.Element {
const { data: shortcuts, isLoading } = useGetShortcuts()
const shortcutIds = useMemo(() => {
if (shortcuts) {
return flattenShortcuts(shortcuts)
}
return []
}, [shortcuts])
useEffect(() => {
dispatchList({ type: 'RESET' })
}, [])
console.log('shortcutIds: ', shortcutIds)
return (
<SettingsLayout>
<Toaster
containerStyle={{
top: '5rem',
}}
/>
<VStack
css={{ width: '100%', height: '100%' }}
distribution="start"
alignment="center"
>
<VStack
css={{
padding: '24px',
width: '100%',
height: '100%',
gap: '25px',
minWidth: '300px',
maxWidth: '880px',
}}
>
<Box css={{}}>
<StyledText style="fixedHeadline" css={{ my: '6px' }}>
Shortcuts
</StyledText>
<StyledText css={{}}>
Use shortcuts to access your most important reads quickly. You can
create folders for your shortcuts, remove shortcuts, and select
items from your labels, subscriptions, and saved searches to be
added to your shortcuts.
</StyledText>
</Box>
<HStack
css={{
px: '10px',
pt: '2px',
height: '30px',
gap: '5px',
fontSize: '14px',
fontWeight: 'regular',
fontFamily: '$display',
color:
navMenuStyle !== 'shortcuts'
? '$thLibraryMenuSecondary'
: '$thLibraryMenuUnselected',
verticalAlign: 'middle',
borderRadius: '3px',
cursor: 'pointer',
'&:hover': {
backgroundColor: '$thBackground4',
},
}}
alignment="center"
distribution="start"
onClick={(event) => {
setNavMenuStyle(
navMenuStyle == 'shortcuts' ? 'legacy' : 'shortcuts'
)
event.preventDefault()
}}
></HStack>
<Box
css={{
py: '$3',
display: 'grid',
width: '100%',
gridAutoRows: 'auto',
borderRadius: '6px',
gridGap: '40px',
gridTemplateColumns: 'repeat(2, 1fr)',
'@mdDown': {
gridTemplateColumns: 'repeat(1, 1fr)',
},
}}
>
<SelectedItems
shortcuts={shortcuts.items}
dispatchList={dispatchList}
/>
<AvailableItems
shortcuts={shortcuts.items}
dispatchList={dispatchList}
/>
</Box>
</VStack>
</VStack>
{!isLoading &&
shortcutIds.map((shortcutId) => {
return <Box key={shortcutId}>{shortcutId}</Box>
})}
</SettingsLayout>
)
}
@ -228,8 +118,8 @@ export const SectionSeparator = styled(Separator, {
})
type ListProps = {
shortcuts: Shortcut[]
dispatchList: (arg: { type: ListAction; item?: Shortcut | undefined }) => void
shortcutIds: string[]
// dispatchList: (arg: { type: ListAction; item?: Shortcut | undefined }) => void
}
const AvailableItems = (props: ListProps): JSX.Element => {
@ -266,27 +156,29 @@ const AvailableItems = (props: ListProps): JSX.Element => {
const searchSelected = useCallback(
(search: SavedSearch) => {
return !!props.shortcuts.find((shortcut) => shortcut.id == search.id)
return !!props.shortcutIds.find((shortcutId) => shortcutId == search.id)
},
[props]
)
const labelSelected = useCallback(
(label: Label) => {
return !!props.shortcuts.find((shortcut) => shortcut.id == label.id)
return !!props.shortcutIds.find((shortcutId) => shortcutId == label.id)
},
[props]
)
const subscriptionSelected = useCallback(
(subscription: Subscription) => {
return !!props.shortcuts.find(
(shortcut) => shortcut.id == subscription.id
return !!props.shortcutIds.find(
(shortcutId) => shortcutId == subscription.id
)
},
[props]
)
console.log('sortedsavedSearchesL: ', sortedsavedSearches)
return (
<VStack
css={{
@ -300,68 +192,16 @@ const AvailableItems = (props: ListProps): JSX.Element => {
alignment="start"
distribution="start"
>
<StyledText style="settingsSection">Available items</StyledText>
<VStack
css={{
width: '420px',
py: '30px',
pl: '28px', // becomes labels have some margin built in
pr: '30px',
gap: '10px',
bg: '$thLeftMenuBackground',
}}
>
<StyledText style="settingsSection">Saved Searches</StyledText>
{sortedsavedSearches?.map((search) => {
return (
<Button
style="plainIcon"
css={{
display: 'flex',
width: '100%',
p: '5px',
alignItems: 'center',
borderRadius: '5px',
'&:hover': {
bg: '$thLibrarySelectionColor',
color: '$thLibraryMenuSecondary',
},
}}
key={`search-${search.id}`}
onClick={(event) => {
const item: Shortcut = {
id: search.id,
name: search.name,
type: 'label',
section: 'library',
filter: search.filter,
}
props.dispatchList({
item,
type: searchSelected(search) ? 'REMOVE_ITEM' : 'ADD_ITEM',
})
event.preventDefault()
}}
>
{' '}
<StyledText style="settingsItem">{search.name}</StyledText>
<SpanBox css={{ ml: 'auto' }}>
{searchSelected(search) ? (
<CheckSquare size={20} weight="duotone" />
) : (
<Square size={20} weight="duotone" />
)}
</SpanBox>
</Button>
)
})}
<SectionSeparator />
{/* <StyledText style="settingsSection">Available items</StyledText> */}
<SavedSearches {...props} />
<SectionSeparator />
{/*
<StyledText style="settingsSection">Labels</StyledText>
{sortedLabels.map((label) => {
console.log('label: ', label)
return (
<Button
key={`label-${label.id}`}
style="plainIcon"
css={{
display: 'flex',
@ -374,7 +214,6 @@ const AvailableItems = (props: ListProps): JSX.Element => {
color: '$thLibraryMenuSecondary',
},
}}
key={`label-${label.id}`}
onClick={(event) => {
const item: Shortcut = {
id: label.id,
@ -407,8 +246,10 @@ const AvailableItems = (props: ListProps): JSX.Element => {
<StyledText style="settingsSection">Subscriptions</StyledText>
{sortedSubscriptions.map((subscription) => {
console.log('subscription: ', subscription)
return (
<Button
key={`subscription-${subscription.id}`}
style="plainIcon"
css={{
display: 'flex',
@ -421,7 +262,6 @@ const AvailableItems = (props: ListProps): JSX.Element => {
color: '$thLibraryMenuSecondary',
},
}}
key={`subscription-${subscription.id}`}
onClick={(event) => {
const item: Shortcut = {
id: subscription.id,
@ -457,147 +297,35 @@ const AvailableItems = (props: ListProps): JSX.Element => {
</SpanBox>
</Button>
)
})}
</VStack>
})} */}
</VStack>
)
}
type AvailableItemButtonProps = {
shortcut: Shortcut
isSelected: boolean
listAction: (arg: { type: ListAction; item?: Shortcut | undefined }) => void
}
const SavedSearches = (props: ListProps) => {
const { data: savedSearches, isLoading } = useGetSavedSearches()
const AvailableItemButton = (props: AvailableItemButtonProps): JSX.Element => {
const shortcutId = `checkbox-search-${props.shortcut.id}`
return (
<CheckboxButton
itemKey={shortcutId}
title={props.shortcut.filter}
isSelected={props.isSelected}
item={props.shortcut}
listAction={props.listAction}
>
<SpanBox css={{}}>{props.shortcut.name}</SpanBox>
</CheckboxButton>
)
}
const SelectedItems = (props: ListProps): JSX.Element => {
const treeRef = useRef<TreeApi<Shortcut> | undefined>(undefined)
const resetShortcuts = useResetShortcuts()
const createNewFolder = useCallback(async () => {
if (treeRef.current) {
const result = await treeRef.current.create({
type: 'internal',
index: 0,
})
const sortedsavedSearches = useMemo(() => {
if (!savedSearches) {
return []
}
}, [treeRef])
return savedSearches.sort((a, b) =>
a.name.toLocaleLowerCase().localeCompare(b.name.toLocaleLowerCase())
)
}, [savedSearches])
return (
<VStack
css={{
m: '0px',
gap: '10px',
width: '100%',
maxWidth: '400px',
px: '0px',
pb: '25px',
}}
alignment="start"
distribution="start"
>
<StyledText style="settingsSection">Your shortcuts</StyledText>
<Box
css={{
width: '100%',
height: '100%',
pt: '10px',
bg: '$thLeftMenuBackground',
'[role="treeitem"]': {
outline: 'none',
},
'[role="treeitem"]:focus': {
outline: 'none',
},
}}
>
<ShortcutsTree treeRef={treeRef} />
</Box>
</VStack>
)
}
type CheckboxButtonProps = {
itemKey: string
title: string
isSelected: boolean
item: Shortcut
listAction: (arg: { type: ListAction; item?: Shortcut | undefined }) => void
children: ReactNode
}
function CheckboxButton(props: CheckboxButtonProps): JSX.Element {
const handleChange = useCallback(
(selected: boolean) => {
if (!selected) {
props.listAction({
type: 'REMOVE_ITEM',
item: props.item,
})
} else {
props.listAction({
type: 'ADD_ITEM',
item: props.item,
})
}
},
[props]
)
return (
<HStack
key={props.itemKey}
title={props.title}
css={{
px: '10px',
pt: '2px',
height: '30px',
gap: '5px',
fontSize: '14px',
fontWeight: 'regular',
fontFamily: '$display',
color: props.isSelected
? '$thLibraryMenuSecondary'
: '$thLibraryMenuUnselected',
verticalAlign: 'middle',
borderRadius: '3px',
cursor: 'pointer',
m: '0px',
'&:hover': {
backgroundColor: '$thBackground4',
},
}}
alignment="center"
distribution="start"
onClick={(event) => {
handleChange(!props.isSelected)
event.preventDefault()
}}
>
{props.isSelected ? (
<CheckSquare size={20} weight="duotone" />
) : (
<Square size={20} weight="duotone" />
)}
{props.children}
</HStack>
<>
{/* <StyledText style="settingsSection">Saved Searches</StyledText> */}
{/* <Box> */}
{!isLoading &&
(savedSearches ?? []).map((search) => {
return (
<Box key={`saved-search-${search.id}`} suppressHydrationWarning>
{search.name}
</Box>
)
})}
{/* </Box> */}
</>
)
}

View file

@ -48,13 +48,6 @@ export default function SubscriptionsPage(): JSX.Element {
pageId="settings-subscriptions-tag"
pageInfoLink="https://docs.omnivore.app/using/feeds.html"
headerTitle="Subscriptions"
suggestionInfo={{
title: 'View and manage all your Feed and Newsletter subscriptions',
message:
'Use this page to view and manage all the Feeds (RSS & Atom) and Newsletters you have subscribed to.',
docs: 'https://docs.omnivore.app/using/inbox.html',
key: '--settings-recent-subscriptions-show-help',
}}
>
<>
{sortedSubscriptions.length > 0 ? (

View file

@ -7575,6 +7575,13 @@
dependencies:
defer-to-connect "^1.0.1"
"@tanstack/query-async-storage-persister@^5.51.21":
version "5.51.21"
resolved "https://registry.yarnpkg.com/@tanstack/query-async-storage-persister/-/query-async-storage-persister-5.51.21.tgz#27e6635d89e0814c65586b8047372349698c7841"
integrity sha512-T22f99fDKk+XrT0kCEwETNehn8gjGfdNaaYM0xRA7VvwFKUKNYETOwUQgXV6kZ+xg6LKbZeI22YsTcuYDFOx5w==
dependencies:
"@tanstack/query-persist-client-core" "5.51.21"
"@tanstack/query-core@5.51.21":
version "5.51.21"
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.51.21.tgz#a510469c6c30d3de2a8b8798e340169a4b0fd08f"