Repository navigation
fix: [Agent] Clicking the "Go to Chat" icon on an agent card yields no response, and it is impossible to enter the chat page. - #7859
Conversation
…o response, and it is impossible to enter the chat page.
| <el-button text @click="toChat"> | ||
| <MkIcon name="icon_new-chat_outlined" /> | ||
| </el-button> | ||
| </MkTooltip> |
There was a problem hiding this comment.
Review
🔴 Bugs / will break at runtime
- Unsafe optional chain → TypeError
properties?.api_input_field_list.map(...)The ?. chain guards up to api_input_field_list, but .map is called directly on it. If api_input_field_list is undefined (very common), this throws inside a computed and breaks rendering of the whole card list.
const list = props.application?.work_flow?.nodes?.find(n => n.id === 'base-node')?.properties?.api_input_field_list ?? []- Empty URL opens a blank tab
const accessUrl = ok.access_token ? `...` : ''
window.open(accessUrl, '_blank')When the token is missing you call window.open(''), which opens an empty tab. Guard before opening (and ideally show an error/toast).
-
el-buttonclick bubbles to the card click handler
The card root has@click="handleOpen", so clicking the chat button also fires the card click (emittingclick, potentially navigating). Use@click.stop="toChat". -
Malformed URL when there is no query
`${...}/${ok.access_token}/${apiQuery.value}`With apiQuery === '' you get a trailing slash .../token/; with a query you get .../token/?a=b. The slash before an optional query is almost certainly unintended:
`${window.location.origin}${chatBasePath}/${ok.access_token}${apiQuery.value}`🟠 Security / robustness
- Reverse tabnabbing — always pass
noopener,noreferrer:
window.open(url, '_blank', 'noopener,noreferrer')-
No error handling / no loading state —
.thenwithout.catchgives an unhandled rejection; rapid clicks fire multiple token requests. Preferasync/await+try/catch+ aloadingref that disables the button. -
No URL encoding —
f.variable/f.default_valuecan contain&,=, spaces, Chinese text, etc.:
return `${encodeURIComponent(f.variable)}=${encodeURIComponent(f.default_value ?? '')}`- Access token in the URL path is exposed in browser history, server logs, and
Refererheaders. At minimum this is worth a comment/confirmation with the backend; a short-lived token or header-based auth is preferable.
🟡 Code quality / style
-
Imports are not at the top of the file.
import applicationAPI,useRoute/useRouter,computed, andCHAT_API_BASE_PATHare declared afterdefineOptions/defineProps/defineEmits. This violatesimport/first, hurts readability and may break some tooling. Consolidate all imports at the top and merge duplicates (vue,vue-router). -
Unused import —
useRouteis never used. -
(f: any)— give it a proper type (ApiInputField), and type the computed's return asstring. -
Simplification:
const apiQuery = computed(() => {
const fields = props.application?.work_flow?.nodes
?.find(n => n.id === 'base-node')?.properties?.api_input_field_list ?? []
const query = fields.map(...).join('&')
return query ? `?${query}` : ''
})-
chatBasePathdoesn't depend on reactive state — move it to module scope so it isn't recomputed per instance. AlsoCHAT_API_BASE_PATH.replace(/\/api$/, '')silently does nothing if the constant has a trailing slash (/api/); consider normalizing or asserting. -
Business logic leaking into a presentational card.
ApplicationCardis now coupled towork_flowinternals and the application API. Extract into a composable, e.g.useApplicationChat(application)returning{ apiQuery, openChat, loading }. -
Double guard mismatch —
:class="{ 'cursor-pointer': !selectable }"implies the card is clickable when not selectable, buthandleOpenonly emits when!selectable. Correct, but thetoChatbutton is rendered unconditionally in the footer; consider hiding/disabling it when!application.is_publish(the siblingv-ifblock implies unpublished apps shouldn't be chatted with). -
Diff noise — the re-formatting of
MkResourceCardandMkStatusLabel(re-wrapping attributes) is unrelated to the feature and makes review harder. Revert it or split into a separate commit.
Suggested rewrite (core part)
import { computed, ref } from 'vue'
import { useRouter } from 'vue-router'
import applicationAPI from '@/api/admin/workspace/application/application'
import { CHAT_API_BASE_PATH } from '@/api/constants'
const CHAT_BASE_PATH = CHAT_API_BASE_PATH.replace(/\/api\/?$/, '')
const router = useRouter()
const apiQuery = computed(() => {
const fields =
props.application?.work_flow?.nodes
?.find(n => n.id === 'base-node')
?.properties?.api_input_field_list ?? []
const query = fields
.map(f => `${encodeURIComponent(f.variable)}=${encodeURIComponent(f.default_value ?? '')}`)
.join('&')
return query ? `?${query}` : ''
})
const chatLoading = ref(false)
async function toChat() {
if (chatLoading.value) return
chatLoading.value = true
try {
const { access_token } = await applicationAPI.getAccessToken(props.application.id)
if (!access_token) {
// ElMessage.error('获取访问令牌失败')
return
}
const url = `${window.location.origin}${CHAT_BASE_PATH}/${access_token}${apiQuery.value}`
window.open(url, '_blank', 'noopener,noreferrer')
} catch (e) {
// ElMessage.error('打开对话失败')
} finally {
chatLoading.value = false
}
}<el-button text :loading="chatLoading" @click.stop="toChat">
fix: [Agent] Clicking the "Go to Chat" icon on an agent card yields no response, and it is impossible to enter the chat page.