Skip to content

Commit 125bcf7

Browse files
committed
Implement dedicated message handlers and UI support for deleting preset groups and separators
1 parent 9a8c103 commit 125bcf7

10 files changed

Lines changed: 247 additions & 111 deletions

File tree

‎packages/ui/src/components/editor/panel/Presets/Presets.stories.tsx‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ export const Primary = () => {
4242
on_preset_delete={(index) => {
4343
console.log('on_preset_delete', index)
4444
}}
45+
on_group_delete={(index) => {
46+
console.log('on_group_delete', index)
47+
}}
48+
on_separator_delete={(index) => {
49+
console.log('on_separator_delete', index)
50+
}}
4551
on_toggle_selected_preset={(name) =>
4652
console.log('on_toggle_selected_preset', name)
4753
}

‎packages/ui/src/components/editor/panel/Presets/Presets.tsx‎

Lines changed: 80 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,14 @@ export namespace Presets {
6262
create_on_index?: number
6363
move_preset_with_name_after?: string
6464
}) => void
65-
on_create_separator: (options?: {
66-
create_on_index?: number
67-
}) => void
65+
on_create_separator: (options?: { create_on_index?: number }) => void
6866
on_preset_copy: (name: string) => void
6967
on_presets_reorder: (reordered_presets: Preset[]) => void
7068
on_preset_edit: (name: string) => void
7169
on_preset_duplicate: (index: number) => void
7270
on_preset_delete: (index: number) => void
71+
on_group_delete: (index: number) => void
72+
on_separator_delete: (index: number) => void
7373
on_toggle_selected_preset: (name: string) => void
7474
on_toggle_preset_pinned: (name: string) => void
7575
on_toggle_group_collapsed: (name: string) => void
@@ -117,11 +117,17 @@ export const Presets: React.FC<Presets.Props> = (props) => {
117117
const visible_presets: (Presets.Preset & { original_index: number })[] = []
118118
let is_in_collapsed_group = false
119119
for (const [index, preset] of presets.entries()) {
120-
if (is_in_collapsed_group && preset.chatbot) {
120+
if (
121+
is_in_collapsed_group &&
122+
(preset.chatbot || preset.name === undefined) &&
123+
presets[index - 1]?.name
124+
) {
121125
continue
122126
}
123127
if (!preset.chatbot) {
124128
is_in_collapsed_group = !!preset.is_collapsed
129+
} else {
130+
is_in_collapsed_group = false
125131
}
126132
visible_presets.push({ ...preset, original_index: index })
127133
}
@@ -140,7 +146,8 @@ export const Presets: React.FC<Presets.Props> = (props) => {
140146
}
141147
const last_preset = props.presets[props.presets.length - 1]
142148
// A group is a preset without a `chatbot` property
143-
const is_last_item_a_group = last_preset && !last_preset.chatbot
149+
const is_last_item_a_group =
150+
last_preset && last_preset.name && !last_preset.chatbot
144151
if (!is_last_item_a_group) {
145152
const trailing_group_item: Presets.Preset & { id: string } = {
146153
name: 'Group',
@@ -352,53 +359,38 @@ export const Presets: React.FC<Presets.Props> = (props) => {
352359
return
353360
}
354361

355-
// Handle preset dragged under trailing group
356-
const last_item = new_state[new_state.length - 1]
357-
const second_to_last_item =
358-
new_state.length > 1 ? new_state[new_state.length - 2] : null
359-
360-
if (
361-
last_item?.id === TRAILING_GROUP_ID &&
362-
second_to_last_item &&
363-
second_to_last_item.chatbot
364-
) {
365-
props.on_create_group({
366-
instant: true,
367-
move_preset_with_name_after: second_to_last_item.name
368-
})
369-
return
370-
}
371-
372-
// Handle trailing group item drag
373-
const trailing_group_item = new_state.find(
374-
(item) => item.id === TRAILING_GROUP_ID
362+
// Handle trailing separator item drag
363+
const trailing_separator_item = new_state.find(
364+
(item) => item.id === TRAILING_SEPARATOR_ID
375365
)
376-
const trailing_group_was_moved =
377-
trailing_group_item &&
366+
const trailing_separator_was_moved =
367+
trailing_separator_item &&
378368
sortable_list.findIndex(
379-
(item) => item.id === TRAILING_GROUP_ID
369+
(item) => item.id === TRAILING_SEPARATOR_ID
380370
) !==
381-
new_state.findIndex((item) => item.id === TRAILING_GROUP_ID)
371+
new_state.findIndex(
372+
(item) => item.id === TRAILING_SEPARATOR_ID
373+
)
382374

383-
if (trailing_group_item && trailing_group_was_moved) {
384-
const trailing_group_item_index = new_state.findIndex(
385-
(item) => item.id === TRAILING_GROUP_ID
375+
if (trailing_separator_item && trailing_separator_was_moved) {
376+
const trailing_separator_item_index = new_state.findIndex(
377+
(item) => item.id === TRAILING_SEPARATOR_ID
386378
)
387-
const new_state_without_trailing_group = new_state.filter(
388-
(item) => item.id !== TRAILING_GROUP_ID
379+
const new_state_without_trailing_separator = new_state.filter(
380+
(item) => item.id !== TRAILING_SEPARATOR_ID
389381
)
390382

391-
// Determine where to insert the new group
383+
// Determine where to insert the new separator
392384
let target_full_index: number
393385

394386
if (
395-
trailing_group_item_index <
396-
new_state_without_trailing_group.length
387+
trailing_separator_item_index <
388+
new_state_without_trailing_separator.length
397389
) {
398390
// Dropped between items - find the preset at or after this position
399391
const preset_at_drop_location =
400-
new_state_without_trailing_group[
401-
trailing_group_item_index
392+
new_state_without_trailing_separator[
393+
trailing_separator_item_index
402394
]
403395

404396
if (preset_at_drop_location) {
@@ -422,47 +414,58 @@ export const Presets: React.FC<Presets.Props> = (props) => {
422414
target_full_index = props.presets.length
423415
}
424416

425-
// Create group at calculated position
426-
props.on_create_group({
427-
create_on_index: target_full_index,
428-
instant: true
417+
props.on_create_separator({
418+
create_on_index: target_full_index
429419
})
430420
return
431421
}
432422

433-
// Handle trailing separator item drag
434-
const trailing_separator_item = new_state.find(
435-
(item) => item.id === TRAILING_SEPARATOR_ID
423+
// Handle trailing group item drag
424+
const trailing_group_item = new_state.find(
425+
(item) => item.id === TRAILING_GROUP_ID
436426
)
437-
const trailing_separator_was_moved =
438-
trailing_separator_item &&
427+
const trailing_group_was_moved =
428+
trailing_group_item &&
439429
sortable_list.findIndex(
440-
(item) => item.id === TRAILING_SEPARATOR_ID
430+
(item) => item.id === TRAILING_GROUP_ID
441431
) !==
442-
new_state.findIndex(
443-
(item) => item.id === TRAILING_SEPARATOR_ID
444-
)
432+
new_state.findIndex((item) => item.id === TRAILING_GROUP_ID)
445433

446-
if (trailing_separator_item && trailing_separator_was_moved) {
447-
const trailing_separator_item_index = new_state.findIndex(
448-
(item) => item.id === TRAILING_SEPARATOR_ID
434+
if (trailing_group_item && trailing_group_was_moved) {
435+
const trailing_group_item_index = new_state.findIndex(
436+
(item) => item.id === TRAILING_GROUP_ID
449437
)
450-
const new_state_without_trailing_separator =
451-
new_state.filter(
452-
(item) => item.id !== TRAILING_SEPARATOR_ID
453-
)
438+
const item_after_tg = new_state[trailing_group_item_index + 1]
439+
const item_after_that =
440+
new_state[trailing_group_item_index + 2]
454441

455-
// Determine where to insert the new separator
442+
// A preset was dragged to the end to create a new group
443+
if (
444+
item_after_tg?.chatbot &&
445+
item_after_that?.id === TRAILING_SEPARATOR_ID
446+
) {
447+
props.on_create_group({
448+
instant: true,
449+
move_preset_with_name_after: item_after_tg.name
450+
})
451+
return
452+
}
453+
454+
const new_state_without_trailing_group = new_state.filter(
455+
(item) => item.id !== TRAILING_GROUP_ID
456+
)
457+
458+
// Determine where to insert the new group
456459
let target_full_index: number
457460

458461
if (
459-
trailing_separator_item_index <
460-
new_state_without_trailing_separator.length
462+
trailing_group_item_index <
463+
new_state_without_trailing_group.length
461464
) {
462465
// Dropped between items - find the preset at or after this position
463466
const preset_at_drop_location =
464-
new_state_without_trailing_separator[
465-
trailing_separator_item_index
467+
new_state_without_trailing_group[
468+
trailing_group_item_index
466469
]
467470

468471
if (preset_at_drop_location) {
@@ -486,8 +489,10 @@ export const Presets: React.FC<Presets.Props> = (props) => {
486489
target_full_index = props.presets.length
487490
}
488491

489-
props.on_create_separator({
490-
create_on_index: target_full_index
492+
// Create group at calculated position
493+
props.on_create_group({
494+
create_on_index: target_full_index,
495+
instant: true
491496
})
492497
return
493498
}
@@ -521,10 +526,10 @@ export const Presets: React.FC<Presets.Props> = (props) => {
521526
i++
522527
) {
523528
const child_candidate = props.presets[i]
524-
if (child_candidate.chatbot) {
529+
if (child_candidate.chatbot && child_candidate.name) {
525530
reordered_presets.push(child_candidate)
526531
} else {
527-
// next group found
532+
// next group or separator found
528533
break
529534
}
530535
}
@@ -591,7 +596,7 @@ export const Presets: React.FC<Presets.Props> = (props) => {
591596
title="Delete"
592597
on_click={(e) => {
593598
e.stopPropagation()
594-
props.on_preset_delete(preset.original_index!)
599+
props.on_separator_delete(preset.original_index!)
595600
}}
596601
/>
597602
</div>
@@ -744,7 +749,7 @@ export const Presets: React.FC<Presets.Props> = (props) => {
744749
i++
745750
) {
746751
const child_preset = props.presets[i]
747-
if (!child_preset.chatbot) {
752+
if (!child_preset.chatbot || !child_preset.name) {
748753
break
749754
}
750755
preset_count++
@@ -914,7 +919,11 @@ export const Presets: React.FC<Presets.Props> = (props) => {
914919
title="Delete"
915920
on_click={(e) => {
916921
e.stopPropagation()
917-
props.on_preset_delete(preset.original_index!)
922+
if (preset.chatbot) {
923+
props.on_preset_delete(preset.original_index!)
924+
} else {
925+
props.on_group_delete(preset.original_index!)
926+
}
918927
}}
919928
/>
920929
</div>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import * as vscode from 'vscode'
2+
import { PanelProvider } from '@/views/panel/backend/panel-provider'
3+
import { dictionary } from '@shared/constants/dictionary'
4+
import { DeleteGroupMessage } from '@/views/panel/types/messages'
5+
import { ConfigPresetFormat } from '@/views/panel/backend/utils/preset-format-converters'
6+
7+
export const handle_delete_group = async (
8+
panel_provider: PanelProvider,
9+
message: DeleteGroupMessage,
10+
webview_view: vscode.WebviewView
11+
): Promise<void> => {
12+
const group_index = message.index
13+
const config = vscode.workspace.getConfiguration('codeWebChat')
14+
const presets_config_key = panel_provider.get_presets_config_key()
15+
const current_presets =
16+
config.get<ConfigPresetFormat[]>(presets_config_key, []) || []
17+
18+
if (group_index < 0 || group_index >= current_presets.length) return
19+
20+
const deleted_group = current_presets[group_index]
21+
const item_type = 'group'
22+
23+
const group_name = deleted_group.name
24+
const is_unnamed = !group_name || /^\(\d+\)$/.test(group_name.trim())
25+
const has_affixes =
26+
!!deleted_group.promptPrefix || !!deleted_group.promptSuffix
27+
28+
const should_show_confirmation = !is_unnamed || has_affixes
29+
30+
if (should_show_confirmation) {
31+
const display_group_name = is_unnamed ? 'Unnamed' : group_name
32+
33+
const delete_button = 'Delete'
34+
const result = await vscode.window.showInformationMessage(
35+
'Please confirm',
36+
{
37+
modal: true,
38+
detail: is_unnamed
39+
? `Are you sure you want to delete this ${item_type}?`
40+
: `Are you sure you want to delete ${item_type} "${display_group_name}"?`
41+
},
42+
delete_button
43+
)
44+
45+
if (result != delete_button) {
46+
return
47+
}
48+
}
49+
50+
const updated_presets = [...current_presets]
51+
updated_presets.splice(group_index, 1)
52+
53+
try {
54+
await config.update(
55+
presets_config_key,
56+
updated_presets,
57+
vscode.ConfigurationTarget.Global
58+
)
59+
60+
panel_provider.send_presets_to_webview(webview_view.webview)
61+
} catch (error) {
62+
vscode.window.showErrorMessage(
63+
dictionary.error_message.FAILED_TO_DELETE_ITEM(item_type, error)
64+
)
65+
}
66+
}

0 commit comments

Comments
 (0)