fix(ui-goal): order goal actions edit, clear, pause and tighten icon gaps
Refs #8024 Co-authored-by: Yifffan <[email protected]>
This commit is contained in:
1 parent
6a315e6aea
commit
eba9e768e6
12 files changed
+32
-30
No files matched your search
@@ -1,4 +1,4 @@
|
||||
- text: Ongoing Goal guard rapid clear clicks
|
||||
- button "Pause goal"
|
||||
- button "Edit goal"
|
||||
- button "Clear goal"
|
||||
- button "Pause goal"
|
||||
@@ -1,4 +1,4 @@
|
||||
- text: Blocked Goal retry with the edited plan
|
||||
- button "Resume goal"
|
||||
- button "Edit goal"
|
||||
- button "Clear goal"
|
||||
- button "Resume goal"
|
||||
@@ -1,4 +1,4 @@
|
||||
- text: Inactive Goal guard rapid clear clicks
|
||||
- button "Resume goal"
|
||||
- button "Edit goal"
|
||||
- button "Clear goal"
|
||||
- button "Resume goal"
|
||||
@@ -206,7 +206,7 @@
|
||||
display: flex;
|
||||
flex: none;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.status {
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
en: d152484eb41ac6b4
|
||||
zh: 09388d293f9be9cb
|
||||
/deepseek-ai-dsh-client-ui-goal/use-this-package:
|
||||
en: 7f6620a84a087d07
|
||||
zh: 80071126cc64b3e5
|
||||
en: a70a68194ca0c799
|
||||
zh: 3830bcebfa1879a9
|
||||
/deepseek-ai-dsh-client-ui-goal/use-this-package/the-command-input-bubble:
|
||||
en: 05f0360b6c6dd3e9
|
||||
zh: d14c3f15dc4cea5b
|
||||
|
||||
@@ -25,7 +25,7 @@ The Web GUI goal surface shows both the durable goal state and its current proce
|
||||
<a id="use-this-package"></a>
|
||||
## Use this package
|
||||
|
||||
Mount this plugin alongside `ui-conversation` and the goal domain package; the strip then appears as the second card in the composer-context stack (after Todo, before Queue) whenever the session has a goal. Todo and Goal use the same panel elevation above the composer. An armed active goal offers pause; an active-but-disarmed, paused, or blocked goal offers resume; edit rewrites the objective in the ui-primitives `InlineEditor`, so multi-line objectives survive editing; clear removes the goal and suppresses the strip until the projection catches up.
|
||||
Mount this plugin alongside `ui-conversation` and the goal domain package; the strip then appears as the second card in the composer-context stack (after Todo, before Queue) whenever the session has a goal. Todo and Goal use the same panel elevation above the composer. The strip orders its actions edit, clear, then pause or resume, matching the Queue rows' edit and remove positions. An armed active goal offers pause; an active-but-disarmed, paused, or blocked goal offers resume; edit rewrites the objective in the ui-primitives `InlineEditor`, so multi-line objectives survive editing; clear removes the goal and suppresses the strip until the projection catches up.
|
||||
|
||||
### The command-input bubble
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ Web GUI 的 goal 界面同时显示持久 goal 状态及当前的进程本地激
|
||||
<a id="use-this-package"></a>
|
||||
## 使用本包
|
||||
|
||||
与 `ui-conversation` 及 goal 领域包一起挂载本插件;只要会话存在目标,条带就会作为 composer 上下文堆栈的第二张卡片出现(位于 Todo 之后、Queue 之前)。Todo 与 Goal 使用相同的面板 elevation,使其位于 composer 层级之上。已 armed 的 active goal 提供暂停动作;active-but-disarmed、paused 或 blocked 的 goal 提供恢复;编辑在 ui-primitives 的 `InlineEditor` 中重写目标文本,多行目标编辑后仍保留换行;清除移除目标,并在投影追上之前抑制条带。
|
||||
与 `ui-conversation` 及 goal 领域包一起挂载本插件;只要会话存在目标,条带就会作为 composer 上下文堆栈的第二张卡片出现(位于 Todo 之后、Queue 之前)。Todo 与 Goal 使用相同的面板 elevation,使其位于 composer 层级之上。条带的动作按编辑、清除、暂停或恢复的顺序排列,与 Queue 行的编辑和移除位置一致。已 armed 的 active goal 提供暂停动作;active-but-disarmed、paused 或 blocked 的 goal 提供恢复;编辑在 ui-primitives 的 `InlineEditor` 中重写目标文本,多行目标编辑后仍保留换行;清除移除目标,并在投影追上之前抑制条带。
|
||||
|
||||
### 指令输入气泡
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
.actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
gap: 8px;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* GoalBar: the goal indicator docked above the message composer (input dock
|
||||
* strip). A present goal shows a goal glyph, a phase label, the truncated
|
||||
* objective, and icon actions — resume when active-disarmed, paused, or
|
||||
* blocked, edit (inline form in the same strip), and clear. Goal creation
|
||||
* lives on the `/goal` command, not here: loading (undefined), no goal
|
||||
* objective, and icon actions — edit (inline form in the same strip), clear,
|
||||
* then pause when armed or resume when active-disarmed, paused, or blocked.
|
||||
* Goal creation lives on the `/goal` command, not here: loading (undefined), no goal
|
||||
* (null), and complete goals render nothing. Durable state arrives as the projected whole snapshot;
|
||||
* process-local activation arrives through the injected activation hook.
|
||||
*/
|
||||
@@ -137,20 +137,6 @@ export function GoalBar({ goal, activation, onEdit, onPause, onResume, onClear,
|
||||
<span className={css.objective}>{goal.objective}</span>
|
||||
{actionError !== null && <span className={css.error} role="alert">{actionError}</span>}
|
||||
<div className={css.actions}>
|
||||
{goal.phase === 'active' && activation === 'armed' && (
|
||||
<Tooltip portal label={t('action.pause')} side="bottom" delayMs={500}>
|
||||
<button type="button" className={css.iconBtn} disabled={pending} onClick={() => { void runAction(onPause) }} aria-label={t('action.pause')}>
|
||||
<IconPauseOutlineRegular size={14} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
{showResume && (
|
||||
<Tooltip portal label={t('action.resume')} side="bottom" delayMs={500}>
|
||||
<button type="button" className={css.iconBtn} disabled={pending} onClick={() => { void runAction(onResume) }} aria-label={t('action.resume')}>
|
||||
<IconPlayOutlineRegular size={14} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip portal label={t('action.edit')} side="bottom" delayMs={500}>
|
||||
<button
|
||||
type="button"
|
||||
@@ -167,6 +153,20 @@ export function GoalBar({ goal, activation, onEdit, onPause, onResume, onClear,
|
||||
<IconTrashOutlineRegular size={14} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
{goal.phase === 'active' && activation === 'armed' && (
|
||||
<Tooltip portal label={t('action.pause')} side="bottom" delayMs={500}>
|
||||
<button type="button" className={css.iconBtn} disabled={pending} onClick={() => { void runAction(onPause) }} aria-label={t('action.pause')}>
|
||||
<IconPauseOutlineRegular size={14} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
{showResume && (
|
||||
<Tooltip portal label={t('action.resume')} side="bottom" delayMs={500}>
|
||||
<button type="button" className={css.iconBtn} disabled={pending} onClick={() => { void runAction(onResume) }} aria-label={t('action.resume')}>
|
||||
<IconPlayOutlineRegular size={14} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -146,9 +146,10 @@ describe('GoalBar', () => {
|
||||
expect(screen.getByRole('textbox', { name: '目标内容' })).toBeTruthy()
|
||||
})
|
||||
|
||||
it('active goal: the pause action pauses', () => {
|
||||
it('active goal: the pause action follows edit and clear, and pauses', () => {
|
||||
const actions = makeActions()
|
||||
render(<GoalBar goal={makeGoal()} activation="armed" {...actions} t={t} />)
|
||||
expect(screen.getAllByRole('button').map(b => b.getAttribute('aria-label'))).toEqual(['编辑目标', '清除目标', '暂停目标'])
|
||||
fireEvent.click(screen.getByRole('button', { name: '暂停目标' }))
|
||||
expect(actions.onPause).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
@@ -163,10 +164,11 @@ describe('GoalBar', () => {
|
||||
expect(screen.queryByRole('button', { name: '暂停目标' })).toBeNull()
|
||||
})
|
||||
|
||||
it('paused goal: "已暂停的目标" with a resume action before edit', () => {
|
||||
it('paused goal: "已暂停的目标" with a resume action after edit and clear', () => {
|
||||
const actions = makeActions()
|
||||
render(<GoalBar goal={makeGoal({ phase: 'paused' })} {...actions} t={t} />)
|
||||
expect(screen.getByText('已暂停的目标')).toBeTruthy()
|
||||
expect(screen.getAllByRole('button').map(b => b.getAttribute('aria-label'))).toEqual(['编辑目标', '清除目标', '恢复目标'])
|
||||
fireEvent.click(screen.getByRole('button', { name: '恢复目标' }))
|
||||
expect(actions.onResume).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
@@ -45,9 +45,9 @@
|
||||
- button "Bad response"
|
||||
- button "Branch into a new conversation"
|
||||
- text: {{clock}} Inactive Goal Keep working after Stop
|
||||
- button "Resume goal"
|
||||
- button "Edit goal"
|
||||
- button "Clear goal"
|
||||
- button "Resume goal"
|
||||
- textbox "Message or run a task, / commands, @ files or sessions"
|
||||
- button "Add files or run commands"
|
||||
- 'button "Access mode, current: Workspace Write"': Workspace Write
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
- region "To-dos":
|
||||
- button "To-dos 1 completed · 1 in progress"
|
||||
- text: Ongoing Goal Keep the composer context panels aligned
|
||||
- button "Pause goal"
|
||||
- button "Edit goal"
|
||||
- button "Clear goal"
|
||||
- button "Pause goal"
|
||||
- button "2 queued messages"
|
||||
- textbox "Cmd/Ctrl+Enter steers all queued messages"
|
||||
- button "Add files or run commands"
|
||||
|
||||
Reference in new issue
Block a user