Skip to content

Commit c8b64ac

Browse files
committed
Add a modal component to enable in-UI editing of web configurations
- in `apps/editor/src/views/settings/frontend/providers` create a provider that shows a modal in the middle. The modal component should be placed in `packages/ui/src/components/editor/settings` and should be simple - just dim background and show the children in the middle without any styling. We will create various modal components later on. - inspired by how web configuration editing is handled in panel (`apps/editor/src/views/panel/frontend/hooks/panel/use-web-configuration-editing.ts`), open modal on editing a web configuration. The modal should show configuration's name, and nothing else. - Modal component should be composable. Its inner component 'Form' should show 'save' button at the bottom and centered heading at the top. use it here [Fragment] - place ModalForm in `packages/ui/src/components/editor/settings/Modal/ModalForm`, with a separate stylesheet file - rename ModalForm to Form
1 parent 14efe0b commit c8b64ac

9 files changed

Lines changed: 242 additions & 117 deletions

File tree

‎apps/editor/src/views/settings/frontend/Settings.tsx‎

Lines changed: 134 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ import { use_settings } from './hooks/use-settings'
33
import { post_message } from './utils/post-message'
44
import { BackendMessage } from '../types/messages'
55
import { Home, NavItem } from './Home/Home'
6+
import { use_web_configuration_editing } from './hooks/use-web-configuration-editing'
7+
import { Modal as UiModal } from '@ui/components/editor/settings/Modal'
68

79
const vscode = acquireVsCodeApi()
810

911
export const Settings = () => {
1012
const settings_hook = use_settings(vscode)
13+
const { updating_web_configuration, set_updating_web_configuration } = use_web_configuration_editing()
1114
const [scroll_to_section_on_load, set_scroll_to_section_on_load] =
1215
useState<NavItem>()
1316

@@ -52,114 +55,136 @@ export const Settings = () => {
5255
if (!all_data_loaded) return null
5356

5457
return (
55-
<Home
56-
providers={settings_hook.providers!}
57-
api_configurations={settings_hook.api_configurations!}
58-
defaults={settings_hook.defaults!}
59-
edit_context_system_instructions={
60-
settings_hook.edit_context_system_instructions!
61-
}
62-
context_size_warning_threshold={
63-
settings_hook.context_size_warning_threshold!
64-
}
65-
include_prompts_in_commit_messages={
66-
settings_hook.include_prompts_in_commit_messages!
67-
}
68-
voice_input_instructions={settings_hook.voice_input_instructions!}
69-
voice_input_push_to_talk={settings_hook.voice_input_push_to_talk!}
70-
commit_message_instructions={settings_hook.commit_message_instructions!}
71-
edit_format_instructions={settings_hook.edit_format_instructions!}
72-
are_automatic_checkpoints_disabled={
73-
settings_hook.are_automatic_checkpoints_disabled!
74-
}
75-
checkpoint_lifespan={settings_hook.checkpoint_lifespan!}
76-
gemini_user_id={settings_hook.gemini_user_id!}
77-
ai_studio_user_id={settings_hook.ai_studio_user_id!}
78-
send_with_shift_enter={settings_hook.send_with_shift_enter!}
79-
check_new_files={settings_hook.check_new_files!}
80-
reuse_last_tab={settings_hook.reuse_last_tab!}
81-
clear_checks_in_workspace_behavior={
82-
settings_hook.clear_checks_in_workspace_behavior!
83-
}
84-
extended_cache_duration_for_anthropic={
85-
settings_hook.extended_cache_duration_for_anthropic!
86-
}
87-
auto_run_intelligent_update={settings_hook.auto_run_intelligent_update!}
88-
set_providers={settings_hook.set_providers}
89-
set_api_configurations={settings_hook.set_api_configurations}
90-
on_context_size_warning_threshold_change={
91-
settings_hook.handle_context_size_warning_threshold_change
92-
}
93-
on_voice_input_instructions_change={
94-
settings_hook.handle_voice_input_instructions_change
95-
}
96-
on_voice_input_push_to_talk_change={
97-
settings_hook.handle_voice_input_push_to_talk_change
98-
}
99-
on_commit_instructions_change={
100-
settings_hook.handle_commit_instructions_change
101-
}
102-
on_include_prompts_in_commit_messages_change={
103-
settings_hook.handle_include_prompts_in_commit_messages_change
104-
}
105-
on_edit_context_system_instructions_change={
106-
settings_hook.handle_edit_context_system_instructions_change
107-
}
108-
on_edit_format_instructions_change={
109-
settings_hook.handle_edit_format_instructions_change
110-
}
111-
on_automatic_checkpoints_toggle={
112-
settings_hook.handle_automatic_checkpoints_toggle
113-
}
114-
on_checkpoint_lifespan_change={
115-
settings_hook.handle_checkpoint_lifespan_change
116-
}
117-
on_clear_checks_in_workspace_behavior_change={
118-
settings_hook.handle_clear_checks_in_workspace_behavior_change
119-
}
120-
on_gemini_user_id_change={settings_hook.handle_gemini_user_id_change}
121-
on_ai_studio_user_id_change={
122-
settings_hook.handle_ai_studio_user_id_change
123-
}
124-
on_send_with_shift_enter_change={
125-
settings_hook.handle_send_with_shift_enter_change
126-
}
127-
on_check_new_files_change={settings_hook.handle_check_new_files_change}
128-
on_reuse_last_tab_change={settings_hook.handle_reuse_last_tab_change}
129-
on_auto_run_intelligent_update_change={
130-
settings_hook.handle_auto_run_intelligent_update_change
131-
}
132-
on_extended_cache_duration_for_anthropic_change={
133-
settings_hook.handle_extended_cache_duration_for_anthropic_change
134-
}
135-
on_open_keybindings={settings_hook.handle_open_keybindings}
136-
on_open_editor_settings={settings_hook.handle_open_editor_settings}
137-
on_open_ignore_patterns_settings={
138-
settings_hook.handle_open_ignore_patterns_settings
139-
}
140-
on_open_allow_patterns_settings={
141-
settings_hook.handle_open_allow_patterns_settings
142-
}
143-
on_reorder_providers={settings_hook.handle_reorder_providers}
144-
on_add_provider={settings_hook.handle_add_provider}
145-
on_delete_provider={settings_hook.handle_delete_provider}
146-
on_edit_provider={settings_hook.handle_edit_provider}
147-
on_add_api_configuration={settings_hook.handle_add_api_configuration}
148-
on_reorder_api_configurations={settings_hook.handle_reorder_api_configurations}
149-
on_edit_api_configuration={settings_hook.handle_edit_api_configuration}
150-
on_duplicate_api_configuration={settings_hook.handle_duplicate_api_configuration}
151-
on_delete_api_configuration={settings_hook.handle_delete_api_configuration}
152-
on_set_default_api_configuration={settings_hook.handle_set_default_api_configuration}
153-
on_select_default_api_configuration={settings_hook.handle_select_default_api_configuration}
154-
web_configurations={settings_hook.web_configurations!}
155-
set_web_configurations={settings_hook.set_web_configurations}
156-
on_reorder_web_configurations={settings_hook.handle_reorder_web_configurations}
157-
on_add_web_configuration={settings_hook.handle_add_web_configuration}
158-
on_duplicate_web_configuration={settings_hook.handle_duplicate_web_configuration}
159-
on_edit_web_configuration={settings_hook.handle_edit_web_configuration}
160-
on_delete_web_configuration={settings_hook.handle_delete_web_configuration}
161-
on_open_external_url={settings_hook.handle_open_external_url}
162-
scroll_to_section_on_load={scroll_to_section_on_load}
163-
/>
58+
<>
59+
<Home
60+
providers={settings_hook.providers!}
61+
api_configurations={settings_hook.api_configurations!}
62+
defaults={settings_hook.defaults!}
63+
edit_context_system_instructions={
64+
settings_hook.edit_context_system_instructions!
65+
}
66+
context_size_warning_threshold={
67+
settings_hook.context_size_warning_threshold!
68+
}
69+
include_prompts_in_commit_messages={
70+
settings_hook.include_prompts_in_commit_messages!
71+
}
72+
voice_input_instructions={settings_hook.voice_input_instructions!}
73+
voice_input_push_to_talk={settings_hook.voice_input_push_to_talk!}
74+
commit_message_instructions={settings_hook.commit_message_instructions!}
75+
edit_format_instructions={settings_hook.edit_format_instructions!}
76+
are_automatic_checkpoints_disabled={
77+
settings_hook.are_automatic_checkpoints_disabled!
78+
}
79+
checkpoint_lifespan={settings_hook.checkpoint_lifespan!}
80+
gemini_user_id={settings_hook.gemini_user_id!}
81+
ai_studio_user_id={settings_hook.ai_studio_user_id!}
82+
send_with_shift_enter={settings_hook.send_with_shift_enter!}
83+
check_new_files={settings_hook.check_new_files!}
84+
reuse_last_tab={settings_hook.reuse_last_tab!}
85+
clear_checks_in_workspace_behavior={
86+
settings_hook.clear_checks_in_workspace_behavior!
87+
}
88+
extended_cache_duration_for_anthropic={
89+
settings_hook.extended_cache_duration_for_anthropic!
90+
}
91+
auto_run_intelligent_update={settings_hook.auto_run_intelligent_update!}
92+
set_providers={settings_hook.set_providers}
93+
set_api_configurations={settings_hook.set_api_configurations}
94+
on_context_size_warning_threshold_change={
95+
settings_hook.handle_context_size_warning_threshold_change
96+
}
97+
on_voice_input_instructions_change={
98+
settings_hook.handle_voice_input_instructions_change
99+
}
100+
on_voice_input_push_to_talk_change={
101+
settings_hook.handle_voice_input_push_to_talk_change
102+
}
103+
on_commit_instructions_change={
104+
settings_hook.handle_commit_instructions_change
105+
}
106+
on_include_prompts_in_commit_messages_change={
107+
settings_hook.handle_include_prompts_in_commit_messages_change
108+
}
109+
on_edit_context_system_instructions_change={
110+
settings_hook.handle_edit_context_system_instructions_change
111+
}
112+
on_edit_format_instructions_change={
113+
settings_hook.handle_edit_format_instructions_change
114+
}
115+
on_automatic_checkpoints_toggle={
116+
settings_hook.handle_automatic_checkpoints_toggle
117+
}
118+
on_checkpoint_lifespan_change={
119+
settings_hook.handle_checkpoint_lifespan_change
120+
}
121+
on_clear_checks_in_workspace_behavior_change={
122+
settings_hook.handle_clear_checks_in_workspace_behavior_change
123+
}
124+
on_gemini_user_id_change={settings_hook.handle_gemini_user_id_change}
125+
on_ai_studio_user_id_change={
126+
settings_hook.handle_ai_studio_user_id_change
127+
}
128+
on_send_with_shift_enter_change={
129+
settings_hook.handle_send_with_shift_enter_change
130+
}
131+
on_check_new_files_change={settings_hook.handle_check_new_files_change}
132+
on_reuse_last_tab_change={settings_hook.handle_reuse_last_tab_change}
133+
on_auto_run_intelligent_update_change={
134+
settings_hook.handle_auto_run_intelligent_update_change
135+
}
136+
on_extended_cache_duration_for_anthropic_change={
137+
settings_hook.handle_extended_cache_duration_for_anthropic_change
138+
}
139+
on_open_keybindings={settings_hook.handle_open_keybindings}
140+
on_open_editor_settings={settings_hook.handle_open_editor_settings}
141+
on_open_ignore_patterns_settings={
142+
settings_hook.handle_open_ignore_patterns_settings
143+
}
144+
on_open_allow_patterns_settings={
145+
settings_hook.handle_open_allow_patterns_settings
146+
}
147+
on_reorder_providers={settings_hook.handle_reorder_providers}
148+
on_add_provider={settings_hook.handle_add_provider}
149+
on_delete_provider={settings_hook.handle_delete_provider}
150+
on_edit_provider={settings_hook.handle_edit_provider}
151+
on_add_api_configuration={settings_hook.handle_add_api_configuration}
152+
on_reorder_api_configurations={settings_hook.handle_reorder_api_configurations}
153+
on_edit_api_configuration={settings_hook.handle_edit_api_configuration}
154+
on_duplicate_api_configuration={settings_hook.handle_duplicate_api_configuration}
155+
on_delete_api_configuration={settings_hook.handle_delete_api_configuration}
156+
on_set_default_api_configuration={settings_hook.handle_set_default_api_configuration}
157+
on_select_default_api_configuration={settings_hook.handle_select_default_api_configuration}
158+
web_configurations={settings_hook.web_configurations!}
159+
set_web_configurations={settings_hook.set_web_configurations}
160+
on_reorder_web_configurations={settings_hook.handle_reorder_web_configurations}
161+
on_add_web_configuration={settings_hook.handle_add_web_configuration}
162+
on_duplicate_web_configuration={settings_hook.handle_duplicate_web_configuration}
163+
on_edit_web_configuration={(id) => {
164+
const config = settings_hook.web_configurations?.find(
165+
(c, index) => (c.name ?? `unnamed-${index}`) === id
166+
)
167+
if (config) {
168+
set_updating_web_configuration(config)
169+
}
170+
}}
171+
on_delete_web_configuration={settings_hook.handle_delete_web_configuration}
172+
on_open_external_url={settings_hook.handle_open_external_url}
173+
scroll_to_section_on_load={scroll_to_section_on_load}
174+
/>
175+
{updating_web_configuration && (
176+
<UiModal on_close={() => set_updating_web_configuration(undefined)}>
177+
<UiModal.Form
178+
title="Edit Web Configuration"
179+
on_save={() => set_updating_web_configuration(undefined)}
180+
on_cancel={() => set_updating_web_configuration(undefined)}
181+
>
182+
<div style={{ textAlign: 'center' }}>
183+
{updating_web_configuration.name}
184+
</div>
185+
</UiModal.Form>
186+
</UiModal>
187+
)}
188+
</>
164189
)
165190
}

‎apps/editor/src/views/settings/frontend/hooks/use-settings.ts‎

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -277,13 +277,6 @@ export const use_settings = (vscode: any) => {
277277
})
278278
}
279279

280-
const handle_edit_web_configuration = (web_configuration_id: string) => {
281-
post_message(vscode, {
282-
command: 'CREATE_WEB_CONFIGURATION',
283-
web_configuration_id
284-
})
285-
}
286-
287280
const handle_delete_web_configuration = (name: string) => {
288281
post_message(vscode, {
289282
command: 'DELETE_WEB_CONFIGURATION',
@@ -485,7 +478,6 @@ export const use_settings = (vscode: any) => {
485478
handle_reorder_web_configurations,
486479
handle_add_web_configuration,
487480
handle_duplicate_web_configuration,
488-
handle_edit_web_configuration,
489481
handle_delete_web_configuration,
490482
handle_voice_input_instructions_change,
491483
handle_voice_input_push_to_talk_change,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { useState } from 'react'
2+
import { WebConfiguration } from '@shared/types/web-configuration'
3+
4+
export const use_web_configuration_editing = () => {
5+
const [updating_web_configuration, set_updating_web_configuration] = useState<WebConfiguration>()
6+
7+
return {
8+
updating_web_configuration,
9+
set_updating_web_configuration
10+
}
11+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
.form {
2+
display: flex;
3+
flex-direction: column;
4+
padding: 24px;
5+
background-color: var(--vscode-editor-background);
6+
color: var(--vscode-editor-foreground);
7+
border-radius: 8px;
8+
min-width: 300px;
9+
gap: 24px;
10+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
11+
}
12+
13+
.header {
14+
text-align: center;
15+
font-size: 16px;
16+
font-weight: 600;
17+
margin: 0;
18+
}
19+
20+
.body {
21+
flex: 1;
22+
}
23+
24+
.footer {
25+
display: flex;
26+
justify-content: flex-end;
27+
gap: 12px;
28+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from 'react'
2+
import styles from './Form.module.scss'
3+
import { Button } from '../../../common/Button'
4+
5+
export type FormProps = {
6+
title: string
7+
children: React.ReactNode
8+
on_save: () => void
9+
on_cancel?: () => void
10+
save_label?: string
11+
}
12+
13+
export const Form: React.FC<FormProps> = ({ title, children, on_save, on_cancel, save_label = 'Save' }) => {
14+
return (
15+
<div className={styles.form}>
16+
<div className={styles.header}>{title}</div>
17+
<div className={styles.body}>{children}</div>
18+
<div className={styles.footer}>
19+
{on_cancel && (
20+
<Button is_secondary on_click={on_cancel}>
21+
Cancel
22+
</Button>
23+
)}
24+
<Button on_click={on_save}>{save_label}</Button>
25+
</div>
26+
</div>
27+
)
28+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './Form'
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.overlay {
2+
position: fixed;
3+
top: 0;
4+
left: 0;
5+
right: 0;
6+
bottom: 0;
7+
background-color: rgba(0, 0, 0, 0.5);
8+
display: flex;
9+
align-items: center;
10+
justify-content: center;
11+
z-index: 9999;
12+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react'
2+
import styles from './Modal.module.scss'
3+
import { Form } from './Form'
4+
5+
export type ModalProps = {
6+
children: React.ReactNode
7+
on_close?: () => void
8+
}
9+
10+
const ModalRoot: React.FC<ModalProps> = ({ children, on_close }) => {
11+
return (
12+
<div
13+
className={styles.overlay}
14+
onClick={on_close}
15+
>
16+
<div onClick={(e) => e.stopPropagation()}>
17+
{children}
18+
</div>
19+
</div>
20+
)
21+
}
22+
23+
export type { FormProps } from './Form'
24+
25+
export const Modal = Object.assign(ModalRoot, {
26+
Form
27+
})
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './Modal'

0 commit comments

Comments
 (0)