* 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>
185 lines
5.5 KiB
TypeScript
185 lines
5.5 KiB
TypeScript
import { ActionFunction, LoaderFunction, redirect } from 'react-router-dom'
|
|
import { FileLoaderData, HomeLoaderData, IndexLoaderData } from './types'
|
|
import { getProjectMetaByRouteId, PATHS } from './paths'
|
|
import { isDesktop } from './isDesktop'
|
|
import { BROWSER_PATH } from 'lib/paths'
|
|
import {
|
|
BROWSER_FILE_NAME,
|
|
BROWSER_PROJECT_NAME,
|
|
PROJECT_ENTRYPOINT,
|
|
} from 'lib/constants'
|
|
import { loadAndValidateSettings } from './settings/settingsUtils'
|
|
import makeUrlPathRelative from './makeUrlPathRelative'
|
|
import { codeManager } from 'lib/singletons'
|
|
import { fileSystemManager } from 'lang/std/fileSystemManager'
|
|
import { getProjectInfo } from './desktop'
|
|
import { normalizeLineEndings } from 'lib/codeEditor'
|
|
import { OnboardingStatus } from 'wasm-lib/kcl/bindings/OnboardingStatus'
|
|
import { getSettings, settingsActor } from 'machines/appMachine'
|
|
|
|
export const telemetryLoader: LoaderFunction = async ({
|
|
params,
|
|
}): Promise<null> => {
|
|
return null
|
|
}
|
|
|
|
// Redirect users to the appropriate onboarding page if they haven't completed it
|
|
export const onboardingRedirectLoader: ActionFunction = async (args) => {
|
|
const settings = getSettings()
|
|
const onboardingStatus: OnboardingStatus =
|
|
settings.app.onboardingStatus.current || ''
|
|
const notEnRouteToOnboarding = !args.request.url.includes(
|
|
PATHS.ONBOARDING.INDEX
|
|
)
|
|
// '' is the initial state, 'completed' and 'dismissed' are the final states
|
|
const hasValidOnboardingStatus =
|
|
onboardingStatus.length === 0 ||
|
|
!(onboardingStatus === 'completed' || onboardingStatus === 'dismissed')
|
|
const shouldRedirectToOnboarding =
|
|
notEnRouteToOnboarding && hasValidOnboardingStatus
|
|
|
|
if (shouldRedirectToOnboarding) {
|
|
return redirect(
|
|
makeUrlPathRelative(PATHS.ONBOARDING.INDEX) + onboardingStatus.slice(1)
|
|
)
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
export const fileLoader: LoaderFunction = async (
|
|
routerData
|
|
): Promise<FileLoaderData | Response> => {
|
|
const { params } = routerData
|
|
let { configuration } = await loadAndValidateSettings()
|
|
|
|
const projectPathData = await getProjectMetaByRouteId(
|
|
params.id,
|
|
configuration
|
|
)
|
|
const isBrowserProject = params.id === decodeURIComponent(BROWSER_PATH)
|
|
|
|
let code = ''
|
|
|
|
if (!isBrowserProject && projectPathData) {
|
|
const { projectName, projectPath, currentFileName, currentFilePath } =
|
|
projectPathData
|
|
|
|
const urlObj = new URL(routerData.request.url)
|
|
|
|
if (!urlObj.pathname.endsWith('/settings')) {
|
|
const fallbackFile = isDesktop()
|
|
? (await getProjectInfo(projectPath)).default_file
|
|
: ''
|
|
let fileExists = isDesktop()
|
|
if (currentFilePath && fileExists) {
|
|
try {
|
|
await window.electron.stat(currentFilePath)
|
|
} catch (e) {
|
|
if (e === 'ENOENT') {
|
|
fileExists = false
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!fileExists || !currentFileName || !currentFilePath || !projectName) {
|
|
return redirect(
|
|
`${PATHS.FILE}/${encodeURIComponent(
|
|
isDesktop() ? fallbackFile : params.id + '/' + PROJECT_ENTRYPOINT
|
|
)}${new URL(routerData.request.url).search || ''}`
|
|
)
|
|
}
|
|
|
|
code = await window.electron.readFile(currentFilePath, {
|
|
encoding: 'utf-8',
|
|
})
|
|
code = normalizeLineEndings(code)
|
|
|
|
// If persistCode in localStorage is present, it'll persist that code
|
|
// through *anything*. INTENDED FOR TESTS.
|
|
if (window.electron.process.env.IS_PLAYWRIGHT) {
|
|
code = codeManager.localStoragePersistCode() || code
|
|
}
|
|
|
|
// Update both the state and the editor's code.
|
|
// We explicitly do not write to the file here since we are loading from
|
|
// the file system and not the editor.
|
|
codeManager.updateCurrentFilePath(currentFilePath)
|
|
// We pass true on the end here to clear the code editor history.
|
|
// This way undo and redo are not super weird when opening new files.
|
|
codeManager.updateCodeStateEditor(code, true)
|
|
}
|
|
|
|
// Set the file system manager to the project path
|
|
// So that WASM gets an updated path for operations
|
|
fileSystemManager.dir = projectPath
|
|
|
|
const defaultProjectData = {
|
|
name: projectName || 'unnamed',
|
|
path: projectPath,
|
|
children: [],
|
|
kcl_file_count: 0,
|
|
directory_count: 0,
|
|
metadata: null,
|
|
default_file: projectPath,
|
|
}
|
|
|
|
const maybeProjectInfo = isDesktop()
|
|
? await getProjectInfo(projectPath)
|
|
: null
|
|
|
|
const project = maybeProjectInfo ?? defaultProjectData
|
|
|
|
// Fire off the event to load the project settings
|
|
settingsActor.send({
|
|
type: 'load.project',
|
|
project,
|
|
})
|
|
|
|
const projectData: IndexLoaderData = {
|
|
code,
|
|
project,
|
|
file: {
|
|
name: currentFileName || '',
|
|
path: currentFilePath || '',
|
|
children: [],
|
|
},
|
|
}
|
|
|
|
return {
|
|
...projectData,
|
|
}
|
|
}
|
|
|
|
return {
|
|
code,
|
|
project: {
|
|
name: BROWSER_PROJECT_NAME,
|
|
path: '/' + BROWSER_PROJECT_NAME,
|
|
children: [],
|
|
},
|
|
file: {
|
|
name: BROWSER_FILE_NAME,
|
|
path: decodeURIComponent(BROWSER_PATH),
|
|
children: [],
|
|
},
|
|
}
|
|
}
|
|
|
|
// Loads the settings and by extension the projects in the default directory
|
|
// and returns them to the Home route, along with any errors that occurred
|
|
export const homeLoader: LoaderFunction = async ({
|
|
request,
|
|
}): Promise<HomeLoaderData | Response> => {
|
|
const url = new URL(request.url)
|
|
if (!isDesktop()) {
|
|
return redirect(
|
|
PATHS.FILE + '/%2F' + BROWSER_PROJECT_NAME + (url.search || '')
|
|
)
|
|
}
|
|
settingsActor.send({
|
|
type: 'clear.project',
|
|
})
|
|
return {}
|
|
}
|