Skip to content

Commit 703b2d4

Browse files
committed
Rename PromptTypeDropdown to InlineDropdown and implement it in the Home view to allow workspace root selection
- in multi root folder workspaces, place a dropdown to set an active workspace tasks are shown for. Therefore Tabs component will be always used to show 'add task' action. - the workspace's root folder selection dropdown should be rendered in tabs' actions - rename 'prompt type dropdown' to 'inline dropdown', use it for workspace's root folder selection for tasks. - for tasks, wrap the 'inline dropdown' in a proper relative div so it is not rendered over the add button
1 parent 9776fab commit 703b2d4

9 files changed

Lines changed: 95 additions & 137 deletions

File tree

apps/editor/src/views/panel/frontend/Home/Home.module.scss

Lines changed: 6 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -114,19 +114,14 @@
114114
width: 100%;
115115
}
116116

117-
&__tasks {
118-
width: 100%;
117+
&__workspace-dropdown {
118+
position: relative;
119+
height: 24px;
120+
flex: 1;
119121
}
120122

121-
&__tasks-header {
122-
display: flex;
123-
align-items: center;
124-
justify-content: space-between;
125-
padding: 1px 14px 3px 12px;
126-
font-size: 11px;
127-
font-weight: bold;
128-
color: var(--cwc-text-color-dimmed);
129-
opacity: 0.8;
123+
&__tasks {
124+
width: 100%;
130125
}
131126
}
132127

@@ -174,37 +169,3 @@
174169
transform: translateY(-15px);
175170
}
176171
}
177-
178-
.add-button {
179-
appearance: none;
180-
background: none;
181-
border: none;
182-
padding: 0;
183-
margin: 0;
184-
height: 16px;
185-
width: 16px;
186-
color: var(--vscode-icon-foreground);
187-
position: relative;
188-
cursor: pointer;
189-
flex-shrink: 0;
190-
191-
&:focus {
192-
outline: none;
193-
}
194-
195-
&::before {
196-
font-family: 'codicon';
197-
font-size: 14px;
198-
content: '\ea60';
199-
position: absolute;
200-
top: 50%;
201-
left: 50%;
202-
transform: translate(-50%, -50%);
203-
opacity: 0.6;
204-
}
205-
206-
&:hover::before {
207-
opacity: 1;
208-
}
209-
}
210-

apps/editor/src/views/panel/frontend/Home/Home.tsx

Lines changed: 68 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { Task } from '@shared/types/task'
1717
import { use_tasks } from './hooks/use-tasks'
1818
import { use_sticky_mode } from './hooks/use-sticky-mode'
1919
import { SettingsButton as UiSettingsButton } from '@ui/components/editor/panel/SettingsButton'
20+
import { InlineDropdown as UiInlineDropdown } from '@ui/components/editor/panel/InlineDropdown'
2021

2122
type Props = {
2223
vscode: any
@@ -48,8 +49,12 @@ type Props = {
4849
export const Home: React.FC<Props> = (props) => {
4950
const { t } = use_translation()
5051
const [active_tab, set_active_tab] = useState<'tasks' | 'checkpoints'>('tasks')
52+
const [active_workspace_root, set_active_workspace_root] = useState<string>()
5153
const { is_mode_sticky, is_hiding, responses_ref, mode_ref, handle_scroll } = use_sticky_mode()
5254

55+
const roots = Object.keys(props.tasks)
56+
const active_root = active_workspace_root && roots.includes(active_workspace_root) ? active_workspace_root : roots[0]
57+
5358
useEffect(() => {
5459
const handle_mouse_up = (event: MouseEvent) => {
5560
if (props.is_active && event.button == 4) {
@@ -163,19 +168,32 @@ export const Home: React.FC<Props> = (props) => {
163168
on_tab_change={(id) => set_active_tab(id as 'tasks' | 'checkpoints')}
164169
actions={
165170
active_tab == 'tasks' ? (
166-
Object.keys(props.tasks).length == 1 ? (
167-
<UiIconButton
168-
codicon_icon="add"
169-
title={t('home.tasks.add')}
170-
on_click={(e) => {
171-
e.stopPropagation()
172-
const roots = Object.keys(props.tasks)
173-
if (roots.length > 0) {
174-
handle_add(roots[0], props.tasks[roots[0]], 'top')
175-
}
176-
}}
177-
/>
178-
) : undefined
171+
<>
172+
{roots.length > 1 && (
173+
<div className={styles['inner__workspace-dropdown']}>
174+
<UiInlineDropdown
175+
options={roots.map((root) => ({
176+
value: root,
177+
label: root.split(/[\\/]/).pop() || root
178+
}))}
179+
selected_value={active_root!}
180+
on_change={(val) => set_active_workspace_root(val)}
181+
/>
182+
</div>
183+
)}
184+
{roots.length > 0 && (
185+
<UiIconButton
186+
codicon_icon="add"
187+
title={t('home.tasks.add')}
188+
on_click={(e) => {
189+
e.stopPropagation()
190+
if (active_root) {
191+
handle_add(active_root, props.tasks[active_root], 'top')
192+
}
193+
}}
194+
/>
195+
)}
196+
</>
179197
) : (
180198
<>
181199
{props.has_temp_checkpoint && (
@@ -213,70 +231,43 @@ export const Home: React.FC<Props> = (props) => {
213231

214232
{active_tab == 'tasks' && (
215233
<>
216-
{Object.keys(props.tasks).length == 1 &&
217-
props.tasks[Object.keys(props.tasks)[0]].length == 0 && (
218-
<div className={styles.inner__empty}>
219-
{t('home.tasks.empty')}
220-
</div>
221-
)}
222-
{Object.entries(props.tasks)
223-
.filter(([_, tasks], __, arr) =>
224-
arr.length == 1 ? tasks.length > 0 : true
225-
)
226-
.map(([workspace_root_folder, tasks], _, entries) => (
227-
<div
228-
key={workspace_root_folder}
229-
className={styles.inner__tasks}
230-
>
231-
{entries.length > 1 && (
232-
<div className={styles['inner__tasks-header']}>
233-
<span>
234-
{workspace_root_folder.split(/[\\/]/).pop() ||
235-
workspace_root_folder}
236-
</span>
237-
<button
238-
className={styles['add-button']}
239-
title={t('home.tasks.add')}
240-
onClick={() => {
241-
handle_add(workspace_root_folder, tasks, 'top')
242-
}}
243-
/>
244-
</div>
245-
)}
246-
{tasks.length > 0 && (
247-
<UiTasks
248-
tasks={tasks}
249-
on_reorder={(new_tasks) =>
250-
handle_reorder(workspace_root_folder, new_tasks)
251-
}
252-
on_change={(updated_task) => {
253-
handle_change(
254-
workspace_root_folder,
255-
tasks,
256-
updated_task
257-
)
258-
}}
259-
on_add={() => {
260-
handle_add(workspace_root_folder, tasks)
261-
}}
262-
on_add_subtask={(parent_task) => {
263-
handle_add_subtask(
264-
workspace_root_folder,
265-
tasks,
266-
parent_task
267-
)
268-
}}
269-
on_delete={(timestamp) => {
270-
handle_delete(workspace_root_folder, timestamp)
271-
}}
272-
on_forward={(text) => {
273-
props.on_task_forward(text)
274-
}}
275-
placeholder={t('home.tasks.placeholder')}
276-
/>
277-
)}
278-
</div>
279-
))}
234+
{roots.length == 0 && (
235+
<div className={styles.inner__empty}>
236+
{t('home.tasks.empty')}
237+
</div>
238+
)}
239+
{active_root && (
240+
<div className={styles.inner__tasks}>
241+
{props.tasks[active_root].length == 0 ? (
242+
<div className={styles.inner__empty}>
243+
{t('home.tasks.empty')}
244+
</div>
245+
) : (
246+
<UiTasks
247+
tasks={props.tasks[active_root]}
248+
on_reorder={(new_tasks) =>
249+
handle_reorder(active_root, new_tasks)
250+
}
251+
on_change={(updated_task) => {
252+
handle_change(active_root, props.tasks[active_root], updated_task)
253+
}}
254+
on_add={() => {
255+
handle_add(active_root, props.tasks[active_root])
256+
}}
257+
on_add_subtask={(parent_task) => {
258+
handle_add_subtask(active_root, props.tasks[active_root], parent_task)
259+
}}
260+
on_delete={(timestamp) => {
261+
handle_delete(active_root, timestamp)
262+
}}
263+
on_forward={(text) => {
264+
props.on_task_forward(text)
265+
}}
266+
placeholder={t('home.tasks.placeholder')}
267+
/>
268+
)}
269+
</div>
270+
)}
280271
</>
281272
)}
282273

apps/editor/src/views/panel/frontend/Main/MainView/components/Header/Header.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useRef, useCallback } from 'react'
22
import { MODE, Mode } from '@/views/panel/types/main-view-mode'
33
import { use_is_narrow_viewport, use_is_mac } from '@shared/hooks'
44
import { ApiPromptType, WebPromptType } from '@shared/types/prompt-types'
5-
import { PromptTypeDropdown } from '@ui/components/editor/panel/PromptTypeDropdown'
5+
import { InlineDropdown as UiInlineDropdown } from '@ui/components/editor/panel/InlineDropdown'
66
import { IconButton as UiIconButton } from '@ui/components/editor/common/IconButton'
77
import styles from './Header.module.scss'
88
import {
@@ -74,7 +74,7 @@ export const Header: React.FC<Props> = (props) => {
7474
ref={dropdown_container_ref}
7575
>
7676
{props.mode == MODE.WEB && (
77-
<PromptTypeDropdown
77+
<UiInlineDropdown
7878
options={Object.entries(web_prompt_type_labels).map(
7979
([value, label]) => ({
8080
value: value as WebPromptType,
@@ -94,7 +94,7 @@ export const Header: React.FC<Props> = (props) => {
9494
/>
9595
)}
9696
{props.mode == MODE.API && (
97-
<PromptTypeDropdown
97+
<UiInlineDropdown
9898
options={Object.entries(api_prompt_type_labels).map(
9999
([value, label]) => ({
100100
value: value as ApiPromptType,

packages/ui/src/components/editor/panel/PromptTypeDropdown/PromptTypeDropdown.module.scss renamed to packages/ui/src/components/editor/panel/InlineDropdown/InlineDropdown.module.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// InlineDropdown styles
2+
13
.container {
24
position: absolute;
35
top: 0;

packages/ui/src/components/editor/panel/PromptTypeDropdown/PromptTypeDropdown.stories.tsx renamed to packages/ui/src/components/editor/panel/InlineDropdown/InlineDropdown.stories.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { PromptTypeDropdown } from './PromptTypeDropdown'
1+
import { InlineDropdown } from './InlineDropdown'
22
import { useState } from 'react'
33

44
export default {
5-
component: PromptTypeDropdown
5+
component: InlineDropdown
66
}
77

88
export const Default = () => {
@@ -14,7 +14,7 @@ export const Default = () => {
1414

1515
return (
1616
<div style={{ width: '200px' }}>
17-
<PromptTypeDropdown
17+
<InlineDropdown
1818
options={options}
1919
selected_value={selected}
2020
on_change={set_selected}
@@ -32,7 +32,7 @@ export const WithInfo = () => {
3232

3333
return (
3434
<div style={{ width: '200px' }}>
35-
<PromptTypeDropdown
35+
<InlineDropdown
3636
options={options}
3737
selected_value={selected}
3838
on_change={set_selected}
@@ -51,7 +51,7 @@ export const LongList = () => {
5151

5252
return (
5353
<div style={{ width: '200px' }}>
54-
<PromptTypeDropdown
54+
<InlineDropdown
5555
options={options}
5656
selected_value={selected}
5757
on_change={set_selected}

packages/ui/src/components/editor/panel/PromptTypeDropdown/PromptTypeDropdown.tsx renamed to packages/ui/src/components/editor/panel/InlineDropdown/InlineDropdown.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { useState, useRef, useEffect } from 'react'
2-
import styles from './PromptTypeDropdown.module.scss'
2+
import styles from './InlineDropdown.module.scss'
33
import cn from 'classnames'
44
import { DropdownMenu } from '../../common/DropdownMenu'
55

6-
export namespace PromptTypeDropdown {
6+
export namespace InlineDropdown {
77
export type Option<T extends string> = {
88
value: T
99
label: string
@@ -21,8 +21,8 @@ export namespace PromptTypeDropdown {
2121
}
2222
}
2323

24-
export const PromptTypeDropdown = <T extends string>(
25-
props: PromptTypeDropdown.Props<T>
24+
export const InlineDropdown = <T extends string>(
25+
props: InlineDropdown.Props<T>
2626
) => {
2727
const [is_open, set_is_open] = useState(false)
2828
const [just_opened, set_just_opened] = useState(false)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './InlineDropdown'
2+

packages/ui/src/components/editor/panel/PromptTypeDropdown/index.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

packages/ui/src/components/editor/panel/Tabs/Tabs.module.scss

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
.tabs {
2-
height: 28px;
2+
height: 26px;
33
padding: 0 12px;
44
margin-bottom: 8px;
55
display: flex;
66
justify-content: space-between;
77
align-items: center;
8-
border-bottom: 1px solid var(--cwc-border-color-dimmed);
8+
gap: 14px;
99

1010
&__list {
1111
display: flex;
@@ -60,5 +60,8 @@
6060
&__actions {
6161
display: flex;
6262
align-items: center;
63+
justify-content: flex-end;
64+
flex: 1;
65+
gap: 8px;
6366
}
6467
}

0 commit comments

Comments
 (0)