1
- import { ChatBubbleLeftIcon } from "@heroicons/react/24/outline" ;
2
- import { Link , useParams } from "react-router-dom" ;
1
+ import { Link , useNavigate , useParams } from "react-router-dom" ;
3
2
import { useMessage } from "../../../hooks/useMessage" ;
4
3
import { PlaygroundHistory } from "./types" ;
4
+ import {
5
+ EllipsisHorizontalIcon ,
6
+ PencilIcon ,
7
+ TrashIcon ,
8
+ } from "@heroicons/react/24/outline" ;
9
+ import { Dropdown , notification } from "antd" ;
10
+ import api from "../../../services/api" ;
11
+ import { useMutation , useQueryClient } from "@tanstack/react-query" ;
12
+ import { Spin } from "antd" ;
13
+ import React from "react" ;
5
14
6
15
export const PlaygroundHistoryCard = ( {
7
16
item,
8
17
} : {
9
18
item : PlaygroundHistory ;
10
19
} ) => {
11
- const { historyId, setMessages , setHistory , setIsLoading } = useMessage ( ) ;
20
+ const { historyId, setHistoryId , setMessages , setHistory } = useMessage ( ) ;
12
21
const params = useParams < { id : string ; history_id ?: string } > ( ) ;
22
+ const navigate = useNavigate ( ) ;
23
+ const queryClient = useQueryClient ( ) ;
24
+ const [ processingId , setProcessingId ] = React . useState < string | null > ( null ) ;
25
+
26
+ const onDelete = async ( ) => {
27
+ const url = `bot/playground/history/${ item . id } ` ;
28
+ const response = await api . delete ( url ) ;
29
+ return response . data ;
30
+ } ;
31
+
32
+ const onEdit = async ( title : string ) => {
33
+ const url = `bot/playground/history/${ item . id } ` ;
34
+ const response = await api . put ( url , { title } ) ;
35
+ return response . data ;
36
+ } ;
37
+
38
+ const { mutate : editHistory , isLoading : isEditing } = useMutation ( onEdit , {
39
+ onSuccess : ( ) => {
40
+ queryClient . invalidateQueries ( [
41
+ "getBotPlaygroundHistory" ,
42
+ params . id ,
43
+ params . history_id ,
44
+ ] ) ;
45
+ } ,
46
+ onError : ( ) => {
47
+ notification . error ( {
48
+ message : "Error" ,
49
+ description : "Something went wrong" ,
50
+ } ) ;
51
+ } ,
52
+ } ) ;
53
+
54
+ const { mutate : deleteHistory , isLoading : isDeleting } = useMutation (
55
+ onDelete ,
56
+ {
57
+ onSuccess : ( ) => {
58
+ if ( historyId === item . id ) {
59
+ setHistoryId ( null ) ;
60
+ setMessages ( [ ] ) ;
61
+ setHistory ( [ ] ) ;
62
+ navigate ( `/bot/${ params . id } ` ) ;
63
+ }
64
+ queryClient . invalidateQueries ( [
65
+ "getBotPlaygroundHistory" ,
66
+ params . id ,
67
+ params . history_id ,
68
+ ] ) ;
69
+ } ,
70
+ onError : ( ) => {
71
+ notification . error ( {
72
+ message : "Error" ,
73
+ description : "Something went wrong" ,
74
+ } ) ;
75
+ } ,
76
+ }
77
+ ) ;
78
+
13
79
return (
14
- < Link
15
- to = { `/bot/${ params . id } /playground/${ item . id } ` }
16
- onClick = { ( ) => {
17
- setIsLoading ( true ) ;
18
- setMessages ( [ ] ) ;
19
- setHistory ( [ ] ) ;
20
- } }
80
+ < div
21
81
className = { `flex py-2 px-2 items-center gap-3 relative rounded-md truncate hover:pr-4 group transition-opacity duration-300 ease-in-out ${
22
82
historyId === item . id
23
83
? item . id === params . history_id
@@ -26,17 +86,73 @@ export const PlaygroundHistoryCard = ({
26
86
: "bg-gray-100 dark:bg-[#0a0a0a] dark:text-gray-200"
27
87
} `}
28
88
>
29
- < ChatBubbleLeftIcon className = "w-5 h-5 text-gray-400 dark:text-gray-600 group-hover:text-gray-500 dark:group-hover:text-gray-400 transition-colors" />
30
- < div className = "flex-1 overflow-hidden break-all" >
89
+ < Link
90
+ to = { `/bot/${ params . id } /playground/${ item . id } ` }
91
+ className = "flex-1 overflow-hidden break-all"
92
+ >
31
93
< span
32
94
className = "text-gray-500 dark:text-gray-400 text-sm font-semibold truncate"
33
95
title = { item . title }
34
96
>
35
- { item . title . length > 20
36
- ? item . title . substring ( 0 , 20 ) + "..."
37
- : item . title }
97
+ { item . title }
38
98
</ span >
39
- </ div >
40
- </ Link >
99
+ </ Link >
100
+ < Dropdown
101
+ disabled = { ( isDeleting || isEditing ) && processingId === item . id }
102
+ menu = { {
103
+ items : [
104
+ {
105
+ key : "1" ,
106
+ label : (
107
+ < button
108
+ className = "flex items-center gap-2 w-full "
109
+ onClick = { ( ) => {
110
+ const newTitle = prompt ( "Enter new title" , item . title ) ;
111
+ if ( newTitle ) {
112
+ editHistory ( newTitle ) ;
113
+ setProcessingId ( item . id ) ;
114
+ }
115
+ } }
116
+ >
117
+ < PencilIcon className = "w-3 h-3 text-gray-500 dark:text-gray-400" />
118
+ < span > Edit</ span >
119
+ </ button >
120
+ ) ,
121
+ } ,
122
+ {
123
+ key : "2" ,
124
+ label : (
125
+ < button
126
+ onClick = { ( ) => {
127
+ deleteHistory ( ) ;
128
+ setProcessingId ( item . id ) ;
129
+ } }
130
+ className = "flex items-center gap-2 w-full text-red-500"
131
+ >
132
+ < TrashIcon className = "w-3 h-3 text-red-500 dark:text-red-400" />
133
+ < span > Delete</ span >
134
+ </ button >
135
+ ) ,
136
+ } ,
137
+ ] ,
138
+ } }
139
+ >
140
+ { ( isDeleting || isEditing ) && processingId === item . id ? (
141
+ < Spin />
142
+ ) : (
143
+ < EllipsisHorizontalIcon
144
+ className = { `text-gray-500 dark:text-gray-400 w-5 h-5
145
+ ${
146
+ historyId === item . id
147
+ ? item . id === params . history_id
148
+ ? "opacity-100"
149
+ : "opacity-100"
150
+ : "opacity-0 hover:opacity-100 group-hover:opacity-100"
151
+ }
152
+ ` }
153
+ />
154
+ ) }
155
+ </ Dropdown >
156
+ </ div >
41
157
) ;
42
158
} ;
0 commit comments