Merge pull request #4267 from omnivore-app/fix/web-infinite-scroll
More debugging on infinite scroll
This commit is contained in:
@ -211,6 +211,7 @@ export function HomeContainer(): JSX.Element {
|
||||
const shouldFallback =
|
||||
homeData.error || (!homeData.isValidating && !hasTopPicks(homeData))
|
||||
const searchData = useGetLibraryItems(
|
||||
'home',
|
||||
undefined,
|
||||
{
|
||||
limit: 10,
|
||||
|
||||
@ -89,7 +89,7 @@ export function DiscoverContainer(): JSX.Element {
|
||||
}
|
||||
setPage(page + 1)
|
||||
}, [page, isLoading])
|
||||
useFetchMore(handleFetchMore)
|
||||
// useFetchMore(handleFetchMore)
|
||||
|
||||
const handleSaveDiscover = async (
|
||||
discoverArticleId: string,
|
||||
|
||||
@ -54,8 +54,8 @@ import { theme } from '../../tokens/stitches.config'
|
||||
import { emptyTrashMutation } from '../../../lib/networking/mutations/emptyTrashMutation'
|
||||
import { State } from '../../../lib/networking/fragments/articleFragment'
|
||||
import { useHandleAddUrl } from '../../../lib/hooks/useHandleAddUrl'
|
||||
import { QueryClient, useQueryClient } from '@tanstack/react-query'
|
||||
import { useGetViewer } from '../../../lib/networking/viewer/useGetViewer'
|
||||
import { Spinner } from '@phosphor-icons/react/dist/ssr'
|
||||
|
||||
export type LayoutType = 'LIST_LAYOUT' | 'GRID_LAYOUT'
|
||||
|
||||
@ -117,11 +117,14 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
|
||||
const {
|
||||
data: itemsPages,
|
||||
isLoading,
|
||||
isFetchingNextPage,
|
||||
isFetching,
|
||||
fetchNextPage,
|
||||
fetchPreviousPage,
|
||||
hasNextPage,
|
||||
hasPreviousPage,
|
||||
error: fetchItemsError,
|
||||
} = useGetLibraryItems(props.folder, queryInputs)
|
||||
} = useGetLibraryItems(props.folder ?? 'home', props.folder, queryInputs)
|
||||
|
||||
useEffect(() => {
|
||||
if (queryValue.startsWith('#')) {
|
||||
@ -157,6 +160,7 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
|
||||
}, [router.asPath])
|
||||
|
||||
const libraryItems = useMemo(() => {
|
||||
console.log('library items: ', itemsPages)
|
||||
const items =
|
||||
itemsPages?.pages
|
||||
.flatMap((ad: LibraryItems) => {
|
||||
@ -184,16 +188,16 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
|
||||
.map((li) => li.node.id)
|
||||
}, [libraryItems])
|
||||
|
||||
const refreshProcessingItems = useRefreshProcessingItems()
|
||||
// const refreshProcessingItems = useRefreshProcessingItems()
|
||||
|
||||
useEffect(() => {
|
||||
if (processingItems.length) {
|
||||
refreshProcessingItems.mutateAsync({
|
||||
attempt: 0,
|
||||
itemIds: processingItems,
|
||||
})
|
||||
}
|
||||
}, [processingItems])
|
||||
// useEffect(() => {
|
||||
// if (processingItems.length) {
|
||||
// refreshProcessingItems.mutateAsync({
|
||||
// attempt: 0,
|
||||
// itemIds: processingItems,
|
||||
// })
|
||||
// }
|
||||
// }, [processingItems])
|
||||
|
||||
const focusFirstItem = useCallback(() => {
|
||||
if (libraryItems.length < 1) {
|
||||
@ -295,6 +299,7 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
|
||||
}, [libraryItems, activeCardId])
|
||||
|
||||
useEffect(() => {
|
||||
console.log('active card id: ', activeCardId)
|
||||
if (activeCardId && !alreadyScrolled.current) {
|
||||
scrollToActiveCard(activeCardId)
|
||||
alreadyScrolled.current = true
|
||||
@ -789,6 +794,33 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
|
||||
[itemsPages, multiSelectMode, checkedItems]
|
||||
)
|
||||
|
||||
// return (
|
||||
// <InfiniteScroll
|
||||
// dataLength={libraryItems.length}
|
||||
// next={fetchNextPage}
|
||||
// hasMore={hasNextPage}
|
||||
// loader={<h4>Loading...</h4>}
|
||||
// endMessage={
|
||||
// <p style={{ textAlign: 'center' }}>
|
||||
// <b>Yay! You have seen it all</b>
|
||||
// </p>
|
||||
// }
|
||||
// >
|
||||
// {libraryItems.map((item) => {
|
||||
// return (
|
||||
// <Box
|
||||
// key={item.node.id}
|
||||
// onClick={() => {
|
||||
// router.push(`/${viewerData?.profile.username}/${item.node.slug}`)
|
||||
// }}
|
||||
// >
|
||||
// {item.cursor}: {item.node.title}
|
||||
// </Box>
|
||||
// )
|
||||
// })}
|
||||
// </InfiniteScroll>
|
||||
// )
|
||||
|
||||
return (
|
||||
<HomeFeedGrid
|
||||
folder={props.folder}
|
||||
@ -821,7 +853,7 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
|
||||
loadMore={fetchNextPage}
|
||||
hasMore={hasNextPage ?? false}
|
||||
hasData={!!itemsPages}
|
||||
isValidating={isLoading}
|
||||
isValidating={isLoading || isFetchingNextPage}
|
||||
fetchItemsError={!!fetchItemsError}
|
||||
labelsTarget={labelsTarget}
|
||||
setLabelsTarget={setLabelsTarget}
|
||||
@ -1150,16 +1182,20 @@ export function LibraryItemsLayout(
|
||||
css={{ width: '100%', mt: '$2', mb: '$4' }}
|
||||
>
|
||||
{props.hasMore ? (
|
||||
<Button
|
||||
style="ctaGray"
|
||||
css={{
|
||||
cursor: props.isValidating ? 'not-allowed' : 'pointer',
|
||||
}}
|
||||
onClick={props.loadMore}
|
||||
disabled={props.isValidating}
|
||||
>
|
||||
{props.isValidating ? 'Loading' : 'Load More'}
|
||||
</Button>
|
||||
props.isValidating ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
<Button
|
||||
style="ctaGray"
|
||||
css={{
|
||||
cursor: props.isValidating ? 'not-allowed' : 'pointer',
|
||||
}}
|
||||
onClick={props.loadMore}
|
||||
disabled={props.isValidating}
|
||||
>
|
||||
{props.isValidating ? 'Loading' : 'More search results'}
|
||||
</Button>
|
||||
)
|
||||
) : (
|
||||
<StyledText style="caption"></StyledText>
|
||||
)}
|
||||
|
||||
@ -1,28 +1,24 @@
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
|
||||
export const useFetchMore = (callback: () => void, delay = 500): void => {
|
||||
export const useFetchMore = (fetchNextPage: () => void, delay = 500): void => {
|
||||
const [first, setFirst] = useState(true)
|
||||
const [lastScrollTop, setLastScrollTop] = useState(0)
|
||||
const throttleTimeout = useRef<NodeJS.Timeout | undefined>(undefined)
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window === 'undefined') {
|
||||
return
|
||||
}
|
||||
|
||||
const callbackInternal = (): void => {
|
||||
const { scrollTop, scrollHeight, clientHeight } =
|
||||
window.document.documentElement
|
||||
const direction = scrollTop > lastScrollTop ? 'down' : 'up'
|
||||
setLastScrollTop(scrollTop)
|
||||
|
||||
if (scrollTop + clientHeight >= scrollHeight - scrollHeight / 3) {
|
||||
console.log(
|
||||
'calling fetchMore: scrollTop + clientHeight >= scrollHeight - scrollHeight / 3',
|
||||
scrollTop,
|
||||
clientHeight,
|
||||
scrollHeight,
|
||||
scrollHeight / 3
|
||||
)
|
||||
callback()
|
||||
if (
|
||||
direction == 'down' &&
|
||||
scrollTop + clientHeight >= scrollHeight - scrollHeight / 3
|
||||
) {
|
||||
fetchNextPage()
|
||||
}
|
||||
|
||||
throttleTimeout.current = undefined
|
||||
}
|
||||
|
||||
@ -42,5 +38,5 @@ export const useFetchMore = (callback: () => void, delay = 500): void => {
|
||||
return () => {
|
||||
window.removeEventListener('scroll', handleScroll)
|
||||
}
|
||||
}, [callback, delay, first, setFirst])
|
||||
}, [fetchNextPage, delay, first, setFirst])
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@ import {
|
||||
GQL_SET_LINK_ARCHIVED,
|
||||
GQL_UPDATE_LIBRARY_ITEM,
|
||||
} from './gql'
|
||||
import { useState } from 'react'
|
||||
|
||||
function gqlFetcher(
|
||||
query: string,
|
||||
@ -173,11 +174,8 @@ export const insertItemInCache = (
|
||||
const keys = queryClient
|
||||
.getQueryCache()
|
||||
.findAll({ queryKey: ['libraryItems'] })
|
||||
console.log('keys: ', keys)
|
||||
|
||||
keys.forEach((query) => {
|
||||
queryClient.setQueryData(query.queryKey, (data: any) => {
|
||||
console.log('data, data.pages', data)
|
||||
if (!data) return data
|
||||
if (data.pages.length > 0) {
|
||||
const firstPage = data.pages[0] as LibraryItems
|
||||
@ -202,43 +200,139 @@ export const insertItemInCache = (
|
||||
},
|
||||
]
|
||||
data.pages[0] = firstPage
|
||||
console.log('data: ', data)
|
||||
return data
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// const useOptimizedPageFetcher = (
|
||||
// section: string,
|
||||
// folder: string | undefined,
|
||||
// { limit, searchQuery, includeCount }: LibraryItemsQueryInput,
|
||||
// enabled = true
|
||||
// ) => {
|
||||
// const [pages, setPages] = useState([])
|
||||
// const queryClient = useQueryClient()
|
||||
// const fullQuery = folder
|
||||
// ? (`in:${folder} use:folders ` + (searchQuery ?? '')).trim()
|
||||
// : searchQuery ?? ''
|
||||
// }
|
||||
|
||||
interface CachedPagesData {
|
||||
pageParams: string[]
|
||||
pages: LibraryItems[]
|
||||
}
|
||||
|
||||
export function useGetLibraryItems(
|
||||
section: string,
|
||||
folder: string | undefined,
|
||||
{ limit, searchQuery, includeCount }: LibraryItemsQueryInput,
|
||||
enabled = true
|
||||
) {
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const INITIAL_INDEX = '0'
|
||||
const fullQuery = folder
|
||||
? (`in:${folder} use:folders ` + (searchQuery ?? '')).trim()
|
||||
: searchQuery ?? ''
|
||||
|
||||
const queryKey = ['libraryItems', section, fullQuery]
|
||||
return useInfiniteQuery({
|
||||
queryKey: ['libraryItems', fullQuery],
|
||||
queryFn: async ({ pageParam }) => {
|
||||
// If no folder is specified cache this as `home`
|
||||
queryKey,
|
||||
queryFn: async ({ queryKey, pageParam, meta }) => {
|
||||
console.log('pageParam and limit', Number(pageParam), limit)
|
||||
const cached = queryClient.getQueryData(queryKey) as CachedPagesData
|
||||
if (pageParam !== INITIAL_INDEX) {
|
||||
// check in the query cache, if there is an item for this page
|
||||
// in the query page, check if pageIndex - 1 was unchanged since
|
||||
// the last query, this will determine if we should refetch this
|
||||
// page and subsequent pages.
|
||||
if (cached) {
|
||||
const idx = cached.pageParams.indexOf(pageParam)
|
||||
|
||||
// First check if the previous page had detected a modification
|
||||
// if it had we keep fetching until we find a
|
||||
if (
|
||||
idx > 0 &&
|
||||
idx < cached.pages.length &&
|
||||
cached.pages[idx - 1].pageInfo.wasUnchanged
|
||||
) {
|
||||
const cachedResult = cached.pages[idx]
|
||||
console.log('found cached page result: ', cachedResult)
|
||||
return {
|
||||
edges: cachedResult.edges,
|
||||
pageInfo: {
|
||||
...cachedResult.pageInfo,
|
||||
wasUnchanged: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const response = (await gqlFetcher(gqlSearchQuery(includeCount), {
|
||||
after: pageParam,
|
||||
first: limit,
|
||||
query: fullQuery,
|
||||
includeContent: false,
|
||||
})) as LibraryItemsData
|
||||
return response.search
|
||||
let wasUnchanged = false
|
||||
if (cached && cached.pageParams.indexOf(pageParam) > -1) {
|
||||
const idx = cached.pageParams.indexOf(pageParam)
|
||||
// // if there is a cache, check to see if the page is already in it
|
||||
// // and mark whether or not the page has changed
|
||||
try {
|
||||
const cachedIds = cached.pages[idx].edges.map((m) => m.node.id)
|
||||
const resultIds = response.search.edges.map((m) => m.node.id)
|
||||
const compareFunc = (a: string[], b: string[]) =>
|
||||
a.length === b.length &&
|
||||
a.every((element, index) => element === b[index])
|
||||
wasUnchanged = compareFunc(cachedIds, resultIds)
|
||||
console.log('previous unchanged', wasUnchanged, cachedIds, resultIds)
|
||||
} catch (err) {
|
||||
console.log('error: ', err)
|
||||
}
|
||||
}
|
||||
return {
|
||||
edges: response.search.edges,
|
||||
pageInfo: {
|
||||
...response.search.pageInfo,
|
||||
wasUnchanged,
|
||||
lastUpdated: new Date(),
|
||||
},
|
||||
}
|
||||
},
|
||||
enabled,
|
||||
initialPageParam: '0',
|
||||
refetchOnMount: false,
|
||||
refetchOnWindowFocus: false,
|
||||
staleTime: 10 * 60 * 1000,
|
||||
getNextPageParam: (lastPage: LibraryItems) => {
|
||||
initialPageParam: INITIAL_INDEX,
|
||||
getNextPageParam: (lastPage: LibraryItems, pages) => {
|
||||
return lastPage.pageInfo.hasNextPage
|
||||
? lastPage?.pageInfo?.endCursor
|
||||
: undefined
|
||||
},
|
||||
select: (data) => {
|
||||
const now = new Date()
|
||||
|
||||
// Filter pages based on the lastUpdated condition
|
||||
const filteredPages = data.pages.slice(0, 5).concat(
|
||||
data.pages.slice(5).filter((page, index) => {
|
||||
if (page.pageInfo?.lastUpdated) {
|
||||
const lastUpdatedDate = new Date(page.pageInfo.lastUpdated)
|
||||
const diffMinutes =
|
||||
(now.getTime() - lastUpdatedDate.getTime()) / (1000 * 60)
|
||||
console.log(`page: ${index} age: ${diffMinutes}`)
|
||||
return diffMinutes <= 10
|
||||
}
|
||||
return true
|
||||
})
|
||||
)
|
||||
console.log('setting filteredPages: ', filteredPages)
|
||||
|
||||
return {
|
||||
...data,
|
||||
pages: filteredPages,
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -531,7 +625,9 @@ export function useRefreshProcessingItems() {
|
||||
attempt: number
|
||||
itemIds: string[]
|
||||
}) => {
|
||||
const fullQuery = `in:all includes:${variables.itemIds.join(',')}`
|
||||
const fullQuery = `in:all includes:${variables.itemIds
|
||||
.slice(0, 5)
|
||||
.join(',')}`
|
||||
const result = (await gqlFetcher(gqlSearchQuery(), {
|
||||
first: 10,
|
||||
query: fullQuery,
|
||||
@ -1029,6 +1125,10 @@ export type PageInfo = {
|
||||
startCursor: string
|
||||
endCursor: string
|
||||
totalCount: number
|
||||
|
||||
// used internally for some cache handling
|
||||
lastUpdated?: Date
|
||||
wasUnchanged?: boolean
|
||||
}
|
||||
|
||||
type SetLinkArchivedInput = {
|
||||
|
||||
@ -114,8 +114,6 @@ const showToastWithAction = (
|
||||
action: () => Promise<void>,
|
||||
options?: ToastOptions
|
||||
) => {
|
||||
console.trace('show success: ', message)
|
||||
|
||||
return toast(
|
||||
({ id }) => (
|
||||
<FullWidthContainer alignment="center">
|
||||
|
||||
@ -305,7 +305,7 @@ export default function Reader(): JSX.Element {
|
||||
perform: () => {
|
||||
const navReturn = window.localStorage.getItem('nav-return')
|
||||
if (navReturn) {
|
||||
router.push(navReturn)
|
||||
router.push(navReturn, navReturn, { scroll: false })
|
||||
return
|
||||
}
|
||||
const query = window.sessionStorage.getItem('q')
|
||||
|
||||
@ -33,7 +33,7 @@ import React from 'react'
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
gcTime: 1000 * 60 * 60 * 48, // 48 hours
|
||||
gcTime: 1000 * 60 * 60 * 4, // 4hrs
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@ -45,6 +45,7 @@ export default function Home(): JSX.Element {
|
||||
// return <HomeContainer />
|
||||
return (
|
||||
<LibraryContainer
|
||||
key={name}
|
||||
folder={undefined}
|
||||
filterFunc={(item) => {
|
||||
return (
|
||||
@ -59,6 +60,7 @@ export default function Home(): JSX.Element {
|
||||
case 'library':
|
||||
return (
|
||||
<LibraryContainer
|
||||
key={name}
|
||||
folder="inbox"
|
||||
filterFunc={(item) => {
|
||||
return (
|
||||
@ -73,6 +75,7 @@ export default function Home(): JSX.Element {
|
||||
case 'subscriptions':
|
||||
return (
|
||||
<LibraryContainer
|
||||
key={name}
|
||||
folder="following"
|
||||
filterFunc={(item) => {
|
||||
return (
|
||||
@ -87,6 +90,7 @@ export default function Home(): JSX.Element {
|
||||
case 'search':
|
||||
return (
|
||||
<LibraryContainer
|
||||
key={name}
|
||||
folder={undefined}
|
||||
filterFunc={(item) => {
|
||||
console.log('item: ', item)
|
||||
@ -98,6 +102,7 @@ export default function Home(): JSX.Element {
|
||||
case 'archive':
|
||||
return (
|
||||
<LibraryContainer
|
||||
key={name}
|
||||
folder="archive"
|
||||
filterFunc={(item) => {
|
||||
return item.state == 'ARCHIVED'
|
||||
@ -108,6 +113,7 @@ export default function Home(): JSX.Element {
|
||||
case 'trash':
|
||||
return (
|
||||
<LibraryContainer
|
||||
key={name}
|
||||
folder="trash"
|
||||
filterFunc={(item) => {
|
||||
return item.state == 'DELETED'
|
||||
|
||||
@ -92,7 +92,7 @@ export default function Account(): JSX.Element {
|
||||
isUsernameValidationLoading,
|
||||
])
|
||||
|
||||
const { data: itemsPages, isLoading } = useGetLibraryItems('all', {
|
||||
const { data: itemsPages, isLoading } = useGetLibraryItems('search', 'all', {
|
||||
limit: 0,
|
||||
searchQuery: '',
|
||||
sortDescending: false,
|
||||
|
||||
@ -33,12 +33,16 @@ export default function BulkPerformer(): JSX.Element {
|
||||
const [runningState, setRunningState] = useState<RunningState>('none')
|
||||
const bulkAction = useBulkActions()
|
||||
|
||||
const { data: itemsPages, isLoading } = useGetLibraryItems(undefined, {
|
||||
searchQuery: query,
|
||||
limit: 1,
|
||||
sortDescending: false,
|
||||
includeCount: true,
|
||||
})
|
||||
const { data: itemsPages, isLoading } = useGetLibraryItems(
|
||||
'search',
|
||||
undefined,
|
||||
{
|
||||
searchQuery: query,
|
||||
limit: 1,
|
||||
sortDescending: false,
|
||||
includeCount: true,
|
||||
}
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
setExpectedCount(itemsPages?.pages.find(() => true)?.pageInfo.totalCount)
|
||||
|
||||
31
yarn.lock
31
yarn.lock
@ -29428,7 +29428,7 @@ string-template@~0.2.1:
|
||||
resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add"
|
||||
integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=
|
||||
|
||||
"string-width-cjs@npm:string-width@^4.2.0":
|
||||
"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.2.2, string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
@ -29454,15 +29454,6 @@ string-width@^1.0.1:
|
||||
is-fullwidth-code-point "^2.0.0"
|
||||
strip-ansi "^4.0.0"
|
||||
|
||||
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.2.2, string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
dependencies:
|
||||
emoji-regex "^8.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
string-width@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
|
||||
@ -29617,7 +29608,7 @@ string_decoder@~1.1.1:
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
@ -29652,13 +29643,6 @@ strip-ansi@^6.0.0:
|
||||
dependencies:
|
||||
ansi-regex "^5.0.0"
|
||||
|
||||
strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-ansi@^7.0.0:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2"
|
||||
@ -32358,7 +32342,7 @@ workerpool@6.2.1:
|
||||
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343"
|
||||
integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==
|
||||
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
@ -32384,15 +32368,6 @@ wrap-ansi@^6.0.1, wrap-ansi@^6.2.0:
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
dependencies:
|
||||
ansi-styles "^4.0.0"
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
|
||||
|
||||
Reference in New Issue
Block a user