Skip to content
Open
17 changes: 13 additions & 4 deletions spx-gui/src/apps/xbuilder/pages/editor/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import EditorContextProvider from '@/components/editor/EditorContextProvider.vue
import ProjectEditor from '@/components/editor/ProjectEditor.vue'
import { CodeEditorProvider, loadMonaco } from '@/components/editor/spx-code-editor'
import { usePublishProject } from '@/components/project'
import { useTutorial } from '@/components/tutorials/tutorial'
import { EditingMode, type ILocalCache } from '@/components/editor/editing'
import { EditorState } from '@/components/editor/editor-state'
import { cloudHelpers } from '@/models/common/cloud'
Expand All @@ -84,6 +85,7 @@ const i18n = useI18n()
const { t } = i18n
const { isOnline } = useNetwork()
const m = useMessage()
const tutorial = useTutorial()

const confirmOpenTargetWithAnotherInCache = (targetName: string, cachedName: string): Promise<boolean> => {
return confirm({
Expand Down Expand Up @@ -213,17 +215,24 @@ onBeforeRouteLeave(async () => {
* If it is OK to leave, return true, otherwise return false.
*/
async function checkChangesNotToBeSaved(es: EditorState) {
if (tutorial.consumeSkipLeaveConfirm()) return true
const hasEdits = es.editing.mode === EditingMode.EffectFree && es.editing.dirty
if (!hasEdits) return true
const inTutorial = tutorial.currentCourse != null
return confirm({
title: t({
en: 'Leave editor',
zh: '离开编辑器'
}),
content: t({
en: `Project edits will not be saved if you leave now. Are you sure to leave?`,
zh: `若现在离开,对项目的修改将不会被保存。确定要离开吗?`
}),
content: inTutorial
? t({
en: `Tutorial edits will not be saved if you leave now. Are you sure to leave?`,
zh: `教程中的修改不会被保存,确认要离开吗?`
})
: t({
Comment thread
Ethanlita marked this conversation as resolved.
Outdated
en: `Project edits will not be saved if you leave now. Are you sure to leave?`,
zh: `若现在离开,对项目的修改将不会被保存。确定要离开吗?`
}),
cancelText: t({
en: 'Keep editing',
zh: '继续编辑'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ function handleCancel() {
emit('cancelled')
}

function handleBrowseTutorials() {
function handleBackToCourseSeries() {
emit('cancelled')
router.push('/tutorials')
props.tutorial.requestSkipLeaveConfirm()
router.push(`/course-series/${props.series.id}`)
Comment thread
Ethanlita marked this conversation as resolved.
Outdated
Comment thread
Ethanlita marked this conversation as resolved.
Outdated
}

const hasNextCourse = computed(() => {
Expand Down Expand Up @@ -96,8 +97,8 @@ const { fn: handleStartNextCourse } = useMessageHandle(
<div class="mt-2 text-base">{{ courseCompleteMessage }}</div>

<div class="mt-10 w-full flex flex-col gap-5">
<UIButton type="neutral" size="large" @click="handleBrowseTutorials">
{{ $t({ zh: '浏览所有课程', en: 'Browse all courses' }) }}
<UIButton type="neutral" size="large" @click="handleBackToCourseSeries">
{{ $t({ zh: '返回系列课程', en: 'Back to Series Courses' }) }}
Comment thread
Ethanlita marked this conversation as resolved.
Outdated
</UIButton>
<UIButton v-if="hasNextCourse" size="large" @click="handleStartNextCourse">
{{ $t({ zh: '学习下一个课程', en: 'Learn next course' }) }}
Expand Down
17 changes: 17 additions & 0 deletions spx-gui/src/components/tutorials/tutorial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,19 @@ export class Tutorial {
this.abandonPredictionCountRef.value = 0
}

// One-shot flag to skip the editor's leave confirmation on the next navigation.
// Used when leaving the editor is an explicit, expected action (e.g. clicking
// "back to course series" in the course success modal), making a confirm redundant.
private skipLeaveConfirmOnce = false
requestSkipLeaveConfirm() {
this.skipLeaveConfirmOnce = true
}
consumeSkipLeaveConfirm() {
const skip = this.skipLeaveConfirmOnce
this.skipLeaveConfirmOnce = false
return skip
}
Comment thread
Ethanlita marked this conversation as resolved.
Outdated

async startCourse(course: Course, series: CourseSeries): Promise<void> {
try {
this.copilot.endCurrentSession()
Expand All @@ -71,6 +84,10 @@ export class Tutorial {
const { entrypoint } = course

if (entrypoint) {
// A course entrypoint may point to a non-editor route. Navigating away from the
// editor would otherwise trigger its leave confirmation, but starting a course is
// an explicit, expected action, so skip the confirmation for this navigation.
this.requestSkipLeaveConfirm()
await this.router.push(entrypoint)
await until(this.isRouteLoaded)
await timeout(100) // Wait for detailed UI rendering
Expand Down