Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions ui/e2e/workspace.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,18 +201,11 @@ test("new-task shortcuts and deletion keep task selection usable", async ({
await prompt.fill("/new");
await page.getByRole("button", { name: "Send task", exact: true }).click();
await expect(prompt).toHaveValue("");
await expect
.poll(async () => {
const selected = await page.evaluate(() =>
localStorage.getItem("shadow:selected"),
);
return Boolean(selected && selected !== first);
})
.toBe(true);
const toDelete = await page.evaluate(() =>
localStorage.getItem("shadow:selected"),
);
expect(toDelete).not.toBe(first);
await expect(page.locator(".loading-task")).toHaveCount(0);
await page.keyboard.press("Control+k");
await page
.getByRole("textbox", { name: "Search commands" })
Expand Down
25 changes: 16 additions & 9 deletions ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ const formatTokens = (n: number) =>
n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n);
const draftKey = (id: string, workspace: string) =>
`shadow:draft:${id || workspace}`;
const isSessionCommand = (text: string) =>
["/new", "/clear"].includes(text.trim());

export default function App() {
const [ready, setReady] = useState(false);
Expand Down Expand Up @@ -111,6 +113,7 @@ export default function App() {
const selectedRef = useRef("");
const selection = useRef(0);
const submittingRef = useRef(false);
const taskRef = useRef("");
const toastSeq = useRef(0);
const booted = useRef(false);
const activationQueue = useRef<Promise<unknown>>(Promise.resolve());
Expand Down Expand Up @@ -156,6 +159,7 @@ export default function App() {
});
const { transcript, setTranscript, job, busy, connection } = conversation;
const locked = busy || submitting || switching;
taskRef.current = task;

async function reloadConfig() {
const [config, state, modelData, providerData] = await Promise.all([
Expand All @@ -173,9 +177,11 @@ export default function App() {
async function openSession(id: string) {
if (submittingRef.current) return;
if (selectedRef.current) {
if (task)
localStorage.setItem(draftKey(selectedRef.current, workspace), task);
else localStorage.removeItem(draftKey(selectedRef.current, workspace));
const draft = taskRef.current;
if (draft && !isSessionCommand(draft))
localStorage.setItem(draftKey(selectedRef.current, workspace), draft);
else if (!draft)
localStorage.removeItem(draftKey(selectedRef.current, workspace));
}
const ticket = ++selection.current;
setSwitching(true);
Expand Down Expand Up @@ -255,6 +261,7 @@ export default function App() {
useEffect(() => {
const key = draftKey(sessionId, workspace);
const timer = setTimeout(() => {
if (isSessionCommand(task)) return;
if (task) localStorage.setItem(key, task);
else localStorage.removeItem(key);
}, 200);
Expand Down Expand Up @@ -303,14 +310,15 @@ export default function App() {
return () => clearInterval(timer);
}, [job?.id, busy]);

async function newSession() {
if (submitting || switching) return;
async function newSession(opts?: { force?: boolean }) {
if (!opts?.force && (submitting || switching)) return;
if (!workspace) {
setOverlay("project");
return;
}
try {
const created = await api.createSession(workspace, "New task");
localStorage.setItem("shadow:selected", created.id);
await openSession(created.id);
promptRef.current?.focus();
} catch (e) {
Expand Down Expand Up @@ -369,7 +377,7 @@ export default function App() {
const [name, ...rest] = text.slice(1).split(" ");
const args = rest.join(" ");
if (name === "new" || name === "clear") {
await newSession();
await newSession({ force: true });
return;
}
const panels: Record<string, DrawerTab> = {
Expand Down Expand Up @@ -397,9 +405,8 @@ export default function App() {
async function submit() {
if (locked || submittingRef.current || (!task.trim() && !chips.length))
return;
if (["/new", "/clear"].includes(task.trim())) {
setTask("");
await newSession();
if (isSessionCommand(task)) {
await newSession({ force: true });
return;
}
const original = task;
Expand Down
Loading