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 renamed = renaming && list?.find((each) => each.id === renaming.session);
|
||||||
const branch = renamed?.branches.find((each) => each.conversation === renaming?.conversation);
|
const branch = renamed?.branches.find((each) => each.conversation === renaming?.conversation);
|
||||||
const { setChoice } = useNewSessionState();
|
const { setChoice, setLocation } = useNewSessionState();
|
||||||
const onNew = useCallback(() => {
|
const onNew = useCallback(() => {
|
||||||
setChoice(undefined);
|
setChoice(undefined);
|
||||||
navigate({});
|
navigate({});
|
||||||
setTimeout(() => document.querySelector<HTMLTextAreaElement>(".composer textarea")?.focus(), 50);
|
setTimeout(() => document.querySelector<HTMLTextAreaElement>(".composer textarea")?.focus(), 50);
|
||||||
}, [setChoice]);
|
}, [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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<Drawer
|
<Drawer
|
||||||
|
|
@ -196,6 +204,7 @@ function Sidebar() {
|
||||||
onBranch={owner ? onBranch : undefined}
|
onBranch={owner ? onBranch : undefined}
|
||||||
onRenameBranch={owner ? onRenameBranch : undefined}
|
onRenameBranch={owner ? onRenameBranch : undefined}
|
||||||
onNew={onNew}
|
onNew={onNew}
|
||||||
|
onNewIn={owner ? onNewIn : undefined}
|
||||||
onCollapse={toggleSidebar}
|
onCollapse={toggleSidebar}
|
||||||
onSearch={search ? onSearch : undefined}
|
onSearch={search ? onSearch : undefined}
|
||||||
onRestore={onRestore}
|
onRestore={onRestore}
|
||||||
|
|
|
||||||
|
|
@ -274,6 +274,7 @@ export const Drawer = memo(function Drawer({
|
||||||
onBranch,
|
onBranch,
|
||||||
onRenameBranch,
|
onRenameBranch,
|
||||||
onNew,
|
onNew,
|
||||||
|
onNewIn,
|
||||||
onCollapse,
|
onCollapse,
|
||||||
onProviders,
|
onProviders,
|
||||||
onEnvs,
|
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). */
|
/** Asks for a new label of one of a session's `/tree` branches (the owner's). */
|
||||||
onRenameBranch?: (id: string, conversationId: number) => void;
|
onRenameBranch?: (id: string, conversationId: number) => void;
|
||||||
onNew: () => 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;
|
onCollapse: () => void;
|
||||||
onProviders: () => void;
|
onProviders: () => void;
|
||||||
onEnvs: () => void;
|
onEnvs: () => void;
|
||||||
|
|
@ -412,45 +415,62 @@ export const Drawer = memo(function Drawer({
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<div className="session-scroll">
|
<div className="session-scroll">
|
||||||
{ordered.map(([location, list]) => (
|
{ordered.map(([location, list]) => {
|
||||||
<section key={location} className="group">
|
// A group holds at least one session; its first names the folder's location.
|
||||||
<h3 title={list[0] ? `${list[0].env ? `${list[0].env}:` : ""}${list[0].cwd}` : location}>
|
const first = list[0];
|
||||||
<FolderIcon /> {location}
|
return (
|
||||||
</h3>
|
<section key={location} className="group">
|
||||||
{list.map((session) => (
|
<h3 title={first ? `${first.env ? `${first.env}:` : ""}${first.cwd}` : location}>
|
||||||
<SessionRow
|
<FolderIcon />
|
||||||
key={session.id}
|
<span className="group-label">{location}</span>
|
||||||
session={session}
|
{onNewIn && !archived && first && (
|
||||||
archived={archived}
|
<button
|
||||||
conversationId={session.id === activeId ? conversationId : session.main}
|
type="button"
|
||||||
onOpen={onOpen}
|
className="group-new"
|
||||||
onBranch={onBranch}
|
aria-label={`New session in ${location}`}
|
||||||
onRenameBranch={onRenameBranch}
|
title={`New session in ${location}`}
|
||||||
active={session.id === activeId}
|
disabled={!connected}
|
||||||
>
|
onClick={() => onNewIn(first.env ?? null, first.cwd)}
|
||||||
<button
|
>
|
||||||
type="button"
|
<PlusIcon size={14} />
|
||||||
className={`session-main ${session.id === activeId && conversationId === session.main ? "active" : ""}`}
|
</button>
|
||||||
onClick={() => (archived ? restore(session.id) : onOpen(session.id))}
|
)}
|
||||||
|
</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">
|
<button
|
||||||
{session.pinned && <PinIcon size={12} />}
|
type="button"
|
||||||
{session.title}
|
className={`session-main ${session.id === activeId && conversationId === session.main ? "active" : ""}`}
|
||||||
</span>
|
onClick={() => (archived ? restore(session.id) : onOpen(session.id))}
|
||||||
<span className="session-meta">
|
>
|
||||||
{session.worker.error && (
|
<span className="session-title">
|
||||||
<span className="error session-worker-error" title={session.worker.error}>
|
{session.pinned && <PinIcon size={12} />}
|
||||||
Worker failed
|
{session.title}
|
||||||
</span>
|
</span>
|
||||||
)}
|
<span className="session-meta">
|
||||||
<SessionDot worker={session.worker} />
|
{session.worker.error && (
|
||||||
{archived ? "Tap to restore" : ago(session.updatedAt)}
|
<span className="error session-worker-error" title={session.worker.error}>
|
||||||
</span>
|
Worker failed
|
||||||
</button>
|
</span>
|
||||||
</SessionRow>
|
)}
|
||||||
))}
|
<SessionDot worker={session.worker} />
|
||||||
</section>
|
{archived ? "Tap to restore" : ago(session.updatedAt)}
|
||||||
))}
|
</span>
|
||||||
|
</button>
|
||||||
|
</SessionRow>
|
||||||
|
))}
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
})}
|
||||||
{results && results.messages.length > 0 && (
|
{results && results.messages.length > 0 && (
|
||||||
<section className="group">
|
<section className="group">
|
||||||
<h3>Messages</h3>
|
<h3>Messages</h3>
|
||||||
|
|
|
||||||
|
|
@ -2830,6 +2830,25 @@ button.diff-number:hover {
|
||||||
letter-spacing: 0;
|
letter-spacing: 0;
|
||||||
white-space: nowrap;
|
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 {
|
.session-main {
|
||||||
min-height: var(--control);
|
min-height: var(--control);
|
||||||
padding-top: var(--s1);
|
padding-top: var(--s1);
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,16 @@ describe("drawer and new-session parity", { skip: !browserTests }, () => {
|
||||||
"Pinned parent",
|
"Pinned parent",
|
||||||
"Recent sibling",
|
"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");
|
const chat = await holdIn(owner, Chat, { session: pinned.id, conversation: 1 }, "participant");
|
||||||
await chat.send({ text: "subagent", requestId: "drawer-child" }, BACKGROUND_CONTEXT);
|
await chat.send({ text: "subagent", requestId: "drawer-child" }, BACKGROUND_CONTEXT);
|
||||||
const agents = await holdIn(owner, Subagents, {}, "reader");
|
const agents = await holdIn(owner, Subagents, {}, "reader");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue