mirror of
https://github.com/stablyai/orca.git
synced 2026-11-15 10:27:33 +00:00
Preserve the quiet-worker wait through Off and tidy its settings row
Keep the previous accepted wait as the in-session draft, give the help text more space, and explain invalid input without the numeric safety limit. Co-authored-by: Taras Kornichuk <dread9ko@gmail.com>
This commit is contained in:
co-authored by
Taras Kornichuk
parent
bdf701c81f
commit
e4aff599dc
+6
@@ -35,6 +35,12 @@ it('records inherited Off as a choice and resets only on the explicit default ac
|
||||
fireEvent.keyDown(input, { key: 'Enter' })
|
||||
expect(settings.orchestrationQuietWorkerMinutes).toBe(23)
|
||||
expect(document.activeElement).toBe(input)
|
||||
fireEvent.change(input, { target: { value: 'invalid' } })
|
||||
fireEvent.blur(input)
|
||||
fireEvent.click(screen.getByRole('radio', { name: 'Off' }))
|
||||
expect(settings.orchestrationQuietWorkerMinutes).toBe(0)
|
||||
fireEvent.click(screen.getByRole('radio', { name: 'After' }))
|
||||
expect(settings.orchestrationQuietWorkerMinutes).toBe(23)
|
||||
write.mockClear()
|
||||
for (const value of ['', '1.5', '-1', '0', '18764998448', '1e3']) {
|
||||
fireEvent.change(screen.getByRole('textbox', { name: 'Minutes' }), { target: { value } })
|
||||
|
||||
+40
-39
@@ -2,10 +2,9 @@ import { useId, useState } from 'react'
|
||||
import type { GlobalSettings } from '../../../../../shared/global-settings-types'
|
||||
import {
|
||||
isWorkerQuietMinutes,
|
||||
MAX_WORKER_QUIET_MINUTES,
|
||||
resolveWorkerQuietMinutes
|
||||
} from '../../../../../shared/orchestration/workers/worker-quiet-settings'
|
||||
import { useIntlLocale, useTranslate } from '@/i18n/use-translate'
|
||||
import { useTranslate } from '@/i18n/use-translate'
|
||||
import { Input } from '../../ui/input'
|
||||
import { Button } from '../../ui/button'
|
||||
import { SettingsRow, SettingsSegmentedControl } from '../form-controls/SettingsFormControls'
|
||||
@@ -21,7 +20,6 @@ export function OrchestrationWorkerQuietSetting({
|
||||
updateSettings
|
||||
}: Props): React.JSX.Element {
|
||||
const t = useTranslate()
|
||||
const intlLocale = useIntlLocale()
|
||||
const id = useId()
|
||||
const raw = settings.orchestrationQuietWorkerMinutes
|
||||
const minutes = resolveWorkerQuietMinutes(settings)
|
||||
@@ -29,7 +27,8 @@ export function OrchestrationWorkerQuietSetting({
|
||||
const [draft, setDraft] = useState({ raw, value: String(minutes || 15) })
|
||||
const [invalid, setInvalid] = useState(false)
|
||||
if (!Object.is(draft.raw, raw)) {
|
||||
setDraft({ raw, value: minutes > 0 ? String(minutes) : draft.value })
|
||||
const draftMinutes = minutes || (isWorkerQuietMinutes(draft.raw) ? draft.raw : 0)
|
||||
setDraft({ raw, value: draftMinutes > 0 ? String(draftMinutes) : draft.value })
|
||||
setInvalid(false)
|
||||
}
|
||||
const save = (value: number | null): void => {
|
||||
@@ -49,6 +48,7 @@ export function OrchestrationWorkerQuietSetting({
|
||||
}
|
||||
return (
|
||||
<SettingsRow
|
||||
alignTop
|
||||
labelId={id}
|
||||
label={getWorkerQuietTitle(t)}
|
||||
description={
|
||||
@@ -73,15 +73,14 @@ export function OrchestrationWorkerQuietSetting({
|
||||
<span id={`${id}-error`} role="alert" className="block text-destructive">
|
||||
{t(
|
||||
'auto.components.settings.OrchestrationPane.workerQuietInvalid',
|
||||
'Enter a whole number of minutes between 1 and {{max}}.',
|
||||
{ max: MAX_WORKER_QUIET_MINUTES.toLocaleString(intlLocale) }
|
||||
'Enter a whole number of minutes (1 or more).'
|
||||
)}
|
||||
</span>
|
||||
) : null}
|
||||
</>
|
||||
}
|
||||
control={
|
||||
<div className="flex flex-wrap items-center justify-end gap-2">
|
||||
<div className="flex flex-col items-end gap-2">
|
||||
<SettingsSegmentedControl
|
||||
value={minutes ? 'after' : 'off'}
|
||||
ariaLabelledBy={id}
|
||||
@@ -97,38 +96,40 @@ export function OrchestrationWorkerQuietSetting({
|
||||
]}
|
||||
onChange={(value) => (value === 'off' ? save(0) : commit())}
|
||||
/>
|
||||
<Input
|
||||
type="text"
|
||||
inputMode="numeric"
|
||||
aria-label={t(
|
||||
'auto.components.settings.OrchestrationPane.workerQuietMinutes',
|
||||
'Minutes'
|
||||
)}
|
||||
aria-invalid={invalid}
|
||||
aria-describedby={invalid ? `${id}-error` : undefined}
|
||||
value={draft.value}
|
||||
onChange={(event) => {
|
||||
setDraft({ raw, value: event.target.value })
|
||||
setInvalid(false)
|
||||
}}
|
||||
onBlur={() => {
|
||||
if (minutes > 0) {
|
||||
commit()
|
||||
}
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter' && minutes > 0) {
|
||||
commit()
|
||||
}
|
||||
}}
|
||||
className="w-24"
|
||||
/>
|
||||
<span className="text-settings-detail text-muted-foreground">
|
||||
{t('auto.components.settings.OrchestrationPane.workerQuietUnit', 'minutes')}
|
||||
</span>
|
||||
<Button variant="ghost" size="sm" disabled={!chosen} onClick={() => save(null)}>
|
||||
{t('auto.components.settings.OrchestrationPane.workerQuietReset', 'Use default')}
|
||||
</Button>
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
type="text"
|
||||
inputMode="numeric"
|
||||
aria-label={t(
|
||||
'auto.components.settings.OrchestrationPane.workerQuietMinutes',
|
||||
'Minutes'
|
||||
)}
|
||||
aria-invalid={invalid}
|
||||
aria-describedby={invalid ? `${id}-error` : undefined}
|
||||
value={draft.value}
|
||||
onChange={(event) => {
|
||||
setDraft({ raw, value: event.target.value })
|
||||
setInvalid(false)
|
||||
}}
|
||||
onBlur={() => {
|
||||
if (minutes > 0) {
|
||||
commit()
|
||||
}
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter' && minutes > 0) {
|
||||
commit()
|
||||
}
|
||||
}}
|
||||
className="w-24"
|
||||
/>
|
||||
<span className="text-settings-detail text-muted-foreground">
|
||||
{t('auto.components.settings.OrchestrationPane.workerQuietUnit', 'minutes')}
|
||||
</span>
|
||||
<Button variant="ghost" size="sm" disabled={!chosen} onClick={() => save(null)}>
|
||||
{t('auto.components.settings.OrchestrationPane.workerQuietReset', 'Use default')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -11,6 +11,6 @@ export function getWorkerQuietTitle(t: Translate = translate): string {
|
||||
export function getWorkerQuietDescription(t: Translate = translate): string {
|
||||
return t(
|
||||
'auto.components.settings.OrchestrationPane.workerQuietDescription',
|
||||
'This is only a notice. Workers keep running. Orca waits four times longer while a tool is running or progress is unavailable. Controls quiet notices generated by this Orca runtime. Other execution hosts use their own setting.'
|
||||
'Notice only. Workers keep running. Waits 4× longer for tools or unavailable progress. Each host uses its own setting.'
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9183,7 +9183,7 @@
|
||||
"nestedWorkerDepthTitle": "Nested worker depth",
|
||||
"nestedWorkerDepthDescription": "How many generations of dispatched workers may spawn their own workers. 1 keeps the agent tree flat: a coordinator dispatches workers, and those workers do not dispatch.",
|
||||
"workerQuietTitle": "Tell the coordinator when a worker has made no progress for…",
|
||||
"workerQuietDescription": "This is only a notice. Workers keep running. Orca waits four times longer while a tool is running or progress is unavailable. Controls quiet notices generated by this Orca runtime. Other execution hosts use their own setting.",
|
||||
"workerQuietDescription": "Notice only. Workers keep running. Waits 4× longer for tools or unavailable progress. Each host uses its own setting.",
|
||||
"workerQuietChosen": "Your choice",
|
||||
"workerQuietDefault": "Using default ({{value}})",
|
||||
"workerQuietWait": "{{count}} minutes",
|
||||
@@ -9192,7 +9192,7 @@
|
||||
"workerQuietMinutes": "Minutes",
|
||||
"workerQuietUnit": "minutes",
|
||||
"workerQuietReset": "Use default",
|
||||
"workerQuietInvalid": "Enter a whole number of minutes between 1 and {{max}}.",
|
||||
"workerQuietInvalid": "Enter a whole number of minutes (1 or more).",
|
||||
"workerAutoReleaseTitle": "Auto-close finished workers",
|
||||
"workerAutoReleaseDescription": "Closes a worker's terminal or chat 2 minutes after it finishes, unless you choose Keep open. If it starts working again, the 2 minutes start over when it finishes.",
|
||||
"workerAutoReleaseKeywordClose": "close",
|
||||
|
||||
Reference in New Issue
Block a user