diff --git a/web/package.json b/web/package.json index 2a23206..ce5efa6 100644 --- a/web/package.json +++ b/web/package.json @@ -23,6 +23,7 @@ "react-i18next": "^11.10.0", "react-konva": "^17.0.2-4", "react-measure": "^2.5.2", + "react-query": "^3.17.0", "react-scripts": "4.0.3", "react-virtualized-auto-sizer": "^1.0.5", "react-window": "^1.8.6", diff --git a/web/src/components/Add/AddDialog.jsx b/web/src/components/Add/AddDialog.jsx index 6e5bdbf..aa59b0b 100644 --- a/web/src/components/Add/AddDialog.jsx +++ b/web/src/components/Add/AddDialog.jsx @@ -15,11 +15,17 @@ import { ButtonWrapper, Content, Header } from './style' import RightSideComponent from './RightSideComponent' import LeftSideComponent from './LeftSideComponent' -export default function AddDialog({ handleClose }) { +export default function AddDialog({ + handleClose, + hash: originalHash, + title: originalTitle, + name: originalName, + poster: originalPoster, +}) { const { t } = useTranslation() - const [torrentSource, setTorrentSource] = useState('') - const [title, setTitle] = useState('') - const [posterUrl, setPosterUrl] = useState('') + const [torrentSource, setTorrentSource] = useState(originalHash || '') + const [title, setTitle] = useState(originalTitle || '') + const [posterUrl, setPosterUrl] = useState(originalPoster || '') const [isPosterUrlCorrect, setIsPosterUrlCorrect] = useState(false) const [isTorrentSourceCorrect, setIsTorrentSourceCorrect] = useState(false) const [posterList, setPosterList] = useState() @@ -29,9 +35,22 @@ export default function AddDialog({ handleClose }) { const [posterSearchLanguage, setPosterSearchLanguage] = useState(currentLang === 'ru' ? 'ru' : 'en') const [isLoadingButton, setIsLoadingButton] = useState(false) const [skipDebounce, setSkipDebounce] = useState(false) + const [isEditMode, setIsEditMode] = useState(false) const fullScreen = useMediaQuery('@media (max-width:930px)') + useEffect(() => { + if (originalHash) { + setIsEditMode(true) + + checkImageURL(posterUrl).then(correctImage => { + correctImage ? setIsPosterUrlCorrect(true) : removePoster() + }) + } + // This is needed only on mount + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + const posterSearch = useMemo( () => (movieName, language, { shouldRefreshMainPoster = false } = {}) => { @@ -97,7 +116,7 @@ export default function AddDialog({ handleClose }) { posterSearch(title, posterSearchLanguage) setSkipDebounce(false) } else { - delayedPosterSearch(title, posterSearchLanguage) + title === '' ? removePoster() : delayedPosterSearch(title, posterSearchLanguage) } }, [title, prevTitleState, delayedPosterSearch, posterSearch, posterSearchLanguage, skipDebounce]) @@ -118,7 +137,16 @@ export default function AddDialog({ handleClose }) { const handleSave = () => { setIsLoadingButton(true) - if (selectedFile) { + if (isEditMode) { + axios + .post(torrentsHost(), { + action: 'set', + hash: originalHash, + title: title === '' ? originalName : title, + poster: posterUrl, + }) + .finally(handleClose) + } else if (selectedFile) { // file save const data = new FormData() data.append('save', 'true') @@ -143,16 +171,18 @@ export default function AddDialog({ handleClose }) { fullWidth maxWidth='md' > -
{t('AddNewTorrent')}
+
{t(isEditMode ? 'EditTorrent' : 'AddNewTorrent')}
- - + + {!isEditMode && ( + + )} - {isLoadingButton ? : t('Add')} + {isLoadingButton ? : t(isEditMode ? 'Save' : 'Add')} diff --git a/web/src/components/Add/RightSideComponent.jsx b/web/src/components/Add/RightSideComponent.jsx index b76e917..75da6f0 100644 --- a/web/src/components/Add/RightSideComponent.jsx +++ b/web/src/components/Add/RightSideComponent.jsx @@ -1,5 +1,4 @@ import { useTranslation } from 'react-i18next' -import { v4 as uuidv4 } from 'uuid' import { NoImageIcon } from 'icons' import { TextField } from '@material-ui/core' @@ -71,7 +70,7 @@ export default function RightSideComponent({ ?.filter(url => url !== posterUrl) .slice(0, 12) .map(url => ( - userChangesPosterUrl(url)} key={uuidv4()}> + userChangesPosterUrl(url)} key={url}> poster ))} diff --git a/web/src/components/Add/style.js b/web/src/components/Add/style.js index 5374a5f..b286159 100644 --- a/web/src/components/Add/style.js +++ b/web/src/components/Add/style.js @@ -13,16 +13,23 @@ export const Header = styled.div` ` export const Content = styled.div` - background: linear-gradient(145deg, #e4f6ed, #b5dec9); - flex: 1; - display: grid; - grid-template-columns: repeat(2, 1fr); - border-bottom: 1px solid rgba(0, 0, 0, 0.12); - overflow: auto; + ${({ isEditMode }) => css` + background: linear-gradient(145deg, #e4f6ed, #b5dec9); + flex: 1; + display: grid; + grid-template-columns: repeat(${isEditMode ? '1' : '2'}, 1fr); + border-bottom: 1px solid rgba(0, 0, 0, 0.12); + overflow: auto; - @media (max-width: 930px) { - grid-template-columns: 1fr; - } + @media (max-width: 540px) { + ${'' /* Just for bug fixing on small screens */} + overflow: scroll; + } + + @media (max-width: 930px) { + grid-template-columns: 1fr; + } + `} ` export const RightSide = styled.div` diff --git a/web/src/components/DialogTorrentDetailsContent/TorrentCache/LargeSnake.jsx b/web/src/components/DialogTorrentDetailsContent/TorrentCache/LargeSnake.jsx index e2d8dbe..82e1d56 100644 --- a/web/src/components/DialogTorrentDetailsContent/TorrentCache/LargeSnake.jsx +++ b/web/src/components/DialogTorrentDetailsContent/TorrentCache/LargeSnake.jsx @@ -1,9 +1,10 @@ import { FixedSizeGrid as Grid } from 'react-window' import AutoSizer from 'react-virtualized-auto-sizer' +import { memo } from 'react' import { getLargeSnakeColors } from './colors' -const Cell = ({ columnIndex, rowIndex, style, data }) => { +const Cell = memo(({ columnIndex, rowIndex, style, data }) => { const { columnCount, cacheMap, gutterSize, borderSize, pieces } = data const itemIndex = rowIndex * columnCount + columnIndex @@ -21,7 +22,7 @@ const Cell = ({ columnIndex, rowIndex, style, data }) => { } return
-} +}) const gutterSize = 2 const borderSize = 1 diff --git a/web/src/components/DialogTorrentDetailsContent/index.jsx b/web/src/components/DialogTorrentDetailsContent/index.jsx index dc0fd45..f111305 100644 --- a/web/src/components/DialogTorrentDetailsContent/index.jsx +++ b/web/src/components/DialogTorrentDetailsContent/index.jsx @@ -100,17 +100,20 @@ export default function DialogTorrentDetailsContent({ closeDialog, torrent }) { }, [hash]) const bufferSize = settings?.PreloadBuffer ? Capacity : 33554432 // Default is 32mb if PreloadBuffer is false - // const bufferSize = Capacity - const getTitle = value => { - const torrentParsedName = value && ptt.parse(value) + const getParsedTitle = () => { const newNameStrings = [] - if (torrentParsedName?.title) newNameStrings.push(` ${torrentParsedName?.title}`) - if (torrentParsedName?.year) newNameStrings.push(`. ${torrentParsedName?.year}.`) - if (torrentParsedName?.resolution) newNameStrings.push(` (${torrentParsedName?.resolution})`) + const torrentParsedName = name && ptt.parse(name) - return newNameStrings.join(' ') + if (title !== name) { + newNameStrings.push(title) + } else if (torrentParsedName?.title) newNameStrings.push(torrentParsedName?.title) + + if (torrentParsedName?.year) newNameStrings.push(torrentParsedName?.year) + if (torrentParsedName?.resolution) newNameStrings.push(torrentParsedName?.resolution) + + return newNameStrings.join('. ') } return ( @@ -141,13 +144,13 @@ export default function DialogTorrentDetailsContent({ closeDialog, torrent }) { {poster ? poster : }
- {name && name !== title ? ( + {title && name !== title ? ( <> - {shortenText(getTitle(name), 50)} - {shortenText(title, 160)} + {shortenText(getParsedTitle(), 55)} + {shortenText(ptt.parse(name).title, 110)} ) : ( - {shortenText(getTitle(title), 50)} + {shortenText(getParsedTitle(), 55)} )} diff --git a/web/src/components/Settings.jsx b/web/src/components/Settings.jsx index f54a944..3e5cb5c 100644 --- a/web/src/components/Settings.jsx +++ b/web/src/components/Settings.jsx @@ -40,8 +40,8 @@ export default function SettingsDialog() { .catch(() => setShow(false)) }, [tsHost]) - const onInputHost = event => { - const host = event.target.value + const onInputHost = ({ target: { value } }) => { + const host = value.replace(/\/$/gi, '') setTorrServerHost(host) setTSHost(host) } diff --git a/web/src/components/TorrentCard/index.jsx b/web/src/components/TorrentCard/index.jsx index b9abfa6..dc88def 100644 --- a/web/src/components/TorrentCard/index.jsx +++ b/web/src/components/TorrentCard/index.jsx @@ -1,6 +1,11 @@ import 'fontsource-roboto' -import { forwardRef, useState } from 'react' -import { UnfoldMore as UnfoldMoreIcon, Close as CloseIcon, Delete as DeleteIcon } from '@material-ui/icons' +import { forwardRef, memo, useState } from 'react' +import { + UnfoldMore as UnfoldMoreIcon, + Edit as EditIcon, + Close as CloseIcon, + Delete as DeleteIcon, +} from '@material-ui/icons' import { getPeerString, humanizeSize, shortenText } from 'utils/Utils' import { torrentsHost } from 'utils/Hosts' import { NoImageIcon } from 'icons' @@ -11,12 +16,13 @@ import { Button, DialogActions, DialogTitle, useMediaQuery, useTheme } from '@ma import axios from 'axios' import ptt from 'parse-torrent-title' import { useTranslation } from 'react-i18next' +import AddDialog from 'components/Add/AddDialog' import { StyledButton, TorrentCard, TorrentCardButtons, TorrentCardDescription, TorrentCardPoster } from './style' const Transition = forwardRef((props, ref) => ) -export default function Torrent({ torrent }) { +const Torrent = ({ torrent }) => { const { t } = useTranslation() const [isDetailedInfoOpened, setIsDetailedInfoOpened] = useState(false) const [isDeleteTorrentOpened, setIsDeleteTorrentOpened] = useState(false) @@ -36,6 +42,10 @@ export default function Torrent({ torrent }) { const parsedTitle = (title || name) && ptt.parse(title || name).title + const [isEditDialogOpen, setIsEditDialogOpen] = useState(false) + const handleClickOpenEditDialog = () => setIsEditDialogOpen(true) + const handleCloseEditDialog = () => setIsEditDialogOpen(false) + return ( <> @@ -49,6 +59,11 @@ export default function Torrent({ torrent }) { {t('Details')} + + + {t('Edit')} + + dropTorrent(torrent)}> {t('Drop')} @@ -118,6 +133,12 @@ export default function Torrent({ torrent }) { + + {isEditDialogOpen && ( + + )} ) } + +export default memo(Torrent) diff --git a/web/src/components/TorrentCard/style.js b/web/src/components/TorrentCard/style.js index 7695aba..eb696bb 100644 --- a/web/src/components/TorrentCard/style.js +++ b/web/src/components/TorrentCard/style.js @@ -66,7 +66,11 @@ export const TorrentCardButtons = styled.div` gap: 10px; @media (max-width: 1260px), (max-height: 500px) { - grid-template-columns: repeat(3, 1fr); + grid-template-columns: repeat(4, 1fr); + } + + @media (max-width: 340px) { + gap: 5px; } ` export const TorrentCardDescription = styled.div` @@ -165,10 +169,13 @@ export const StyledButton = styled.button` text-transform: uppercase; background: #268757; color: #fff; - font-size: 1rem; + font-size: 0.9rem; font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif; letter-spacing: 0.009em; - padding: 10px 20px; + padding: 0 12px; + svg { + width: 20px; + } :hover { background: #2a7e54; @@ -179,28 +186,21 @@ export const StyledButton = styled.button` } @media (max-width: 1260px), (max-height: 500px) { - padding: 5px 10px; - font-size: 0.8rem; - - svg { - width: 20px; - } - } - - @media (max-width: 770px) { - font-size: 0.7rem; - - svg { - width: 15px; - } - } - - @media (max-width: 420px) { padding: 7px 10px; justify-content: center; + font-size: 0.8rem; svg { display: none; } } + + @media (max-width: 770px) { + font-size: 0.7rem; + } + + @media (max-width: 420px) { + font-size: 0.6rem; + padding: 7px 5px; + } ` diff --git a/web/src/components/TorrentList.jsx b/web/src/components/TorrentList.jsx index e4119fd..0a4fc5f 100644 --- a/web/src/components/TorrentList.jsx +++ b/web/src/components/TorrentList.jsx @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from 'react' +import { useState } from 'react' import { Typography } from '@material-ui/core' import { torrentsHost } from 'utils/Hosts' import TorrentCard from 'components/TorrentCard' @@ -6,34 +6,26 @@ import axios from 'axios' import CircularProgress from '@material-ui/core/CircularProgress' import { TorrentListWrapper, CenteredGrid } from 'components/App/style' import { useTranslation } from 'react-i18next' +import { useQuery } from 'react-query' + +const getTorrents = async () => { + try { + const { data } = await axios.post(torrentsHost(), { action: 'list' }) + return data + } catch (error) { + throw new Error(null) + } +} export default function TorrentList() { const { t } = useTranslation() - const [torrents, setTorrents] = useState([]) - const [isLoading, setIsLoading] = useState(true) const [isOffline, setIsOffline] = useState(true) - const timerID = useRef(-1) - - useEffect(() => { - timerID.current = setInterval(() => { - // getting torrent list - axios - .post(torrentsHost(), { action: 'list' }) - .then(({ data }) => { - // updating torrent list - setTorrents(data) - setIsOffline(false) - }) - .catch(() => { - // resetting torrent list - setTorrents([]) - setIsOffline(true) - }) - .finally(() => setIsLoading(false)) - }, 1000) - - return () => clearInterval(timerID.current) - }, []) + const { data: torrents, isLoading } = useQuery('torrents', getTorrents, { + retry: 1, + refetchInterval: 1000, + onError: () => setIsOffline(true), + onSuccess: () => setIsOffline(false), + }) if (isLoading || isOffline || !torrents.length) { return ( diff --git a/web/src/index.jsx b/web/src/index.jsx index 1e33667..d9e88e1 100644 --- a/web/src/index.jsx +++ b/web/src/index.jsx @@ -1,13 +1,19 @@ import { StrictMode } from 'react' import ReactDOM from 'react-dom' +import { QueryClientProvider, QueryClient } from 'react-query' + +import App from './components/App' import 'i18n' import './index.css' -import App from './components/App' + +const queryClient = new QueryClient() ReactDOM.render( - + + + , document.getElementById('root'), ) diff --git a/web/src/locales/en/translation.json b/web/src/locales/en/translation.json index 98a1532..6e0b6d3 100644 --- a/web/src/locales/en/translation.json +++ b/web/src/locales/en/translation.json @@ -4,6 +4,7 @@ "Add": "Add", "AddFromLink": "Add from Link", "AddNewTorrent": "Add new torrent", + "EditTorrent": "Edit torrent", "AddRetrackers": "Add retrackers", "Buffer": "Preload Buffer / Cache", "BufferNote": "Enable “Preload Buffer” in settings to see cache loading progress", @@ -110,5 +111,6 @@ "WrongTorrentSource": "Wrong torrent source", "ScrollDown": "scroll down", "Cache": "Cache", - "Data": "Data" + "Data": "Data", + "Edit": "Edit" } \ No newline at end of file diff --git a/web/src/locales/ru/translation.json b/web/src/locales/ru/translation.json index 198d5a2..2fce006 100644 --- a/web/src/locales/ru/translation.json +++ b/web/src/locales/ru/translation.json @@ -4,6 +4,7 @@ "Add": "Добавить", "AddFromLink": "Добавить", "AddNewTorrent": "Добавить новый торрент", + "EditTorrent": "Изменить торрент", "AddRetrackers": "Добавлять", "Buffer": "Предзагрузка / Кеш", "BufferNote": "Включите «Наполнять кеш перед началом воспроизведения» в настройках для показа заполнения кеша", @@ -109,6 +110,7 @@ "AddTorrentSourceNotification": "Сначала добавьте торрент источник", "WrongTorrentSource": "Неправильный torrent источник", "ScrollDown": "прокрутить вниз", - "Cache": "Кэш", - "Data": "Данные" + "Cache": "Кеш", + "Data": "Данные", + "Edit": "Изменить" } \ No newline at end of file diff --git a/web/yarn.lock b/web/yarn.lock index bb34a6a..4e7b69f 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -1181,6 +1181,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.12.5", "@babel/runtime@^7.6.2": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.5.tgz#665450911c6031af38f81db530f387ec04cd9a98" + integrity sha512-121rumjddw9c3NCQ55KGkyE1h/nzWhU/owjhw0l4mQrkzz4x9SGS1X8gFLraHwX7td3Yo4QTL+qj0NcIzN87BA== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.10.4", "@babel/template@^7.12.13", "@babel/template@^7.3.3": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327" @@ -3245,6 +3252,11 @@ bfj@^7.0.2: hoopy "^0.1.4" tryer "^1.0.1" +big-integer@^1.6.16: + version "1.6.48" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.48.tgz#8fd88bd1632cba4a1c8c3e3d7159f08bb95b4b9e" + integrity sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w== + big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -3356,6 +3368,20 @@ braces@^3.0.1, braces@~3.0.2: dependencies: fill-range "^7.0.1" +broadcast-channel@^3.4.1: + version "3.7.0" + resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937" + integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg== + dependencies: + "@babel/runtime" "^7.7.2" + detect-node "^2.1.0" + js-sha3 "0.8.0" + microseconds "0.2.0" + nano-time "1.0.0" + oblivious-set "1.0.0" + rimraf "3.0.2" + unload "2.2.0" + brorand@^1.0.1, brorand@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" @@ -4674,7 +4700,7 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -detect-node@^2.0.4: +detect-node@^2.0.4, detect-node@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== @@ -7668,6 +7694,11 @@ jest@26.6.0: import-local "^3.0.2" jest-cli "^26.6.0" +js-sha3@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -8221,6 +8252,14 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +match-sorter@^6.0.2: + version "6.3.0" + resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.0.tgz#454a1b31ed218cddbce6231a0ecb5fdc549fed01" + integrity sha512-efYOf/wUpNb8FgNY+cOD2EIJI1S5I7YPKsw0LBp7wqPh5pmMS6i/wr3ZWwfwrAw1NvqTA2KUReVRWDX84lUcOQ== + dependencies: + "@babel/runtime" "^7.12.5" + remove-accents "0.4.2" + matchdep@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/matchdep/-/matchdep-2.0.0.tgz#c6f34834a0d8dbc3b37c27ee8bbcb27c7775582e" @@ -8340,6 +8379,11 @@ micromatch@^4.0.2: braces "^3.0.1" picomatch "^2.2.3" +microseconds@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39" + integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA== + miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -8539,6 +8583,13 @@ nan@^2.12.1: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== +nano-time@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef" + integrity sha1-sFVPaa2J4i0JB/ehKwmTpdlhN+8= + dependencies: + big-integer "^1.6.16" + nanoid@^3.1.23: version "3.1.23" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81" @@ -8868,6 +8919,11 @@ object.values@^1.1.0, object.values@^1.1.3: es-abstract "^1.18.0-next.2" has "^1.0.3" +oblivious-set@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566" + integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw== + obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" @@ -10439,6 +10495,15 @@ react-measure@^2.5.2: prop-types "^15.6.2" resize-observer-polyfill "^1.5.0" +react-query@^3.17.0: + version "3.17.0" + resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.17.0.tgz#461c0a030044760cd874c7ea8aa9d55c2dceb15d" + integrity sha512-/qUNb6ESCz75Z/bR5p/ztp5ipRj8IQSiIpHK3AkCLTT4IqZsceAoD+9B+wbitA0LkxsR3snGrpgKUc9MMYQ/Ow== + dependencies: + "@babel/runtime" "^7.5.5" + broadcast-channel "^3.4.1" + 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" @@ -10739,6 +10804,11 @@ relateurl@^0.2.7: resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= +remove-accents@0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5" + integrity sha1-CkPTqq4egNuRngeuJUsoXZ4ce7U= + remove-bom-buffer@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz#c2bf1e377520d324f623892e33c10cac2c252b53" @@ -10962,6 +11032,13 @@ rgba-regex@^1.0.0: resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= +rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + rimraf@^2.5.4, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -10969,13 +11046,6 @@ rimraf@^2.5.4, rimraf@^2.6.3: dependencies: glob "^7.1.3" -rimraf@^3.0.0, rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" @@ -12455,6 +12525,14 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== +unload@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7" + integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA== + dependencies: + "@babel/runtime" "^7.6.2" + detect-node "^2.0.4" + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"