diff --git a/spx-backend/cmd/spx-backend/gop_autogen.go b/spx-backend/cmd/spx-backend/gop_autogen.go index da5a285cd..138c17bef 100644 --- a/spx-backend/cmd/spx-backend/gop_autogen.go +++ b/spx-backend/cmd/spx-backend/gop_autogen.go @@ -130,7 +130,7 @@ func (this *AppV2) MainEntry() { //line cmd/spx-backend/main.yap:50:1 if serverErr != nil && !errors.Is(serverErr, http.ErrServerClosed) { //line cmd/spx-backend/main.yap:51:1 - logger.Fatalln("Server error:", this.err) + logger.Fatalln("Server error:", serverErr) } //line cmd/spx-backend/main.yap:54:1 shutdownCtx, cancel := context.WithTimeout(context.Background(), time.Minute) diff --git a/spx-backend/cmd/spx-backend/main.yap b/spx-backend/cmd/spx-backend/main.yap index 42b7ff6ad..9e514705e 100644 --- a/spx-backend/cmd/spx-backend/main.yap +++ b/spx-backend/cmd/spx-backend/main.yap @@ -48,7 +48,7 @@ go func() { }() <-stopCtx.Done() if serverErr != nil && !errors.Is(serverErr, http.ErrServerClosed) { - logger.Fatalln("Server error:", err) + logger.Fatalln("Server error:", serverErr) } shutdownCtx, cancel := context.WithTimeout(context.Background(), time.Minute) diff --git a/spx-gui/src/components/project/ProjectSharingLinkModal.vue b/spx-gui/src/components/project/ProjectSharingLinkModal.vue new file mode 100644 index 000000000..47e561e3c --- /dev/null +++ b/spx-gui/src/components/project/ProjectSharingLinkModal.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/spx-gui/src/components/project/index.ts b/spx-gui/src/components/project/index.ts index 6498ce6fe..0cc81a5b3 100644 --- a/spx-gui/src/components/project/index.ts +++ b/spx-gui/src/components/project/index.ts @@ -1,11 +1,12 @@ import { useRouter } from 'vue-router' -import { useModal, useConfirmDialog, useMessage } from '@/components/ui' +import { useModal, useConfirmDialog } from '@/components/ui' import { IsPublic, deleteProject } from '@/apis/project' import ProjectCreateModal from './ProjectCreateModal.vue' import ProjectOpenModal from './ProjectOpenModal.vue' -import { useI18n, type LocaleMessage } from '@/utils/i18n' +import ProjectSharingLinkModal from './ProjectSharingLinkModal.vue' +import { useI18n } from '@/utils/i18n' import type { Project } from '@/models/project' -import { getProjectEditorRoute, getProjectShareRoute } from '@/router' +import { getProjectEditorRoute } from '@/router' export function useCreateProject() { const modal = useModal(ProjectCreateModal) @@ -26,8 +27,8 @@ export function useOpenProject() { } export function useRemoveProject() { - const withConfirm = useConfirmDialog() const { t } = useI18n() + const withConfirm = useConfirmDialog() return async function removeProject(owner: string, name: string) { return withConfirm({ @@ -41,94 +42,61 @@ export function useRemoveProject() { } } -/** Copy sharing link for given project */ -export function useShareProject() { - const m = useMessage() - const { t } = useI18n() - return async function shareProject(project: Project) { - const { owner, name } = project - // TODO: the check should be unnecessary - if (owner == null || name == null) throw new Error(`owner (${owner}), name (${name}) required`) - await navigator.clipboard.writeText(`${location.origin}${getProjectShareRoute(owner, name)}`) - m.success(t({ en: 'Link copied to clipboard', zh: '分享链接已复制到剪贴板' })) +export function useCreateProjectSharingLink() { + const modal = useModal(ProjectSharingLinkModal) + + return async function createProjectSharingLink(project: Project) { + await modal({ project }) } } /** - * Save and share given project - * - save current project state + * Share given project * - make project public * - copy sharing link */ -export function useSaveAndShareProject() { +export function useShareProject() { const { t } = useI18n() const withConfirm = useConfirmDialog() - const shareProject = useShareProject() + const createProjectSharingLink = useCreateProjectSharingLink() - async function saveAndShare(project: Project) { - if (project.isPublic !== IsPublic.public || project.hasUnsyncedChanges) { - project.setPublic(IsPublic.public) - await project.saveToCloud() - } - await shareProject(project) - } - - async function saveAndShareWithConfirm(project: Project, confirmMessage: LocaleMessage) { - await withConfirm({ - title: t({ en: 'Share project', zh: '分享项目' }), - content: t(confirmMessage), - confirmHandler: () => saveAndShare(project) - }) + async function makePublic(project: Project) { + project.setPublic(IsPublic.public) + await project.saveToCloud() } - return async function saveAndShareProject(project: Project) { - const { isPublic, hasUnsyncedChanges } = project - if (isPublic == null) throw new Error('isPublic required') - - if (isPublic === IsPublic.public) { - if (!hasUnsyncedChanges) return saveAndShare(project) - else - return saveAndShareWithConfirm(project, { - en: "To share the project, we will save the project's current state to cloud", - zh: '分享操作会将当前项目状态保存到云端' - }) - } else { - if (!hasUnsyncedChanges) - return saveAndShareWithConfirm(project, { - en: 'To share the project, we will make the project public', - zh: '分享操作会将当前项目设置为公开' - }) - else - return saveAndShareWithConfirm(project, { - en: "To share the project, we will save the project's current state to cloud & make it public", - zh: '分享操作会将当前项目状态保存到云端,并将项目设置为公开' - }) + return async function shareProject(project: Project) { + if (project.isPublic !== IsPublic.public) { + await withConfirm({ + title: t({ en: 'Share project', zh: '分享项目' }), + content: t({ + en: 'To share the current project, it will be made public. Would you like to proceed?', + zh: '为了分享当前项目,它将被设置为公开。确认继续吗?' + }), + confirmHandler: () => makePublic(project) + }) } + return createProjectSharingLink(project) } } export function useStopSharingProject() { - const withConfirm = useConfirmDialog() const { t } = useI18n() + const withConfirm = useConfirmDialog() + + async function makePersonal(project: Project) { + project.setPublic(IsPublic.personal) + await project.saveToCloud() + } return async function stopSharingProject(project: Project) { - let confirmMessage = { - en: 'If sharing stopped, others will no longer have permission to access the project, and all project-sharing links will expire', - zh: '停止分享后,其他人不再可以访问项目,所有的项目分享链接也将失效' - } - if (project.hasUnsyncedChanges) { - confirmMessage = { - en: `The project's current state will be saved to cloud. ${confirmMessage.en}`, - zh: `当前项目状态将被保存到云端;${confirmMessage.zh}` - } - } return withConfirm({ title: t({ en: 'Stop sharing project', zh: '停止分享项目' }), - content: t(confirmMessage), - confirmHandler: async () => { - project.setPublic(IsPublic.personal) - await project.saveToCloud() - } + content: t({ + en: 'If sharing is stopped, others will no longer have access to the current project, and its sharing links will expire. Would you like to proceed?', + zh: '如果停止分享,其他人将无法访问当前项目,且分享链接将会失效。确认继续吗?' + }), + confirmHandler: () => makePersonal(project) }) } } diff --git a/spx-gui/src/components/project/runner/IframeDisplay.vue b/spx-gui/src/components/project/runner/IframeDisplay.vue index d054e1fd3..5f2e1583b 100644 --- a/spx-gui/src/components/project/runner/IframeDisplay.vue +++ b/spx-gui/src/components/project/runner/IframeDisplay.vue @@ -1,12 +1,10 @@