workspaces to dashboards, imap email sync, ffmpeg tool, tts fix, file browser refresh, automation sidebar reorder

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-02 20:00:45 +00:00
co-authored by Claude Opus 4.6
parent bd362dc586
commit 927267e041
98 changed files with 1176 additions and 802 deletions
@@ -0,0 +1,25 @@
import { useParams, Navigate } from 'react-router';
import { useDashboardState } from 'state/useDashboardState';
import type { LayoutNode, DashboardDefinition } from 'officerdev';
import { WorkspaceView, createDefaultLayout } from 'officerdev';
export const DashboardScreen = () => {
const { id } = useParams<{ id: string }>();
const { value: dashboards, isLoaded } = useDashboardState<DashboardDefinition[]>('workspaces', []);
const ws = dashboards.find((w) => w.id === id);
if (!isLoaded) return null;
if (!ws) return <Navigate to="/dashboards" replace />;
return <DashboardScreenInner dashboard={ws} />;
};
const DashboardScreenInner = ({ dashboard }: { dashboard: DashboardDefinition }) => {
const wsState = useDashboardState<LayoutNode>(`ws-layout-${dashboard.id}`, createDefaultLayout());
return (
<div className="h-full w-full">
<WorkspaceView workspace={wsState} cwd={dashboard.cwd} root={dashboard.root} />
</div>
);
};
@@ -0,0 +1,26 @@
import type { LayoutNode } from 'officerdev';
import { WorkspaceView, SELECTED_DASHBOARD_KEY } from 'officerdev';
import { useIsMobile } from 'hooks/useIsMobile';
import { useGlobal } from 'hooks/useGlobal';
import { useDashboardState } from 'state/useDashboardState';
import { defaultLayout } from './defaultLayout';
export const DashboardsScreen = () => {
const workspace = useDashboardState<LayoutNode>('screens/dashboards', defaultLayout);
const isMobile = useIsMobile();
const [selected, setSelected] = useGlobal<string | null>(SELECTED_DASHBOARD_KEY, null);
const mobilePanelId = isMobile && selected ? 'ws-home-right' : undefined;
return (
<div className="h-full w-full">
<WorkspaceView
workspace={workspace}
locked
mobilePanelId={mobilePanelId}
onMobilePanelChange={(id) => {
if (!id) setSelected(null);
}}
/>
</div>
);
};
@@ -0,0 +1,11 @@
import type { LayoutNode } from 'officerdev';
export const defaultLayout: LayoutNode = {
type: 'group',
id: 'ws-home-root',
direction: 'horizontal',
children: [
{ node: { type: 'panel', id: 'ws-home-list', appType: 'dashboard-list' }, size: 50 },
{ node: { type: 'panel', id: 'ws-home-right', appType: 'dashboard-preview' }, size: 50 },
],
};
@@ -0,0 +1,2 @@
export { DashboardsScreen } from './DashboardsScreen';
export { DashboardScreen } from './DashboardScreen';