mirror of
https://github.com/davidkaya/aryx.git
synced 2026-08-27 05:13:58 +02:00
feat: replace top-level New Session button with contextual buttons
Remove the single New Session button from the sidebar top and replace it with contextual creation buttons scoped to each section: - Scratchpad section: 'New Scratchpad' button that auto-creates a scratchpad session with the first available single-agent pattern - Project groups: 'New Session' button that opens the pattern picker modal pre-scoped to that project - WelcomePane: primary action updated to 'New Scratchpad' Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
+26
-8
@@ -22,7 +22,7 @@ import {
|
|||||||
resolveReasoningEffort,
|
resolveReasoningEffort,
|
||||||
} from '@shared/domain/models';
|
} from '@shared/domain/models';
|
||||||
import type { PatternDefinition } from '@shared/domain/pattern';
|
import type { PatternDefinition } from '@shared/domain/pattern';
|
||||||
import { isScratchpadProject } from '@shared/domain/project';
|
import { isScratchpadProject, SCRATCHPAD_PROJECT_ID } from '@shared/domain/project';
|
||||||
import { applyScratchpadSessionConfig } from '@shared/domain/session';
|
import { applyScratchpadSessionConfig } from '@shared/domain/session';
|
||||||
import type { LspProfileDefinition, McpServerDefinition } from '@shared/domain/tooling';
|
import type { LspProfileDefinition, McpServerDefinition } from '@shared/domain/tooling';
|
||||||
import type { WorkspaceState } from '@shared/domain/workspace';
|
import type { WorkspaceState } from '@shared/domain/workspace';
|
||||||
@@ -89,7 +89,7 @@ export default function App() {
|
|||||||
const [isRefreshingCapabilities, setIsRefreshingCapabilities] = useState(false);
|
const [isRefreshingCapabilities, setIsRefreshingCapabilities] = useState(false);
|
||||||
|
|
||||||
const [showSettings, setShowSettings] = useState(false);
|
const [showSettings, setShowSettings] = useState(false);
|
||||||
const [showNewSession, setShowNewSession] = useState(false);
|
const [newSessionProjectId, setNewSessionProjectId] = useState<string>();
|
||||||
|
|
||||||
// Load workspace on mount
|
// Load workspace on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -201,6 +201,21 @@ export default function App() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleCreateScratchpad = () => {
|
||||||
|
const singlePatterns = workspace.patterns
|
||||||
|
.filter((p) => p.mode === 'single' && p.availability !== 'unavailable')
|
||||||
|
.sort((a, b) => {
|
||||||
|
if (a.isFavorite && !b.isFavorite) return -1;
|
||||||
|
if (!a.isFavorite && b.isFavorite) return 1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
const defaultPattern = singlePatterns[0];
|
||||||
|
if (defaultPattern) {
|
||||||
|
void api.createSession({ projectId: SCRATCHPAD_PROJECT_ID, patternId: defaultPattern.id });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Determine main content
|
// Determine main content
|
||||||
let content: React.ReactNode;
|
let content: React.ReactNode;
|
||||||
let detailPanel: React.ReactNode | undefined;
|
let detailPanel: React.ReactNode | undefined;
|
||||||
@@ -253,7 +268,7 @@ export default function App() {
|
|||||||
<WelcomePane
|
<WelcomePane
|
||||||
hasProjects={hasUserProjects}
|
hasProjects={hasUserProjects}
|
||||||
onAddProject={() => void api.addProject()}
|
onAddProject={() => void api.addProject()}
|
||||||
onNewSession={() => setShowNewSession(true)}
|
onNewScratchpad={() => handleCreateScratchpad()}
|
||||||
onOpenSettings={() => setShowSettings(true)}
|
onOpenSettings={() => setShowSettings(true)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -309,7 +324,10 @@ export default function App() {
|
|||||||
sidebar={
|
sidebar={
|
||||||
<Sidebar
|
<Sidebar
|
||||||
onAddProject={() => void api.addProject()}
|
onAddProject={() => void api.addProject()}
|
||||||
onNewSession={() => setShowNewSession(true)}
|
onCreateScratchpad={() => handleCreateScratchpad()}
|
||||||
|
onNewProjectSession={(projectId) => {
|
||||||
|
setNewSessionProjectId(projectId);
|
||||||
|
}}
|
||||||
onOpenSettings={() => setShowSettings(true)}
|
onOpenSettings={() => setShowSettings(true)}
|
||||||
onProjectSelect={(projectId) => {
|
onProjectSelect={(projectId) => {
|
||||||
void api.selectProject(projectId);
|
void api.selectProject(projectId);
|
||||||
@@ -337,12 +355,12 @@ export default function App() {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{showNewSession && (
|
{newSessionProjectId && (
|
||||||
<NewSessionModal
|
<NewSessionModal
|
||||||
defaultProjectId={workspace.selectedProjectId}
|
defaultProjectId={newSessionProjectId}
|
||||||
onClose={() => setShowNewSession(false)}
|
onClose={() => setNewSessionProjectId(undefined)}
|
||||||
onCreate={(projectId, patternId) => {
|
onCreate={(projectId, patternId) => {
|
||||||
setShowNewSession(false);
|
setNewSessionProjectId(undefined);
|
||||||
void api.createSession({ projectId, patternId });
|
void api.createSession({ projectId, patternId });
|
||||||
}}
|
}}
|
||||||
onTogglePatternFavorite={(patternId, isFavorite) => {
|
onTogglePatternFavorite={(patternId, isFavorite) => {
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ import type { WorkspaceState } from '@shared/domain/workspace';
|
|||||||
interface SidebarProps {
|
interface SidebarProps {
|
||||||
workspace: WorkspaceState;
|
workspace: WorkspaceState;
|
||||||
onAddProject: () => void;
|
onAddProject: () => void;
|
||||||
onNewSession: () => void;
|
onCreateScratchpad: () => void;
|
||||||
|
onNewProjectSession: (projectId: string) => void;
|
||||||
onProjectSelect: (projectId?: string) => void;
|
onProjectSelect: (projectId?: string) => void;
|
||||||
onSessionSelect: (sessionId: string) => void;
|
onSessionSelect: (sessionId: string) => void;
|
||||||
onOpenSettings: () => void;
|
onOpenSettings: () => void;
|
||||||
@@ -310,6 +311,8 @@ function ProjectGroup({
|
|||||||
onRenameSubmit,
|
onRenameSubmit,
|
||||||
onRenameCancel,
|
onRenameCancel,
|
||||||
onRefreshGitContext,
|
onRefreshGitContext,
|
||||||
|
onNewSession,
|
||||||
|
newSessionLabel,
|
||||||
}: {
|
}: {
|
||||||
project: ProjectRecord;
|
project: ProjectRecord;
|
||||||
sessions: SessionRecord[];
|
sessions: SessionRecord[];
|
||||||
@@ -321,6 +324,8 @@ function ProjectGroup({
|
|||||||
onRenameSubmit: (sessionId: string, title: string) => void;
|
onRenameSubmit: (sessionId: string, title: string) => void;
|
||||||
onRenameCancel: () => void;
|
onRenameCancel: () => void;
|
||||||
onRefreshGitContext?: (projectId: string) => void;
|
onRefreshGitContext?: (projectId: string) => void;
|
||||||
|
onNewSession?: () => void;
|
||||||
|
newSessionLabel?: string;
|
||||||
}){
|
}){
|
||||||
const [expanded, setExpanded] = useState(true);
|
const [expanded, setExpanded] = useState(true);
|
||||||
const isScratchpad = isScratchpadProject(project);
|
const isScratchpad = isScratchpadProject(project);
|
||||||
@@ -414,6 +419,16 @@ function ProjectGroup({
|
|||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
|
{onNewSession && (
|
||||||
|
<button
|
||||||
|
className="flex w-full items-center justify-center gap-1.5 rounded-md border border-dashed border-zinc-700/60 bg-zinc-800/20 px-2.5 py-1.5 text-[12px] font-medium text-zinc-500 transition hover:border-indigo-500/40 hover:bg-indigo-500/5 hover:text-indigo-300"
|
||||||
|
onClick={onNewSession}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<Plus className="size-3.5" />
|
||||||
|
{newSessionLabel ?? 'New Session'}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -425,7 +440,8 @@ function ProjectGroup({
|
|||||||
export function Sidebar({
|
export function Sidebar({
|
||||||
workspace,
|
workspace,
|
||||||
onAddProject,
|
onAddProject,
|
||||||
onNewSession,
|
onCreateScratchpad,
|
||||||
|
onNewProjectSession,
|
||||||
onProjectSelect,
|
onProjectSelect,
|
||||||
onSessionSelect,
|
onSessionSelect,
|
||||||
onOpenSettings,
|
onOpenSettings,
|
||||||
@@ -537,18 +553,6 @@ export function Sidebar({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* New session CTA */}
|
|
||||||
<div className="px-3 pt-2 pb-1">
|
|
||||||
<button
|
|
||||||
className="flex w-full items-center justify-center gap-2 rounded-lg border border-dashed border-zinc-700 bg-zinc-800/30 px-3 py-2 text-[13px] font-medium text-zinc-400 transition hover:border-indigo-500/40 hover:bg-indigo-500/5 hover:text-indigo-300"
|
|
||||||
onClick={onNewSession}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<Plus className="size-4" />
|
|
||||||
New Session
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Session list */}
|
{/* Session list */}
|
||||||
<div
|
<div
|
||||||
className="flex-1 overflow-y-auto px-2 py-2"
|
className="flex-1 overflow-y-auto px-2 py-2"
|
||||||
@@ -600,6 +604,8 @@ export function Sidebar({
|
|||||||
project={scratchpadProject}
|
project={scratchpadProject}
|
||||||
selectedSessionId={workspace.selectedSessionId}
|
selectedSessionId={workspace.selectedSessionId}
|
||||||
sessions={workspace.sessions.filter((session) => session.projectId === scratchpadProject.id)}
|
sessions={workspace.sessions.filter((session) => session.projectId === scratchpadProject.id)}
|
||||||
|
onNewSession={onCreateScratchpad}
|
||||||
|
newSessionLabel="New Scratchpad"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -646,6 +652,7 @@ export function Sidebar({
|
|||||||
project={project}
|
project={project}
|
||||||
selectedSessionId={workspace.selectedSessionId}
|
selectedSessionId={workspace.selectedSessionId}
|
||||||
sessions={workspace.sessions.filter((session) => session.projectId === project.id)}
|
sessions={workspace.sessions.filter((session) => session.projectId === project.id)}
|
||||||
|
onNewSession={() => onNewProjectSession(project.id)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import { MessageSquare, Plus, Settings } from 'lucide-react';
|
|||||||
|
|
||||||
interface WelcomePaneProps {
|
interface WelcomePaneProps {
|
||||||
hasProjects: boolean;
|
hasProjects: boolean;
|
||||||
onNewSession: () => void;
|
onNewScratchpad: () => void;
|
||||||
onAddProject: () => void;
|
onAddProject: () => void;
|
||||||
onOpenSettings: () => void;
|
onOpenSettings: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function WelcomePane({
|
export function WelcomePane({
|
||||||
hasProjects,
|
hasProjects,
|
||||||
onNewSession,
|
onNewScratchpad,
|
||||||
onAddProject,
|
onAddProject,
|
||||||
onOpenSettings,
|
onOpenSettings,
|
||||||
}: WelcomePaneProps) {
|
}: WelcomePaneProps) {
|
||||||
@@ -31,11 +31,11 @@ export function WelcomePane({
|
|||||||
<div className="flex flex-col items-center gap-2">
|
<div className="flex flex-col items-center gap-2">
|
||||||
<button
|
<button
|
||||||
className="flex items-center gap-2 rounded-lg bg-indigo-600 px-5 py-2.5 text-sm font-medium text-white transition hover:bg-indigo-500"
|
className="flex items-center gap-2 rounded-lg bg-indigo-600 px-5 py-2.5 text-sm font-medium text-white transition hover:bg-indigo-500"
|
||||||
onClick={onNewSession}
|
onClick={onNewScratchpad}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<Plus className="size-4" />
|
<Plus className="size-4" />
|
||||||
New Session
|
New Scratchpad
|
||||||
</button>
|
</button>
|
||||||
{!hasProjects && (
|
{!hasProjects && (
|
||||||
<button
|
<button
|
||||||
|
|||||||
Reference in New Issue
Block a user