-
Notifications
You must be signed in to change notification settings - Fork 2.6k
feat: add ToolStoreDescDrawer component and integrate with ToolListContainer #4155
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| <template> | ||
| <el-drawer v-model="visibleInternalDesc" size="60%" :append-to-body="true"> | ||
| <template #header> | ||
| <div class="flex align-center" style="margin-left: -8px"> | ||
| <el-button class="cursor mr-4" link @click.prevent="visibleInternalDesc = false"> | ||
| <el-icon :size="20"> | ||
| <Back /> | ||
| </el-icon> | ||
| </el-button> | ||
| <h4>详情</h4> | ||
| </div> | ||
| </template> | ||
|
|
||
| <div> | ||
| <div class="card-header"> | ||
| <div class="flex-between"> | ||
| <div class="title flex align-center"> | ||
| <el-avatar | ||
| v-if="isAppIcon(toolDetail?.icon)" | ||
| shape="square" | ||
| :size="64" | ||
| style="background: none" | ||
| class="mr-8" | ||
| > | ||
| <img :src="toolDetail?.icon" alt="" /> | ||
| </el-avatar> | ||
| <el-avatar | ||
| v-else-if="toolDetail?.name" | ||
| :name="toolDetail?.name" | ||
| pinyinColor | ||
| shape="square" | ||
| :size="64" | ||
| class="mr-8" | ||
| /> | ||
| <div class="ml-16"> | ||
| <h3 class="mb-8">{{ toolDetail.name }}</h3> | ||
| <el-text type="info" v-if="toolDetail?.desc"> | ||
| {{ toolDetail.desc }} | ||
| </el-text> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div class="mt-16"> | ||
| <el-text type="info"> | ||
| <div>{{ $t('common.author') }}: MaxKB</div> | ||
| </el-text> | ||
| </div> | ||
| </div> | ||
| <MdPreview | ||
| ref="editorRef" | ||
| editorId="preview-only" | ||
| :modelValue="markdownContent" | ||
| style="background: none" | ||
| noImgZoomIn | ||
| /> | ||
| </div> | ||
| </el-drawer> | ||
| </template> | ||
|
|
||
| <script setup lang="ts"> | ||
| import { ref, watch } from 'vue' | ||
| import { cloneDeep } from 'lodash' | ||
| import { isAppIcon } from '@/utils/common' | ||
| const emit = defineEmits(['refresh', 'addTool']) | ||
| const visibleInternalDesc = ref(false) | ||
| const markdownContent = ref('') | ||
| const toolDetail = ref<any>({}) | ||
| watch(visibleInternalDesc, (bool) => { | ||
| if (!bool) { | ||
| markdownContent.value = '' | ||
| } | ||
| }) | ||
| const open = (data: any, detail: any) => { | ||
| toolDetail.value = detail | ||
| if (data) { | ||
| markdownContent.value = cloneDeep(data) | ||
| } | ||
| visibleInternalDesc.value = true | ||
| } | ||
| defineExpose({ | ||
| open | ||
| }) | ||
| </script> | ||
| <style lang="scss"></style> | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The provided Vue component template has several minor issues and can be optimized slightly: Irregularities and Issues:
Optimization Suggestions:
Here's an updated version of the code incorporating these suggestions: @@ -0,0 +1,75 @@
<template>
<el-drawer v-model="visibleInternalDesc" title="详情" append-to-body draggable=true>
<div class="drawer-container">
<div class="flex items-center justify-start mt-4 mb-4">
<el-button class="btn-close cursor ml-auto" icon="BackIcon" @click.prevent="closeDrawer()"/>
<h4 class="font-bold text-lg">工具详情</h4>
</div>
<div class="detail-card mx-auto w-full py-4 px-8 border rounded shadow-md">
<!-- Tools Icon -->
<div class="flex items-center mb-2">
<img v-if="isAppIcon(toolDetail?.icon)" :src="toolDetail.icon" alt="" class="w-16 h-16 bg-transparent mr-4 object-cover rounded">
<span v-else-if="toolDetail.name" class="pinyin-color">{{ toolDetail.name }}</span>
</div>
<div>
<!-- Tool Detail Details -->
<h3 class="text-xl font-semibold">{{ toolDetail.name }}</h3>
<p v-if="toolDetail.desc" class="mt-2 text-gray-600">{{ toolDetail.desc }}</p>
<!-- Author Information -->
<small class="block text-sm text-gray-500 mt-4">{{ $t('common.author') }}: MaxKB</small>
</div>
</div>
<div class="md-preview">
<MdPreview ref="editorRef" editorId="preview-only" :model-value="markdownContent" />
</div>
</div>
</el-drawer>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { cloneDeep, isAppIcon } from '@/utils/common';
const emit = defineEmits(['refresh', 'addTool']);
const visibleInternalDesc = ref(false);
const markdownContent = ref('');
const toolDetail = ref<{ icon?: string, name?: string, desc?: string | null }>({});
function closeDrawer() {
toggleVisible();
}
function toggleVisible(state?: boolean) {
console.log(`Close drawer state: ${state ?? visibleInternalDesc.value}`);
visibleInternalDesc.value = state !== undefined ? state : !visibleInternalDesc.value;
if (!visibleInternalDesc.value) {
markdownContent.value = '';
}
}
watch(visibleInternalDesc, val => {
// Automatically open modal on initial rendering
if (!val && document.querySelector('#app') && window.location.hash === '#/tool-detail/:id') {
setTimeout(() => {
const hashParts = location.hash.split('/').slice(2); // [tabID, id]
let objHash;
switch(hashParts[0]) {
case 'tools':
if (window.$toolDataList[hashParts[1]]) {
objHash = { ...cloneDeep(window.$toolDataList[hashParts[1]], true), app_id: hashParts[1] };
} else {
return;
}
break;
case 'projects':
if (window.$data.project_list.find(p => p.proj_id === parseInt(hashParts[1], 10))) {
objHash = {}; // Placeholder since projects don't have detailed data
} else {
return;
}
break;
}
// Close the sidebar before opening
document.body.click();
toolDetail.value.icon = objHash.icon;
toolDetail.value.name = objHash.text;
toolDetail.value.app_id = objHash.app_id;
setOpen(objHash.text == "")?{}:objHash);
toggleVisible(true);
setTimeout(() => {
const domEle = document.getElementById("project_detail");
window.scrollTo(domEle.offsetTop, dom Ele.clientHeight / 10);
}, 50);
emit('changeTitle');
var tabName = "#/";
if (hashParts.length > 1){
tabName = '#'+'/'+hash.parts.join('/');
}
window.history.replaceState({}, "", tabName);
});
}
});
function open(
data: { icon?: string; name?: string },
detail: { icon?: string, name?: string, desc?: string | null })
{
if (data) {
toolDetail.value.icon = data.icon;
toolDetail.value.name = data.name;
markdownContent.value = cloneDeep(detail || {}, true) as never;
} else {
// Clear details or set default if required
toolDetail.value.icon = "";
toolDetail.value.name = "未找到";
markdownContent.value = "<p>请提供更详细的信息。</p>";
}
toggleVisible(true);
}
defineExpose({ open, closeDrawer, toggleVisible });
</script>Key Changes Made:
Additional Considerations:
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -138,7 +138,7 @@ | |
| v-model="item.source" | ||
| size="small" | ||
| style="width: 85px" | ||
| @change="form_data.tool_params[form_data.params_nested] = {}; form_data.tool_params[form_data.params_nested][item.label.label]" | ||
| @change="form_data.tool_params[form_data.params_nested] = {}; form_data.tool_params[form_data.params_nested][item.label.label] = ''" | ||
| > | ||
| <el-option | ||
| :label="$t('views.applicationWorkflow.nodes.replyNode.replyContent.reference')" | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is one issue with the proposed change that could lead undefined behavior in your JavaScript object: form_data.tool_params[form_data.params_nested] = {};
(form_data.tool_params[form_data.params_nested])[item.label.label]This line should be changed to use an assignment operator: const nestedParams = form_data.tool_params[form_data.params_nested];
nestedParams[item.label.label] = '';The original code would create a new empty object every time If <el-select v-model="item.source" size="small" style="width: 85px;" @change="onChangeForm">
<!-- Options -->
</el-select>Then define methods: {
onChangeForm() {
const labelValue = item.label?.label || ''; // Use optional chaining for safety
form_data.tool_params[form_data.params_nested] ??= {};
form_data.tool_params[form_data.params_nested][labelValue] = '';
}
}If there's a specific reason why you need to use bracket syntax ( |
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no direct error in this code snippet that prevents it from functioning correctly. However, there are a few areas for consideration:
Potential Issues
Missing Import: Ensure that
ToolStoreDescDraweris available before being used. Since it's imported at the top but not referenced anywhere else, it doesn't affect the functionality.Unused Variable: The variable
storeTools.value.filter(...)appears to be undefined based on the context provided (storeToolsis likely defined elsewhere but not used).Unnecessary Comments: Some comments could be removed as they don't add value without explanation and can sometimes contribute clutter if misaligned with code content.
Redundant Code: Conditional checks like checking both
tool_type === 'MCP'anddata?.versioncould benefit from simplification. If one condition implies the other (e.g., MCP has specific properties), these checks might be redundant.Optimization Suggestions
Code Simplification:
Error Handling:
Performance Enhancements:
Code Readability:
Here’s an optimized version of the relevant part of your code considering some of these suggestions:
This revised version reduces redundancy, includes missing imports, improves readability, and simplifies some conditions where possible while ensuring the main functionality remains intact.