diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock
index eb55e8549..7a4b4f5ae 100644
--- a/src-tauri/Cargo.lock
+++ b/src-tauri/Cargo.lock
@@ -2626,6 +2626,7 @@ dependencies = [
"tower-lsp",
"ts-rs",
"url",
+ "urlencoding",
"uuid",
"validator",
"wasm-bindgen",
@@ -6258,6 +6259,12 @@ dependencies = [
"serde",
]
+[[package]]
+name = "urlencoding"
+version = "2.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
+
[[package]]
name = "urlpattern"
version = "0.2.0"
diff --git a/src/components/HelpMenu.tsx b/src/components/HelpMenu.tsx
index 3de0f1eb0..ebd780dbc 100644
--- a/src/components/HelpMenu.tsx
+++ b/src/components/HelpMenu.tsx
@@ -6,6 +6,7 @@ import { useLocation, useNavigate } from 'react-router-dom'
import { createAndOpenNewProject } from 'lib/tauriFS'
import { paths } from 'lib/paths'
import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath'
+import { useLspContext } from './LspProvider'
const HelpMenuDivider = () => (
@@ -13,6 +14,7 @@ const HelpMenuDivider = () => (
export function HelpMenu(props: React.PropsWithChildren) {
const location = useLocation()
+ const { onProjectOpen } = useLspContext()
const filePath = useAbsoluteFilePath()
const isInProject = location.pathname.includes(paths.FILE)
const navigate = useNavigate()
@@ -106,9 +108,9 @@ export function HelpMenu(props: React.PropsWithChildren) {
},
})
if (isInProject) {
- navigate('onboarding')
+ navigate(filePath + paths.ONBOARDING.INDEX)
} else {
- createAndOpenNewProject(navigate)
+ createAndOpenNewProject({ onProjectOpen, navigate })
}
}}
>
diff --git a/src/components/ModelingSidebar/ModelingPanes/index.ts b/src/components/ModelingSidebar/ModelingPanes/index.ts
index 878c4a9e6..8c3d27cc1 100644
--- a/src/components/ModelingSidebar/ModelingPanes/index.ts
+++ b/src/components/ModelingSidebar/ModelingPanes/index.ts
@@ -3,7 +3,6 @@ import {
faBugSlash,
faCode,
faCodeCommit,
- faExclamationCircle,
faSquareRootVariable,
} from '@fortawesome/free-solid-svg-icons'
import { KclEditorMenu } from 'components/ModelingSidebar/ModelingPanes/KclEditorMenu'
diff --git a/src/components/Settings/AllSettingsFields.tsx b/src/components/Settings/AllSettingsFields.tsx
index b855a2dbb..4eaf7d04e 100644
--- a/src/components/Settings/AllSettingsFields.tsx
+++ b/src/components/Settings/AllSettingsFields.tsx
@@ -19,7 +19,8 @@ import { createAndOpenNewProject, getSettingsFolderPaths } from 'lib/tauriFS'
import { paths } from 'lib/paths'
import { useDotDotSlash } from 'hooks/useDotDotSlash'
import { sep } from '@tauri-apps/api/path'
-import { ForwardedRef, forwardRef } from 'react'
+import { ForwardedRef, forwardRef, useEffect } from 'react'
+import { useLspContext } from 'components/LspProvider'
interface AllSettingsFieldsProps {
searchParamTab: SettingsLevel
@@ -33,9 +34,10 @@ export const AllSettingsFields = forwardRef(
) => {
const location = useLocation()
const navigate = useNavigate()
+ const { onProjectOpen } = useLspContext()
const dotDotSlash = useDotDotSlash()
const {
- settings: { send, context },
+ settings: { send, context, state },
} = useSettingsAuthContext()
const projectPath =
@@ -48,19 +50,37 @@ export const AllSettingsFields = forwardRef(
)
: undefined
- function restartOnboarding() {
+ async function restartOnboarding() {
send({
type: `set.app.onboardingStatus`,
data: { level: 'user', value: '' },
})
-
- if (isFileSettings) {
- navigate(dotDotSlash(1) + paths.ONBOARDING.INDEX)
- } else {
- createAndOpenNewProject(navigate)
- }
}
+ /**
+ * A "listener" for the XState to return to "idle" state
+ * when the user resets the onboarding, using the callback above
+ */
+ useEffect(() => {
+ async function navigateToOnboardingStart() {
+ if (
+ state.context.app.onboardingStatus.user === '' &&
+ state.matches('idle')
+ ) {
+ if (isFileSettings) {
+ // If we're in a project, first navigate to the onboarding start here
+ // so we can trigger the warning screen if necessary
+ navigate(dotDotSlash(1) + paths.ONBOARDING.INDEX)
+ } else {
+ // If we're in the global settings, create a new project and navigate
+ // to the onboarding start in that project
+ await createAndOpenNewProject({ onProjectOpen, navigate })
+ }
+ }
+ }
+ navigateToOnboardingStart()
+ }, [isFileSettings, navigate, state])
+
return (
diff --git a/src/lib/tauriFS.ts b/src/lib/tauriFS.ts
index cc79e2517..c9cf838f2 100644
--- a/src/lib/tauriFS.ts
+++ b/src/lib/tauriFS.ts
@@ -14,6 +14,7 @@ import {
listProjects,
readAppSettingsFile,
} from './tauri'
+import { engineCommandManager } from './singletons'
export const isHidden = (fileOrDir: FileEntry) =>
!!fileOrDir.name?.startsWith('.')
@@ -116,9 +117,23 @@ export async function getSettingsFolderPaths(projectPath?: string) {
}
}
-export async function createAndOpenNewProject(
+export async function createAndOpenNewProject({
+ onProjectOpen,
+ navigate,
+}: {
+ onProjectOpen: (
+ project: {
+ name: string | null
+ path: string | null
+ } | null,
+ file: FileEntry | null
+ ) => void
navigate: (path: string) => void
-) {
+}) {
+ // Clear the scene and end the session.
+ engineCommandManager.endSession()
+
+ // Create a new project with the onboarding project name
const configuration = await readAppSettingsFile()
const projects = await listProjects(configuration)
const nextIndex = getNextProjectIndex(ONBOARDING_PROJECT_NAME, projects)
@@ -126,6 +141,24 @@ export async function createAndOpenNewProject(
ONBOARDING_PROJECT_NAME,
nextIndex
)
- const newFile = await createNewProjectDirectory(name, bracket, configuration)
- navigate(`${paths.FILE}/${encodeURIComponent(newFile.path)}`)
+ const newProject = await createNewProjectDirectory(
+ name,
+ bracket,
+ configuration
+ )
+
+ // Prep the LSP and navigate to the onboarding start
+ onProjectOpen(
+ {
+ name: newProject.name,
+ path: newProject.path,
+ },
+ null
+ )
+ navigate(
+ `${paths.FILE}/${encodeURIComponent(newProject.default_file)}${
+ paths.ONBOARDING.INDEX
+ }`
+ )
+ return newProject
}
diff --git a/src/routes/Onboarding/Introduction.tsx b/src/routes/Onboarding/Introduction.tsx
index 9078f7107..7dc5ae1ca 100644
--- a/src/routes/Onboarding/Introduction.tsx
+++ b/src/routes/Onboarding/Introduction.tsx
@@ -3,22 +3,16 @@ import { onboardingPaths } from 'routes/Onboarding/paths'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { Themes, getSystemTheme } from 'lib/theme'
import { bracket } from 'lib/exampleKcl'
-import {
- getNextProjectIndex,
- interpolateProjectNameWithIndex,
-} from 'lib/tauriFS'
+import { createAndOpenNewProject } from 'lib/tauriFS'
import { isTauri } from 'lib/isTauri'
-import { useNavigate } from 'react-router-dom'
-import { paths } from 'lib/paths'
+import { useNavigate, useRouteLoaderData } from 'react-router-dom'
import { codeManager, kclManager } from 'lib/singletons'
-import { join } from '@tauri-apps/api/path'
-import {
- APP_NAME,
- ONBOARDING_PROJECT_NAME,
- PROJECT_ENTRYPOINT,
-} from 'lib/constants'
-import { createNewProjectDirectory, listProjects } from 'lib/tauri'
+import { APP_NAME } from 'lib/constants'
import { useState } from 'react'
+import { useLspContext } from 'components/LspProvider'
+import { IndexLoaderData } from 'lib/types'
+import { paths } from 'lib/paths'
+import { useFileContext } from 'hooks/useFileContext'
/**
* Show either a welcome screen or a warning screen
@@ -47,30 +41,28 @@ function OnboardingResetWarning(props: OnboardingResetWarningProps) {
{!isTauri() ? (
) : (
-
+
)}
)
}
-function OnboardingWarningDesktop() {
+function OnboardingWarningDesktop(props: OnboardingResetWarningProps) {
const navigate = useNavigate()
const dismiss = useDismiss()
+ const loaderData = useRouteLoaderData(paths.FILE) as IndexLoaderData
+ const { context: fileContext } = useFileContext()
+ const { onProjectClose, onProjectOpen } = useLspContext()
- async function createAndOpenNewProject() {
- const projects = await listProjects()
- const nextIndex = getNextProjectIndex(ONBOARDING_PROJECT_NAME, projects)
- const name = interpolateProjectNameWithIndex(
- ONBOARDING_PROJECT_NAME,
- nextIndex
- )
- const newFile = await createNewProjectDirectory(name, bracket)
- navigate(
- `${paths.FILE}/${encodeURIComponent(
- await join(newFile.path, PROJECT_ENTRYPOINT)
- )}${paths.ONBOARDING.INDEX}`
+ async function onAccept() {
+ onProjectClose(
+ loaderData.file || null,
+ fileContext.project.path || null,
+ false
)
+ await createAndOpenNewProject({ onProjectOpen, navigate })
+ props.setShouldShowWarning(false)
}
return (
@@ -88,11 +80,7 @@ function OnboardingWarningDesktop() {
{
- void createAndOpenNewProject()
- codeManager.updateCodeEditor(bracket)
- dismiss()
- }}
+ next={onAccept}
nextText="Make a new project"
/>
>
diff --git a/src/routes/Onboarding/index.tsx b/src/routes/Onboarding/index.tsx
index a0a0e8454..ea9f12988 100644
--- a/src/routes/Onboarding/index.tsx
+++ b/src/routes/Onboarding/index.tsx
@@ -79,7 +79,7 @@ export const onboardingRoutes = [
export function useDemoCode() {
useEffect(() => {
- if (!editorManager.editorView) return
+ if (!editorManager.editorView || codeManager.code === bracket) return
setTimeout(async () => {
codeManager.updateCodeStateEditor(bracket)
kclManager.isFirstRender = true