Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ui/src/assets/icon_tool_shop.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 0 additions & 3 deletions ui/src/assets/node/icon_tool.svg

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
:source="prologue"
:send-message="sendMessage"
reasoning_content=""
:type="type"
></MdRenderer>
</el-card>
</div>
Expand All @@ -35,7 +36,6 @@ const props = defineProps<{
sendMessage: (question: string, other_params_data?: any, chat?: chatType) => void
}>()


const showAvatar = computed(() => {
return props.application.show_avatar == undefined ? true : props.application.show_avatar
})
Expand Down
21 changes: 21 additions & 0 deletions ui/src/components/app-icon/ToolIcon.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<template>
<el-avatar v-if="type == 'MCP'" shape="square" :size="size">
<img src="@/assets/workflow/icon_mcp.svg" style="width: 75%" alt="" />
</el-avatar>
<el-avatar v-else class="avatar-green" shape="square" :size="size">
<img src="@/assets/workflow/icon_tool.svg" style="width: 58%" alt="" />
</el-avatar>
</template>
<script setup lang="ts">
defineOptions({ name: 'ToolIcon' })
const props = defineProps({
type: {
type: [String, Number],
default: '',
},
size: {
type: [String, Number],
default: 32,
},
})
</script>
10 changes: 5 additions & 5 deletions ui/src/components/folder-breadcrumb/index.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<template>
<el-breadcrumb separator-icon="ArrowRight" style="line-height: 22px">
<h2 v-if="breadcrumbData?.length === 1" class="ellipsis" :title="breadcrumbData[0]?.name">
{{ breadcrumbData[0]?.name }}
</h2>
<el-breadcrumb-item v-for="(item, index) in breadcrumbData" :key="index" v-else>
<h2 v-if="breadcrumbData?.length === 1" class="ellipsis" :title="breadcrumbData[0]?.name">
{{ breadcrumbData[0]?.name }}
</h2>
<el-breadcrumb separator-icon="ArrowRight" style="line-height: normal" class="mt-4" v-else>
<el-breadcrumb-item v-for="(item, index) in breadcrumbData" :key="index">
<h5 class="ml-4 ellipsis" v-if="index === breadcrumbData.length - 1" :title="item.name">
{{ item.name }}
</h5>
Expand Down
2 changes: 2 additions & 0 deletions ui/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import TagEllipsis from './tag-ellipsis/index.vue'
import CardCheckbox from './card-checkbox/index.vue'
import AiChat from './ai-chat/index.vue'
import KnowledgeIcon from './app-icon/KnowledgeIcon.vue'
import ToolIcon from './app-icon/ToolIcon.vue'
import TagGroup from './tag-group/index.vue'
import WorkspaceDropdown from './workspace-dropdown/index.vue'
import FolderBreadcrumb from './folder-breadcrumb/index.vue'
Expand Down Expand Up @@ -52,6 +53,7 @@ export default {
app.component('CardCheckbox', CardCheckbox)
app.component('AiChat', AiChat)
app.component('KnowledgeIcon', KnowledgeIcon)
app.component('ToolIcon', ToolIcon)
app.component('TagGroup', TagGroup)
app.component('WorkspaceDropdown', WorkspaceDropdown)
app.component('FolderBreadcrumb', FolderBreadcrumb)
Expand Down
8 changes: 6 additions & 2 deletions ui/src/components/markdown/MdRenderer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
<template v-for="(item, index) in md_view_list" :key="index">
<div
v-if="item.type === 'question'"
@click="sendMessage ? sendMessage(item.content, 'new') : (content: string) => {}"
@click="
sendMessage && type !== 'log' ? sendMessage(item.content, 'new') : (content: string) => {}
"
class="problem-button mt-4 mb-4 flex"
:class="sendMessage ? 'cursor' : 'disabled'"
:class="sendMessage && type !== 'log' ? 'cursor' : 'disabled'"
>
<AppIcon iconName="app-edit" class="mr-8" style="margin-top: 2px"></AppIcon>
{{ item.content }}
Expand Down Expand Up @@ -61,6 +63,7 @@ config({
tokens[idx].attrSet('target', '_blank')
return md.renderer.renderToken(tokens, idx, options)
}
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
document.appendChild
},
})
Expand All @@ -74,6 +77,7 @@ const props = withDefaults(
chat_record_id?: string
runtime_node_id?: string
disabled?: boolean
type?: 'log' | 'ai-chat' | 'debug-ai-chat'
}>(),
{
source: '',
Expand Down
4 changes: 2 additions & 2 deletions ui/src/layout/components/breadcrumb/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
>
<img :src="resetUrl(current?.icon, resetUrl('./favicon.ico'))" alt="" />
</el-avatar>
<LogoIcon
<!-- <LogoIcon
v-else-if="isApplication"
height="28px"
style="width: 28px; height: 28px; display: block"
class="mr-8"
/>
/> -->
<KnowledgeIcon v-else-if="isKnowledge" :type="current?.type" class="mr-8" />

<div class="ellipsis" :title="current?.name">{{ current?.name }}</div>
Expand Down
2 changes: 2 additions & 0 deletions ui/src/locales/lang/en-US/views/tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,11 @@ export default {
inputPlaceholder: 'Please enter parameter values',
},
mcp: {
title: 'MCP Service',
label: 'MCP Server Config',
placeholder: 'Please enter MCP Server config',
tip: 'Only supports SSE and Streamable HTTP calling methods',
requiredMessage: 'Please enter MCP Server Config',
},
debug: {
run: 'Run',
Expand Down
2 changes: 2 additions & 0 deletions ui/src/locales/lang/zh-CN/views/tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ export default {
inputPlaceholder: '请输入参数值',
},
mcp: {
title: 'MCP 服务',
label: 'MCP Server Config',
placeholder: '请输入MCP Server配置',
tip: '仅支持SSE、Streamable HTTP调用方式',
requiredMessage: '请输入 MCP Server Config',
},
debug: {
run: '运行',
Expand Down
2 changes: 2 additions & 0 deletions ui/src/locales/lang/zh-Hant/views/tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,11 @@ export default {
inputPlaceholder: '請輸入參數值',
},
mcp: {
title: 'MCP 服務',
label: 'MCP Server Config',
placeholder: '請輸入MCP Server配置',
tip: '僅支援SSE、Streamable HTTP呼叫方式',
requiredMessage: '請輸入 MCP Server Config',
},
debug: {
run: '運行',
Expand Down
1 change: 1 addition & 0 deletions ui/src/styles/component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@

// radio-button-group
.app-radio-button-group {
background: #ffffff;
border: 1px solid var(--app-border-color-dark);
border-radius: var(--el-border-radius-base);
.el-radio-button {
Expand Down
5 changes: 5 additions & 0 deletions ui/src/styles/element-plus.scss
Original file line number Diff line number Diff line change
Expand Up @@ -282,3 +282,8 @@
.el-tag {
padding: 0 6px;
}

// el-input
.el-input {
--el-input-text-color: var(--el-text-color-primary);
}
6 changes: 3 additions & 3 deletions ui/src/views/application/component/AddKnowledgeDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@

<el-scrollbar>
<div class="p-16-24 pt-0" style="height: calc(100vh - 200px)">
<el-row :gutter="12" v-loading="loading" v-if="filterData.length">
<el-row :gutter="12" v-loading="loading || apiLoading" v-if="filterData.length">
<el-col
:span="12"
v-for="(item, index) in filterData.filter((v: any) => v.resource_type !== 'folder')"
Expand Down Expand Up @@ -132,7 +132,7 @@ const currentEmbedding = ref('')
const searchValue = ref('')
const searchData = ref<Array<any>>([])
const knowledgeList = ref<Array<any>>([])
const loading = ref(false)
const apiLoading = ref(false)

const filterData = computed(() => {
return currentEmbedding.value
Expand Down Expand Up @@ -228,7 +228,7 @@ function getList() {
isShared: folder_id === 'share',
systemType: apiType.value,
})
.getKnowledgeList({ folder_id }, loading)
.getKnowledgeList({ folder_id }, apiLoading)
.then((res: any) => {
knowledgeList.value = uniqueArray([...knowledgeList.value, ...res.data], 'id')
searchData.value = res.data
Expand Down
83 changes: 59 additions & 24 deletions ui/src/views/application/component/McpServersDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
ref="paramFormRef"
:model="form"
require-asterisk-position="right"
hide-required-asterisk
@submit.prevent
>
<el-form-item>
<el-radio-group v-model="form.mcp_source">
Expand All @@ -22,27 +24,58 @@
<el-radio value="custom">{{ $t('common.custom') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="form.mcp_source === 'referencing'">
<el-form-item
v-if="form.mcp_source === 'referencing'"
:rules="[
{
required: true,
message:
$t('common.selectPlaceholder') +
` MCP ${$t('views.applicationWorkflow.nodes.mcpNode.tool')}`,
},
]"
prop="mcp_tool_id"
>
<template #label>
{{ `MCP ${$t('views.applicationWorkflow.nodes.mcpNode.tool')}` }}
<span class="color-danger">*</span>
</template>
<el-select v-model="form.mcp_tool_id" filterable>
<el-option
v-for="mcpTool in mcpToolSelectOptions"
:key="mcpTool.id"
:label="mcpTool.name"
:value="mcpTool.id"
>
<span>{{ mcpTool.name }}</span>
<el-tag v-if="mcpTool.scope === 'SHARED'" type="info" class="info-tag ml-8 mt-4">
{{ $t('views.shared.title') }}
</el-tag>
<div class="flex align-center">
<el-avatar shape="square" :size="20" class="mr-8">
<img src="@/assets/workflow/icon_mcp.svg" style="width: 75%" alt="" />
</el-avatar>
<span>{{ mcpTool.name }}</span>
<el-tag v-if="mcpTool.scope === 'SHARED'" type="info" class="info-tag ml-8 mt-4">
{{ $t('views.shared.title') }}
</el-tag>
</div>
</el-option>
</el-select>
</el-form-item>
<el-form-item
v-else
:label="$t('views.applicationWorkflow.nodes.mcpNode.configLabel')"
prop="mcp_servers"
:rules="[{ required: true, message: $t('common.required') }]"
:rules="[
{
required: true,
message: $t('common.inputPlaceholder') + ' ' + $t('views.tool.form.mcp.label'),
},
]"
>
<template #label>
{{ $t('views.tool.form.mcp.label') }}
<span class="color-danger">*</span>
<el-text type="info" class="color-secondary">
({{ $t('views.tool.form.mcp.tip') }})
</el-text>
</template>
<el-input
v-model="form.mcp_servers"
:rows="6"
Expand All @@ -63,9 +96,9 @@
</el-dialog>
</template>
<script setup lang="ts">
import {computed, inject, onMounted, ref, watch} from 'vue'
import {loadSharedApi} from "@/utils/dynamics-api/shared-api.ts";
import {useRoute} from "vue-router";
import { computed, inject, onMounted, ref, watch } from 'vue'
import { loadSharedApi } from '@/utils/dynamics-api/shared-api.ts'
import { useRoute } from 'vue-router'

const getApplicationDetail = inject('getApplicationDetail') as any
const applicationDetail = getApplicationDetail()
Expand Down Expand Up @@ -106,38 +139,40 @@ watch(dialogVisible, (bool) => {
mcp_tool_id: '',
mcp_source: 'referencing',
}
paramFormRef.value?.clearValidate()
}
})


function getMcpToolSelectOptions() {
const obj =
apiType.value === 'systemManage'
? {
scope: 'WORKSPACE',
tool_type: 'MCP',
workspace_id: applicationDetail.value?.workspace_id,
}
scope: 'WORKSPACE',
tool_type: 'MCP',
workspace_id: applicationDetail.value?.workspace_id,
}
: {
scope: 'WORKSPACE',
tool_type: 'MCP',
}
scope: 'WORKSPACE',
tool_type: 'MCP',
}

loadSharedApi({type: 'tool', systemType: apiType.value})
loadSharedApi({ type: 'tool', systemType: apiType.value })
.getAllToolList(obj, loading)
.then((res: any) => {
mcpToolSelectOptions.value = [...res.data.shared_tools, ...res.data.tools]
.filter((item: any) => item.is_active)
mcpToolSelectOptions.value = [...res.data.shared_tools, ...res.data.tools].filter(
(item: any) => item.is_active,
)
})
}

const open = (data: any) => {
form.value = {...form.value, ...data}
form.value = { ...form.value, ...data }
form.value.mcp_source = data.mcp_source || 'referencing'
dialogVisible.value = true
}

const submit = () => {
paramFormRef.value.validate().then((valid: any) => {
paramFormRef.value.validate((valid: any) => {
if (valid) {
emit('refresh', form.value)
dialogVisible.value = false
Expand All @@ -149,6 +184,6 @@ onMounted(() => {
getMcpToolSelectOptions()
})

defineExpose({open})
defineExpose({ open })
</script>
<style lang="scss" scoped></style>
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The provided code is mostly clean but has a few areas that could be improved:

  1. Template Tags: There are some unnecessary HTML comments and tags like <template #label> without corresponding content. These should either contain text or conditional rendering logic.

  2. Error Handling: The @submit.prevent does not do anything meaningful because there's no form submission in this component. It would work with Vue forms, so ensure you have a valid form set up for handling submissions.

  3. Language Translation References ($t) Usage: Ensure all $t references point to existing keys in your translation files. If they don't exist, replace them with suitable placeholders like 'common.someKey'.

  4. Conditional Rendering Logic: In the v-if block for mcp_tool_id, you've added required validation rules directly within the template using inline script. This can make it difficult to manage and test changes later. Consider moving these rules into an array of objects or outside the template where it's easier to read and maintain.

Here’s a slightly adjusted version with a focus on improving readability and ensuring proper usage ofVue features:

<template>
  <!-- Form definition goes here -->
</template>

<script setup lang="ts">
// Import statements and other variables defined below...

function submit() {
  paramFormRef.value.validate((valid: boolean) =>
    valid && emit('refresh', form.value)
  ).catch(() => {});
}
</script>

Additional Corrections:

  1. Move Conditional Validation Rules Outside Template:
const rules = [
{
  validator: (_, value) => !!value || ($i18n.t("common.inputRequired") + " MCP Tool"),
},
]

<el-form-item label="MCP Tool" prop="mcpToolId" :rules="rules">
  <!-- Select Input Placeholder-->
</el-form-item>

This way, rules remain decoupled from the UI elements. Also, handle errors gracefully during validation.

  1. Simplify Form Item Label with Inline Tooltip:
<label>
  MCP Tool Required *
  <Tooltip icon="el-icon-exclamation-circle"></Tooltip>
</label>

For tooltips, include a proper tooltip provider such as Element Plus’s ElTooltip.

By implementing these corrections and enhancements, the code will become more robust, user-friendly, and maintainable while keeping its functionality intact.

12 changes: 11 additions & 1 deletion ui/src/views/paragraph/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,12 @@
clearable
>
<template #prepend>
<el-select v-model="searchType" placeholder="Select" style="width: 80px">
<el-select
v-model="searchType"
placeholder="Select"
style="width: 80px"
@change="searchTypeChange"
>
<el-option :label="$t('common.title')" value="title" />
<el-option :label="$t('common.content')" value="content" />
</el-select>
Expand Down Expand Up @@ -227,6 +232,11 @@ const title = ref('')
const search = ref('')
const searchType = ref('title')

const searchTypeChange = () => {
search.value = ''
}


const dialogVisible = ref(false)
watch(
() => ParagraphDialogRef.value?.dialogVisible,
Expand Down
Loading
Loading