[Refactor] decouple settingsMachine from React (#5142)

* Remove unnecessary console.log

* Create a global appMachine

* Strip authMachine of side-effects

* Replace react-bound authMachine use with XState actor use

* Fix import goof

* Register auth commands directly!

* Don't provide anything to settingsMachine from React

* Remove unecessary async

* Make it possible to load project settings via a sent event, without React

* Make settingsMachine ready to be an actor

* Remove settingsLoader use

* Replace all useSettingsAuthContext use with direct actor use

* Add logic to clear project settings, fmt

* fmt

* Clear and load project settings from routeLoaders, but using actor

* Remove useRefreshSettings

* Restore use of useToken() that wasn't working for some reason

* Migrate useFileSystemWatcher use to RouteProvider

* Surface wasm_bindgen unavailable error to console

* Remove unnecessary use of Jest settings wrappers

* Replace dynamic import with actor.getSnapshot

* Migrate system theme and theme color watching from useEffects to actors/actions

* Migrate cursor color effect

* Remove unused code that is now in RouteProvider

* Migrate route commands registration further down for now, out of SettingsAuthProvider

* Migrate settings command registration out of SettingsAuthProvider.tsx

* Delete SettingsAuthProvider.tsx!

* Remove unused settingsLoader!

* fmt and remove comments

* Use actor for routeLoader

* Fix project read error due to uninitialized WASM

* Fix user settings load error due to uninitialized WASM

* Move settingsActor into appActor as a spawned child

* Trying to fix unit tests

* Remove unused imports and demo window attachments

* fmt

* Fix testing issues caused by circular dependency

* Add `setThemeColor` to a few actions list it was missing from

* fmt

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Fix "Execute AST" action in browser, where currentProject is `undefined`

* Update commands list when currentProject changes

* Fix `clearProjectSettings`, which was passing along non-settings context

* Fix onboarding test that actually needed the onboarding initially dismissed

* Add scrollIntoView to make this test more reliable

* @lf94's feedback I missed

I got distracted by a million other things last week

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)"

This reverts commit 129226c6ef.

* fmt

* revert bad snapshot

* Fix up camera movement test locator

* Fix test that was flipping the user settings without waiting

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Frank Noirot
2025-02-21 13:47:36 -05:00
committed by GitHub
parent 4d1eaf9381
commit 46b4b01d23
60 changed files with 791 additions and 780 deletions

View File

@ -1,17 +1,36 @@
import { useEffect, useState, createContext, ReactNode } from 'react'
import { useNavigation, useLocation } from 'react-router-dom'
import {
useNavigation,
useLocation,
useNavigate,
useRouteLoaderData,
} from 'react-router-dom'
import { PATHS } from 'lib/paths'
import { markOnce } from 'lib/performance'
import { useAuthNavigation } from 'hooks/useAuthNavigation'
import { useAuthState } from 'machines/appMachine'
import { IndexLoaderData } from 'lib/types'
import { getAppSettingsFilePath } from 'lib/desktop'
import { isDesktop } from 'lib/isDesktop'
import { trap } from 'lib/trap'
import { useFileSystemWatcher } from 'hooks/useFileSystemWatcher'
import { loadAndValidateSettings } from 'lib/settings/settingsUtils'
import { settingsActor } from 'machines/appMachine'
export const RouteProviderContext = createContext({})
export function RouteProvider({ children }: { children: ReactNode }) {
useAuthNavigation()
const loadedProject = useRouteLoaderData(PATHS.FILE) as IndexLoaderData
const [first, setFirstState] = useState(true)
const [settingsPath, setSettingsPath] = useState<string | undefined>(
undefined
)
const navigation = useNavigation()
const navigate = useNavigate()
const location = useLocation()
const authState = useAuthState()
useEffect(() => {
// On initialization, the react-router-dom does not send a 'loading' state event.
// it sends an idle event first.
@ -28,6 +47,41 @@ export function RouteProvider({ children }: { children: ReactNode }) {
setFirstState(false)
}, [navigation])
useEffect(() => {
if (!isDesktop()) return
getAppSettingsFilePath().then(setSettingsPath).catch(trap)
}, [])
useFileSystemWatcher(
async (eventType: string) => {
// If there is a projectPath but it no longer exists it means
// it was exterally removed. If we let the code past this condition
// execute it will recreate the directory due to code in
// loadAndValidateSettings trying to recreate files. I do not
// wish to change the behavior in case anything else uses it.
// Go home.
if (loadedProject?.project?.path) {
if (!window.electron.exists(loadedProject?.project?.path)) {
navigate(PATHS.HOME)
return
}
}
// Only reload if there are changes. Ignore everything else.
if (eventType !== 'change') return
const data = await loadAndValidateSettings(loadedProject?.project?.path)
settingsActor.send({
type: 'Set all settings',
settings: data.settings,
doNotPersist: true,
})
},
[settingsPath, loadedProject?.project?.path].filter(
(x: string | undefined) => x !== undefined
)
)
return (
<RouteProviderContext.Provider value={{}}>
{children}