2024-03-14 15:56:45 -04:00
|
|
|
import { ActionFunction, LoaderFunction, redirect } from 'react-router-dom'
|
2024-04-25 00:13:09 -07:00
|
|
|
import { FileLoaderData, HomeLoaderData, IndexLoaderData } from './types'
|
2024-08-09 02:47:25 -04:00
|
|
|
import { getProjectMetaByRouteId, PATHS } from './paths'
|
2024-08-16 07:15:42 -04:00
|
|
|
import { isDesktop } from './isDesktop'
|
2024-04-02 10:29:34 -04:00
|
|
|
import { BROWSER_PATH } from 'lib/paths'
|
|
|
|
import {
|
|
|
|
BROWSER_FILE_NAME,
|
|
|
|
BROWSER_PROJECT_NAME,
|
|
|
|
PROJECT_ENTRYPOINT,
|
|
|
|
} from 'lib/constants'
|
2024-03-14 15:56:45 -04:00
|
|
|
import { loadAndValidateSettings } from './settings/settingsUtils'
|
|
|
|
import makeUrlPathRelative from './makeUrlPathRelative'
|
2024-08-16 07:15:42 -04:00
|
|
|
import { codeManager, kclManager } from 'lib/singletons'
|
2024-03-14 15:56:45 -04:00
|
|
|
import { fileSystemManager } from 'lang/std/fileSystemManager'
|
2024-04-25 00:13:09 -07:00
|
|
|
import {
|
|
|
|
getProjectInfo,
|
2024-08-16 07:15:42 -04:00
|
|
|
ensureProjectDirectoryExists,
|
2024-04-25 00:13:09 -07:00
|
|
|
listProjects,
|
2024-08-16 07:15:42 -04:00
|
|
|
} from './desktop'
|
2024-04-25 00:13:09 -07:00
|
|
|
import { createSettings } from './settings/initialSettings'
|
2024-03-14 15:56:45 -04:00
|
|
|
|
|
|
|
// The root loader simply resolves the settings and any errors that
|
|
|
|
// occurred during the settings load
|
2024-04-02 10:29:34 -04:00
|
|
|
export const settingsLoader: LoaderFunction = async ({
|
|
|
|
params,
|
2024-04-25 05:52:08 -07:00
|
|
|
}): Promise<
|
|
|
|
ReturnType<typeof createSettings> | ReturnType<typeof redirect>
|
|
|
|
> => {
|
2024-04-25 11:55:11 -07:00
|
|
|
let { settings, configuration } = await loadAndValidateSettings()
|
2024-04-02 10:29:34 -04:00
|
|
|
|
|
|
|
// I don't love that we have to read the settings again here,
|
|
|
|
// but we need to get the project path to load the project settings
|
|
|
|
if (params.id) {
|
2024-04-25 11:55:11 -07:00
|
|
|
const projectPathData = await getProjectMetaByRouteId(
|
|
|
|
params.id,
|
|
|
|
configuration
|
|
|
|
)
|
2024-04-02 10:29:34 -04:00
|
|
|
if (projectPathData) {
|
2024-05-21 18:14:49 -07:00
|
|
|
const { project_path } = projectPathData
|
2024-05-22 14:22:07 -04:00
|
|
|
const { settings: s } = await loadAndValidateSettings(
|
|
|
|
project_path || undefined
|
|
|
|
)
|
2024-08-16 07:15:42 -04:00
|
|
|
return s
|
2024-04-02 10:29:34 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return settings
|
2024-03-14 15:56:45 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Redirect users to the appropriate onboarding page if they haven't completed it
|
2024-04-02 10:29:34 -04:00
|
|
|
export const onboardingRedirectLoader: ActionFunction = async (args) => {
|
2024-04-25 00:13:09 -07:00
|
|
|
const { settings } = await loadAndValidateSettings()
|
2024-04-02 10:29:34 -04:00
|
|
|
const onboardingStatus = settings.app.onboardingStatus.current || ''
|
|
|
|
const notEnRouteToOnboarding = !args.request.url.includes(
|
2024-08-09 02:47:25 -04:00
|
|
|
PATHS.ONBOARDING.INDEX
|
2024-04-02 10:29:34 -04:00
|
|
|
)
|
2024-03-14 15:56:45 -04:00
|
|
|
// '' is the initial state, 'done' and 'dismissed' are the final states
|
|
|
|
const hasValidOnboardingStatus =
|
|
|
|
onboardingStatus.length === 0 ||
|
|
|
|
!(onboardingStatus === 'done' || onboardingStatus === 'dismissed')
|
|
|
|
const shouldRedirectToOnboarding =
|
|
|
|
notEnRouteToOnboarding && hasValidOnboardingStatus
|
|
|
|
|
|
|
|
if (shouldRedirectToOnboarding) {
|
|
|
|
return redirect(
|
2024-08-09 02:47:25 -04:00
|
|
|
makeUrlPathRelative(PATHS.ONBOARDING.INDEX) + onboardingStatus.slice(1)
|
2024-03-14 15:56:45 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2024-04-02 10:29:34 -04:00
|
|
|
return settingsLoader(args)
|
2024-03-14 15:56:45 -04:00
|
|
|
}
|
|
|
|
|
2024-08-16 07:15:42 -04:00
|
|
|
export const fileLoader: LoaderFunction = async (
|
|
|
|
routerData
|
|
|
|
): Promise<FileLoaderData | Response> => {
|
|
|
|
const { params } = routerData
|
2024-04-25 11:55:11 -07:00
|
|
|
let { configuration } = await loadAndValidateSettings()
|
2024-03-14 15:56:45 -04:00
|
|
|
|
2024-04-25 11:55:11 -07:00
|
|
|
const projectPathData = await getProjectMetaByRouteId(
|
|
|
|
params.id,
|
|
|
|
configuration
|
|
|
|
)
|
2024-04-02 10:29:34 -04:00
|
|
|
const isBrowserProject = params.id === decodeURIComponent(BROWSER_PATH)
|
2024-03-14 15:56:45 -04:00
|
|
|
|
2024-04-02 10:29:34 -04:00
|
|
|
if (!isBrowserProject && projectPathData) {
|
2024-04-25 11:55:11 -07:00
|
|
|
const { project_name, project_path, current_file_name, current_file_path } =
|
2024-04-02 10:29:34 -04:00
|
|
|
projectPathData
|
2024-03-14 15:56:45 -04:00
|
|
|
|
2024-08-16 07:15:42 -04:00
|
|
|
const urlObj = new URL(routerData.request.url)
|
|
|
|
let code = ''
|
|
|
|
|
|
|
|
if (!urlObj.pathname.endsWith('/settings')) {
|
|
|
|
if (!current_file_name || !current_file_path || !project_name) {
|
|
|
|
return redirect(
|
|
|
|
`${PATHS.FILE}/${encodeURIComponent(
|
|
|
|
isDesktop()
|
|
|
|
? (await getProjectInfo(project_path)).default_file
|
|
|
|
: params.id + '/' + PROJECT_ENTRYPOINT
|
|
|
|
)}`
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
code = await window.electron.readFile(current_file_path)
|
|
|
|
|
|
|
|
// 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(current_file_path)
|
|
|
|
codeManager.updateCodeStateEditor(code)
|
|
|
|
// We don't want to call await on execute code since we don't want to block the UI
|
|
|
|
kclManager.executeCode(true)
|
2024-04-02 10:29:34 -04:00
|
|
|
}
|
2024-03-14 15:56:45 -04:00
|
|
|
|
|
|
|
// Set the file system manager to the project path
|
|
|
|
// So that WASM gets an updated path for operations
|
2024-04-25 11:55:11 -07:00
|
|
|
fileSystemManager.dir = project_path
|
2024-03-14 15:56:45 -04:00
|
|
|
|
2024-08-16 07:15:42 -04:00
|
|
|
const defaultProjectData = {
|
|
|
|
name: project_name || 'unnamed',
|
|
|
|
path: project_path,
|
|
|
|
children: [],
|
|
|
|
kcl_file_count: 0,
|
|
|
|
directory_count: 0,
|
|
|
|
metadata: null,
|
|
|
|
default_file: project_path,
|
|
|
|
}
|
|
|
|
|
2024-04-02 10:29:34 -04:00
|
|
|
const projectData: IndexLoaderData = {
|
2024-03-14 15:56:45 -04:00
|
|
|
code,
|
2024-08-16 07:15:42 -04:00
|
|
|
project: isDesktop()
|
|
|
|
? (await getProjectInfo(project_path)) ?? defaultProjectData
|
|
|
|
: defaultProjectData,
|
2024-03-14 15:56:45 -04:00
|
|
|
file: {
|
2024-08-16 07:15:42 -04:00
|
|
|
name: current_file_name || '',
|
|
|
|
path: current_file_path?.split('/').slice(0, -1).join('/') ?? '',
|
2024-04-25 00:13:09 -07:00
|
|
|
children: [],
|
2024-03-14 15:56:45 -04:00
|
|
|
},
|
|
|
|
}
|
2024-04-02 10:29:34 -04:00
|
|
|
|
|
|
|
return {
|
|
|
|
...projectData,
|
|
|
|
}
|
2024-03-14 15:56:45 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
code: '',
|
2024-04-02 10:29:34 -04:00
|
|
|
project: {
|
|
|
|
name: BROWSER_PROJECT_NAME,
|
|
|
|
path: '/' + BROWSER_PROJECT_NAME,
|
|
|
|
children: [],
|
|
|
|
},
|
|
|
|
file: {
|
|
|
|
name: BROWSER_FILE_NAME,
|
|
|
|
path: decodeURIComponent(BROWSER_PATH),
|
2024-04-25 00:13:09 -07:00
|
|
|
children: [],
|
2024-04-02 10:29:34 -04:00
|
|
|
},
|
2024-03-14 15:56:45 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 (): Promise<
|
|
|
|
HomeLoaderData | Response
|
|
|
|
> => {
|
2024-08-16 07:15:42 -04:00
|
|
|
if (!isDesktop()) {
|
2024-08-09 02:47:25 -04:00
|
|
|
return redirect(PATHS.FILE + '/%2F' + BROWSER_PROJECT_NAME)
|
2024-03-14 15:56:45 -04:00
|
|
|
}
|
2024-04-25 00:13:09 -07:00
|
|
|
const { configuration } = await loadAndValidateSettings()
|
2024-04-02 10:29:34 -04:00
|
|
|
|
2024-08-16 07:15:42 -04:00
|
|
|
const projectDir = await ensureProjectDirectoryExists(configuration)
|
2024-03-14 15:56:45 -04:00
|
|
|
|
2024-04-25 00:13:09 -07:00
|
|
|
if (projectDir) {
|
|
|
|
const projects = await listProjects(configuration)
|
2024-03-14 15:56:45 -04:00
|
|
|
|
|
|
|
return {
|
|
|
|
projects,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return {
|
|
|
|
projects: [],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|