feat: add Makelore Robot hardware module

This commit is contained in:
2026-08-13 23:17:22 +08:00
parent 22add3f01f
commit aba5cae286
25 changed files with 3169 additions and 72 deletions

View File

@@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next';
import { useLocation, useNavigate } from 'react-router-dom';
import {
BarChart3,
Cpu,
ChevronRight,
Crown,
ExternalLink,
@@ -208,7 +209,9 @@ export function Sidebar({ workspaceLayout = false, sidebarPeekOpen = false, onSi
const tokenUsageRequestIdRef = useRef(0);
const navigate = useNavigate();
const location = useLocation();
const isPaintingModule = getAiModuleForPath(location.pathname) === 'painting';
const activeModule = getAiModuleForPath(location.pathname);
const isProgrammingModule = activeModule === 'programming';
const isPaintingModule = activeModule === 'painting';
const projectConfigPath = '/project-config';
const visibleProjects = opencodeProjects;
const selectedProjectFolderName = getFolderName(newProjectSelectedPath);
@@ -237,21 +240,21 @@ export function Sidebar({ workspaceLayout = false, sidebarPeekOpen = false, onSi
const weeklyRefreshLabel = getRefreshTimeLabel(tokenUsageState.usage?.weekly_refresh_at);
useEffect(() => {
if (isPaintingModule) return;
if (!isProgrammingModule) return;
void loadProjectList().catch(() => undefined);
}, [isPaintingModule, loadProjectList]);
}, [isProgrammingModule, loadProjectList]);
useEffect(() => {
if (isPaintingModule) return;
if (!isProgrammingModule) return;
for (const project of visibleProjects) {
void loadProjectConfig(project.id).catch(() => undefined);
}
}, [isPaintingModule, loadProjectConfig, visibleProjects]);
}, [isProgrammingModule, loadProjectConfig, visibleProjects]);
useEffect(() => {
if (isPaintingModule) return;
if (!isProgrammingModule) return;
void refreshProviderSnapshot().catch(() => undefined);
}, [isPaintingModule, refreshProviderSnapshot]);
}, [isProgrammingModule, refreshProviderSnapshot]);
useEffect(() => {
if (!authUser || !profileAccountKey) return;
@@ -648,7 +651,7 @@ export function Sidebar({ workspaceLayout = false, sidebarPeekOpen = false, onSi
<div className="min-h-0 flex-1 overflow-auto px-2 py-2">
{isPaintingModule ? (
<ImageWorkspaceSidebar sidebarCollapsed={sidebarCollapsed} />
) : (
) : isProgrammingModule ? (
<>
<button
type="button"
@@ -732,10 +735,31 @@ export function Sidebar({ workspaceLayout = false, sidebarPeekOpen = false, onSi
) : null}
</div>
</>
) : (
<div data-testid="sidebar-robot-navigation" className="px-2 py-3">
<button
type="button"
aria-label="机器人工作台"
aria-current="page"
onClick={() => navigate('/ai-hardware')}
className={cn(
'flex min-h-10 w-full items-center gap-2 rounded-lg bg-brand-soft px-2 py-2 text-left text-sm font-semibold text-foreground',
sidebarCollapsed && 'justify-center px-0',
)}
>
<Cpu className="h-4 w-4 shrink-0 text-brand" />
{!sidebarCollapsed ? <span>机器人工作台</span> : null}
</button>
{!sidebarCollapsed ? (
<p className="mt-3 px-2 text-xs font-medium leading-5 text-muted-foreground">
管理机器人智能体、设备绑定与配置。
</p>
) : null}
</div>
)}
</div>
{!isPaintingModule && createDialogOpen ? (
{isProgrammingModule && createDialogOpen ? (
<Dialog
open={createDialogOpen}
onOpenChange={(open) => {
@@ -934,7 +958,7 @@ export function Sidebar({ workspaceLayout = false, sidebarPeekOpen = false, onSi
</Dialog>
) : null}
{!isPaintingModule && projectEntryError && typeof document !== 'undefined'
{isProgrammingModule && projectEntryError && typeof document !== 'undefined'
? createPortal(
<div
data-testid="project-config-error-overlay"
@@ -976,7 +1000,7 @@ export function Sidebar({ workspaceLayout = false, sidebarPeekOpen = false, onSi
)
: null}
{!isPaintingModule ? (
{isProgrammingModule ? (
<ConfirmDialog
open={Boolean(removeProjectCandidate)}
title={`移除项目“${removeProjectCandidate?.name ?? ''}”?`}