* Remove unused `telemetryLoader` * Remove onboarding redirect behavior * Allow subRoute to be passed to navigateToProject * Replace warning dialog routes with toasts * Wire up new utilities and toasts to UI components * Add home sidebar buttons for tutorial flow * Rename menu item * Add flex-1 so home-layout fills available space * Remove onboarding avatar tests, they are becoming irrelevant * Consolidate onboarding tests to one longer one and update it to not use pixel color checks, and use fixtures. * Shorten warning toast button text * tsc, lint, and circular deps * Update circular dep file * Fix mistakes made in circular update tweaking * One more dumb created circular dep * Update src/routes/Onboarding/utils.tsx Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com> * Fix narrow screen home layout breaking * fix: kevin, navigation routes fixed * fix: filename parsing is correct now for onboarding with the last file sep * Fix e2e test state checks that are diff on Linux * Create onboarding project entirely through systemIOMachine * Fix Windows path construction * Make utility to verify a string is an onboarding value * Little biome formatting suggestion fix * Units onboarding step was not using OnboardingButtons * Add type checking of next and previous status, fix useNextClick * Update `OnboardingStatus` type on WASM side * Make onboarding different on browser and web, placeholder component * Show proof of concept with custom content per route * Make text type args not insta dismiss when you click anywhere * Make some utility hooks for the onboarding * Update requestedProjectName along with requestedProjectName * Build out a rough draft of desktop onboarding * Remove unused onboarding route files * Build out rough draft of browser onboarding content * @jgomez720 browser flow feedback * @jgomez420 desktop feedback * tsc and lints * Tweaks * Import is dead, long live Add files * What's up with my inability to type "highlight"? * Codespell and String casting * Update browser sample to be axial fan * lint and tsc * codespell again * Remove unused nightmare function `useDemoCode` * Add a few unit tests * Update desktop to use bulk file creation from #6747 * Oops overwrote main.kcl on the modify with text-to-cad step * Undo the dumb use of `sep` that I introduced * Fix up project test which was fragile to the number of steps in the onboarding smh * Fix up onboarding flow test * typo --------- Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com> Co-authored-by: Kevin Nadro <kevin@zoo.dev>
206 lines
5.8 KiB
TypeScript
206 lines
5.8 KiB
TypeScript
import type { LoaderFunction } from 'react-router-dom'
|
|
import { redirect } from 'react-router-dom'
|
|
import { waitFor } from 'xstate'
|
|
|
|
import { fileSystemManager } from '@src/lang/std/fileSystemManager'
|
|
import { normalizeLineEndings } from '@src/lib/codeEditor'
|
|
import {
|
|
BROWSER_FILE_NAME,
|
|
BROWSER_PROJECT_NAME,
|
|
FILE_EXT,
|
|
PROJECT_ENTRYPOINT,
|
|
} from '@src/lib/constants'
|
|
import { getProjectInfo } from '@src/lib/desktop'
|
|
import { isDesktop } from '@src/lib/isDesktop'
|
|
import {
|
|
BROWSER_PATH,
|
|
PATHS,
|
|
getProjectMetaByRouteId,
|
|
safeEncodeForRouterPaths,
|
|
} from '@src/lib/paths'
|
|
import {
|
|
loadAndValidateSettings,
|
|
readLocalStorageAppSettingsFile,
|
|
} from '@src/lib/settings/settingsUtils'
|
|
import { codeManager } from '@src/lib/singletons'
|
|
import type {
|
|
FileLoaderData,
|
|
HomeLoaderData,
|
|
IndexLoaderData,
|
|
} from '@src/lib/types'
|
|
import { settingsActor } from '@src/lib/singletons'
|
|
import { readAppSettingsFile } from '@src/lib/desktop'
|
|
|
|
export const fileLoader: LoaderFunction = async (
|
|
routerData
|
|
): Promise<FileLoaderData | Response> => {
|
|
const { params } = routerData
|
|
let { configuration } = await loadAndValidateSettings()
|
|
|
|
const projectPathData = await getProjectMetaByRouteId(
|
|
readAppSettingsFile,
|
|
readLocalStorageAppSettingsFile,
|
|
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 we are navigating to the project and want to navigate to its
|
|
// default file, redirect to it keeping everything else in the URL the same.
|
|
if (projectPath && !currentFileName && fileExists && params.id) {
|
|
const encodedId = safeEncodeForRouterPaths(params.id)
|
|
const requestUrlWithDefaultFile = routerData.request.url.replace(
|
|
encodedId,
|
|
safeEncodeForRouterPaths(fallbackFile)
|
|
)
|
|
return redirect(requestUrlWithDefaultFile)
|
|
}
|
|
|
|
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,
|
|
readWriteAccess: true,
|
|
}
|
|
|
|
const maybeProjectInfo = isDesktop()
|
|
? await getProjectInfo(projectPath)
|
|
: null
|
|
|
|
const project = maybeProjectInfo ?? defaultProjectData
|
|
|
|
// Fire off the event to load the project settings
|
|
// once we know it's idle.
|
|
await waitFor(settingsActor, (state) => state.matches('idle'))
|
|
settingsActor.send({
|
|
type: 'load.project',
|
|
project,
|
|
})
|
|
|
|
const projectData: IndexLoaderData = {
|
|
code,
|
|
project,
|
|
file: {
|
|
name: currentFileName || '',
|
|
path: currentFilePath || '',
|
|
children: [],
|
|
},
|
|
}
|
|
|
|
return {
|
|
...projectData,
|
|
}
|
|
}
|
|
|
|
const project = {
|
|
name: BROWSER_PROJECT_NAME,
|
|
path: `/${BROWSER_PROJECT_NAME}`,
|
|
children: [
|
|
{
|
|
name: `${BROWSER_FILE_NAME}.${FILE_EXT}`,
|
|
path: BROWSER_PATH,
|
|
children: [],
|
|
},
|
|
],
|
|
default_file: BROWSER_FILE_NAME,
|
|
directory_count: 0,
|
|
kcl_file_count: 1,
|
|
metadata: null,
|
|
readWriteAccess: true,
|
|
}
|
|
|
|
// Fire off the event to load the project settings
|
|
// once we know it's idle.
|
|
await waitFor(settingsActor, (state) => state.matches('idle'))
|
|
settingsActor.send({
|
|
type: 'load.project',
|
|
project,
|
|
})
|
|
|
|
return {
|
|
code,
|
|
project,
|
|
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 {}
|
|
}
|