improve tool messages with copy to clipboard and styling

This commit is contained in:
Nemo Godebski-Pedersen 2025-04-08 16:30:19 +01:00
parent 0c51cb8a7d
commit 5e78b4f1b0
4 changed files with 118 additions and 19 deletions

13
package-lock.json generated
View File

@ -43,6 +43,7 @@
"vanilla-jsoneditor": "^2.3.3",
"vue": "^3.5.1",
"vue-i18n": "^9.4.0",
"vue-json-pretty": "^2.4.0",
"vue-router": "^4.2.2",
"vue-socket.io": "^3.0.10",
"ws": "^8.18.0"
@ -14018,6 +14019,18 @@
"vue": "^3.0.0"
}
},
"node_modules/vue-json-pretty": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/vue-json-pretty/-/vue-json-pretty-2.4.0.tgz",
"integrity": "sha512-e9bP41DYYIc2tWaB6KuwqFJq5odZ8/GkE6vHQuGcbPn37kGk4a3n1RNw3ZYeDrl66NWXgTlOfS+M6NKkowmkWw==",
"engines": {
"node": ">= 10.0.0",
"npm": ">= 5.0.0"
},
"peerDependencies": {
"vue": ">=3.0.0"
}
},
"node_modules/vue-router": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.0.tgz",

View File

@ -55,6 +55,7 @@
"vanilla-jsoneditor": "^2.3.3",
"vue": "^3.5.1",
"vue-i18n": "^9.4.0",
"vue-json-pretty": "^2.4.0",
"vue-router": "^4.2.2",
"vue-socket.io": "^3.0.10",
"ws": "^8.18.0"

View File

@ -116,8 +116,7 @@ export default {
}
.tool-calls-container {
display: flex;
flex-direction: row;
width: auto;
flex-direction: column;
max-width: min(600px, calc(100% - 60px));
}

View File

@ -1,5 +1,8 @@
<script lang="ts">
import { ArrowDown, ArrowUp, RefreshRight, Check } from '@element-plus/icons-vue'
import { ArrowDown, ArrowUp, RefreshRight, Check, DocumentCopy } from '@element-plus/icons-vue'
import VueJsonPretty from 'vue-json-pretty';
import { ElMessage } from 'element-plus';
import 'vue-json-pretty/lib/styles.css';
export default {
props: {
@ -29,6 +32,27 @@ export default {
toggleExpanded() {
this.expanded = !this.expanded;
},
copyToClipboard(text: string) {
navigator.clipboard.writeText(text)
.then(() => {
ElMessage({
message: 'Copied to clipboard!',
type: 'success',
duration: 2000
});
})
.catch(err => {
console.error('Failed to copy: ', err);
ElMessage({
message: 'Failed to copy to clipboard',
type: 'error',
duration: 2000
});
});
}
},
components: {
VueJsonPretty,
},
}
@ -36,21 +60,39 @@ export default {
<template>
<div class="tool-message-container" @click="toggleExpanded">
<div class="status" v-bind:class="status">
<div v-if="status === 'pending'">
<el-icon class="is-loading" color="#20cbeb"><RefreshRight /></el-icon>
<div class="tool-message-container" v-bind:class="expanded? 'expanded':''">
<div class="tool-message-header">
<div class="status" v-bind:class="status">
<div v-if="status === 'pending'">
<el-icon class="is-loading" color="#20cbeb"><RefreshRight /></el-icon>
</div>
<div v-else-if="status === 'success'">
<el-icon color="#00ff18"><Check /></el-icon>
</div>
</div>
<div v-else-if="status === 'success'">
<el-icon color="#00ff18"><Check /></el-icon>
<div class="tool-name">{{ name }}</div>
<div class="expand-icon" @click="toggleExpanded">
<el-icon><ArrowDown v-if="!expanded" /><ArrowUp v-else /></el-icon>
</div>
</div>
<div class="tool-name">{{ name }}</div>
<div class="expand-icon">
<el-icon><ArrowDown v-if="!expanded" /><ArrowUp v-else /></el-icon>
</div>
<div v-if="expanded" class="tool-detail">
<div class="tool-id">ID: {{ toolCallId }}</div>
<h4>Result:</h4>
<div v-if="result" class="tool-result-container">
<div class="copy-to-clipboard">
<el-button size="small" circle @click="copyToClipboard(JSON.stringify(result, null, 2))" :dark="true"><el-icon><DocumentCopy /></el-icon></el-button>
</div>
<el-scrollbar wrap-class="tool-result">
<vue-json-pretty :data="result" :expand-depth="2" />
</el-scrollbar>
<!-- <div>{{ JSON.stringify(result, null, 2) }}</div> -->
</div>
</div>
</div>
<el-card v-if="expanded" class="tool-details">
<!-- <el-card v-if="expanded" class="tool-details">
<template #header>
<div class="tool-id">ID: {{ toolCallId }}</div>
</template>
@ -62,8 +104,7 @@ export default {
</template>
<!-- Add other information here -->
</el-card>
</el-card> -->
</template>
<style scoped>
@ -74,10 +115,55 @@ export default {
font-size: small;
padding: 10px;
border-radius: 10px;
margin: 0 10px 0 0;
margin: 10px 0 0 0;
display: flex;
flex-direction: row;
width: auto;
flex-direction: column;
width: 100%;
}
.copy-to-clipboard {
display: inline-block;
position: absolute;
top: 10px;
right: 20px;
z-index: 10;;
}
.tool-result {
position: absolute;
top: 10px;
left: 10px;
}
.tool-result-container {
background-color: #1e2a3a;
padding: 10px;
border-radius: 10px;
margin-top: 10px;
width: 90%;
position: relative;
height: 400px;
box-shadow: inset 0px 0px 17px -6px rgba(0,0,0,0.75);
overflow: auto;
}
.expand-icon {
margin-left: auto;
cursor: pointer;
}
.tool-message-header {
display: flex;
flex-direction: row;
align-items: center;
width: 100%;
}
.tool-detail {
margin-top: 10px;
}
</style>