mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
feat(p2): add a + button to sidebar folders to start a new session there
This commit is contained in:
parent
55a5c69145
commit
5a31a6d5f4
4 changed files with 97 additions and 39 deletions
|
|
@ -178,12 +178,20 @@ function Sidebar() {
|
|||
);
|
||||
const renamed = renaming && list?.find((each) => each.id === renaming.session);
|
||||
const branch = renamed?.branches.find((each) => each.conversation === renaming?.conversation);
|
||||
const { setChoice } = useNewSessionState();
|
||||
const { setChoice, setLocation } = useNewSessionState();
|
||||
const onNew = useCallback(() => {
|
||||
setChoice(undefined);
|
||||
navigate({});
|
||||
setTimeout(() => document.querySelector<HTMLTextAreaElement>(".composer textarea")?.focus(), 50);
|
||||
}, [setChoice]);
|
||||
// A folder's "+": the new session starts in that folder's location.
|
||||
const onNewIn = useCallback(
|
||||
(env: string | null, cwd: string) => {
|
||||
setLocation({ env, cwd });
|
||||
onNew();
|
||||
},
|
||||
[setLocation, onNew],
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<Drawer
|
||||
|
|
@ -196,6 +204,7 @@ function Sidebar() {
|
|||
onBranch={owner ? onBranch : undefined}
|
||||
onRenameBranch={owner ? onRenameBranch : undefined}
|
||||
onNew={onNew}
|
||||
onNewIn={owner ? onNewIn : undefined}
|
||||
onCollapse={toggleSidebar}
|
||||
onSearch={search ? onSearch : undefined}
|
||||
onRestore={onRestore}
|
||||
|
|
|
|||
|
|
@ -274,6 +274,7 @@ export const Drawer = memo(function Drawer({
|
|||
onBranch,
|
||||
onRenameBranch,
|
||||
onNew,
|
||||
onNewIn,
|
||||
onCollapse,
|
||||
onProviders,
|
||||
onEnvs,
|
||||
|
|
@ -294,6 +295,8 @@ export const Drawer = memo(function Drawer({
|
|||
/** Asks for a new label of one of a session's `/tree` branches (the owner's). */
|
||||
onRenameBranch?: (id: string, conversationId: number) => void;
|
||||
onNew: () => void;
|
||||
/** Starts a new session in a sidebar folder's location; absent: folders have no "+". */
|
||||
onNewIn?: (env: string | null, cwd: string) => void;
|
||||
onCollapse: () => void;
|
||||
onProviders: () => void;
|
||||
onEnvs: () => void;
|
||||
|
|
@ -412,45 +415,62 @@ export const Drawer = memo(function Drawer({
|
|||
/>
|
||||
</label>
|
||||
<div className="session-scroll">
|
||||
{ordered.map(([location, list]) => (
|
||||
<section key={location} className="group">
|
||||
<h3 title={list[0] ? `${list[0].env ? `${list[0].env}:` : ""}${list[0].cwd}` : location}>
|
||||
<FolderIcon /> {location}
|
||||
</h3>
|
||||
{list.map((session) => (
|
||||
<SessionRow
|
||||
key={session.id}
|
||||
session={session}
|
||||
archived={archived}
|
||||
conversationId={session.id === activeId ? conversationId : session.main}
|
||||
onOpen={onOpen}
|
||||
onBranch={onBranch}
|
||||
onRenameBranch={onRenameBranch}
|
||||
active={session.id === activeId}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className={`session-main ${session.id === activeId && conversationId === session.main ? "active" : ""}`}
|
||||
onClick={() => (archived ? restore(session.id) : onOpen(session.id))}
|
||||
{ordered.map(([location, list]) => {
|
||||
// A group holds at least one session; its first names the folder's location.
|
||||
const first = list[0];
|
||||
return (
|
||||
<section key={location} className="group">
|
||||
<h3 title={first ? `${first.env ? `${first.env}:` : ""}${first.cwd}` : location}>
|
||||
<FolderIcon />
|
||||
<span className="group-label">{location}</span>
|
||||
{onNewIn && !archived && first && (
|
||||
<button
|
||||
type="button"
|
||||
className="group-new"
|
||||
aria-label={`New session in ${location}`}
|
||||
title={`New session in ${location}`}
|
||||
disabled={!connected}
|
||||
onClick={() => onNewIn(first.env ?? null, first.cwd)}
|
||||
>
|
||||
<PlusIcon size={14} />
|
||||
</button>
|
||||
)}
|
||||
</h3>
|
||||
{list.map((session) => (
|
||||
<SessionRow
|
||||
key={session.id}
|
||||
session={session}
|
||||
archived={archived}
|
||||
conversationId={session.id === activeId ? conversationId : session.main}
|
||||
onOpen={onOpen}
|
||||
onBranch={onBranch}
|
||||
onRenameBranch={onRenameBranch}
|
||||
active={session.id === activeId}
|
||||
>
|
||||
<span className="session-title">
|
||||
{session.pinned && <PinIcon size={12} />}
|
||||
{session.title}
|
||||
</span>
|
||||
<span className="session-meta">
|
||||
{session.worker.error && (
|
||||
<span className="error session-worker-error" title={session.worker.error}>
|
||||
Worker failed
|
||||
</span>
|
||||
)}
|
||||
<SessionDot worker={session.worker} />
|
||||
{archived ? "Tap to restore" : ago(session.updatedAt)}
|
||||
</span>
|
||||
</button>
|
||||
</SessionRow>
|
||||
))}
|
||||
</section>
|
||||
))}
|
||||
<button
|
||||
type="button"
|
||||
className={`session-main ${session.id === activeId && conversationId === session.main ? "active" : ""}`}
|
||||
onClick={() => (archived ? restore(session.id) : onOpen(session.id))}
|
||||
>
|
||||
<span className="session-title">
|
||||
{session.pinned && <PinIcon size={12} />}
|
||||
{session.title}
|
||||
</span>
|
||||
<span className="session-meta">
|
||||
{session.worker.error && (
|
||||
<span className="error session-worker-error" title={session.worker.error}>
|
||||
Worker failed
|
||||
</span>
|
||||
)}
|
||||
<SessionDot worker={session.worker} />
|
||||
{archived ? "Tap to restore" : ago(session.updatedAt)}
|
||||
</span>
|
||||
</button>
|
||||
</SessionRow>
|
||||
))}
|
||||
</section>
|
||||
);
|
||||
})}
|
||||
{results && results.messages.length > 0 && (
|
||||
<section className="group">
|
||||
<h3>Messages</h3>
|
||||
|
|
|
|||
|
|
@ -2830,6 +2830,25 @@ button.diff-number:hover {
|
|||
letter-spacing: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.group-label {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.group-new {
|
||||
display: inline-flex;
|
||||
flex: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: var(--control-sm);
|
||||
height: var(--control-sm);
|
||||
margin: calc(-1 * var(--s1)) 0;
|
||||
color: var(--faint);
|
||||
}
|
||||
.group-new:hover:not(:disabled) {
|
||||
color: var(--text);
|
||||
}
|
||||
.session-main {
|
||||
min-height: var(--control);
|
||||
padding-top: var(--s1);
|
||||
|
|
|
|||
|
|
@ -146,6 +146,16 @@ describe("drawer and new-session parity", { skip: !browserTests }, () => {
|
|||
"Pinned parent",
|
||||
"Recent sibling",
|
||||
]);
|
||||
// A folder's "+" opens a new session in that folder.
|
||||
const label = await browser.evaluate<string>(
|
||||
`document.querySelector('.session-scroll .group h3 .group-label').textContent`,
|
||||
);
|
||||
await browser.click(".session-scroll .group h3 .group-new");
|
||||
await browser.wait(
|
||||
`location.pathname==='/' && document.querySelector('.cwd-pick span')?.textContent===${JSON.stringify(label)}`,
|
||||
);
|
||||
await browser.open(`http://127.0.0.1:${fixture.server.port}/s/${pinned.id}`);
|
||||
await browser.wait(`[...document.querySelectorAll('.session-title')].some(e=>e.textContent==='Pinned parent')`);
|
||||
const chat = await holdIn(owner, Chat, { session: pinned.id, conversation: 1 }, "participant");
|
||||
await chat.send({ text: "subagent", requestId: "drawer-child" }, BACKGROUND_CONTEXT);
|
||||
const agents = await holdIn(owner, Subagents, {}, "reader");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue