fix: move Code return navigation into the chat sidebar
This commit is contained in:
1 parent
a77ddbd681
commit
10b179fb71
4 files changed
+104
-6
No files matched your search
@@ -0,0 +1,46 @@
|
||||
# Task: Move Code return navigation into the coding workspace
|
||||
|
||||
## Identity
|
||||
|
||||
- Task ID: 20260929-code-back-entry-33d87a81
|
||||
- Mode: Feature
|
||||
- Branch: codex/20260929-code-back-entry-33d87a81-code-back-entry
|
||||
- Worktree: /Users/chillishark/Makelore 麦洛/.codex-worktrees/makelore/20260929-empty-work-merge-39c633d0
|
||||
- Base commit: a77ddbd6813bb71d490544edfef6e1f35240070f
|
||||
- Owner: codex
|
||||
- Status: Ready for Integration
|
||||
|
||||
## Scope
|
||||
|
||||
- Move the existing “编程 Code” module-home return entry from the project configuration sidebar into the Coding chat/workspace sidebar below the brand. Retain its `/module-select` target and the configuration page's own back action.
|
||||
|
||||
## Intent And Constraints
|
||||
|
||||
- User first requested understanding only, confirmed the two-page interpretation, then explicitly approved implementation. Preserve existing light styling, projects, conversation drafts/history, module access and other module navigation. No live-app update, merge, push or deployment is requested for this new change.
|
||||
- Reused the clean, completed prior merge checkout after releasing its ready task ownership; old branch/commits remain. Created a new branch at current main a77ddbd, then successfully claimed this new task and verified exact task/mode/worktree/branch/base/reservation. No source from occupied foreign worktrees adopted.
|
||||
|
||||
## Project Context Loaded
|
||||
|
||||
- Task identity: as above, feature mode; ownership verified. Read active task and entry/memory index. Previously loaded positioning, current-state, decision-index, teacher ADR, architecture/domain, evidence, commitments and stale items are unchanged from 5aabaaf, verified by Git diff. Current AGENTS still requires existing light system, local project state and Main-owned APIs.
|
||||
- Product/context: current main includes empty-work behavior, teacher voice/model controls and compact published shortcuts. This is a small navigation relocation within the existing sidebar; no new visual system is needed. Inspected screenshots, Sidebar, ModuleSwitcher, MainLayout, module route definitions, layout CSS and existing navigation tests.
|
||||
- Peer scopes reviewed read-only. Active teacher-group-intro and child-language tasks have undefined scope, so coordination context is unknown; neither supplies a known dependency on module-return navigation. Existing teacher/UI tasks are ready. This task owns Sidebar navigation plus focused test/README updates only; no shared canonical docs.
|
||||
- Relevant behavior: original “编程 Code” ModuleSwitcher navigates to `/module-select`, not a project reset. `/chat` uses the classroom sidebar; project configuration and nested resource pages use the generic sidebar. Retain the original target as the user confirmed.
|
||||
- Gate: Passed. Plan: show the existing module-return control below the Code workspace brand, omit it on `/project-config` and nested configuration routes, keep a compact accessible layout, adjust the existing navigation regression, run typecheck/lint/build and focused UI verification, review and commit.
|
||||
|
||||
## Outcome
|
||||
|
||||
- Reused the existing ModuleSwitcher beneath the brand in the `/chat` sidebar, retaining its compact arrow/text style, accessible return-home label and `/module-select` action. Project configuration and nested resource pages omit the entire sidebar header block, so no empty placeholder remains. Existing configuration back action, sidebar resizing/peek and other module controls are unchanged. README synchronized.
|
||||
|
||||
## Verification
|
||||
|
||||
- pnpm 10.33.4 standard typecheck, changed-file ESLint and production Renderer/Main/Preload/utility build passed. Existing sidebar/peek/module gate and module-navigation unit coverage: 23 tests across four files passed.
|
||||
- Extended one existing navigation scenario; isolated Electron E2E 1/1 passed. It checks Code return beneath the brand, no sidebar entry on configuration or plugin subpage, configuration back to chat, and collapsed-sidebar hover followed by real navigation to `/module-select`. Used an independent test profile/ports; no real user application or conversations were changed. Test command: `corepack pnpm exec playwright test tests/e2e/main-navigation.spec.ts --grep 'opens remembered Code projects' --reporter=list`.
|
||||
- Inspected chat and configuration screenshots; delegated review also checked collapsed peek. Artifacts are under `test-results/main-navigation-Makelore-m-9ce56-instead-of-project-settings/`. Independent code review passed; no additional regression found. Whitespace and task-doc drift checks passed.
|
||||
|
||||
## Follow-ups
|
||||
|
||||
- Source is ready for integration. Main, remote and the running temporary app were not updated by this new task.
|
||||
|
||||
## Promotion Candidates
|
||||
|
||||
- Target: canonical classroom navigation when next integrated. Proposal: Code module-home return is visible below the chat sidebar brand and omitted from project configuration/resource sidebars; original configuration back remains. Evidence: explicit user confirmation, existing component reuse, actual Electron navigation and screenshots. No architecture or module-target change; no further product confirmation required.
|
||||
@@ -31,7 +31,7 @@ Makelore 是一个面向软件、视觉创作、智能机器人与个人云智
|
||||
- macOS 窗口按钮:红色关闭当前窗口,全屏时先退出全屏再关闭;黄色最小化,绿色保留原生缩放/全屏行为。关窗后应用和进行中的后台任务继续运行,点击 Dock、托盘或菜单可重新打开窗口;`Cmd+Q` 退出应用。
|
||||
- 桌面文本右键菜单:主 Renderer 窗口由 Electron Main 提供原生“剪切、复制、粘贴、全选”操作;菜单只在可编辑区域或已有文本选择时出现,普通空白区域不显示,也不向 Renderer 暴露剪贴板 IPC。
|
||||
- AI 编程核心对话运行时:Electron Main 按需启动一个长驻 Pi Agent Server,同一进程内为每条 Conversation 建立独立的 Runtime、Session、凭证视图、扩展上下文和 JSONL 通道,同时复用 Pi 模块与进程启动成本;Server 异常退出时所有旧通道统一失效,下一次恢复只重启一个 Server。正式包中的 Agent Server 从明确传入的 `resources/pi-runtime` 根定位依赖清单与包入口,不从脚本所在目录或应用 `node_modules` 猜测解析。Renderer 不直接启动或调用 Pi,也不读取其 wire 类型。项目与 Conversation 元数据先从本地读取,选中对话后才按需准备对应逻辑线程;输入框不等待运行时准备完成。同一助手工具批次中,会取得项目写租约的 `bash`、`edit`、`write` 与动态产品工具按顺序执行,避免批次在命令启动前自锁;纯只读工具仍可并行。子 Agent 仍使用独立的短生命周期进程,以保留并发配额、故障和写入边界;macOS 上两类后台进程都使用 Electron 自带的 Helper,不在 Dock 中创建额外应用图标。
|
||||
- AI 编程默认入口:进入 Code 后保持在 `/chat`。尚未选择本地项目时,页面以麦洛 M 标识和居中引导语建立焦点,下方提供独立的“新增项目”主操作以及可横向浏览、直接进入的已有项目卡片;项目创建和进入仍复用侧栏现有流程。已有项目的新 Conversation 在可编辑 Composer 上方沿用同一品牌引导,第一条消息出现后切换为正常时间线。
|
||||
- AI 编程默认入口:进入 Code 后保持在 `/chat`。左侧麦洛品牌区下方提供“← 编程 Code”按钮,点击返回模块选择首页;项目配置及其资源子页不再重复显示此侧栏入口,保留配置页自身的返回操作。尚未选择本地项目时,页面以麦洛 M 标识和居中引导语建立焦点,下方提供独立的“新增项目”主操作以及可横向浏览、直接进入的已有项目卡片;项目创建和进入仍复用侧栏现有流程。已有项目的新 Conversation 在可编辑 Composer 上方沿用同一品牌引导,第一条消息出现后切换为正常时间线。
|
||||
- AI 编程历史与配额反馈:Pi 上下文压缩不删除用户可见的 active-branch 历史,压缩摘要保持 Main-private;Renderer 首次渲染最近 120 个节点,向上滚动时按 100 个节点追加更早内容并保持阅读位置。Main 精确识别 `token_point_balance_exhausted` / `词元点数余额不足`,只向 Renderer 投影不可重试的稳定配额错误和安全中文提示,重开会话后仍可见且不暴露上游原始错误或 request id。
|
||||
- 账号词元点数:左下角账户菜单显示本人永久余额和预占,提供充值、充值订单与分页收支记录。真正新注册赠送 100 点,1 元充值 50 点,永久有效;旧账户不补送,旧会员/订阅/周额度/重置卡入口已移除。家长充值始终进入自己的钱包,青少年可查看自己的精确余额;使用他人共享钱包时仅显示可用状态,不显示付款人的余额或记录。Main 持有凭据并转发充值请求;付款结果未知时沿用原请求并核查原订单,只有服务端确认才显示到账。扫码信息缺失时可到网页账户页继续原订单,付款来源也由网页账户页管理。需配套部署 Works Square 永久点数 API 与 0094 迁移;本地模拟验收不代表真实支付通过。
|
||||
- 桌面性能策略:应用窗口使用不透明浅色表面并默认保留硬件合成;仅在显式安全模式或短时间内重复 GPU 进程崩溃时启用软件渲染,并把故障原因保存在用户数据目录。启动关键路径只创建本地应用壳,认证、代理、同步、更新和遥测在首帧后延迟初始化;开发版可通过 `app:performance` 快照观察 GPU、进程、WebContents、事件循环与 Renderer Long Task 聚合指标。
|
||||
|
||||
@@ -133,6 +133,7 @@ export function Sidebar({
|
||||
const isProgrammingModule = activeModule === 'programming';
|
||||
const isPaintingModule = activeModule === 'painting';
|
||||
const isRobotModule = activeModule === 'robot';
|
||||
const isProjectConfigPage = location.pathname === '/project-config' || location.pathname.startsWith('/project-config/');
|
||||
const visibleProjects = projects;
|
||||
const selectedProjectFolderName = getFolderName(newProjectSelectedPath);
|
||||
const accountName = userProfile?.displayName?.trim() || getAuthUserDisplayName(authUser) || '未登录用户';
|
||||
@@ -403,7 +404,7 @@ export function Sidebar({
|
||||
)}
|
||||
>
|
||||
{workspaceLayout && !sidebarPinnedCollapsed && <ClassroomSidebarResizer />}
|
||||
<div
|
||||
{!isProjectConfigPage && <div
|
||||
className={cn(
|
||||
'bg-transparent px-3 text-foreground',
|
||||
isPaintingModule && !sidebarCollapsed ? 'pb-2 pt-10' : 'py-2',
|
||||
@@ -411,12 +412,13 @@ export function Sidebar({
|
||||
)}
|
||||
>
|
||||
<div className="min-w-0 w-full">
|
||||
{workspaceLayout ? <button type="button" aria-label="返回首页" title="返回首页" onClick={() => navigate('/module-select')} className="classroom-brand flex w-full items-center gap-2 rounded-lg text-left">
|
||||
{workspaceLayout && <button type="button" aria-label="返回首页" title="返回首页" onClick={() => navigate('/module-select')} className="classroom-brand flex w-full items-center gap-2 rounded-lg text-left">
|
||||
<span className="classroom-brand-mark"><img src={classroomMark} alt="" className="h-7 w-7" /></span>
|
||||
<span className="min-w-0"><span className="block text-base font-semibold tracking-tight">麦洛</span><span className="classroom-brand-caption">把脑洞变成作品</span></span>
|
||||
</button> : <ModuleSwitcher sidebarCollapsed={sidebarCollapsed} compact={!sidebarCollapsed} />}
|
||||
</button>}
|
||||
<ModuleSwitcher sidebarCollapsed={sidebarCollapsed} compact={!sidebarCollapsed} />
|
||||
</div>
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
<div className="classroom-sidebar-content min-h-0 flex-1 overflow-auto px-2 py-2">
|
||||
{isPaintingModule ? (
|
||||
|
||||
@@ -50,7 +50,7 @@ async function seedInactiveCodingProjects(resources: { rootDir: string; userData
|
||||
}
|
||||
|
||||
test.describe('Makelore module navigation without setup flow', () => {
|
||||
test('offers a create CTA and horizontal cards for remembered inactive Code projects', async ({
|
||||
test('opens remembered Code projects and keeps the module return entry in chat instead of project settings', async ({
|
||||
electronTestResources,
|
||||
launchElectronApp,
|
||||
}) => {
|
||||
@@ -76,6 +76,56 @@ test.describe('Makelore module navigation without setup flow', () => {
|
||||
await expect(page.getByTestId('coding-chat-panel')).toBeVisible();
|
||||
await expect(page.getByTestId('coding-existing-projects')).toHaveCount(0);
|
||||
await expect(page.getByTestId('sidebar-course-project-project-storybook')).toHaveAttribute('aria-current', 'page');
|
||||
|
||||
const sidebar = page.getByTestId('sidebar');
|
||||
const moduleReturn = sidebar.getByTestId('sidebar-module-switcher-trigger');
|
||||
await expect(moduleReturn).toBeVisible();
|
||||
await expect(moduleReturn).toContainText('编程 Code');
|
||||
await expect(moduleReturn).toHaveAttribute('aria-label', '返回首页');
|
||||
await expect(sidebar.getByTestId('sidebar-module-return-icon')).toBeVisible();
|
||||
await expect(moduleReturn).toHaveCSS('padding-top', '8px');
|
||||
const brandBox = await sidebar.locator('.classroom-brand').boundingBox();
|
||||
const returnBox = await moduleReturn.boundingBox();
|
||||
expect(brandBox).not.toBeNull();
|
||||
expect(returnBox).not.toBeNull();
|
||||
expect(returnBox!.y).toBeGreaterThanOrEqual(brandBox!.y + brandBox!.height);
|
||||
await page.screenshot({ path: test.info().outputPath('chat-code-return-entry.png') });
|
||||
|
||||
await sidebar.getByRole('button', { name: '项目设置', exact: true }).click();
|
||||
await expect(page).toHaveURL(/\/project-config$/);
|
||||
await expect(page.getByTestId('project-configuration-page')).toBeVisible();
|
||||
await expect(sidebar.getByTestId('sidebar-module-switcher')).toHaveCount(0);
|
||||
const projectBack = page.getByTestId('project-configuration-back-button');
|
||||
await expect(projectBack).toBeVisible();
|
||||
await page.screenshot({ path: test.info().outputPath('project-config-without-module-return.png') });
|
||||
await projectBack.click();
|
||||
await expect(page).toHaveURL(/\/chat$/);
|
||||
await expect(moduleReturn).toBeVisible();
|
||||
|
||||
await sidebar.getByRole('button', { name: '项目设置', exact: true }).click();
|
||||
await page.getByTestId('resource-card-plugins').click();
|
||||
await expect(page).toHaveURL(/\/project-config\/plugins\?/);
|
||||
const plugins = page.getByTestId('project-plugins-sheet');
|
||||
await expect(plugins).toBeVisible();
|
||||
await expect(sidebar.getByTestId('sidebar-module-switcher')).toHaveCount(0);
|
||||
await page.screenshot({ path: test.info().outputPath('project-config-plugins-without-module-return.png') });
|
||||
await plugins.getByRole('button', { name: '关闭', exact: true }).click();
|
||||
await expect(page).toHaveURL(/\/project-config$/);
|
||||
await expect(projectBack).toBeVisible();
|
||||
await sidebar.getByTestId('sidebar-course-project-project-storybook').click();
|
||||
await expect(page).toHaveURL(/\/chat$/);
|
||||
|
||||
const sidebarToggle = page.getByTestId('titlebar-sidebar-toggle');
|
||||
await sidebarToggle.click();
|
||||
await page.getByTestId('coding-chat-panel').click({ position: { x: 500, y: 200 } });
|
||||
await expect(sidebar).toHaveAttribute('aria-hidden', 'true');
|
||||
await sidebarToggle.hover();
|
||||
await expect(sidebar).toHaveAttribute('aria-hidden', 'false');
|
||||
await expect(moduleReturn).toBeVisible();
|
||||
await page.screenshot({ path: test.info().outputPath('chat-collapsed-hover-code-return.png') });
|
||||
await moduleReturn.click();
|
||||
await expect(page).toHaveURL(/\/module-select$/);
|
||||
await expect(page.getByTestId('ai-module-selection-page')).toBeVisible();
|
||||
} finally {
|
||||
await closeElectronApp(app);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user