diff --git a/frontend/package.json b/frontend/package.json index 0e6a56e5..e9450763 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -21,7 +21,7 @@ "react-dom": "^18.3.1", "react-router-dom": "^6.23.1", "react-virtuoso": "^4.7.11", - "recoil": "^0.7.7", + "jotai": "^2.10.2", "rxjs": "^7.8.1" }, "devDependencies": { diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index d4ae3aa0..65d0deba 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -29,6 +29,9 @@ importers: fp-ts: specifier: ^2.16.5 version: 2.16.5 + jotai: + specifier: ^2.10.2 + version: 2.10.2(@types/react@18.3.3)(react@18.3.1) react: specifier: ^18.3.1 version: 18.3.1 @@ -41,9 +44,6 @@ importers: react-virtuoso: specifier: ^4.7.11 version: 4.7.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - recoil: - specifier: ^0.7.7 - version: 0.7.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rxjs: specifier: ^7.8.1 version: 7.8.1 @@ -854,9 +854,6 @@ packages: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - hamt_plus@1.0.2: - resolution: {integrity: sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA==} - has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} @@ -894,6 +891,18 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + jotai@2.10.2: + resolution: {integrity: sha512-DqsBTlRglIBviuJLfK6JxZzpd6vKfbuJ4IqRCz70RFEDeZf46Fcteb/FXxNr1UnoxR5oUy3oq7IE8BrEq0G5DQ==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=17.0.0' + react: '>=17.0.0' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1025,18 +1034,6 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} - recoil@0.7.7: - resolution: {integrity: sha512-8Og5KPQW9LwC577Vc7Ug2P0vQshkv1y3zG3tSSkWMqkWSwHmE+by06L8JtnGocjW6gcCvfwB3YtrJG6/tWivNQ==} - peerDependencies: - react: '>=16.13.1' - react-dom: '*' - react-native: '*' - peerDependenciesMeta: - react-dom: - optional: true - react-native: - optional: true - regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} @@ -1894,8 +1891,6 @@ snapshots: globals@11.12.0: {} - hamt_plus@1.0.2: {} - has-flag@3.0.0: {} has@1.0.3: @@ -1929,6 +1924,11 @@ snapshots: is-number@7.0.0: {} + jotai@2.10.2(@types/react@18.3.3)(react@18.3.1): + optionalDependencies: + '@types/react': 18.3.3 + react: 18.3.1 + js-tokens@4.0.0: {} js-yaml@4.1.0: @@ -2050,13 +2050,6 @@ snapshots: dependencies: picomatch: 2.3.1 - recoil@0.7.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - hamt_plus: 1.0.2 - react: 18.3.1 - optionalDependencies: - react-dom: 18.3.1(react@18.3.1) - regenerator-runtime@0.14.1: {} resolve-from@4.0.0: {} diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 8ba11882..e7e294c4 100755 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,11 +1,11 @@ import { RouterProvider } from 'react-router-dom' -import { RecoilRoot } from 'recoil' +import { Provider } from 'jotai' import { router } from './router' export function App() { return ( - + - + ) } \ No newline at end of file diff --git a/frontend/src/Layout.tsx b/frontend/src/Layout.tsx index 377bf438..6ed6518c 100644 --- a/frontend/src/Layout.tsx +++ b/frontend/src/Layout.tsx @@ -19,7 +19,6 @@ import Typography from '@mui/material/Typography' import { grey } from '@mui/material/colors' import { useMemo, useState } from 'react' import { Link, Outlet } from 'react-router-dom' -import { useRecoilValue } from 'recoil' import { settingsState } from './atoms/settings' import AppBar from './components/AppBar' import Drawer from './components/Drawer' @@ -29,11 +28,12 @@ import SocketSubscriber from './components/SocketSubscriber' import ThemeToggler from './components/ThemeToggler' import { useI18n } from './hooks/useI18n' import Toaster from './providers/ToasterProvider' +import { useAtomValue } from 'jotai' export default function Layout() { const [open, setOpen] = useState(false) - const settings = useRecoilValue(settingsState) + const settings = useAtomValue(settingsState) const mode = settings.theme const theme = useMemo(() => diff --git a/frontend/src/atoms/downloadTemplate.ts b/frontend/src/atoms/downloadTemplate.ts index 346931f3..3cf0276e 100644 --- a/frontend/src/atoms/downloadTemplate.ts +++ b/frontend/src/atoms/downloadTemplate.ts @@ -1,50 +1,40 @@ import { getOrElse } from 'fp-ts/lib/Either' import { pipe } from 'fp-ts/lib/function' -import { atom, selector } from 'recoil' import { ffetch } from '../lib/httpClient' import { CustomTemplate } from '../types' import { serverSideCookiesState, serverURL } from './settings' +import { atom } from 'jotai' +import { atomWithStorage } from 'jotai/utils' -export const cookiesTemplateState = selector({ - key: 'cookiesTemplateState', - get: ({ get }) => get(serverSideCookiesState) +export const cookiesTemplateState = atom>(async (get) => + await get(serverSideCookiesState) ? '--cookies=cookies.txt' : '' -}) +) -export const customArgsState = atom({ - key: 'customArgsState', - default: localStorage.getItem('customArgs') ?? '', - effects: [ - ({ onSet }) => onSet(e => localStorage.setItem('customArgs', e)) - ] -}) +export const customArgsState = atomWithStorage( + 'customArgs', + localStorage.getItem('customArgs') ?? '' +) -export const filenameTemplateState = atom({ - key: 'filenameTemplateState', - default: localStorage.getItem('lastFilenameTemplate') ?? '', - effects: [ - ({ onSet }) => onSet(e => localStorage.setItem('lastFilenameTemplate', e)) - ] -}) +export const filenameTemplateState = atomWithStorage( + 'lastFilenameTemplate', + localStorage.getItem('lastFilenameTemplate') ?? '' +) -export const downloadTemplateState = selector({ - key: 'downloadTemplateState', - get: ({ get }) => - `${get(customArgsState)} ${get(cookiesTemplateState)}` - .replace(/ +/g, ' ') - .trim() -}) +export const downloadTemplateState = atom((get) => + `${get(customArgsState)} ${get(cookiesTemplateState)}` + .replace(/ +/g, ' ') + .trim() +) -export const savedTemplatesState = selector({ - key: 'savedTemplatesState', - get: async ({ get }) => { - const task = ffetch(`${get(serverURL)}/api/v1/template/all`) - const either = await task() +export const savedTemplatesState = atom>(async (get) => { + const task = ffetch(`${get(serverURL)}/api/v1/template/all`) + const either = await task() - return pipe( - either, - getOrElse(() => new Array()) - ) - } -}) \ No newline at end of file + return pipe( + either, + getOrElse(() => new Array()) + ) +} +) \ No newline at end of file diff --git a/frontend/src/atoms/downloads.ts b/frontend/src/atoms/downloads.ts index cedf6e35..46c1d9bf 100644 --- a/frontend/src/atoms/downloads.ts +++ b/frontend/src/atoms/downloads.ts @@ -1,22 +1,13 @@ import * as O from 'fp-ts/Option' import { pipe } from 'fp-ts/lib/function' -import { atom, selector } from 'recoil' import { RPCResult } from '../types' +import { atom } from 'jotai' -export const downloadsState = atom>({ - key: 'downloadsState', - default: O.none -}) +export const downloadsState = atom>(O.none) -export const loadingDownloadsState = selector({ - key: 'loadingDownloadsState', - get: ({ get }) => O.isNone(get(downloadsState)) -}) +export const loadingDownloadsState = atom((get) => O.isNone(get(downloadsState))) -export const activeDownloadsState = selector({ - key: 'activeDownloadsState', - get: ({ get }) => pipe( - get(downloadsState), - O.getOrElse(() => new Array()) - ) -}) \ No newline at end of file +export const activeDownloadsState = atom((get) => pipe( + get(downloadsState), + O.getOrElse(() => new Array()) +)) \ No newline at end of file diff --git a/frontend/src/atoms/i18n.ts b/frontend/src/atoms/i18n.ts index aacccff6..c9e0299b 100644 --- a/frontend/src/atoms/i18n.ts +++ b/frontend/src/atoms/i18n.ts @@ -1,9 +1,5 @@ -import { selector } from 'recoil' +import { atom } from 'jotai' import I18nBuilder from '../lib/intl' import { languageState } from './settings' -export const i18nBuilderState = selector({ - key: 'i18nBuilderState', - get: ({ get }) => new I18nBuilder(get(languageState)), - dangerouslyAllowMutability: true, -}) +export const i18nBuilderState = atom((get) => new I18nBuilder(get(languageState))) diff --git a/frontend/src/atoms/rpc.ts b/frontend/src/atoms/rpc.ts index 82df50b8..948ede49 100644 --- a/frontend/src/atoms/rpc.ts +++ b/frontend/src/atoms/rpc.ts @@ -1,23 +1,17 @@ -import { atom, selector } from 'recoil' +import { atom } from 'jotai' import { RPCClient } from '../lib/rpcClient' import { rpcHTTPEndpoint, rpcWebSocketEndpoint } from './settings' +import { atomWithStorage } from 'jotai/utils' -export const rpcClientState = selector({ - key: 'rpcClientState', - get: ({ get }) => - new RPCClient( - get(rpcHTTPEndpoint), - get(rpcWebSocketEndpoint), - localStorage.getItem('token') ?? '' - ), - dangerouslyAllowMutability: true, -}) +export const rpcClientState = atom((get) => + new RPCClient( + get(rpcHTTPEndpoint), + get(rpcWebSocketEndpoint), + localStorage.getItem('token') ?? '' + ), +) -export const rpcPollingTimeState = atom({ - key: 'rpcPollingTimeState', - default: Number(localStorage.getItem('rpc-polling-time')) || 1000, - effects: [ - ({ onSet }) => - onSet(a => localStorage.setItem('rpc-polling-time', a.toString())) - ] -}) \ No newline at end of file +export const rpcPollingTimeState = atomWithStorage( + 'rpc-polling-time', + Number(localStorage.getItem('rpc-polling-time')) || 1000 +) \ No newline at end of file diff --git a/frontend/src/atoms/settings.ts b/frontend/src/atoms/settings.ts index 4340aa20..c5e7addd 100644 --- a/frontend/src/atoms/settings.ts +++ b/frontend/src/atoms/settings.ts @@ -1,8 +1,9 @@ import { pipe } from 'fp-ts/lib/function' import { matchW } from 'fp-ts/lib/TaskEither' -import { atom, selector } from 'recoil' import { ffetch } from '../lib/httpClient' import { prefersDarkMode } from '../utils' +import { atomWithStorage } from 'jotai/utils' +import { atom } from 'jotai' export const languages = [ 'english', @@ -40,194 +41,126 @@ export interface SettingsState { appTitle: string } -export const languageState = atom({ - key: 'languageState', - default: localStorage.getItem('language') as Language || 'english', - effects: [ - ({ onSet }) => - onSet(l => localStorage.setItem('language', l.toString())) - ] -}) - -export const themeState = atom({ - key: 'themeStateState', - default: localStorage.getItem('theme') as Theme || 'system', - effects: [ - ({ onSet }) => - onSet(l => localStorage.setItem('theme', l.toString())) - ] -}) - -export const serverAddressState = atom({ - key: 'serverAddressState', - default: localStorage.getItem('server-addr') || window.location.hostname, - effects: [ - ({ onSet }) => - onSet(a => localStorage.setItem('server-addr', a.toString())) - ] -}) - -export const serverPortState = atom({ - key: 'serverPortState', - default: Number(localStorage.getItem('server-port')) || Number(window.location.port), - effects: [ - ({ onSet }) => - onSet(a => localStorage.setItem('server-port', a.toString())) - ] -}) - -export const latestCliArgumentsState = atom({ - key: 'latestCliArgumentsState', - default: localStorage.getItem('cli-args') || '--no-mtime', - effects: [ - ({ onSet }) => - onSet(a => localStorage.setItem('cli-args', a.toString())) - ] -}) - -export const formatSelectionState = atom({ - key: 'formatSelectionState', - default: localStorage.getItem('format-selection') === "true", - effects: [ - ({ onSet }) => - onSet(a => localStorage.setItem('format-selection', a.toString())) - ] -}) - -export const fileRenamingState = atom({ - key: 'fileRenamingState', - default: localStorage.getItem('file-renaming') === "true", - effects: [ - ({ onSet }) => - onSet(a => localStorage.setItem('file-renaming', a.toString())) - ] -}) - -export const pathOverridingState = atom({ - key: 'pathOverridingState', - default: localStorage.getItem('path-overriding') === "true", - effects: [ - ({ onSet }) => - onSet(a => localStorage.setItem('path-overriding', a.toString())) - ] -}) - -export const enableCustomArgsState = atom({ - key: 'enableCustomArgsState', - default: localStorage.getItem('enable-custom-args') === "true", - effects: [ - ({ onSet }) => - onSet(a => localStorage.setItem('enable-custom-args', a.toString())) - ] -}) - -export const listViewState = atom({ - key: 'listViewState', - default: localStorage.getItem('listview') === "true", - effects: [ - ({ onSet }) => - onSet(a => localStorage.setItem('listview', a.toString())) - ] -}) - -export const servedFromReverseProxyState = atom({ - key: 'servedFromReverseProxyState', - default: localStorage.getItem('reverseProxy') === "true" || window.location.port == "", - effects: [ - ({ onSet }) => - onSet(a => localStorage.setItem('reverseProxy', a.toString())) - ] -}) - -export const servedFromReverseProxySubDirState = atom({ - key: 'servedFromReverseProxySubDirState', - default: localStorage.getItem('reverseProxySubDir') ?? '', - effects: [ - ({ onSet }) => - onSet(a => localStorage.setItem('reverseProxySubDir', a)) - ] -}) - -export const appTitleState = atom({ - key: 'appTitleState', - default: localStorage.getItem('appTitle') ?? 'yt-dlp Web UI', - effects: [ - ({ onSet }) => - onSet(a => localStorage.setItem('appTitle', a.toString())) - ] -}) - -export const serverAddressAndPortState = selector({ - key: 'serverAddressAndPortState', - get: ({ get }) => { - if (get(servedFromReverseProxySubDirState)) { - return `${get(serverAddressState)}/${get(servedFromReverseProxySubDirState)}/` - } - if (get(servedFromReverseProxyState)) { - return `${get(serverAddressState)}` - } - return `${get(serverAddressState)}:${get(serverPortState)}` +export const languageState = atomWithStorage( + 'language', + localStorage.getItem('language') as Language || 'english' +) + +export const themeState = atomWithStorage( + 'theme', + localStorage.getItem('theme') as Theme || 'system' +) + +export const serverAddressState = atomWithStorage( + 'server-addr', + localStorage.getItem('server-addr') || window.location.hostname +) + +export const serverPortState = atomWithStorage( + 'server-port', + Number(localStorage.getItem('server-port')) || Number(window.location.port) +) + +export const latestCliArgumentsState = atomWithStorage( + 'cli-args', + localStorage.getItem('cli-args') || '--no-mtime' +) + +export const formatSelectionState = atomWithStorage( + 'format-selection', + localStorage.getItem('format-selection') === 'true' +) + +export const fileRenamingState = atomWithStorage( + 'file-renaming', + localStorage.getItem('file-renaming') === 'true' +) + +export const pathOverridingState = atomWithStorage( + 'path-overriding', + localStorage.getItem('path-overriding') === 'true' +) + +export const enableCustomArgsState = atomWithStorage( + 'enable-custom-args', + localStorage.getItem('enable-custom-args') === 'true' +) + +export const listViewState = atomWithStorage( + 'listview', + localStorage.getItem('listview') === 'true' +) + +export const servedFromReverseProxyState = atomWithStorage( + 'reverseProxy', + localStorage.getItem('reverseProxy') === 'true' || window.location.port == '' +) + +export const servedFromReverseProxySubDirState = atomWithStorage( + 'reverseProxySubDir', + localStorage.getItem('reverseProxySubDir') ?? '' +) + +export const appTitleState = atomWithStorage( + 'appTitle', + localStorage.getItem('appTitle') ?? 'yt-dlp Web UI' +) + +export const serverAddressAndPortState = atom((get) => { + if (get(servedFromReverseProxySubDirState)) { + return `${get(serverAddressState)}/${get(servedFromReverseProxySubDirState)}/` } -}) - -export const serverURL = selector({ - key: 'serverURL', - get: ({ get }) => - `${window.location.protocol}//${get(serverAddressAndPortState)}` -}) - -export const rpcWebSocketEndpoint = selector({ - key: 'rpcWebSocketEndpoint', - get: ({ get }) => { - const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:' - return `${proto}//${get(serverAddressAndPortState)}/rpc/ws` + if (get(servedFromReverseProxyState)) { + return `${get(serverAddressState)}` } + return `${get(serverAddressState)}:${get(serverPortState)}` }) -export const rpcHTTPEndpoint = selector({ - key: 'rpcHTTPEndpoint', - get: ({ get }) => { - const proto = window.location.protocol - return `${proto}//${get(serverAddressAndPortState)}/rpc/http` - } -}) +export const serverURL = atom((get) => + `${window.location.protocol}//${get(serverAddressAndPortState)}` +) -export const serverSideCookiesState = selector({ - key: 'serverSideCookiesState', - get: async ({ get }) => await pipe( - ffetch>(`${get(serverURL)}/api/v1/cookies`), - matchW( - () => '', - (r) => r.cookies - ) - )() -}) +export const rpcWebSocketEndpoint = atom((get) => { + const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:' + return `${proto}//${get(serverAddressAndPortState)}/rpc/ws` +} +) -const themeSelector = selector({ - key: 'themeSelector', - get: ({ get }) => { - const theme = get(themeState) - if ((theme === 'system' && prefersDarkMode()) || theme === 'dark') { - return 'dark' - } - return 'light' +export const rpcHTTPEndpoint = atom((get) => { + const proto = window.location.protocol + return `${proto}//${get(serverAddressAndPortState)}/rpc/http` +} +) + +export const serverSideCookiesState = atom>(async (get) => await pipe( + ffetch>(`${get(serverURL)}/api/v1/cookies`), + matchW( + () => '', + (r) => r.cookies + ) +)()) + +const themeSelector = atom((get) => { + const theme = get(themeState) + if ((theme === 'system' && prefersDarkMode()) || theme === 'dark') { + return 'dark' } -}) - -export const settingsState = selector({ - key: 'settingsState', - get: ({ get }) => ({ - serverAddr: get(serverAddressState), - serverPort: get(serverPortState), - language: get(languageState), - theme: get(themeSelector), - cliArgs: get(latestCliArgumentsState), - formatSelection: get(formatSelectionState), - fileRenaming: get(fileRenamingState), - pathOverriding: get(pathOverridingState), - enableCustomArgs: get(enableCustomArgsState), - listView: get(listViewState), - servedFromReverseProxy: get(servedFromReverseProxyState), - appTitle: get(appTitleState) - }) -}) \ No newline at end of file + return 'light' +} +) + +export const settingsState = atom((get) => ({ + serverAddr: get(serverAddressState), + serverPort: get(serverPortState), + language: get(languageState), + theme: get(themeSelector), + cliArgs: get(latestCliArgumentsState), + formatSelection: get(formatSelectionState), + fileRenaming: get(fileRenamingState), + pathOverriding: get(pathOverridingState), + enableCustomArgs: get(enableCustomArgsState), + listView: get(listViewState), + servedFromReverseProxy: get(servedFromReverseProxyState), + appTitle: get(appTitleState) +}) +) \ No newline at end of file diff --git a/frontend/src/atoms/status.ts b/frontend/src/atoms/status.ts index b171fce7..fc98bdcf 100644 --- a/frontend/src/atoms/status.ts +++ b/frontend/src/atoms/status.ts @@ -1,45 +1,34 @@ import { pipe } from 'fp-ts/lib/function' import { of } from 'fp-ts/lib/Task' import { getOrElse } from 'fp-ts/lib/TaskEither' -import { atom, selector } from 'recoil' import { ffetch } from '../lib/httpClient' import { RPCVersion } from '../types' import { rpcClientState } from './rpc' import { serverURL } from './settings' +import { atom } from 'jotai' -export const connectedState = atom({ - key: 'connectedState', - default: false -}) +export const connectedState = atom(false) -export const freeSpaceBytesState = selector({ - key: 'freeSpaceBytesState', - get: async ({ get }) => { - const res = await get(rpcClientState).freeSpace() - .catch(() => ({ result: 0 })) - return res.result - } +export const freeSpaceBytesState = atom(async (get) => { + const res = await get(rpcClientState) + .freeSpace() + .catch(() => ({ result: 0 })) + return res.result }) -export const availableDownloadPathsState = selector({ - key: 'availableDownloadPathsState', - get: async ({ get }) => { - const res = await get(rpcClientState).directoryTree() - .catch(() => ({ result: [] })) - return res.result - } +export const availableDownloadPathsState = atom(async (get) => { + const res = await get(rpcClientState).directoryTree() + .catch(() => ({ result: [] })) + return res.result }) -export const ytdlpRpcVersionState = selector({ - key: 'ytdlpRpcVersionState', - get: async ({ get }) => await pipe( - ffetch(`${get(serverURL)}/api/v1/version`), - getOrElse(() => pipe( - { - rpcVersion: 'unknown version', - ytdlpVersion: 'unknown version', - }, - of - )), - )() -}) \ No newline at end of file +export const ytdlpRpcVersionState = atom>(async (get) => await pipe( + ffetch(`${get(serverURL)}/api/v1/version`), + getOrElse(() => pipe( + { + rpcVersion: 'unknown version', + ytdlpVersion: 'unknown version', + }, + of + )), +)()) \ No newline at end of file diff --git a/frontend/src/atoms/toast.ts b/frontend/src/atoms/toast.ts index 326b91f4..fa11b9f8 100644 --- a/frontend/src/atoms/toast.ts +++ b/frontend/src/atoms/toast.ts @@ -1,5 +1,5 @@ import { AlertColor } from '@mui/material' -import { atom } from 'recoil' +import { atom } from 'jotai' export type Toast = { open: boolean, @@ -9,7 +9,4 @@ export type Toast = { severity?: AlertColor } -export const toastListState = atom({ - key: 'toastListState', - default: [], -}) \ No newline at end of file +export const toastListState = atom([]) \ No newline at end of file diff --git a/frontend/src/atoms/ui.ts b/frontend/src/atoms/ui.ts index c745defe..4e0d8b5f 100644 --- a/frontend/src/atoms/ui.ts +++ b/frontend/src/atoms/ui.ts @@ -1,14 +1,10 @@ -import { atom, selector } from 'recoil' +import { atom } from 'jotai' import { activeDownloadsState } from './downloads' -export const loadingAtom = atom({ - key: 'loadingAtom', - default: true -}) +export const loadingAtom = atom(true) -export const totalDownloadSpeedState = selector({ - key: 'totalDownloadSpeedState', - get: ({ get }) => get(activeDownloadsState) +export const totalDownloadSpeedState = atom((get) => + get(activeDownloadsState) .map(d => d.progress.speed) .reduce((curr, next) => curr + next, 0) -}) \ No newline at end of file +) \ No newline at end of file diff --git a/frontend/src/components/CookiesTextField.tsx b/frontend/src/components/CookiesTextField.tsx index 40781f4b..6d64b302 100644 --- a/frontend/src/components/CookiesTextField.tsx +++ b/frontend/src/components/CookiesTextField.tsx @@ -5,12 +5,12 @@ import * as O from 'fp-ts/Option' import { matchW } from 'fp-ts/lib/TaskEither' import { pipe } from 'fp-ts/lib/function' import { useMemo } from 'react' -import { useRecoilValue } from 'recoil' import { Subject, debounceTime, distinctUntilChanged } from 'rxjs' import { serverSideCookiesState, serverURL } from '../atoms/settings' import { useSubscription } from '../hooks/observable' import { useToast } from '../hooks/toast' import { ffetch } from '../lib/httpClient' +import { useAtomValue } from 'jotai' const validateCookie = (cookie: string) => pipe( cookie, @@ -75,8 +75,8 @@ const noopValidator = (s: string): E.Either => pipe( const isCommentOrNewLine = (s: string) => s === '' || s.startsWith('\n') || s.startsWith('#') const CookiesTextField: React.FC = () => { - const serverAddr = useRecoilValue(serverURL) - const savedCookies = useRecoilValue(serverSideCookiesState) + const serverAddr = useAtomValue(serverURL) + const savedCookies = useAtomValue(serverSideCookiesState) const { pushMessage } = useToast() diff --git a/frontend/src/components/DownloadCard.tsx b/frontend/src/components/DownloadCard.tsx index efbb0d55..3ec27851 100644 --- a/frontend/src/components/DownloadCard.tsx +++ b/frontend/src/components/DownloadCard.tsx @@ -16,10 +16,10 @@ import { Typography } from '@mui/material' import { useCallback } from 'react' -import { useRecoilValue } from 'recoil' import { serverURL } from '../atoms/settings' import { RPCResult } from '../types' import { base64URLEncode, ellipsis, formatSize, formatSpeedMiB, mapProcessStatus } from '../utils' +import { useAtomValue } from 'jotai' type Props = { download: RPCResult @@ -37,7 +37,7 @@ const Resolution: React.FC<{ resolution?: string }> = ({ resolution }) => { } const DownloadCard: React.FC = ({ download, onStop, onCopy }) => { - const serverAddr = useRecoilValue(serverURL) + const serverAddr = useAtomValue(serverURL) const isCompleted = useCallback( () => download.progress.percentage === '-1', diff --git a/frontend/src/components/DownloadDialog.tsx b/frontend/src/components/DownloadDialog.tsx index 5151184b..953c2eb3 100644 --- a/frontend/src/components/DownloadDialog.tsx +++ b/frontend/src/components/DownloadDialog.tsx @@ -30,7 +30,6 @@ import { useState, useTransition } from 'react' -import { useRecoilState, useRecoilValue } from 'recoil' import { customArgsState, downloadTemplateState, filenameTemplateState, savedTemplatesState } from '../atoms/downloadTemplate' import { settingsState } from '../atoms/settings' import { availableDownloadPathsState, connectedState } from '../atoms/status' @@ -42,6 +41,7 @@ import { toFormatArgs } from '../utils' import ExtraDownloadOptions from './ExtraDownloadOptions' import { useToast } from '../hooks/toast' import LoadingBackdrop from './LoadingBackdrop' +import { useAtom, useAtomValue } from 'jotai' const Transition = forwardRef(function Transition( props: TransitionProps & { @@ -59,11 +59,11 @@ type Props = { } const DownloadDialog: FC = ({ open, onClose, onDownloadStart }) => { - const settings = useRecoilValue(settingsState) - const isConnected = useRecoilValue(connectedState) - const availableDownloadPaths = useRecoilValue(availableDownloadPathsState) - const downloadTemplate = useRecoilValue(downloadTemplateState) - const savedTemplates = useRecoilValue(savedTemplatesState) + const settings = useAtomValue(settingsState) + const isConnected = useAtomValue(connectedState) + const availableDownloadPaths = useAtomValue(availableDownloadPathsState) + const downloadTemplate = useAtomValue(downloadTemplateState) + const savedTemplates = useAtomValue(savedTemplatesState) const [downloadFormats, setDownloadFormats] = useState() const [pickedVideoFormat, setPickedVideoFormat] = useState('') @@ -71,11 +71,11 @@ const DownloadDialog: FC = ({ open, onClose, onDownloadStart }) => { const [pickedBestFormat, setPickedBestFormat] = useState('') const [isFormatsLoading, setIsFormatsLoading] = useState(false) - const [customArgs, setCustomArgs] = useRecoilState(customArgsState) + const [customArgs, setCustomArgs] = useAtom(customArgsState) const [downloadPath, setDownloadPath] = useState('') - const [filenameTemplate, setFilenameTemplate] = useRecoilState( + const [filenameTemplate, setFilenameTemplate] = useAtom( filenameTemplateState ) diff --git a/frontend/src/components/Downloads.tsx b/frontend/src/components/Downloads.tsx index 5caa3ec4..836a229f 100644 --- a/frontend/src/components/Downloads.tsx +++ b/frontend/src/components/Downloads.tsx @@ -1,5 +1,5 @@ +import { useAtom, useAtomValue } from 'jotai' import { useEffect } from 'react' -import { useRecoilState, useRecoilValue } from 'recoil' import { loadingDownloadsState } from '../atoms/downloads' import { listViewState } from '../atoms/settings' import { loadingAtom } from '../atoms/ui' @@ -7,10 +7,10 @@ import DownloadsGridView from './DownloadsGridView' import DownloadsTableView from './DownloadsTableView' const Downloads: React.FC = () => { - const tableView = useRecoilValue(listViewState) - const loadingDownloads = useRecoilValue(loadingDownloadsState) + const tableView = useAtomValue(listViewState) + const loadingDownloads = useAtomValue(loadingDownloadsState) - const [isLoading, setIsLoading] = useRecoilState(loadingAtom) + const [isLoading, setIsLoading] = useAtom(loadingAtom) useEffect(() => { if (loadingDownloads) { diff --git a/frontend/src/components/DownloadsGridView.tsx b/frontend/src/components/DownloadsGridView.tsx index ca2fc4e3..1f97b14a 100644 --- a/frontend/src/components/DownloadsGridView.tsx +++ b/frontend/src/components/DownloadsGridView.tsx @@ -1,5 +1,5 @@ import { Grid } from '@mui/material' -import { useRecoilValue } from 'recoil' +import { useAtomValue } from 'jotai' import { activeDownloadsState } from '../atoms/downloads' import { useToast } from '../hooks/toast' import { useI18n } from '../hooks/useI18n' @@ -8,7 +8,7 @@ import { ProcessStatus, RPCResult } from '../types' import DownloadCard from './DownloadCard' const DownloadsGridView: React.FC = () => { - const downloads = useRecoilValue(activeDownloadsState) + const downloads = useAtomValue(activeDownloadsState) const { i18n } = useI18n() const { client } = useRPC() diff --git a/frontend/src/components/DownloadsTableView.tsx b/frontend/src/components/DownloadsTableView.tsx index d15dff9b..c9c3b060 100644 --- a/frontend/src/components/DownloadsTableView.tsx +++ b/frontend/src/components/DownloadsTableView.tsx @@ -20,12 +20,12 @@ import { } from "@mui/material" import { forwardRef } from 'react' import { TableComponents, TableVirtuoso } from 'react-virtuoso' -import { useRecoilValue } from 'recoil' import { activeDownloadsState } from '../atoms/downloads' import { serverURL } from '../atoms/settings' import { useRPC } from '../hooks/useRPC' import { ProcessStatus, RPCResult } from '../types' import { base64URLEncode, formatSize, formatSpeedMiB } from "../utils" +import { useAtomValue } from 'jotai' const columns = [ { @@ -119,8 +119,8 @@ function fixedHeaderContent() { } const DownloadsTableView: React.FC = () => { - const downloads = useRecoilValue(activeDownloadsState) - const serverAddr = useRecoilValue(serverURL) + const downloads = useAtomValue(activeDownloadsState) + const serverAddr = useAtomValue(serverURL) const { client } = useRPC() const viewFile = (path: string) => { diff --git a/frontend/src/components/ExtraDownloadOptions.tsx b/frontend/src/components/ExtraDownloadOptions.tsx index 0d4ae8e8..83dda1fc 100644 --- a/frontend/src/components/ExtraDownloadOptions.tsx +++ b/frontend/src/components/ExtraDownloadOptions.tsx @@ -1,13 +1,13 @@ import { Autocomplete, Box, TextField, Typography } from '@mui/material' -import { useRecoilState, useRecoilValue } from 'recoil' import { customArgsState, savedTemplatesState } from '../atoms/downloadTemplate' import { useI18n } from '../hooks/useI18n' +import { useAtom, useAtomValue } from 'jotai' const ExtraDownloadOptions: React.FC = () => { const { i18n } = useI18n() - const customTemplates = useRecoilValue(savedTemplatesState) - const [, setCustomArgs] = useRecoilState(customArgsState) + const customTemplates = useAtomValue(savedTemplatesState) + const [, setCustomArgs] = useAtom(customArgsState) return ( <> diff --git a/frontend/src/components/Footer.tsx b/frontend/src/components/Footer.tsx index 1d643298..ee777b6c 100644 --- a/frontend/src/components/Footer.tsx +++ b/frontend/src/components/Footer.tsx @@ -2,7 +2,6 @@ import DownloadIcon from '@mui/icons-material/Download' import SettingsEthernet from '@mui/icons-material/SettingsEthernet' import { AppBar, CircularProgress, Divider, Toolbar } from '@mui/material' import { Suspense } from 'react' -import { useRecoilValue } from 'recoil' import { settingsState } from '../atoms/settings' import { connectedState } from '../atoms/status' import { totalDownloadSpeedState } from '../atoms/ui' @@ -10,11 +9,12 @@ import { useI18n } from '../hooks/useI18n' import { formatSpeedMiB } from '../utils' import FreeSpaceIndicator from './FreeSpaceIndicator' import VersionIndicator from './VersionIndicator' +import { useAtomValue } from 'jotai' const Footer: React.FC = () => { - const settings = useRecoilValue(settingsState) - const isConnected = useRecoilValue(connectedState) - const totalDownloadSpeed = useRecoilValue(totalDownloadSpeedState) + const settings = useAtomValue(settingsState) + const isConnected = useAtomValue(connectedState) + const totalDownloadSpeed = useAtomValue(totalDownloadSpeedState) const mode = settings.theme const { i18n } = useI18n() diff --git a/frontend/src/components/FreeSpaceIndicator.tsx b/frontend/src/components/FreeSpaceIndicator.tsx index 46dd979e..70941ec2 100644 --- a/frontend/src/components/FreeSpaceIndicator.tsx +++ b/frontend/src/components/FreeSpaceIndicator.tsx @@ -1,10 +1,10 @@ import StorageIcon from '@mui/icons-material/Storage' -import { useRecoilValue } from 'recoil' import { freeSpaceBytesState } from '../atoms/status' import { formatSize } from '../utils' +import { useAtomValue } from 'jotai' const FreeSpaceIndicator = () => { - const freeSpace = useRecoilValue(freeSpaceBytesState) + const freeSpace = useAtomValue(freeSpaceBytesState) return (
{ - const [, setIsLoading] = useRecoilState(loadingAtom) + const setIsLoading = useSetAtom(loadingAtom) const [openDownload, setOpenDownload] = useState(false) const [openEditor, setOpenEditor] = useState(false) diff --git a/frontend/src/components/HomeSpeedDial.tsx b/frontend/src/components/HomeSpeedDial.tsx index f53ad505..0659fd8d 100644 --- a/frontend/src/components/HomeSpeedDial.tsx +++ b/frontend/src/components/HomeSpeedDial.tsx @@ -9,7 +9,7 @@ import { SpeedDialAction, SpeedDialIcon } from '@mui/material' -import { useRecoilState, useRecoilValue } from 'recoil' +import { useAtom, useAtomValue } from 'jotai' import { listViewState, serverURL } from '../atoms/settings' import { useI18n } from '../hooks/useI18n' import { useRPC } from '../hooks/useRPC' @@ -20,8 +20,8 @@ type Props = { } const HomeSpeedDial: React.FC = ({ onDownloadOpen, onEditorOpen }) => { - const serverAddr = useRecoilValue(serverURL) - const [listView, setListView] = useRecoilState(listViewState) + const serverAddr = useAtomValue(serverURL) + const [listView, setListView] = useAtom(listViewState) const { i18n } = useI18n() const { client } = useRPC() diff --git a/frontend/src/components/LogTerminal.tsx b/frontend/src/components/LogTerminal.tsx index f6cabdba..0d070bea 100644 --- a/frontend/src/components/LogTerminal.tsx +++ b/frontend/src/components/LogTerminal.tsx @@ -1,7 +1,7 @@ import { useEffect, useMemo, useRef, useState } from 'react' -import { useRecoilValue } from 'recoil' import { serverURL } from '../atoms/settings' import { useI18n } from '../hooks/useI18n' +import { useAtomValue } from 'jotai' const token = localStorage.getItem('token') @@ -11,7 +11,7 @@ const LogTerminal: React.FC = () => { const boxRef = useRef(null) - const serverAddr = useRecoilValue(serverURL) + const serverAddr = useAtomValue(serverURL) const { i18n } = useI18n() diff --git a/frontend/src/components/SocketSubscriber.tsx b/frontend/src/components/SocketSubscriber.tsx index 91df41a0..75043837 100644 --- a/frontend/src/components/SocketSubscriber.tsx +++ b/frontend/src/components/SocketSubscriber.tsx @@ -1,7 +1,6 @@ import * as O from 'fp-ts/Option' import { useEffect, useMemo } from 'react' import { useNavigate } from 'react-router-dom' -import { useRecoilState, useRecoilValue } from 'recoil' import { take, timer } from 'rxjs' import { downloadsState } from '../atoms/downloads' import { rpcPollingTimeState } from '../atoms/rpc' @@ -12,15 +11,16 @@ import { useToast } from '../hooks/toast' import { useI18n } from '../hooks/useI18n' import { useRPC } from '../hooks/useRPC' import { datetimeCompareFunc, isRPCResponse } from '../utils' +import { useAtom, useAtomValue, useSetAtom } from 'jotai' interface Props extends React.HTMLAttributes { } const SocketSubscriber: React.FC = () => { - const [connected, setIsConnected] = useRecoilState(connectedState) - const [, setDownloads] = useRecoilState(downloadsState) + const [connected, setIsConnected] = useAtom(connectedState) + const setDownloads = useSetAtom(downloadsState) - const serverAddressAndPort = useRecoilValue(serverAddressAndPortState) - const rpcPollingTime = useRecoilValue(rpcPollingTimeState) + const serverAddressAndPort = useAtomValue(serverAddressAndPortState) + const rpcPollingTime = useAtomValue(rpcPollingTimeState) const { i18n } = useI18n() const { client } = useRPC() diff --git a/frontend/src/components/Splash.tsx b/frontend/src/components/Splash.tsx index 85def232..0b10cc84 100644 --- a/frontend/src/components/Splash.tsx +++ b/frontend/src/components/Splash.tsx @@ -1,8 +1,8 @@ import CloudDownloadIcon from '@mui/icons-material/CloudDownload' import { Container, SvgIcon, Typography, styled } from '@mui/material' -import { useRecoilValue } from 'recoil' import { activeDownloadsState } from '../atoms/downloads' import { useI18n } from '../hooks/useI18n' +import { useAtomValue } from 'jotai' const FlexContainer = styled(Container)({ display: 'flex', @@ -23,7 +23,7 @@ const Title = styled(Typography)({ export default function Splash() { const { i18n } = useI18n() - const activeDownloads = useRecoilValue(activeDownloadsState) + const activeDownloads = useAtomValue(activeDownloadsState) if (activeDownloads.length !== 0) { return null diff --git a/frontend/src/components/TemplatesEditor.tsx b/frontend/src/components/TemplatesEditor.tsx index f80bd6ac..c642e6bb 100644 --- a/frontend/src/components/TemplatesEditor.tsx +++ b/frontend/src/components/TemplatesEditor.tsx @@ -20,12 +20,12 @@ import { TransitionProps } from '@mui/material/transitions' import { matchW } from 'fp-ts/lib/Either' import { pipe } from 'fp-ts/lib/function' import { forwardRef, useEffect, useState, useTransition } from 'react' -import { useRecoilValue } from 'recoil' import { serverURL } from '../atoms/settings' import { useToast } from '../hooks/toast' import { useI18n } from '../hooks/useI18n' import { ffetch } from '../lib/httpClient' import { CustomTemplate } from '../types' +import { useAtomValue } from 'jotai' const Transition = forwardRef(function Transition( props: TransitionProps & { @@ -45,7 +45,7 @@ const TemplatesEditor: React.FC = ({ open, onClose }) => { const [templateName, setTemplateName] = useState('') const [templateContent, setTemplateContent] = useState('') - const serverAddr = useRecoilValue(serverURL) + const serverAddr = useAtomValue(serverURL) const [isPending, startTransition] = useTransition() const [templates, setTemplates] = useState([]) diff --git a/frontend/src/components/ThemeToggler.tsx b/frontend/src/components/ThemeToggler.tsx index 2234f78a..4628b3dd 100644 --- a/frontend/src/components/ThemeToggler.tsx +++ b/frontend/src/components/ThemeToggler.tsx @@ -2,12 +2,12 @@ import Brightness4 from '@mui/icons-material/Brightness4' import Brightness5 from '@mui/icons-material/Brightness5' import BrightnessAuto from '@mui/icons-material/BrightnessAuto' import { ListItemButton, ListItemIcon, ListItemText } from '@mui/material' -import { useRecoilState } from 'recoil' import { Theme, themeState } from '../atoms/settings' import { useI18n } from '../hooks/useI18n' +import { useAtom } from 'jotai' const ThemeToggler: React.FC = () => { - const [theme, setTheme] = useRecoilState(themeState) + const [theme, setTheme] = useAtom(themeState) const actions: Record = { system: , diff --git a/frontend/src/components/VersionIndicator.tsx b/frontend/src/components/VersionIndicator.tsx index e219aa65..5b22d689 100644 --- a/frontend/src/components/VersionIndicator.tsx +++ b/frontend/src/components/VersionIndicator.tsx @@ -1,9 +1,9 @@ import { Chip } from '@mui/material' -import { useRecoilValue } from 'recoil' import { ytdlpRpcVersionState } from '../atoms/status' +import { useAtomValue } from 'jotai' const VersionIndicator: React.FC = () => { - const version = useRecoilValue(ytdlpRpcVersionState) + const version = useAtomValue(ytdlpRpcVersionState) return (
diff --git a/frontend/src/hooks/toast.ts b/frontend/src/hooks/toast.ts index d42b6015..8688248b 100644 --- a/frontend/src/hooks/toast.ts +++ b/frontend/src/hooks/toast.ts @@ -1,9 +1,9 @@ import { AlertColor } from '@mui/material' -import { useRecoilState } from 'recoil' import { toastListState } from '../atoms/toast' +import { useSetAtom } from 'jotai' export const useToast = () => { - const [, setToasts] = useRecoilState(toastListState) + const setToasts = useSetAtom(toastListState) return { pushMessage: (message: string, severity?: AlertColor) => { diff --git a/frontend/src/hooks/useI18n.ts b/frontend/src/hooks/useI18n.ts index bba98025..3f1864e7 100644 --- a/frontend/src/hooks/useI18n.ts +++ b/frontend/src/hooks/useI18n.ts @@ -1,8 +1,8 @@ -import { useRecoilValue } from 'recoil' +import { useAtomValue } from 'jotai' import { i18nBuilderState } from '../atoms/i18n' export const useI18n = () => { - const instance = useRecoilValue(i18nBuilderState) + const instance = useAtomValue(i18nBuilderState) return { i18n: instance diff --git a/frontend/src/hooks/useRPC.ts b/frontend/src/hooks/useRPC.ts index fbb94229..d47044c0 100644 --- a/frontend/src/hooks/useRPC.ts +++ b/frontend/src/hooks/useRPC.ts @@ -1,8 +1,8 @@ -import { useRecoilValue } from 'recoil' +import { useAtomValue } from 'jotai' import { rpcClientState } from '../atoms/rpc' export const useRPC = () => { - const client = useRecoilValue(rpcClientState) + const client = useAtomValue(rpcClientState) return { client diff --git a/frontend/src/providers/ToasterProvider.tsx b/frontend/src/providers/ToasterProvider.tsx index 09191d28..9af9cea7 100644 --- a/frontend/src/providers/ToasterProvider.tsx +++ b/frontend/src/providers/ToasterProvider.tsx @@ -1,10 +1,10 @@ import { Alert, Snackbar } from "@mui/material" -import { useRecoilState } from 'recoil' import { Toast, toastListState } from '../atoms/toast' import { useEffect } from 'react' +import { useAtom } from 'jotai' const Toaster: React.FC = () => { - const [toasts, setToasts] = useRecoilState(toastListState) + const [toasts, setToasts] = useAtom(toastListState) const deletePredicate = (t: Toast) => (Date.now() - t.createdAt) < 2000 diff --git a/frontend/src/views/Archive.tsx b/frontend/src/views/Archive.tsx index ba675bd8..751208f4 100644 --- a/frontend/src/views/Archive.tsx +++ b/frontend/src/views/Archive.tsx @@ -33,7 +33,6 @@ import { matchW } from 'fp-ts/lib/TaskEither' import { pipe } from 'fp-ts/lib/function' import { useEffect, useMemo, useState, useTransition } from 'react' import { useNavigate } from 'react-router-dom' -import { useRecoilValue } from 'recoil' import { BehaviorSubject, Subject, combineLatestWith, map, share } from 'rxjs' import { serverURL } from '../atoms/settings' import { useObservable } from '../hooks/observable' @@ -42,13 +41,14 @@ import { useI18n } from '../hooks/useI18n' import { ffetch } from '../lib/httpClient' import { DirectoryEntry } from '../types' import { base64URLEncode, formatSize } from '../utils' +import { useAtomValue } from 'jotai' export default function Downloaded() { const [menuPos, setMenuPos] = useState({ x: 0, y: 0 }) const [showMenu, setShowMenu] = useState(false) const [currentFile, setCurrentFile] = useState() - const serverAddr = useRecoilValue(serverURL) + const serverAddr = useAtomValue(serverURL) const navigate = useNavigate() const { i18n } = useI18n() diff --git a/frontend/src/views/Home.tsx b/frontend/src/views/Home.tsx index 9b4e7db2..80521b4e 100644 --- a/frontend/src/views/Home.tsx +++ b/frontend/src/views/Home.tsx @@ -1,15 +1,15 @@ import { Container } from '@mui/material' -import { useRecoilValue } from 'recoil' import { loadingAtom } from '../atoms/ui' import Downloads from '../components/Downloads' import HomeActions from '../components/HomeActions' import LoadingBackdrop from '../components/LoadingBackdrop' import Splash from '../components/Splash' +import { useAtomValue } from 'jotai' export default function Home() { - const isLoading = useRecoilValue(loadingAtom) + const isLoading = useAtomValue(loadingAtom) return ( diff --git a/frontend/src/views/Login.tsx b/frontend/src/views/Login.tsx index 208bc184..8b761979 100644 --- a/frontend/src/views/Login.tsx +++ b/frontend/src/views/Login.tsx @@ -16,10 +16,10 @@ import { matchW } from 'fp-ts/lib/TaskEither' import { pipe } from 'fp-ts/lib/function' import { useState } from 'react' import { useNavigate } from 'react-router-dom' -import { useRecoilValue } from 'recoil' import { serverURL } from '../atoms/settings' import { useToast } from '../hooks/toast' import { ffetch } from '../lib/httpClient' +import { useAtomValue } from 'jotai' const LoginContainer = styled(Container)({ display: 'flex', @@ -43,7 +43,7 @@ export default function Login() { const [formHasError, setFormHasError] = useState(false) - const url = useRecoilValue(serverURL) + const url = useAtomValue(serverURL) const navigate = useNavigate() diff --git a/frontend/src/views/Settings.tsx b/frontend/src/views/Settings.tsx index 269f3932..28cabf35 100644 --- a/frontend/src/views/Settings.tsx +++ b/frontend/src/views/Settings.tsx @@ -19,7 +19,6 @@ import { capitalize } from '@mui/material' import { Suspense, useEffect, useMemo, useState } from 'react' -import { useRecoilState } from 'recoil' import { Subject, debounceTime, @@ -49,25 +48,26 @@ import { useToast } from '../hooks/toast' import { useI18n } from '../hooks/useI18n' import { useRPC } from '../hooks/useRPC' import { validateDomain, validateIP } from '../utils' +import { useAtom } from 'jotai' // NEED ABSOLUTELY TO BE SPLIT IN MULTIPLE COMPONENTS export default function Settings() { - const [reverseProxy, setReverseProxy] = useRecoilState(servedFromReverseProxyState) - const [baseURL, setBaseURL] = useRecoilState(servedFromReverseProxySubDirState) + const [reverseProxy, setReverseProxy] = useAtom(servedFromReverseProxyState) + const [baseURL, setBaseURL] = useAtom(servedFromReverseProxySubDirState) - const [formatSelection, setFormatSelection] = useRecoilState(formatSelectionState) - const [pathOverriding, setPathOverriding] = useRecoilState(pathOverridingState) - const [fileRenaming, setFileRenaming] = useRecoilState(fileRenamingState) - const [enableArgs, setEnableArgs] = useRecoilState(enableCustomArgsState) + const [formatSelection, setFormatSelection] = useAtom(formatSelectionState) + const [pathOverriding, setPathOverriding] = useAtom(pathOverridingState) + const [fileRenaming, setFileRenaming] = useAtom(fileRenamingState) + const [enableArgs, setEnableArgs] = useAtom(enableCustomArgsState) - const [serverAddr, setServerAddr] = useRecoilState(serverAddressState) - const [serverPort, setServerPort] = useRecoilState(serverPortState) + const [serverAddr, setServerAddr] = useAtom(serverAddressState) + const [serverPort, setServerPort] = useAtom(serverPortState) - const [pollingTime, setPollingTime] = useRecoilState(rpcPollingTimeState) - const [language, setLanguage] = useRecoilState(languageState) - const [appTitle, setApptitle] = useRecoilState(appTitleState) + const [pollingTime, setPollingTime] = useAtom(rpcPollingTimeState) + const [language, setLanguage] = useAtom(languageState) + const [appTitle, setApptitle] = useAtom(appTitleState) - const [theme, setTheme] = useRecoilState(themeState) + const [theme, setTheme] = useAtom(themeState) const [invalidIP, setInvalidIP] = useState(false)