* 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>
		
	
		
			
				
	
	
		
			148 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			148 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { useEffect, useMemo, useRef, useState } from 'react'
 | |
| import { useHotKeyListener } from './hooks/useHotKeyListener'
 | |
| import { Stream } from './components/Stream'
 | |
| import { AppHeader } from './components/AppHeader'
 | |
| import { useHotkeys } from 'react-hotkeys-hook'
 | |
| import { useLoaderData, useNavigate } from 'react-router-dom'
 | |
| import { type IndexLoaderData } from 'lib/types'
 | |
| import { PATHS } from 'lib/paths'
 | |
| import { onboardingPaths } from 'routes/Onboarding/paths'
 | |
| import { useEngineConnectionSubscriptions } from 'hooks/useEngineConnectionSubscriptions'
 | |
| import { codeManager, engineCommandManager } from 'lib/singletons'
 | |
| import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath'
 | |
| import { isDesktop } from 'lib/isDesktop'
 | |
| import { useLspContext } from 'components/LspProvider'
 | |
| import { ModelingSidebar } from 'components/ModelingSidebar/ModelingSidebar'
 | |
| import { LowerRightControls } from 'components/LowerRightControls'
 | |
| import ModalContainer from 'react-modal-promise'
 | |
| import useHotkeyWrapper from 'lib/hotkeyWrapper'
 | |
| import Gizmo from 'components/Gizmo'
 | |
| import { CoreDumpManager } from 'lib/coredump'
 | |
| import { UnitsMenu } from 'components/UnitsMenu'
 | |
| import { CameraProjectionToggle } from 'components/CameraProjectionToggle'
 | |
| import { useCreateFileLinkQuery } from 'hooks/useCreateFileLinkQueryWatcher'
 | |
| import { maybeWriteToDisk } from 'lib/telemetry'
 | |
| import { takeScreenshotOfVideoStreamCanvas } from 'lib/screenshot'
 | |
| import { writeProjectThumbnailFile } from 'lib/desktop'
 | |
| import { useRouteLoaderData } from 'react-router-dom'
 | |
| import { useEngineCommands } from 'components/EngineCommands'
 | |
| import { commandBarActor } from 'machines/commandBarMachine'
 | |
| import { useToken } from 'machines/appMachine'
 | |
| import { useSettings } from 'machines/appMachine'
 | |
| maybeWriteToDisk()
 | |
|   .then(() => {})
 | |
|   .catch(() => {})
 | |
| 
 | |
| export function App() {
 | |
|   const { project, file } = useLoaderData() as IndexLoaderData
 | |
| 
 | |
|   // Keep a lookout for a URL query string that invokes the 'import file from URL' command
 | |
|   useCreateFileLinkQuery((argDefaultValues) => {
 | |
|     commandBarActor.send({
 | |
|       type: 'Find and select command',
 | |
|       data: {
 | |
|         groupId: 'projects',
 | |
|         name: 'Import file from URL',
 | |
|         argDefaultValues,
 | |
|       },
 | |
|     })
 | |
|   })
 | |
| 
 | |
|   const navigate = useNavigate()
 | |
|   const filePath = useAbsoluteFilePath()
 | |
|   const { onProjectOpen } = useLspContext()
 | |
|   // We need the ref for the outermost div so we can screenshot the app for
 | |
|   // the coredump.
 | |
|   const ref = useRef<HTMLDivElement>(null)
 | |
| 
 | |
|   const projectName = project?.name || null
 | |
|   const projectPath = project?.path || null
 | |
| 
 | |
|   const [commands] = useEngineCommands()
 | |
|   const [capturedCanvas, setCapturedCanvas] = useState(false)
 | |
|   const loaderData = useRouteLoaderData(PATHS.FILE) as IndexLoaderData
 | |
|   const lastCommandType = commands[commands.length - 1]?.type
 | |
| 
 | |
|   useEffect(() => {
 | |
|     onProjectOpen({ name: projectName, path: projectPath }, file || null)
 | |
|   }, [projectName, projectPath])
 | |
| 
 | |
|   useHotKeyListener()
 | |
| 
 | |
|   const settings = useSettings()
 | |
|   const token = useToken()
 | |
| 
 | |
|   const coreDumpManager = useMemo(
 | |
|     () => new CoreDumpManager(engineCommandManager, codeManager, token),
 | |
|     []
 | |
|   )
 | |
| 
 | |
|   const {
 | |
|     app: { onboardingStatus },
 | |
|   } = settings
 | |
| 
 | |
|   useHotkeys('backspace', (e) => {
 | |
|     e.preventDefault()
 | |
|   })
 | |
|   useHotkeyWrapper(
 | |
|     [isDesktop() ? 'mod + ,' : 'shift + mod + ,'],
 | |
|     () => navigate(filePath + PATHS.SETTINGS),
 | |
|     {
 | |
|       splitKey: '|',
 | |
|     }
 | |
|   )
 | |
| 
 | |
|   const paneOpacity = [onboardingPaths.CAMERA, onboardingPaths.STREAMING].some(
 | |
|     (p) => p === onboardingStatus.current
 | |
|   )
 | |
|     ? 'opacity-20'
 | |
|     : ''
 | |
| 
 | |
|   useEngineConnectionSubscriptions()
 | |
| 
 | |
|   // Generate thumbnail.png when loading the app
 | |
|   useEffect(() => {
 | |
|     if (
 | |
|       isDesktop() &&
 | |
|       !capturedCanvas &&
 | |
|       lastCommandType === 'execution-done'
 | |
|     ) {
 | |
|       setTimeout(() => {
 | |
|         const projectDirectoryWithoutEndingSlash = loaderData?.project?.path
 | |
|         if (!projectDirectoryWithoutEndingSlash) {
 | |
|           return
 | |
|         }
 | |
|         const dataUrl: string = takeScreenshotOfVideoStreamCanvas()
 | |
|         // zoom to fit command does not wait, wait 500ms to see if zoom to fit finishes
 | |
|         writeProjectThumbnailFile(dataUrl, projectDirectoryWithoutEndingSlash)
 | |
|           .then(() => {})
 | |
|           .catch((e) => {
 | |
|             console.error(
 | |
|               `Failed to generate thumbnail for ${projectDirectoryWithoutEndingSlash}`
 | |
|             )
 | |
|             console.error(e)
 | |
|           })
 | |
|       }, 500)
 | |
|     }
 | |
|   }, [lastCommandType])
 | |
| 
 | |
|   return (
 | |
|     <div className="relative h-full flex flex-col" ref={ref}>
 | |
|       <AppHeader
 | |
|         className={'transition-opacity transition-duration-75 ' + paneOpacity}
 | |
|         project={{ project, file }}
 | |
|         enableMenu={true}
 | |
|       />
 | |
|       <ModalContainer />
 | |
|       <ModelingSidebar paneOpacity={paneOpacity} />
 | |
|       <Stream />
 | |
|       {/* <CamToggle /> */}
 | |
|       <LowerRightControls coreDumpManager={coreDumpManager}>
 | |
|         <UnitsMenu />
 | |
|         <Gizmo />
 | |
|         <CameraProjectionToggle />
 | |
|       </LowerRightControls>
 | |
|     </div>
 | |
|   )
 | |
| }
 |