Skip to content

Commit 0d16e31

Browse files
committed
feat: clear conversation (#51, #47)
1 parent d0728fc commit 0d16e31

File tree

9 files changed

+118
-28
lines changed

9 files changed

+118
-28
lines changed

src/_locales/en/main.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,5 +82,7 @@
8282
"Model Name": "Model Name",
8383
"Custom Model API Url": "Custom Model API Url",
8484
"Loading...": "Loading...",
85-
"Feedback": "Feedback"
85+
"Feedback": "Feedback",
86+
"Confirm": "Confirm",
87+
"Clear Conversation": "Clear Conversation"
8688
}

src/_locales/zh-hans/main.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,5 +82,7 @@
8282
"Model Name": "模型名",
8383
"Custom Model API Url": "自定义模型的API地址",
8484
"Loading...": "正在读取...",
85-
"Feedback": "反馈"
85+
"Feedback": "反馈",
86+
"Confirm": "确认",
87+
"Clear Conversation": "清理对话"
8688
}

src/_locales/zh-hant/main.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,5 +82,7 @@
8282
"Model Name": "模型名",
8383
"Custom Model API Url": "自定義模型的API地址",
8484
"Loading...": "正在讀取...",
85-
"Feedback": "反饋"
85+
"Feedback": "反饋",
86+
"Confirm": "確認",
87+
"Clear Conversation": "清理對話"
8688
}

src/background/apis/chatgpt-web.mjs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ export async function setConversationProperty(token, conversationId, propertyObj
2727
await request(token, 'PATCH', `/conversation/${conversationId}`, propertyObject)
2828
}
2929

30+
export async function deleteConversation(token, conversationId) {
31+
if (conversationId) await setConversationProperty(token, conversationId, { is_visible: false })
32+
}
33+
3034
export async function sendModerations(token, question, conversationId, messageId) {
3135
await request(token, 'POST', `/moderations`, {
3236
conversation_id: conversationId,
@@ -48,10 +52,6 @@ export async function getModels(token) {
4852
* @param {string} accessToken
4953
*/
5054
export async function generateAnswersWithChatgptWebApi(port, question, session, accessToken) {
51-
const deleteConversation = () => {
52-
setConversationProperty(accessToken, session.conversationId, { is_visible: false })
53-
}
54-
5555
const controller = new AbortController()
5656
const stopListener = (msg) => {
5757
if (msg.stop) {
@@ -65,7 +65,7 @@ export async function generateAnswersWithChatgptWebApi(port, question, session,
6565
port.onDisconnect.addListener(() => {
6666
console.debug('port disconnected')
6767
controller.abort()
68-
deleteConversation()
68+
deleteConversation(accessToken, session.conversationId)
6969
})
7070

7171
const models = await getModels(accessToken).catch(() => {

src/background/index.mjs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import Browser from 'webextension-polyfill'
22
import ExpiryMap from 'expiry-map'
3-
import { generateAnswersWithChatgptWebApi, sendMessageFeedback } from './apis/chatgpt-web'
3+
import {
4+
deleteConversation,
5+
generateAnswersWithChatgptWebApi,
6+
sendMessageFeedback,
7+
} from './apis/chatgpt-web'
48
import { generateAnswersWithBingWebApi } from './apis/bing-web.mjs'
59
import {
610
generateAnswersWithChatgptApi,
@@ -126,6 +130,10 @@ Browser.runtime.onMessage.addListener(async (message) => {
126130
if (message.type === 'FEEDBACK') {
127131
const token = await getChatGptAccessToken()
128132
await sendMessageFeedback(token, message.data)
133+
} else if (message.type === 'DELETE_CONVERSATION') {
134+
const token = await getChatGptAccessToken()
135+
const data = message.data
136+
await deleteConversation(token, data.conversationId)
129137
}
130138
})
131139

src/components/ConversationCard/index.jsx

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import FloatingToolbar from '../FloatingToolbar'
1212
import { useClampWindowSize } from '../../hooks/use-clamp-window-size'
1313
import { defaultConfig, getUserConfig } from '../../config/index.mjs'
1414
import { useTranslation } from 'react-i18next'
15+
import DeleteButton from '../DeleteButton'
1516

1617
const logo = Browser.runtime.getURL('logo.png')
1718

@@ -221,22 +222,37 @@ function ConversationCard(props) {
221222
}}
222223
/>
223224
)}
224-
<span
225-
title={t('Save Conversation')}
226-
className="gpt-util-icon"
227-
style="margin:15px;"
228-
onClick={() => {
229-
let output = ''
230-
session.conversationRecords.forEach((data) => {
231-
output += `${t('Question')}:\n\n${data.question}\n\n${t('Answer')}:\n\n${
232-
data.answer
233-
}\n\n<hr/>\n\n`
234-
})
235-
const blob = new Blob([output], { type: 'text/plain;charset=utf-8' })
236-
FileSaver.saveAs(blob, 'conversation.md')
237-
}}
238-
>
239-
<DownloadIcon size={16} />
225+
<span className="gpt-util-group">
226+
<DeleteButton
227+
size={16}
228+
onConfirm={() => {
229+
port.postMessage({ stop: true })
230+
Browser.runtime.sendMessage({
231+
type: 'DELETE_CONVERSATION',
232+
data: {
233+
conversationId: session.conversationId,
234+
},
235+
})
236+
setConversationItemData([])
237+
setSession(initSession())
238+
}}
239+
/>
240+
<span
241+
title={t('Save Conversation')}
242+
className="gpt-util-icon"
243+
onClick={() => {
244+
let output = ''
245+
session.conversationRecords.forEach((data) => {
246+
output += `${t('Question')}:\n\n${data.question}\n\n${t('Answer')}:\n\n${
247+
data.answer
248+
}\n\n<hr/>\n\n`
249+
})
250+
const blob = new Blob([output], { type: 'text/plain;charset=utf-8' })
251+
FileSaver.saveAs(blob, 'conversation.md')
252+
}}
253+
>
254+
<DownloadIcon size={16} />
255+
</span>
240256
</span>
241257
</div>
242258
<hr />

src/components/ConversationItem/index.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export function ConversationItem({ type, content, session, done, port }) {
1616
<div className={type} dir="auto">
1717
<div className="gpt-header">
1818
<p>{t('You')}:</p>
19-
<div style="display: flex; gap: 15px;">
19+
<div className="gpt-util-group">
2020
<CopyButton contentFn={() => content} size={14} />
2121
{!collapsed ? (
2222
<span
@@ -47,7 +47,7 @@ export function ConversationItem({ type, content, session, done, port }) {
4747
<p style="white-space: nowrap;">
4848
{session && session.aiName ? `${t(session.aiName)}:` : t('Loading...')}
4949
</p>
50-
<div style="display: flex; gap: 15px; align-items: center; white-space: nowrap;">
50+
<div className="gpt-util-group">
5151
{!done && (
5252
<button
5353
type="button"
@@ -105,7 +105,7 @@ export function ConversationItem({ type, content, session, done, port }) {
105105
<div className={type} dir="auto">
106106
<div className="gpt-header">
107107
<p>{t('Error')}:</p>
108-
<div style="display: flex; gap: 15px;">
108+
<div className="gpt-util-group">
109109
<CopyButton contentFn={() => content} size={14} />
110110
{!collapsed ? (
111111
<span

src/components/DeleteButton/index.jsx

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { useEffect, useRef, useState } from 'react'
2+
import PropTypes from 'prop-types'
3+
import { useTranslation } from 'react-i18next'
4+
import { TrashIcon } from '@primer/octicons-react'
5+
6+
DeleteButton.propTypes = {
7+
onConfirm: PropTypes.func.isRequired,
8+
size: PropTypes.number.isRequired,
9+
}
10+
11+
function DeleteButton({ onConfirm, size }) {
12+
const { t } = useTranslation()
13+
const [waitConfirm, setWaitConfirm] = useState(false)
14+
const confirmRef = useRef(null)
15+
16+
useEffect(() => {
17+
if (waitConfirm) confirmRef.current.focus()
18+
}, [waitConfirm])
19+
20+
return (
21+
<span>
22+
<button
23+
ref={confirmRef}
24+
type="button"
25+
className="normal-button"
26+
style={{
27+
fontSize: '10px',
28+
...(waitConfirm ? {} : { display: 'none' }),
29+
}}
30+
onBlur={() => {
31+
setWaitConfirm(false)
32+
}}
33+
onClick={() => {
34+
setWaitConfirm(false)
35+
onConfirm()
36+
}}
37+
>
38+
{t('Confirm')}
39+
</button>
40+
<span
41+
title={t('Clear Conversation')}
42+
className="gpt-util-icon"
43+
style={waitConfirm ? { display: 'none' } : {}}
44+
onClick={() => {
45+
setWaitConfirm(true)
46+
}}
47+
>
48+
<TrashIcon size={size} />
49+
</span>
50+
</span>
51+
)
52+
}
53+
54+
export default DeleteButton

src/content-script/styles.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,12 @@
169169
color: #f08080;
170170
}
171171

172+
.gpt-util-group {
173+
display: flex;
174+
gap: 15px;
175+
align-items: center;
176+
}
177+
172178
.gpt-util-icon {
173179
display: flex;
174180
cursor: pointer;

0 commit comments

Comments
 (0)