Skip to content

Commit 78a7bfb

Browse files
authored
feat: add shortcut key conflict hint and reset function (#442)
* feat: add shortcut key conflict hint and reset function * docs: update changelog
1 parent 9078c99 commit 78a7bfb

6 files changed

Lines changed: 127 additions & 22 deletions

File tree

docs/content.en/docs/release-notes/_index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Information about release notes of Coco Server is provided here.
3333
- feat: add MCP & call LLM tools #430
3434
- feat: ai assistant supports search and paging #431
3535
- feat: data sources support displaying customized icons #432
36+
- feat: add shortcut key conflict hint and reset function #442
3637

3738
### Bug fix
3839

src/components/Common/HistoryList/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ const HistoryList: FC<HistoryListProps> = (props) => {
159159
ref={listRef}
160160
id={id}
161161
className={clsx(
162-
"flex flex-col h-full overflow-auto px-3 py-2 text-sm bg-[#E6E6E6] dark:bg-[#1F2937] custom-scrollbar"
162+
"flex flex-col h-full overflow-auto px-3 py-2 text-sm bg-[#F3F4F6] dark:bg-[#1F2937] custom-scrollbar"
163163
)}
164164
>
165165
<div className="flex gap-1 children:h-8">
@@ -185,7 +185,7 @@ const HistoryList: FC<HistoryListProps> = (props) => {
185185
</div>
186186

187187
<div
188-
className="size-8 flex items-center justify-center rounded-lg border text-[#0072FF] border-[#E6E6E6] bg-[#E6E6E6] dark:border-[#343D4D] dark:bg-[#1F2937] hover:bg-[#F8F9FA] dark:hover:bg-[#353F4D] cursor-pointer transition"
188+
className="size-8 flex items-center justify-center rounded-lg border text-[#0072FF] border-[#E6E6E6] bg-[#F3F4F6] dark:border-[#343D4D] dark:bg-[#1F2937] hover:bg-[#F8F9FA] dark:hover:bg-[#353F4D] cursor-pointer transition"
189189
onClick={handleRefresh}
190190
>
191191
<VisibleKey shortcut="R" onKeyPress={handleRefresh}>

src/components/Settings/Advanced/components/Shortcuts/index.tsx

Lines changed: 85 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,31 @@
11
import { useTranslation } from "react-i18next";
2-
import { Command } from "lucide-react";
2+
import { Command, RotateCcw } from "lucide-react";
33
import { ChangeEvent, useEffect } from "react";
44

55
import { formatKey } from "@/utils/keyboardUtils";
66
import SettingsItem from "@/components/Settings/SettingsItem";
77
import { isMac } from "@/utils/platform";
8-
import { useShortcutsStore } from "@/stores/shortcutsStore";
8+
import {
9+
INITIAL_MODE_SWITCH,
10+
INITIAL_RETURN_TO_INPUT,
11+
INITIAL_VOICE_INPUT,
12+
INITIAL_ADD_FILE,
13+
INITIAL_DEEP_THINKING,
14+
INITIAL_INTERNET_SEARCH,
15+
INITIAL_INTERNET_SEARCH_SCOPE,
16+
INITIAL_MCP_SEARCH,
17+
INITIAL_MCP_SEARCH_SCOPE,
18+
INITIAL_HISTORICAL_RECORDS,
19+
INITIAL_AI_ASSISTANT,
20+
INITIAL_NEW_SESSION,
21+
INITIAL_FIXED_WINDOW,
22+
INITIAL_SERVICE_LIST,
23+
INITIAL_EXTERNAL,
24+
useShortcutsStore,
25+
} from "@/stores/shortcutsStore";
926
import { ModifierKey } from "@/types/index";
1027
import platformAdapter from "@/utils/platformAdapter";
28+
import { useAppStore } from "@/stores/appStore";
1129

1230
export const modifierKeys: ModifierKey[] = isMac
1331
? ["meta", "ctrl"]
@@ -67,6 +85,7 @@ const Shortcuts = () => {
6785
const setServiceList = useShortcutsStore((state) => state.setServiceList);
6886
const external = useShortcutsStore((state) => state.external);
6987
const setExternal = useShortcutsStore((state) => state.setExternal);
88+
const addError = useAppStore((state) => state.addError);
7089

7190
useEffect(() => {
7291
const unlisten = useShortcutsStore.subscribe((state) => {
@@ -82,91 +101,136 @@ const Shortcuts = () => {
82101
description: "settings.advanced.shortcuts.modeSwitch.description",
83102
value: modeSwitch,
84103
setValue: setModeSwitch,
104+
reset: () => {
105+
setModeSwitch(INITIAL_MODE_SWITCH);
106+
},
85107
},
86108
{
87109
title: "settings.advanced.shortcuts.returnToInput.title",
88110
description: "settings.advanced.shortcuts.returnToInput.description",
89111
value: returnToInput,
90112
setValue: setReturnToInput,
113+
reset: () => {
114+
setReturnToInput(INITIAL_RETURN_TO_INPUT);
115+
},
91116
},
92117
{
93118
title: "settings.advanced.shortcuts.voiceInput.title",
94119
description: "settings.advanced.shortcuts.voiceInput.description",
95120
value: voiceInput,
96121
setValue: setVoiceInput,
122+
reset: () => {
123+
setVoiceInput(INITIAL_VOICE_INPUT);
124+
},
97125
},
98126
{
99127
title: "settings.advanced.shortcuts.addFile.title",
100128
description: "settings.advanced.shortcuts.addFile.description",
101129
value: addFile,
102130
setValue: setAddFile,
131+
reset: () => {
132+
setAddFile(INITIAL_ADD_FILE);
133+
},
103134
},
104135
{
105136
title: "settings.advanced.shortcuts.deepThinking.title",
106137
description: "settings.advanced.shortcuts.deepThinking.description",
107138
value: deepThinking,
108139
setValue: setDeepThinking,
140+
reset: () => {
141+
setDeepThinking(INITIAL_DEEP_THINKING);
142+
},
109143
},
110144
{
111145
title: "settings.advanced.shortcuts.internetSearch.title",
112146
description: "settings.advanced.shortcuts.internetSearch.description",
113147
value: internetSearch,
114148
setValue: setInternetSearch,
149+
reset: () => {
150+
setInternetSearch(INITIAL_INTERNET_SEARCH);
151+
},
115152
},
116153
{
117154
title: "settings.advanced.shortcuts.internetSearchScope.title",
118155
description:
119156
"settings.advanced.shortcuts.internetSearchScope.description",
120157
value: internetSearchScope,
121158
setValue: setInternetSearchScope,
159+
reset: () => {
160+
setInternetSearchScope(INITIAL_INTERNET_SEARCH_SCOPE);
161+
},
122162
},
123163
{
124164
title: "settings.advanced.shortcuts.mcpSearch.title",
125165
description: "settings.advanced.shortcuts.mcpSearch.description",
126166
value: mcpSearch,
127167
setValue: setMcpSearch,
168+
reset: () => {
169+
setMcpSearch(INITIAL_MCP_SEARCH);
170+
},
128171
},
129172
{
130173
title: "settings.advanced.shortcuts.mcpSearchScope.title",
131174
description: "settings.advanced.shortcuts.mcpSearchScope.description",
132175
value: mcpSearchScope,
133176
setValue: setMcpSearchScope,
177+
reset: () => {
178+
setMcpSearchScope(INITIAL_MCP_SEARCH_SCOPE);
179+
},
134180
},
135181
{
136182
title: "settings.advanced.shortcuts.historicalRecords.title",
137183
description: "settings.advanced.shortcuts.historicalRecords.description",
138184
value: historicalRecords,
139185
setValue: setHistoricalRecords,
186+
reset: () => {
187+
setHistoricalRecords(INITIAL_HISTORICAL_RECORDS);
188+
},
140189
},
141190
{
142191
title: "settings.advanced.shortcuts.aiAssistant.title",
143192
description: "settings.advanced.shortcuts.aiAssistant.description",
144193
value: aiAssistant,
145194
setValue: setAiAssistant,
195+
reset: () => {
196+
setAiAssistant(INITIAL_AI_ASSISTANT);
197+
},
146198
},
147199
{
148200
title: "settings.advanced.shortcuts.newSession.title",
149201
description: "settings.advanced.shortcuts.newSession.description",
150202
value: newSession,
151203
setValue: setNewSession,
204+
reset: () => {
205+
setNewSession(INITIAL_NEW_SESSION);
206+
},
152207
},
153208
{
154209
title: "settings.advanced.shortcuts.fixedWindow.title",
155210
description: "settings.advanced.shortcuts.fixedWindow.description",
156211
value: fixedWindow,
157212
setValue: setFixedWindow,
213+
reset: () => {
214+
setFixedWindow(INITIAL_FIXED_WINDOW);
215+
},
158216
},
159217
{
160218
title: "settings.advanced.shortcuts.serviceList.title",
161219
description: "settings.advanced.shortcuts.serviceList.description",
162220
value: serviceList,
163221
setValue: setServiceList,
222+
reset: () => {
223+
setServiceList(INITIAL_SERVICE_LIST);
224+
},
164225
},
165226
{
166227
title: "settings.advanced.shortcuts.external.title",
167228
description: "settings.advanced.shortcuts.external.description",
168229
value: external,
169230
setValue: setExternal,
231+
reset: () => {
232+
setExternal(INITIAL_EXTERNAL);
233+
},
170234
},
171235
];
172236

@@ -186,7 +250,16 @@ const Shortcuts = () => {
186250

187251
const isUsed = Object.values(state).includes(value);
188252

189-
if (isSystemKey || isUsed) return;
253+
if (isSystemKey) {
254+
return addError(
255+
t("settings.advanced.shortcuts.hits.isSystem"),
256+
"warning"
257+
);
258+
}
259+
260+
if (isUsed) {
261+
return addError(t("settings.advanced.shortcuts.hits.isUse"), "warning");
262+
}
190263

191264
setValue(value);
192265
};
@@ -217,7 +290,7 @@ const Shortcuts = () => {
217290
</SettingsItem>
218291

219292
{list.map((item) => {
220-
const { title, description, value, setValue } = item;
293+
const { title, description, value, setValue, reset } = item;
221294

222295
return (
223296
<SettingsItem
@@ -230,13 +303,20 @@ const Shortcuts = () => {
230303
<span>{formatKey(modifierKey)}</span>
231304
<span>+</span>
232305
<input
233-
className="w-20 h-8 px-2 rounded-md border bg-transparent border-black/5 dark:border-white/10"
306+
className="w-20 h-8 px-2 rounded-md border bg-transparent border-black/5 dark:border-white/10 hover:border-[#0072FF] focus:border-[#0072FF] transition"
234307
value={value}
235308
maxLength={1}
236309
onChange={(event) => {
237310
handleChange(event, setValue);
238311
}}
239312
/>
313+
314+
<button
315+
className="flex items-center justify-center size-8 rounded-md border border-black/5 dark:border-white/10 hover:border-[#0072FF] transition"
316+
onClick={reset}
317+
>
318+
<RotateCcw className="size-4 text-[#0072FF]" />
319+
</button>
240320
</div>
241321
</SettingsItem>
242322
);

src/locales/en/translation.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@
146146
"external": {
147147
"title": "Detach Window",
148148
"description": "Shortcut to open the current conversation as an independent window in chat mode."
149+
},
150+
"hits": {
151+
"isSystem": "This shortcut is reserved by the system, please choose another key.",
152+
"isUse": "This shortcut is already in use, please choose another key."
149153
}
150154
},
151155
"connect": {

src/locales/zh/translation.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@
146146
"external": {
147147
"title": "独立窗口",
148148
"description": "在聊天模式下将当前对话打开为一个独立窗口的快捷按键。"
149+
},
150+
"hits": {
151+
"isSystem": "该快捷键已被系统保留,请选择其他按键。",
152+
"isUse": "该快捷键已被占用,请选择其他按键。"
149153
}
150154
},
151155
"connect": {

src/stores/shortcutsStore.ts

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,22 @@ export type IShortcutsStore = {
4545
setResetFixedWindow: (resetFixedWindow: boolean) => void;
4646
};
4747

48+
export const INITIAL_MODE_SWITCH = "T";
49+
export const INITIAL_RETURN_TO_INPUT = "I";
50+
export const INITIAL_VOICE_INPUT = "K";
51+
export const INITIAL_ADD_FILE = "A";
52+
export const INITIAL_DEEP_THINKING = "D";
53+
export const INITIAL_INTERNET_SEARCH = "G";
54+
export const INITIAL_INTERNET_SEARCH_SCOPE = "J";
55+
export const INITIAL_MCP_SEARCH = "B";
56+
export const INITIAL_MCP_SEARCH_SCOPE = "L";
57+
export const INITIAL_HISTORICAL_RECORDS = "Y";
58+
export const INITIAL_AI_ASSISTANT = "U";
59+
export const INITIAL_NEW_SESSION = "N";
60+
export const INITIAL_FIXED_WINDOW = "P";
61+
export const INITIAL_SERVICE_LIST = "S";
62+
export const INITIAL_EXTERNAL = "E";
63+
4864
export const useShortcutsStore = create<IShortcutsStore>()(
4965
persist(
5066
(set) => ({
@@ -58,41 +74,41 @@ export const useShortcutsStore = create<IShortcutsStore>()(
5874
setModifierKeyPressed: (modifierKeyPressed: boolean) => {
5975
return set({ modifierKeyPressed });
6076
},
61-
modeSwitch: "T",
77+
modeSwitch: INITIAL_MODE_SWITCH,
6278
setModeSwitch: (modeSwitch) => set({ modeSwitch }),
63-
returnToInput: "I",
79+
returnToInput: INITIAL_RETURN_TO_INPUT,
6480
setReturnToInput: (returnToInput) => set({ returnToInput }),
65-
voiceInput: "K",
81+
voiceInput: INITIAL_VOICE_INPUT,
6682
setVoiceInput: (voiceInput) => set({ voiceInput }),
67-
addFile: "A",
83+
addFile: INITIAL_ADD_FILE,
6884
setAddFile: (addFile) => set({ addFile }),
69-
deepThinking: "D",
85+
deepThinking: INITIAL_DEEP_THINKING,
7086
setDeepThinking: (deepThinking) => set({ deepThinking }),
71-
internetSearch: "G",
87+
internetSearch: INITIAL_INTERNET_SEARCH,
7288
setInternetSearch: (internetSearch) => set({ internetSearch }),
73-
internetSearchScope: "J",
89+
internetSearchScope: INITIAL_INTERNET_SEARCH_SCOPE,
7490
setInternetSearchScope: (internetSearchScope) => {
7591
return set({ internetSearchScope });
7692
},
77-
mcpSearch: "B",
93+
mcpSearch: INITIAL_MCP_SEARCH,
7894
setMcpSearch: (mcpSearch) => set({ mcpSearch }),
79-
mcpSearchScope: "L",
95+
mcpSearchScope: INITIAL_MCP_SEARCH_SCOPE,
8096
setMcpSearchScope: (mcpSearchScope) => {
8197
return set({ mcpSearchScope });
8298
},
83-
historicalRecords: "Y",
99+
historicalRecords: INITIAL_HISTORICAL_RECORDS,
84100
setHistoricalRecords: (historicalRecords) => {
85101
return set({ historicalRecords });
86102
},
87-
aiAssistant: "U",
103+
aiAssistant: INITIAL_AI_ASSISTANT,
88104
setAiAssistant: (aiAssistant) => set({ aiAssistant }),
89-
newSession: "N",
105+
newSession: INITIAL_NEW_SESSION,
90106
setNewSession: (newSession) => set({ newSession }),
91-
fixedWindow: "P",
107+
fixedWindow: INITIAL_FIXED_WINDOW,
92108
setFixedWindow: (fixedWindow) => set({ fixedWindow }),
93-
serviceList: "S",
109+
serviceList: INITIAL_SERVICE_LIST,
94110
setServiceList: (serviceList) => set({ serviceList }),
95-
external: "E",
111+
external: INITIAL_EXTERNAL,
96112
setExternal: (external) => set({ external }),
97113
resetFixedWindow: false,
98114
setResetFixedWindow: (resetFixedWindow) => {

0 commit comments

Comments
 (0)