From f765a4fd393eb3115ecab5cb20cf6cd577e3f196 Mon Sep 17 00:00:00 2001
From: linshen <32978552+linshenkx@users.noreply.github.com>
Date: Fri, 8 May 2026 22:46:41 +0800
Subject: [PATCH] feat(ui): improve output actions and link handling
- Clear stale history chain metadata when workspace state changes
- Centralize external URL opening behind a shared helper
- Add copy-and-open AI platform actions with localized labels
- Cover workspace and output action behavior with unit tests
---
.../ui/src/components/FavoriteImportPanel.vue | 20 +-
packages/ui/src/components/MainLayout.vue | 16 +-
.../ui/src/components/OutputDisplayCore.vue | 217 ++++++++++++--
.../app-layout/PromptOptimizerApp.vue | 14 +-
.../common/WorkspaceUtilityMenu.vue | 20 +-
.../image-mode/ImageText2ImageWorkspace.vue | 20 +-
.../workspaces/useBasicWorkspaceLogic.ts | 15 +
packages/ui/src/i18n/locales/en-US/core.ts | 12 +
packages/ui/src/i18n/locales/zh-CN/core.ts | 12 +
packages/ui/src/i18n/locales/zh-TW/core.ts | 12 +
packages/ui/src/utils/copy-open-action.ts | 64 ++++
packages/ui/src/utils/copy-open-icons.ts | 65 +++++
packages/ui/src/utils/open-external-url.ts | 28 ++
.../integration/basic-workspace-logic.spec.ts | 78 +++++
.../OutputDisplayCore.copy-open.spec.ts | 276 ++++++++++++++++++
.../components/WorkspaceUtilityMenu.spec.ts | 2 +-
.../unit/utils/open-external-url.spec.ts | 77 +++++
17 files changed, 842 insertions(+), 106 deletions(-)
create mode 100644 packages/ui/src/utils/copy-open-action.ts
create mode 100644 packages/ui/src/utils/copy-open-icons.ts
create mode 100644 packages/ui/src/utils/open-external-url.ts
create mode 100644 packages/ui/tests/unit/components/OutputDisplayCore.copy-open.spec.ts
create mode 100644 packages/ui/tests/unit/utils/open-external-url.spec.ts
diff --git a/packages/ui/src/components/FavoriteImportPanel.vue b/packages/ui/src/components/FavoriteImportPanel.vue
index f1b84cca..fa7c2f4f 100644
--- a/packages/ui/src/components/FavoriteImportPanel.vue
+++ b/packages/ui/src/components/FavoriteImportPanel.vue
@@ -173,6 +173,7 @@ import { getEnvVar } from '@prompt-optimizer/core'
import { useToast } from '../composables/ui/useToast'
import type { AppServices } from '../types/services'
import { getI18nErrorMessage } from '../utils/error'
+import { openExternalUrl } from '../utils/open-external-url'
import { parsePromptGardenImportInput } from '../utils/prompt-garden-import'
import {
importFavoriteResourcePackage,
@@ -230,25 +231,8 @@ const handleFileChange = (options: UploadChangeParam) => {
fileList.value = options.fileList.slice(0, 1)
}
-const openExternalUrl = async (url: string) => {
- if (!url) return
-
- if (typeof window !== 'undefined' && window.electronAPI?.shell) {
- try {
- await window.electronAPI.shell.openExternal(url)
- return
- } catch (error) {
- console.error('[PromptGarden] Failed to open external URL in Electron:', error)
- }
- }
-
- if (typeof window !== 'undefined') {
- window.open(url, '_blank')
- }
-}
-
const handlePromptGardenDiscover = () => {
- void openExternalUrl(promptGardenBaseUrl.value)
+ void openExternalUrl(promptGardenBaseUrl.value, { logPrefix: 'PromptGarden' })
}
const readFileAsArrayBuffer = (file: File) =>
diff --git a/packages/ui/src/components/MainLayout.vue b/packages/ui/src/components/MainLayout.vue
index cec8aa1e..155d10d8 100644
--- a/packages/ui/src/components/MainLayout.vue
+++ b/packages/ui/src/components/MainLayout.vue
@@ -76,6 +76,7 @@ import { NLayout, NLayoutHeader, NLayoutContent, NFlex, NText } from 'naive-ui'
import ToastUI from './Toast.vue'
import logoImage from '../assets/logo.png'
import AppPreviewImage from './media/AppPreviewImage.vue'
+import { openExternalUrl } from '../utils/open-external-url'
const { t } = useI18n()
@@ -125,20 +126,7 @@ const logoSize = computed(() => {
})
const openBrandWebsite = async () => {
- const url = 'https://always200.com'
-
- if (typeof window !== 'undefined' && window.electronAPI?.shell) {
- try {
- await window.electronAPI.shell.openExternal(url)
- return
- } catch (error) {
- console.error('Failed to open brand website in Electron:', error)
- }
- }
-
- if (typeof window !== 'undefined') {
- window.open(url, '_blank')
- }
+ await openExternalUrl('https://always200.com', { logPrefix: 'MainLayout' })
}
diff --git a/packages/ui/src/components/OutputDisplayCore.vue b/packages/ui/src/components/OutputDisplayCore.vue
index 3d1bbc5d..2a5b1fda 100644
--- a/packages/ui/src/components/OutputDisplayCore.vue
+++ b/packages/ui/src/components/OutputDisplayCore.vue
@@ -40,7 +40,6 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
@@ -193,15 +221,19 @@