web: make running composer stoppable
This commit is contained in:
parent
342c3dabb7
commit
862f8f7f98
|
|
@ -416,6 +416,21 @@ Deno.test("Worker Console page is routed by runtime_id and worker_id through bac
|
||||||
!consolePage.includes("void refreshConsole();\n });\n\n $effect"),
|
!consolePage.includes("void refreshConsole();\n });\n\n $effect"),
|
||||||
"target-change effect should load data without depending on manual refresh state reads",
|
"target-change effect should load data without depending on manual refresh state reads",
|
||||||
);
|
);
|
||||||
|
assert(
|
||||||
|
consolePage.includes('const workerRunning = $derived(workerState === "running");') &&
|
||||||
|
consolePage.includes(
|
||||||
|
'const composerEditable = $derived(protocolState === "open" && !sending);',
|
||||||
|
) &&
|
||||||
|
consolePage.includes('sendControl({ method: "cancel" }, "Stop")') &&
|
||||||
|
consolePage.includes("enabled: canSubmitDraft") &&
|
||||||
|
consolePage.includes("disabled={!composerEditable}") &&
|
||||||
|
consolePage.includes('class:stop={workerRunning}') &&
|
||||||
|
consolePage.includes('"Stop Worker"') &&
|
||||||
|
consolePage.includes("disabled={composerSubmitDisabled}") &&
|
||||||
|
!consolePage.includes("disabled={!inputReady || sending}") &&
|
||||||
|
!consolePage.includes("enabled: inputReady && !sending"),
|
||||||
|
"Worker Console composer should stay editable during runs and turn the submit button into a Stop control",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test("Account UI owns browser passkey session state without workspace authorization", async () => {
|
Deno.test("Account UI owns browser passkey session state without workspace authorization", async () => {
|
||||||
|
|
|
||||||
|
|
@ -156,8 +156,15 @@
|
||||||
mergeDiagnostics(worker?.diagnostics ?? [], streamDiagnostics),
|
mergeDiagnostics(worker?.diagnostics ?? [], streamDiagnostics),
|
||||||
);
|
);
|
||||||
const workerState = $derived(liveWorkerState ?? worker?.state ?? "loading");
|
const workerState = $derived(liveWorkerState ?? worker?.state ?? "loading");
|
||||||
|
const workerRunning = $derived(workerState === "running");
|
||||||
const inputReady = $derived(workerState === "idle");
|
const inputReady = $derived(workerState === "idle");
|
||||||
const canSend = $derived(inputReady && draft.trim().length > 0 && !sending);
|
const composerEditable = $derived(protocolState === "open" && !sending);
|
||||||
|
const canSubmitDraft = $derived(inputReady && composerEditable);
|
||||||
|
const canSend = $derived(canSubmitDraft && draft.trim().length > 0);
|
||||||
|
const canStopFromComposer = $derived(workerRunning && composerEditable);
|
||||||
|
const composerSubmitDisabled = $derived(
|
||||||
|
workerRunning ? !canStopFromComposer : !canSend,
|
||||||
|
);
|
||||||
|
|
||||||
async function getJson<T>(path: string): Promise<T> {
|
async function getJson<T>(path: string): Promise<T> {
|
||||||
const response = await fetch(path);
|
const response = await fetch(path);
|
||||||
|
|
@ -433,6 +440,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleComposerSubmit(value = draft) {
|
||||||
|
if (workerRunning) {
|
||||||
|
sendControl({ method: "cancel" }, "Stop");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void submitDraft(value);
|
||||||
|
}
|
||||||
|
|
||||||
async function submitDraft(value = draft) {
|
async function submitDraft(value = draft) {
|
||||||
const command = buildComposerRequest(value);
|
const command = buildComposerRequest(value);
|
||||||
if (!command.ok) {
|
if (!command.ok) {
|
||||||
|
|
@ -466,9 +481,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendMessage(event: SubmitEvent) {
|
function sendMessage(event: SubmitEvent) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
await submitDraft();
|
handleComposerSubmit();
|
||||||
}
|
}
|
||||||
|
|
||||||
function workerStateFromProtocolEvent(
|
function workerStateFromProtocolEvent(
|
||||||
|
|
@ -1314,12 +1329,12 @@
|
||||||
bind:this={composerTextareaElement}
|
bind:this={composerTextareaElement}
|
||||||
bind:value={draft}
|
bind:value={draft}
|
||||||
use:chatSubmit={{
|
use:chatSubmit={{
|
||||||
enabled: inputReady && !sending,
|
enabled: canSubmitDraft,
|
||||||
onSubmit: (value) => void submitDraft(value),
|
onSubmit: (value) => handleComposerSubmit(value),
|
||||||
}}
|
}}
|
||||||
use:fitTextarea={{ value: draft, maxRows: 10 }}
|
use:fitTextarea={{ value: draft, maxRows: 10 }}
|
||||||
onkeydown={handleComposerKeydown}
|
onkeydown={handleComposerKeydown}
|
||||||
disabled={!inputReady || sending}></textarea>
|
disabled={!composerEditable}></textarea>
|
||||||
<div class="composer-input-footer">
|
<div class="composer-input-footer">
|
||||||
<div class="composer-footer-slot">
|
<div class="composer-footer-slot">
|
||||||
{#if completionBusy || completionError || completionEntries.length > 0}
|
{#if completionBusy || completionError || completionEntries.length > 0}
|
||||||
|
|
@ -1342,18 +1357,33 @@
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
class="composer-send-button"
|
class="composer-send-button"
|
||||||
|
class:stop={workerRunning}
|
||||||
type="submit"
|
type="submit"
|
||||||
aria-label={sending ? "Sending message" : "Send message"}
|
aria-label={workerRunning
|
||||||
disabled={!canSend}
|
? "Stop Worker"
|
||||||
|
: sending
|
||||||
|
? "Sending message"
|
||||||
|
: "Send message"}
|
||||||
|
disabled={composerSubmitDisabled}
|
||||||
>
|
>
|
||||||
<svg
|
{#if workerRunning}
|
||||||
class="composer-send-icon"
|
<svg
|
||||||
aria-hidden="true"
|
class="composer-send-icon"
|
||||||
viewBox="0 0 24 24"
|
aria-hidden="true"
|
||||||
>
|
viewBox="0 0 24 24"
|
||||||
<path d="M8 6L12 2L16 6" />
|
>
|
||||||
<path d="M12 2V22" />
|
<path d="M7 7H17V17H7Z" />
|
||||||
</svg>
|
</svg>
|
||||||
|
{:else}
|
||||||
|
<svg
|
||||||
|
class="composer-send-icon"
|
||||||
|
aria-hidden="true"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path d="M8 6L12 2L16 6" />
|
||||||
|
<path d="M12 2V22" />
|
||||||
|
</svg>
|
||||||
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1657,6 +1687,11 @@
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.composer-send-button.stop {
|
||||||
|
background: var(--danger);
|
||||||
|
color: var(--bg);
|
||||||
|
}
|
||||||
|
|
||||||
.composer-send-button:disabled {
|
.composer-send-button:disabled {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
opacity: 0.55;
|
opacity: 0.55;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user