Merge branch 'snake-fix'

This commit is contained in:
Daniel Shleifman
2021-06-15 18:09:21 +03:00
11 changed files with 149 additions and 345 deletions

View File

@@ -10,7 +10,6 @@
"fontsource-roboto": "^4.0.0", "fontsource-roboto": "^4.0.0",
"i18next": "^20.3.1", "i18next": "^20.3.1",
"i18next-browser-languagedetector": "^6.1.1", "i18next-browser-languagedetector": "^6.1.1",
"konva": "^8.0.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"material-ui-image": "^3.3.2", "material-ui-image": "^3.3.2",
"parse-torrent": "^9.1.3", "parse-torrent": "^9.1.3",
@@ -21,12 +20,9 @@
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-dropzone": "^11.3.2", "react-dropzone": "^11.3.2",
"react-i18next": "^11.10.0", "react-i18next": "^11.10.0",
"react-konva": "^17.0.2-4",
"react-measure": "^2.5.2", "react-measure": "^2.5.2",
"react-query": "^3.17.0", "react-query": "^3.17.0",
"react-scripts": "4.0.3", "react-scripts": "4.0.3",
"react-virtualized-auto-sizer": "^1.0.5",
"react-window": "^1.8.6",
"styled-components": "^5.3.0", "styled-components": "^5.3.0",
"uuid": "^8.3.2" "uuid": "^8.3.2"
}, },

View File

@@ -1,127 +0,0 @@
import { useEffect, useState } from 'react'
import DialogContent from '@material-ui/core/DialogContent'
import { Stage, Layer } from 'react-konva'
import Measure from 'react-measure'
import { v4 as uuidv4 } from 'uuid'
import styled from 'styled-components'
import { useTranslation } from 'react-i18next'
import SingleBlock from './SingleBlock'
import getShortCacheMap from './getShortCacheMap'
const ScrollNotification = styled.div`
margin-top: 10px;
text-transform: uppercase;
color: rgba(0, 0, 0, 0.5);
align-self: center;
`
export default function DefaultSnake({ isMini, cacheMap, preloadPiecesAmount }) {
const { t } = useTranslation()
const [dimensions, setDimensions] = useState({ width: 0, height: 0 })
const [stageSettings, setStageSettings] = useState({
boxHeight: null,
strokeWidth: null,
marginBetweenBlocks: null,
stageOffset: null,
})
const updateStageSettings = (boxHeight, strokeWidth) => {
setStageSettings({
boxHeight,
strokeWidth,
marginBetweenBlocks: strokeWidth,
stageOffset: strokeWidth * 2,
})
}
useEffect(() => {
// initializing stageSettings
if (isMini) return dimensions.width < 500 ? updateStageSettings(20, 3) : updateStageSettings(24, 4)
updateStageSettings(12, 2)
}, [isMini, dimensions.width])
const miniCacheMaxHeight = 340
const { boxHeight, strokeWidth, marginBetweenBlocks, stageOffset } = stageSettings
const blockSizeWithMargin = boxHeight + strokeWidth + marginBetweenBlocks
const piecesInOneRow = Math.floor((dimensions.width * 0.9) / blockSizeWithMargin)
const shortCacheMap = isMini ? getShortCacheMap({ cacheMap, preloadPiecesAmount, piecesInOneRow }) : []
const amountOfRows = Math.ceil((isMini ? shortCacheMap.length : cacheMap.length) / piecesInOneRow)
const getItemCoordinates = blockOrder => {
const currentRow = Math.floor(blockOrder / piecesInOneRow)
const x = (blockOrder % piecesInOneRow) * blockSizeWithMargin || 0
const y = currentRow * blockSizeWithMargin || 0
return { x, y }
}
return (
<Measure bounds onResize={({ bounds }) => setDimensions(bounds)}>
{({ measureRef }) => (
<div style={{ display: 'flex', flexDirection: 'column' }}>
<DialogContent
ref={measureRef}
{...(isMini
? { style: { padding: 0, maxHeight: `${miniCacheMaxHeight}px`, overflow: 'auto' } }
: { style: { padding: 0 } })}
>
<Stage
style={{ display: 'flex', justifyContent: 'center' }}
offset={{ x: -stageOffset, y: -stageOffset }}
width={stageOffset + blockSizeWithMargin * piecesInOneRow || 0}
height={stageOffset + blockSizeWithMargin * amountOfRows || 0}
>
<Layer>
{isMini
? shortCacheMap.map(({ percentage, isComplete, inProgress, isActive, isReaderRange }, i) => {
const { x, y } = getItemCoordinates(i)
return (
<SingleBlock
key={uuidv4()}
x={x}
y={y}
percentage={percentage}
inProgress={inProgress}
isComplete={isComplete}
isReaderRange={isReaderRange}
isActive={isActive}
boxHeight={boxHeight}
strokeWidth={strokeWidth}
/>
)
})
: cacheMap.map(({ id, percentage, isComplete, inProgress, isActive, isReaderRange }) => {
const { x, y } = getItemCoordinates(id)
return (
<SingleBlock
key={uuidv4()}
x={x}
y={y}
percentage={percentage}
inProgress={inProgress}
isComplete={isComplete}
isReaderRange={isReaderRange}
isActive={isActive}
boxHeight={boxHeight}
strokeWidth={strokeWidth}
/>
)
})}
</Layer>
</Stage>
</DialogContent>
{isMini &&
(stageOffset + blockSizeWithMargin * amountOfRows || 0) >= miniCacheMaxHeight &&
dimensions.height >= miniCacheMaxHeight && <ScrollNotification>{t('ScrollDown')}</ScrollNotification>}
</div>
)}
</Measure>
)
}

View File

@@ -1,59 +0,0 @@
import { FixedSizeGrid as Grid } from 'react-window'
import AutoSizer from 'react-virtualized-auto-sizer'
import { memo } from 'react'
import { getLargeSnakeColors } from './colors'
const Cell = memo(({ columnIndex, rowIndex, style, data }) => {
const { columnCount, cacheMap, gutterSize, borderSize, pieces } = data
const itemIndex = rowIndex * columnCount + columnIndex
const { borderColor, backgroundColor } = getLargeSnakeColors(cacheMap[itemIndex] || {})
const newStyle = {
...style,
left: style.left + gutterSize,
top: style.top + gutterSize,
width: style.width - gutterSize,
height: style.height - gutterSize,
border: `${borderSize}px solid ${borderColor}`,
display: itemIndex >= pieces ? 'none' : null,
background: backgroundColor,
}
return <div style={newStyle} />
})
const gutterSize = 2
const borderSize = 1
const pieceSize = 12
const pieceSizeWithSpacing = pieceSize + gutterSize
export default function LargeSnake({ cacheMap }) {
const pieces = cacheMap.length
return (
<div style={{ height: '60vh', overflow: 'hidden' }}>
<AutoSizer>
{({ height, width }) => {
const columnCount = Math.floor(width / (gutterSize + pieceSize)) - 1
const rowCount = pieces / columnCount + 1
return (
<Grid
columnCount={columnCount}
rowCount={rowCount}
columnWidth={pieceSizeWithSpacing}
rowHeight={pieceSizeWithSpacing}
height={height}
width={width}
itemData={{ columnCount, cacheMap, gutterSize, borderSize, pieces }}
>
{Cell}
</Grid>
)
}}
</AutoSizer>
</div>
)
}

View File

@@ -1,55 +0,0 @@
import { Rect } from 'react-konva'
import { activeColor, completeColor, defaultBorderColor, progressColor, rangeColor } from './colors'
export default function SingleBlock({
x,
y,
percentage,
isActive = false,
inProgress = false,
isReaderRange = false,
isComplete = false,
boxHeight,
strokeWidth,
}) {
const strokeColor = isActive
? activeColor
: isComplete
? completeColor
: inProgress
? progressColor
: isReaderRange
? rangeColor
: defaultBorderColor
const backgroundColor = inProgress ? progressColor : defaultBorderColor
const percentageProgressColor = completeColor
const processCompletedColor = completeColor
return (
<Rect
x={x}
y={y}
stroke={strokeColor}
strokeWidth={strokeWidth}
height={boxHeight}
width={boxHeight}
fillAfterStrokeEnabled
preventDefault={false}
{...(isComplete
? { fill: processCompletedColor }
: inProgress && {
fillLinearGradientStartPointY: boxHeight,
fillLinearGradientEndPointY: 0,
fillLinearGradientColorStops: [
0,
percentageProgressColor,
percentage,
percentageProgressColor,
percentage,
backgroundColor,
],
})}
/>
)
}

View File

@@ -1,26 +0,0 @@
export const defaultBorderColor = '#eef2f4'
export const defaultBackgroundColor = '#fff'
export const completeColor = '#00a572'
export const progressColor = '#ffa724'
export const activeColor = '#000'
export const rangeColor = '#9a9aff'
export const getLargeSnakeColors = ({ isActive, isComplete, inProgress, isReaderRange, percentage }) => {
const gradientBackgroundColor = inProgress ? progressColor : defaultBackgroundColor
const gradient = `linear-gradient(to top, ${completeColor} 0%, ${completeColor} ${
percentage * 100
}%, ${gradientBackgroundColor} ${percentage * 100}%, ${gradientBackgroundColor} 100%)`
const borderColor = isActive
? activeColor
: isComplete
? completeColor
: inProgress
? progressColor
: isReaderRange
? rangeColor
: defaultBorderColor
const backgroundColor = isComplete ? completeColor : inProgress ? gradient : defaultBackgroundColor
return { borderColor, backgroundColor }
}

View File

@@ -1,5 +1,7 @@
export default ({ cacheMap, preloadPiecesAmount, piecesInOneRow }) => { export default ({ cacheMap, preloadPiecesAmount, piecesInOneRow }) => {
const cacheMapWithoutEmptyBlocks = cacheMap.filter(({ isComplete, inProgress }) => inProgress || isComplete) const cacheMapWithoutEmptyBlocks = cacheMap.filter(
({ className }) => className.includes('piece-complete') || className.includes('piece-loading'),
)
const getFullAmountOfBlocks = amountOfBlocks => const getFullAmountOfBlocks = amountOfBlocks =>
// this function counts existed amount of blocks with extra "empty blocks" to fill the row till the end // this function counts existed amount of blocks with extra "empty blocks" to fill the row till the end
@@ -21,7 +23,9 @@ export default ({ cacheMap, preloadPiecesAmount, piecesInOneRow }) => {
const extraBlocksAmount = finalAmountOfBlocksToRenderInShortView - cacheMapWithoutEmptyBlocks.length + 1 const extraBlocksAmount = finalAmountOfBlocksToRenderInShortView - cacheMapWithoutEmptyBlocks.length + 1
// amount of blocks needed to fill the line till the end // amount of blocks needed to fill the line till the end
const extraEmptyBlocksForFillingLine = extraBlocksAmount ? new Array(extraBlocksAmount).fill({}) : [] const extraEmptyBlocksForFillingLine = extraBlocksAmount
? new Array(extraBlocksAmount).fill({ className: 'piece' })
: []
return [...cacheMapWithoutEmptyBlocks, ...extraEmptyBlocksForFillingLine] return [...cacheMapWithoutEmptyBlocks, ...extraEmptyBlocksForFillingLine]
} }

View File

@@ -1,26 +1,59 @@
import { memo } from 'react' import Measure from 'react-measure'
import { useState, memo } from 'react'
import { v4 as uuidv4 } from 'uuid'
import { useTranslation } from 'react-i18next'
import isEqual from 'lodash/isEqual' import isEqual from 'lodash/isEqual'
import { useCreateCacheMap } from '../customHooks' import { useCreateCacheMap } from '../customHooks'
import LargeSnake from './LargeSnake' import { gapBetweenPieces, miniCacheMaxHeight, pieceSizeForMiniMap, defaultPieceSize } from './snakeSettings'
import DefaultSnake from './DefaultSnake' import getShortCacheMap from './getShortCacheMap'
import { SnakeWrapper, PercentagePiece, ScrollNotification } from './style'
const TorrentCache = memo( const TorrentCache = ({ cache, isMini }) => {
({ cache, isMini }) => { const { t } = useTranslation()
const [dimensions, setDimensions] = useState({ width: 0, height: 0 })
const cacheMap = useCreateCacheMap(cache) const cacheMap = useCreateCacheMap(cache)
const preloadPiecesAmount = Math.round(cache.Capacity / cache.PiecesLength - 1) const preloadPiecesAmount = Math.round(cache.Capacity / cache.PiecesLength - 1)
const isSnakeLarge = cacheMap.length > 1000
const pieceSize = isMini ? pieceSizeForMiniMap : defaultPieceSize
let piecesInOneRow
let shotCacheMap
if (isMini) {
const pieceSizeWithGap = pieceSize + gapBetweenPieces
piecesInOneRow = Math.floor((dimensions.width * 0.95) / pieceSizeWithGap)
shotCacheMap = isMini && getShortCacheMap({ cacheMap, preloadPiecesAmount, piecesInOneRow })
}
return isMini ? ( return isMini ? (
<DefaultSnake isMini cacheMap={cacheMap} preloadPiecesAmount={preloadPiecesAmount} /> <Measure bounds onResize={({ bounds }) => setDimensions(bounds)}>
) : isSnakeLarge ? ( {({ measureRef }) => (
<LargeSnake cacheMap={cacheMap} /> <div style={{ display: 'flex', flexDirection: 'column' }}>
<SnakeWrapper ref={measureRef} pieceSize={pieceSize} piecesInOneRow={piecesInOneRow}>
{shotCacheMap.map(({ className, id, percentage }) => (
<span key={id || uuidv4()} className={className}>
{percentage > 0 && percentage <= 100 && <PercentagePiece percentage={percentage} />}
</span>
))}
</SnakeWrapper>
{dimensions.height >= miniCacheMaxHeight && <ScrollNotification>{t('ScrollDown')}</ScrollNotification>}
</div>
)}
</Measure>
) : ( ) : (
<DefaultSnake cacheMap={cacheMap} preloadPiecesAmount={preloadPiecesAmount} /> <SnakeWrapper pieceSize={pieceSize}>
{cacheMap.map(({ className, id, percentage }) => (
<span key={id || uuidv4()} className={className}>
{percentage > 0 && percentage <= 100 && <PercentagePiece percentage={percentage} />}
</span>
))}
</SnakeWrapper>
) )
}, }
export default memo(
TorrentCache,
(prev, next) => isEqual(prev.cache.Pieces, next.cache.Pieces) && isEqual(prev.cache.Readers, next.cache.Readers), (prev, next) => isEqual(prev.cache.Pieces, next.cache.Pieces) && isEqual(prev.cache.Readers, next.cache.Readers),
) )
export default TorrentCache

View File

@@ -0,0 +1,12 @@
export const borderWidth = 1
export const defaultPieceSize = 14
export const pieceSizeForMiniMap = 23
export const gapBetweenPieces = 3
export const miniCacheMaxHeight = 340
export const defaultBorderColor = '#eef2f4'
export const defaultBackgroundColor = '#fff'
export const completeColor = '#00a572'
export const progressColor = '#ffa724'
export const activeColor = '#000'
export const rangeColor = '#9a9aff'

View File

@@ -0,0 +1,66 @@
import styled, { css } from 'styled-components'
import {
defaultBackgroundColor,
defaultBorderColor,
progressColor,
completeColor,
activeColor,
rangeColor,
gapBetweenPieces,
miniCacheMaxHeight,
borderWidth,
} from './snakeSettings'
export const ScrollNotification = styled.div`
margin-top: 10px;
text-transform: uppercase;
color: rgba(0, 0, 0, 0.5);
align-self: center;
`
export const SnakeWrapper = styled.div`
${({ pieceSize, piecesInOneRow }) => css`
display: grid;
gap: ${gapBetweenPieces}px;
grid-template-columns: repeat(${piecesInOneRow || 'auto-fit'}, ${pieceSize}px);
grid-auto-rows: max-content;
justify-content: center;
${piecesInOneRow &&
css`
max-height: ${miniCacheMaxHeight}px;
overflow: auto;
`}
.piece {
width: ${pieceSize}px;
height: ${pieceSize}px;
background: ${defaultBackgroundColor};
border: ${borderWidth}px solid ${defaultBorderColor};
display: grid;
align-items: end;
&-loading {
background: ${progressColor};
border-color: ${progressColor};
}
&-complete {
background: ${completeColor};
border-color: ${completeColor};
}
&-reader {
border-color: ${activeColor};
}
}
.reader-range {
border-color: ${rangeColor};
}
`}
`
export const PercentagePiece = styled.div`
background: ${completeColor};
height: ${({ percentage }) => (percentage / 100) * 12}px;
`

View File

@@ -38,32 +38,32 @@ export const useCreateCacheMap = cache => {
const [cacheMap, setCacheMap] = useState([]) const [cacheMap, setCacheMap] = useState([])
useEffect(() => { useEffect(() => {
if (!cache.PiecesCount || !cache.Pieces) return const { PiecesCount, Pieces, Readers } = cache
const { Pieces, PiecesCount, Readers } = cache
const map = [] const map = []
for (let i = 0; i < PiecesCount; i++) { for (let i = 0; i < PiecesCount; i++) {
const newPiece = { id: i } const newPiece = { id: i }
const currentPiece = Pieces[i] const activeBlock = Pieces[i]
if (currentPiece) { const className = ['piece']
if (currentPiece.Completed && currentPiece.Size === currentPiece.Length) newPiece.isComplete = true
else { if (activeBlock) {
newPiece.inProgress = true const { Completed, Size, Length } = activeBlock
newPiece.percentage = (currentPiece.Size / currentPiece.Length).toFixed(2) className.push(Completed && Size >= Length ? 'piece-complete' : 'piece-loading')
} newPiece.percentage = ((Size / Length) * 100).toFixed(2)
} }
Readers.forEach(r => { Readers.forEach(r => {
if (i === r.Reader) newPiece.isActive = true if (i === r.Reader) {
if (i >= r.Start && i <= r.End) newPiece.isReaderRange = true className.push('piece-reader')
} else if (i >= r.Start && i <= r.End) className.push('reader-range')
}) })
newPiece.className = className.join(' ')
map.push(newPiece) map.push(newPiece)
} }
setCacheMap(map) setCacheMap(map)
}, [cache]) }, [cache])

View File

@@ -1174,7 +1174,7 @@
dependencies: dependencies:
regenerator-runtime "^0.13.4" regenerator-runtime "^0.13.4"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.14.0", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.14.0", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
version "7.14.0" version "7.14.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6"
integrity sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA== integrity sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==
@@ -7938,11 +7938,6 @@ klona@^2.0.4:
resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0" resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0"
integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA== integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==
konva@^8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/konva/-/konva-8.0.1.tgz#f34f483cdf62c36f966addc1a7484ed694313c2b"
integrity sha512-QDppGS1L5Dhod1zjwy9GVVjeyfPBHnPncL5oRh1NyjR1mEvhrLjzflrkdW+p73uFIW9hwCDZVLGxzzjQre9izw==
language-subtag-registry@~0.3.2: language-subtag-registry@~0.3.2:
version "0.3.21" version "0.3.21"
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a" resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a"
@@ -8306,11 +8301,6 @@ media-typer@0.3.0:
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
"memoize-one@>=3.1.1 <6":
version "5.2.1"
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
memory-fs@^0.4.1: memory-fs@^0.4.1:
version "0.4.1" version "0.4.1"
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
@@ -10477,14 +10467,6 @@ react-is@^16.7.0, react-is@^16.8.1:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
react-konva@^17.0.2-4:
version "17.0.2-4"
resolved "https://registry.yarnpkg.com/react-konva/-/react-konva-17.0.2-4.tgz#afd0968e1295b624bf2a7a154ba294e0d5be55cd"
integrity sha512-YvRVPT81y8sMQV1SY1/tIDetGxBK+7Rk86u4LmiyDBLLE17vD78F01b8EC3AuP3nI3hUaTblfBugUF35cm6Etg==
dependencies:
react-reconciler "~0.26.2"
scheduler "^0.20.2"
react-measure@^2.5.2: react-measure@^2.5.2:
version "2.5.2" version "2.5.2"
resolved "https://registry.yarnpkg.com/react-measure/-/react-measure-2.5.2.tgz#4ffc410e8b9cb836d9455a9ff18fc1f0fca67f89" resolved "https://registry.yarnpkg.com/react-measure/-/react-measure-2.5.2.tgz#4ffc410e8b9cb836d9455a9ff18fc1f0fca67f89"
@@ -10504,15 +10486,6 @@ react-query@^3.17.0:
broadcast-channel "^3.4.1" broadcast-channel "^3.4.1"
match-sorter "^6.0.2" match-sorter "^6.0.2"
react-reconciler@~0.26.2:
version "0.26.2"
resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.26.2.tgz#bbad0e2d1309423f76cf3c3309ac6c96e05e9d91"
integrity sha512-nK6kgY28HwrMNwDnMui3dvm3rCFjZrcGiuwLc5COUipBK5hWHLOxMJhSnSomirqWwjPBJKV1QcbkI0VJr7Gl1Q==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
scheduler "^0.20.2"
react-refresh@^0.8.3: react-refresh@^0.8.3:
version "0.8.3" version "0.8.3"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f"
@@ -10594,19 +10567,6 @@ react-transition-group@^4.4.0:
loose-envify "^1.4.0" loose-envify "^1.4.0"
prop-types "^15.6.2" prop-types "^15.6.2"
react-virtualized-auto-sizer@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.5.tgz#9eeeb8302022de56fbd7a860b08513120ce36509"
integrity sha512-kivjYVWX15TX2IUrm8F1jaCEX8EXrpy3DD+u41WGqJ1ZqbljWpiwscV+VxOM1l7sSIM1jwi2LADjhhAJkJ9dxA==
react-window@^1.8.6:
version "1.8.6"
resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.6.tgz#d011950ac643a994118632665aad0c6382e2a112"
integrity sha512-8VwEEYyjz6DCnGBsd+MgkD0KJ2/OXFULyDtorIiTz+QzwoP94tBoA7CnbtyXMm+cCeAUER5KJcPtWl9cpKbOBg==
dependencies:
"@babel/runtime" "^7.0.0"
memoize-one ">=3.1.1 <6"
react@^17.0.2: react@^17.0.2:
version "17.0.2" version "17.0.2"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"