MaxKB/ui/src/views/tool/McpToolFormDrawer.vue

294 lines
7.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-drawer v-model="visible" size="60%" :before-close="close">
<template #header>
<h4>{{ title }}</h4>
</template>
<div>
<h4 class="title-decoration-1 mb-16">
{{ $t('views.model.modelForm.title.baseInfo') }}
</h4>
<el-form
ref="FormRef"
:model="form"
:rules="rules"
label-position="top"
require-asterisk-position="right"
hide-required-asterisk
v-loading="loading"
@submit.prevent
>
<el-form-item :label="$t('views.tool.form.mcpName.label')" prop="name">
<div class="flex w-full">
<div
v-if="form.id"
class="edit-avatar mr-12"
@mouseenter="showEditIcon = true"
@mouseleave="showEditIcon = false"
>
<el-Avatar
v-if="isAppIcon(form.icon)"
:id="form.id"
shape="square"
:size="32"
style="background: none"
>
<img :src="String(form.icon)" alt="" />
</el-Avatar>
<el-avatar v-else shape="square" :size="32">
<img src="@/assets/workflow/icon_mcp.svg" style="width: 75%" alt="" />
</el-avatar>
<el-Avatar
v-if="showEditIcon"
:id="form.id"
shape="square"
class="edit-mask"
:size="32"
@click="openEditAvatar"
>
<AppIcon iconName="app-edit"></AppIcon>
</el-Avatar>
</div>
<el-avatar v-else shape="square" :size="32" class="mr-12">
<img src="@/assets/workflow/icon_mcp.svg" style="width: 75%" alt="" />
</el-avatar>
<el-input
v-model="form.name"
:placeholder="$t('views.tool.form.mcpName.placeholder')"
maxlength="64"
show-word-limit
@blur="form.name = form.name?.trim()"
/>
</div>
</el-form-item>
<el-form-item :label="$t('views.tool.form.mcpDescription.label')">
<el-input
v-model="form.desc"
type="textarea"
:placeholder="$t('views.tool.form.mcpDescription.placeholder')"
maxlength="128"
show-word-limit
:autosize="{ minRows: 3 }"
@blur="form.desc = form.desc?.trim()"
/>
</el-form-item>
<h4 class="title-decoration-1 mb-16">
{{ $t('views.tool.form.mcp.title') }}
</h4>
<el-form-item :label="$t('views.tool.form.mcpDescription.label')" prop="code">
<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.code"
:placeholder="mcpServerJson"
type="textarea"
:autosize="{ minRows: 5 }"
/>
</el-form-item>
</el-form>
</div>
<template #footer>
<div>
<el-button :loading="loading" @click="visible = false">{{ $t('common.cancel') }}</el-button>
<el-button
type="primary"
@click="submit(FormRef)"
:loading="loading"
v-if="isEdit ? permissionPrecise.edit(form?.id as string) : permissionPrecise.create()"
>
{{ isEdit ? $t('common.save') : $t('common.create') }}
</el-button>
</div>
</template>
<EditAvatarDialog ref="EditAvatarDialogRef" @refresh="refreshTool" />
</el-drawer>
</template>
<script setup lang="ts">
import { computed, reactive, ref, watch } from 'vue'
import EditAvatarDialog from '@/views/tool/component/EditAvatarDialog.vue'
import type { toolData } from '@/api/type/tool'
import type { FormInstance } from 'element-plus'
import { MsgConfirm, MsgSuccess } from '@/utils/message'
import { cloneDeep } from 'lodash'
import { t } from '@/locales'
import { isAppIcon } from '@/utils/common'
import { useRoute } from 'vue-router'
import useStore from '@/stores'
import permissionMap from '@/permission'
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
const route = useRoute()
const props = defineProps({
title: String,
})
const { folder, user } = useStore()
const apiType = computed(() => {
if (route.path.includes('shared')) {
return 'systemShare'
} else if (route.path.includes('resource-management')) {
return 'systemManage'
} else {
return 'workspace'
}
})
const permissionPrecise = computed(() => {
return permissionMap['tool'][apiType.value]
})
const emit = defineEmits(['refresh'])
const EditAvatarDialogRef = ref()
const mcpServerJson = `{
"math": {
"url": "your_server",
"transport": "sse"
}
}`
const FormRef = ref()
const isEdit = ref(false)
const loading = ref(false)
const visible = ref(false)
const showEditor = ref(false)
const currentIndex = ref<any>(null)
const showEditIcon = ref(false)
const form = ref<toolData>({
name: '',
desc: '',
code: '',
icon: '',
input_field_list: [],
init_field_list: [],
tool_type: 'MCP',
})
watch(visible, (bool) => {
if (!bool) {
isEdit.value = false
showEditor.value = false
currentIndex.value = null
form.value = {
name: '',
desc: '',
code: '',
icon: '',
input_field_list: [],
init_field_list: [],
tool_type: 'MCP',
}
FormRef.value?.clearValidate()
}
})
const rules = reactive({
name: [
{
required: true,
message: t('views.tool.form.mcpName.requiredMessage'),
trigger: 'blur',
},
],
code: [
{
required: true,
message: t('views.tool.form.mcp.requiredMessage'),
trigger: 'blur',
},
],
})
function close() {
if (!areAllValuesNonEmpty(form.value)) {
visible.value = false
} else {
MsgConfirm(t('common.tip'), t('views.tool.tip.saveMessage'), {
confirmButtonText: t('common.confirm'),
})
.then(() => {
visible.value = false
})
.catch(() => {})
}
}
function areAllValuesNonEmpty(obj: any) {
return Object.values(obj).some((value) => {
return Array.isArray(value)
? value.length !== 0
: value !== null && value !== undefined && value !== ''
})
}
function refreshTool(data: any) {
form.value.icon = data
}
function openEditAvatar() {
EditAvatarDialogRef.value.open(form.value)
}
const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid: any) => {
if (valid) {
if (isEdit.value) {
loadSharedApi({ type: 'tool', systemType: apiType.value })
.putTool(form.value?.id as string, form.value, loading)
.then((res: any) => {
MsgSuccess(t('common.editSuccess'))
emit('refresh', res.data)
return user.profile()
})
.then(() => {
visible.value = false
})
} else {
const obj = {
folder_id: folder.currentFolder?.id,
...form.value,
}
loadSharedApi({ type: 'tool', systemType: apiType.value })
.postTool(obj, loading)
.then((res: any) => {
MsgSuccess(t('common.createSuccess'))
emit('refresh')
return user.profile()
})
.then(() => {
visible.value = false
})
}
}
})
}
const open = (data: any) => {
if (data) {
isEdit.value = data?.id ? true : false
form.value = cloneDeep(data)
}
visible.value = true
setTimeout(() => {
showEditor.value = true
}, 100)
}
defineExpose({
open,
})
</script>
<style lang="scss" scoped></style>