diff --git a/bun.lock b/bun.lock
index 9a31afca..97946082 100644
--- a/bun.lock
+++ b/bun.lock
@@ -101,6 +101,7 @@
"shiki": "^3.22.0",
"sonner": "^2.0.7",
"sounds": "workspace:*",
+ "state": "workspace:*",
"tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7",
"three": "^0.182.0",
@@ -245,6 +246,7 @@
"version": "0.0.1",
"dependencies": {
"hooks": "workspace:*",
+ "state": "workspace:*",
"widgets": "workspace:*",
},
},
@@ -252,6 +254,14 @@
"name": "sounds",
"version": "1.0.0",
},
+ "src/workspaces/state": {
+ "name": "state",
+ "version": "0.0.1",
+ "dependencies": {
+ "hooks": "workspace:*",
+ "officerdev": "workspace:*",
+ },
+ },
"src/workspaces/types": {
"name": "types",
"version": "0.0.1",
@@ -1989,6 +1999,8 @@
"split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
+ "state": ["state@workspace:src/workspaces/state"],
+
"state-local": ["state-local@1.0.7", "", {}, "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w=="],
"stats-gl": ["stats-gl@2.4.2", "", { "dependencies": { "@types/three": "*", "three": "^0.170.0" } }, "sha512-g5O9B0hm9CvnM36+v7SFl39T7hmAlv541tU81ME8YeSb3i1CIP5/QdDeSB3A0la0bKNHpxpwxOVRo2wFTYEosQ=="],
diff --git a/package.json b/package.json
index 8d055704..7d3ddab7 100644
--- a/package.json
+++ b/package.json
@@ -119,6 +119,7 @@
"shiki": "^3.22.0",
"sonner": "^2.0.7",
"sounds": "workspace:*",
+ "state": "workspace:*",
"tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7",
"three": "^0.182.0",
diff --git a/src/apps/officer-web/App.tsx b/src/apps/officer-web/App.tsx
index 5d6df1f7..78fc74e6 100644
--- a/src/apps/officer-web/App.tsx
+++ b/src/apps/officer-web/App.tsx
@@ -2,7 +2,7 @@ import { BrowserRouter, Routes, Route, Navigate } from 'react-router';
import * as Authentication from './Screens/Authentication';
import * as Dashboard from './Screens/Dashboard';
import { useAuth } from 'hooks/useAuth';
-import { useServerSettings } from '@/state/useServerSettings';
+import { useServerSettings } from 'state/useServerSettings';
import { useInitialData } from '@/state/useInitialData';
export function App() {
@@ -51,9 +51,7 @@ export function App() {
} />
} />
} />
- } />
- } />
- } />
+ } />
} />
} />
} />
diff --git a/src/apps/officer-web/Screens/Authentication/LandingPage/LandingPage.tsx b/src/apps/officer-web/Screens/Authentication/LandingPage/LandingPage.tsx
index f23e21e9..f127f72f 100644
--- a/src/apps/officer-web/Screens/Authentication/LandingPage/LandingPage.tsx
+++ b/src/apps/officer-web/Screens/Authentication/LandingPage/LandingPage.tsx
@@ -1,5 +1,5 @@
import { OfficerSvgLogo } from '@/components/Logos';
-import { useLandingPage } from '@/state/useLandingPage';
+import { useLandingPage } from 'state/useLandingPage';
import { Bootstrap } from './Bootstrap';
import { Login } from './Login';
diff --git a/src/apps/officer-web/Screens/Dashboard/Automation/index.tsx b/src/apps/officer-web/Screens/Dashboard/Automation/index.tsx
index 2b76cca3..e267878c 100644
--- a/src/apps/officer-web/Screens/Dashboard/Automation/index.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Automation/index.tsx
@@ -5,8 +5,8 @@ import { useAuth } from 'hooks/useAuth';
import { usePanelChannel } from 'hooks/usePanelChannel';
import type { LayoutNode, PanelComponents } from '@/components/Workspace';
import { WorkspaceLayout } from '@/components/Workspace';
-import { useUserState } from '@/state/useUserState';
-import { appRegistry } from '../Workspaces/app-registry';
+import { useUserState } from 'state/useUserState';
+
import { AutomationRightPanel } from './AutomationRightPanel';
import type { AutomationSelection } from './AutomationRightPanel';
import { AutomationEditChat } from './AutomationEditChat';
@@ -98,7 +98,7 @@ export const Automation = () => {
return (
-
+
);
};
diff --git a/src/apps/officer-web/Screens/Dashboard/ChatHistory/ChatDetailPanel.tsx b/src/apps/officer-web/Screens/Dashboard/ChatHistory/ChatDetailPanel.tsx
index e0538ec3..fbe8ecb3 100644
--- a/src/apps/officer-web/Screens/Dashboard/ChatHistory/ChatDetailPanel.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/ChatHistory/ChatDetailPanel.tsx
@@ -2,7 +2,7 @@ import { useEffect } from 'react';
import { useLocation } from 'react-router';
import { Trash2 } from 'lucide-react';
import { usePanelChannel } from 'hooks/usePanelChannel';
-import { useChatSessions } from '@/state/useChatSessions';
+import { useChatSessions } from 'state/useChatSessions';
import { usePiChat, EmbeddableChat } from 'officerdev';
export type SelectedSession = {
diff --git a/src/apps/officer-web/Screens/Dashboard/ChatHistory/CreateGroupDialog.tsx b/src/apps/officer-web/Screens/Dashboard/ChatHistory/CreateGroupDialog.tsx
index 5ae11530..be2349b5 100644
--- a/src/apps/officer-web/Screens/Dashboard/ChatHistory/CreateGroupDialog.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/ChatHistory/CreateGroupDialog.tsx
@@ -1,6 +1,6 @@
import { useState } from 'react';
import { X } from 'lucide-react';
-import { useChatGroups } from '@/state/useChatGroups';
+import { useChatGroups } from 'state/useChatGroups';
type CreateGroupDialogProps = {
onClose: () => void;
diff --git a/src/apps/officer-web/Screens/Dashboard/ChatHistory/GroupContextMenu.tsx b/src/apps/officer-web/Screens/Dashboard/ChatHistory/GroupContextMenu.tsx
index 688ed08b..e9be9384 100644
--- a/src/apps/officer-web/Screens/Dashboard/ChatHistory/GroupContextMenu.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/ChatHistory/GroupContextMenu.tsx
@@ -1,6 +1,6 @@
import { useState } from 'react';
import { MoreVertical, Edit2, Trash2 } from 'lucide-react';
-import { useChatGroups } from '@/state/useChatGroups';
+import { useChatGroups } from 'state/useChatGroups';
import type { GroupEntry } from 'officerdev';
type GroupContextMenuProps = {
diff --git a/src/apps/officer-web/Screens/Dashboard/ChatHistory/Screen.tsx b/src/apps/officer-web/Screens/Dashboard/ChatHistory/Screen.tsx
index db5c7eb1..4caff5f9 100644
--- a/src/apps/officer-web/Screens/Dashboard/ChatHistory/Screen.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/ChatHistory/Screen.tsx
@@ -1,8 +1,8 @@
import { useEffect, useRef, useCallback, useState } from 'react';
import { Plus, MessageSquare, Folder, ChevronRight, FolderPlus } from 'lucide-react';
import { usePanelChannel } from 'hooks/usePanelChannel';
-import { useChatSessions } from '@/state/useChatSessions';
-import { useChatGroups } from '@/state/useChatGroups';
+import { useChatSessions } from 'state/useChatSessions';
+import { useChatGroups } from 'state/useChatGroups';
import type { SelectedSession } from './ChatDetailPanel';
import { CreateGroupDialog } from './CreateGroupDialog';
import { GroupContextMenu } from './GroupContextMenu';
diff --git a/src/apps/officer-web/Screens/Dashboard/ChatHistory/SessionContextMenu.tsx b/src/apps/officer-web/Screens/Dashboard/ChatHistory/SessionContextMenu.tsx
index c9161d0c..5665c2d5 100644
--- a/src/apps/officer-web/Screens/Dashboard/ChatHistory/SessionContextMenu.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/ChatHistory/SessionContextMenu.tsx
@@ -1,7 +1,7 @@
import { useState } from 'react';
import { MoreVertical, FolderInput, Edit2, Trash2 } from 'lucide-react';
-import { useChatGroups } from '@/state/useChatGroups';
-import { useChatSessions } from '@/state/useChatSessions';
+import { useChatGroups } from 'state/useChatGroups';
+import { useChatSessions } from 'state/useChatSessions';
import type { SessionEntry } from 'officerdev';
type SessionContextMenuProps = {
diff --git a/src/apps/officer-web/Screens/Dashboard/ChatHistory/Widget.tsx b/src/apps/officer-web/Screens/Dashboard/ChatHistory/Widget.tsx
index 674977d2..ca45633c 100644
--- a/src/apps/officer-web/Screens/Dashboard/ChatHistory/Widget.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/ChatHistory/Widget.tsx
@@ -1,7 +1,7 @@
import { Link } from 'react-router';
import { MessageSquare, Trash2 } from 'lucide-react';
import { Widget } from 'widgets/Widget';
-import { useChatSessions } from '@/state/useChatSessions';
+import { useChatSessions } from 'state/useChatSessions';
export const ChatHistory = () => {
const { sessions, deleteSession } = useChatSessions();
diff --git a/src/apps/officer-web/Screens/Dashboard/ChatHistory/index.tsx b/src/apps/officer-web/Screens/Dashboard/ChatHistory/index.tsx
index 3a99c5b3..e2222060 100644
--- a/src/apps/officer-web/Screens/Dashboard/ChatHistory/index.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/ChatHistory/index.tsx
@@ -3,8 +3,8 @@ import { useParams } from 'react-router';
import type { LayoutNode, PanelComponents } from '@/components/Workspace';
import { WorkspaceLayout } from '@/components/Workspace';
import { usePanelChannel } from 'hooks/usePanelChannel';
-import { useChatSessions } from '@/state/useChatSessions';
-import { appRegistry } from '../Workspaces/app-registry';
+import { useChatSessions } from 'state/useChatSessions';
+
import { SessionList } from './Screen';
import { ChatDetailPanel, type SelectedSession } from './ChatDetailPanel';
@@ -50,7 +50,7 @@ export const SessionListPage = ({ isNew }: SessionListPageProps) => {
return (
- {}} registry={appRegistry} components={panelComponents} />
+ {}} components={panelComponents} />
);
};
diff --git a/src/apps/officer-web/Screens/Dashboard/ChatScreen/ChatScreen.tsx b/src/apps/officer-web/Screens/Dashboard/ChatScreen/ChatScreen.tsx
index 5aeb7492..5ebf205e 100644
--- a/src/apps/officer-web/Screens/Dashboard/ChatScreen/ChatScreen.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/ChatScreen/ChatScreen.tsx
@@ -1,6 +1,6 @@
import { useRef, useEffect, useState } from 'react';
import { useNavigate, useLocation } from 'react-router';
-import { useChatSessions } from '@/state/useChatSessions';
+import { useChatSessions } from 'state/useChatSessions';
import { SessionBar, EmbeddableChat, type UsePiChatType, type Attachment } from 'officerdev';
import { Card } from '@/components/Card';
diff --git a/src/apps/officer-web/Screens/Dashboard/Files/FilesScreen.tsx b/src/apps/officer-web/Screens/Dashboard/Files/FilesScreen.tsx
index 5f740980..cc227cf1 100644
--- a/src/apps/officer-web/Screens/Dashboard/Files/FilesScreen.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Files/FilesScreen.tsx
@@ -1,8 +1,7 @@
import type { LayoutNode } from '@/components/Workspace';
import { WorkspaceView } from '@/components/Workspace';
-import { useWorkspacesState } from '@/state/useWorkspacesState';
+import { useWorkspacesState } from 'state/useWorkspacesState';
import { useFileViewerPanels } from 'officerdev';
-import { appRegistry } from '../Workspaces/app-registry';
import { defaultLayout } from './defaultLayout';
export const FilesScreen = () => {
@@ -11,7 +10,7 @@ export const FilesScreen = () => {
return (
-
+
);
};
diff --git a/src/apps/officer-web/Screens/Dashboard/Files/defaultLayout.ts b/src/apps/officer-web/Screens/Dashboard/Files/defaultLayout.ts
index a5dd3d4d..8981a693 100644
--- a/src/apps/officer-web/Screens/Dashboard/Files/defaultLayout.ts
+++ b/src/apps/officer-web/Screens/Dashboard/Files/defaultLayout.ts
@@ -3,5 +3,5 @@ import type { LayoutNode } from '@/components/Workspace';
export const defaultLayout: LayoutNode = {
type: 'panel',
id: 'files-main',
- appType: 'file-browser',
+ appType: 'officerdev/file-browser',
};
diff --git a/src/apps/officer-web/Screens/Dashboard/Home/HomeScreen.tsx b/src/apps/officer-web/Screens/Dashboard/Home/HomeScreen.tsx
index 5cf67f49..9805d538 100644
--- a/src/apps/officer-web/Screens/Dashboard/Home/HomeScreen.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Home/HomeScreen.tsx
@@ -1,6 +1,6 @@
+import type { LayoutNode } from '@/components/Workspace';
import { WorkspaceView } from '@/components/Workspace';
-import { useWorkspacesState } from '@/state/useWorkspacesState';
-import { appRegistry } from '../Workspaces/app-registry';
+import { useWorkspacesState } from 'state/useWorkspacesState';
import { defaultLayout } from './defaultLayout';
export const HomeScreen = () => {
@@ -8,8 +8,7 @@ export const HomeScreen = () => {
return (
-
+
);
};
-
diff --git a/src/apps/officer-web/Screens/Dashboard/Layout/Dock.tsx b/src/apps/officer-web/Screens/Dashboard/Layout/Dock.tsx
index cf94d577..f3c037b4 100644
--- a/src/apps/officer-web/Screens/Dashboard/Layout/Dock.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Layout/Dock.tsx
@@ -120,7 +120,7 @@ export const dockItems: DockItem[] = [
{ label: 'Plans', to: '/plans', icon: FileText, color: '#f472b6' },
{ label: 'Automation', to: '/automation', icon: Bot, color: '#2dd4bf' },
{ label: 'Logs', to: '/task-logs', icon: ScrollText, color: '#94a3b8' },
- { label: 'Terminal', to: '/terminal', icon: Monitor, color: '#f97316', role: 'Super Admin' },
+ { label: 'Terminal', to: '/terminal', icon: Monitor, color: '#f97316' },
{ label: 'Projects', to: '/projects', icon: FolderKanban, color: '#10b981' },
{ label: 'Workspaces', to: '/workspaces', icon: LayoutGrid, color: '#8b5cf6' },
];
diff --git a/src/apps/officer-web/Screens/Dashboard/Layout/Header/UserMenu.tsx b/src/apps/officer-web/Screens/Dashboard/Layout/Header/UserMenu.tsx
index 51756f44..c08e011d 100644
--- a/src/apps/officer-web/Screens/Dashboard/Layout/Header/UserMenu.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Layout/Header/UserMenu.tsx
@@ -5,7 +5,7 @@ import { User, LogOut, Settings, Package, Sun, Moon } from 'lucide-react';
import { useAuth } from 'hooks/useAuth';
import { useTranslation } from '@/lib/i18n';
import { useColorMode } from '@/components/ui/ThemeProvider';
-import { useSettings } from '@/state/useSettings';
+import { useSettings } from 'state/useSettings';
const { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } = Dropdown;
diff --git a/src/apps/officer-web/Screens/Dashboard/OnboardingAdmin/index.tsx b/src/apps/officer-web/Screens/Dashboard/OnboardingAdmin/index.tsx
index bd3e7781..d586469a 100644
--- a/src/apps/officer-web/Screens/Dashboard/OnboardingAdmin/index.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/OnboardingAdmin/index.tsx
@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react';
-import { useServerSettings } from '@/state/useServerSettings';
+import { useServerSettings } from 'state/useServerSettings';
import { ServerTypeCard } from './ServerTypeCard';
import { AIHarnessesCard } from './AIHarnessesCard';
diff --git a/src/apps/officer-web/Screens/Dashboard/Projects/ProjectListApp.tsx b/src/apps/officer-web/Screens/Dashboard/Projects/ProjectListApp.tsx
index 955b4938..aa04981d 100644
--- a/src/apps/officer-web/Screens/Dashboard/Projects/ProjectListApp.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Projects/ProjectListApp.tsx
@@ -5,7 +5,7 @@ import { useQueryClient } from '@tanstack/react-query';
import { useGlobal } from 'hooks/useGlobal';
import { useClient } from 'hooks/useClient';
import { generateSlug } from 'helpers/slug';
-import { useProjectsState } from '@/state/useProjectsState';
+import { useProjectsState } from 'state/useProjectsState';
import type { ProjectDefinition, ProjectType } from '@/components/Workspace';
import {
AlertDialog,
diff --git a/src/apps/officer-web/Screens/Dashboard/Projects/ProjectListScreen.tsx b/src/apps/officer-web/Screens/Dashboard/Projects/ProjectListScreen.tsx
index b8c07988..a7aeb758 100644
--- a/src/apps/officer-web/Screens/Dashboard/Projects/ProjectListScreen.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Projects/ProjectListScreen.tsx
@@ -4,12 +4,12 @@ import { FolderKanban, Plus, ArrowRight, Type, Rocket, FileText, Layout } from '
import { useQueryClient } from '@tanstack/react-query';
import { useGlobal } from 'hooks/useGlobal';
import { useClient } from 'hooks/useClient';
-import { useProjectsState } from '@/state/useProjectsState';
+import { useProjectsState } from 'state/useProjectsState';
import { WorkspaceLayout, WorkspaceView, createDefaultLayout } from '@/components/Workspace';
import type { LayoutNode, ProjectDefinition, ProjectType } from '@/components/Workspace';
import { Button } from '@/components/ui/button';
import { generateSlug, slugify } from 'helpers/slug';
-import { appRegistry } from '../Workspaces/app-registry';
+import { useAppRegistry } from 'officerdev';
import {
SELECTED_PROJECT,
CREATING_PROJECT,
@@ -482,7 +482,7 @@ const TemplatePreviewInner = ({ templateIdx }: { templateIdx: number }) => {
queryClient.setQueryData(PREVIEW_LAYOUT_KEY, next);
};
- return ;
+ return ;
};
const TemplatePreviewPanel = () => {
@@ -524,17 +524,18 @@ const newProjLayout: LayoutNode = {
],
};
-const newProjRegistry = {
- ...appRegistry,
- 'new-proj-details': { name: 'Details', icon: Type, component: DetailsPanel },
- 'new-proj-placeholder': { name: 'Preview', icon: Layout, component: TemplatePreviewPanel },
- 'new-proj-template': { name: 'Template', icon: Layout, component: TemplatePanel },
- 'new-proj-create': { name: 'Create', icon: Rocket, component: CreatePanel },
-};
+const NewProjectForm = () => {
+ const { registry } = useAppRegistry();
+ const newProjRegistry = {
+ ...registry,
+ 'new-proj-details': { name: 'Details', icon: Type, component: DetailsPanel },
+ 'new-proj-placeholder': { name: 'Preview', icon: Layout, component: TemplatePreviewPanel },
+ 'new-proj-template': { name: 'Template', icon: Layout, component: TemplatePanel },
+ 'new-proj-create': { name: 'Create', icon: Rocket, component: CreatePanel },
+ };
-const NewProjectForm = () => (
- {}} registry={newProjRegistry} />
-);
+ return {}} registry={newProjRegistry} />;
+};
const ProjectPreviewEmpty = () => {
const [creating, setCreating] = useGlobal(CREATING_PROJECT, false);
@@ -576,7 +577,7 @@ const ProjectPreviewInner = ({ project }: { project: ProjectDefinition }) => {
const [layout, setLayout] = useProjectsState(`proj-layout-${project.id}`, createDefaultLayout());
const workspace = { id: project.id, name: project.name, cwd: project.cwd };
- return ;
+ return ;
};
const ProjectPreview = () => {
@@ -599,14 +600,14 @@ const ProjectPreview = () => {
);
};
-const projHomeRegistry = {
- ...appRegistry,
- 'project-list': { name: 'Projects', icon: FolderKanban, component: () => },
- 'project-preview': { name: 'Project Preview', icon: FolderKanban, component: ProjectPreview },
-};
-
export const ProjectListScreen = () => {
const [layout, setLayout, isLoaded] = useProjectsState('proj-layout-proj-homepage', defaultLayout);
+ const { registry } = useAppRegistry();
+ const projHomeRegistry = {
+ ...registry,
+ 'project-list': { name: 'Projects', icon: FolderKanban, component: () => },
+ 'project-preview': { name: 'Project Preview', icon: FolderKanban, component: ProjectPreview },
+ };
if (!isLoaded) return null;
diff --git a/src/apps/officer-web/Screens/Dashboard/Projects/ProjectScreen.tsx b/src/apps/officer-web/Screens/Dashboard/Projects/ProjectScreen.tsx
index 821d74c9..e5900134 100644
--- a/src/apps/officer-web/Screens/Dashboard/Projects/ProjectScreen.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Projects/ProjectScreen.tsx
@@ -1,8 +1,8 @@
import { useParams, Navigate } from 'react-router';
-import { useProjectsState } from '@/state/useProjectsState';
+import { useProjectsState } from 'state/useProjectsState';
import { WorkspaceView, createDefaultLayout } from '@/components/Workspace';
import type { LayoutNode, ProjectDefinition } from '@/components/Workspace';
-import { appRegistry } from '../Workspaces/app-registry';
+
export const ProjectScreen = () => {
const { id } = useParams<{ id: string }>();
@@ -25,7 +25,7 @@ const ProjectScreenInner = ({ project }: { project: ProjectDefinition }) => {
workspace={workspace}
layout={layout}
onLayoutChange={setLayout}
- registry={appRegistry}
+
/>
);
diff --git a/src/apps/officer-web/Screens/Dashboard/Settings/ProfileSettings/Appearance.tsx b/src/apps/officer-web/Screens/Dashboard/Settings/ProfileSettings/Appearance.tsx
index 61da9b0d..f07a63ce 100644
--- a/src/apps/officer-web/Screens/Dashboard/Settings/ProfileSettings/Appearance.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Settings/ProfileSettings/Appearance.tsx
@@ -1,4 +1,4 @@
-import { useSettings } from '@/state/useSettings';
+import { useSettings } from 'state/useSettings';
import { themes } from 'themes';
export const Appearance = () => {
diff --git a/src/apps/officer-web/Screens/Dashboard/Settings/ProfileSettings/Languages.tsx b/src/apps/officer-web/Screens/Dashboard/Settings/ProfileSettings/Languages.tsx
index 14859ac1..876b3223 100644
--- a/src/apps/officer-web/Screens/Dashboard/Settings/ProfileSettings/Languages.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Settings/ProfileSettings/Languages.tsx
@@ -1,7 +1,7 @@
import { useState } from 'react';
import { X } from 'lucide-react';
import { Label } from '@/components/ui/label';
-import { useSettings } from '@/state/useSettings';
+import { useSettings } from 'state/useSettings';
import { useTranslation } from '@/lib/i18n';
const LANGUAGES = [
diff --git a/src/apps/officer-web/Screens/Dashboard/Settings/ProfileSettings/TaskDefaults.tsx b/src/apps/officer-web/Screens/Dashboard/Settings/ProfileSettings/TaskDefaults.tsx
index 0407de74..414b6180 100644
--- a/src/apps/officer-web/Screens/Dashboard/Settings/ProfileSettings/TaskDefaults.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Settings/ProfileSettings/TaskDefaults.tsx
@@ -11,8 +11,8 @@ import {
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
-import { useSettings } from '@/state/useSettings';
-import { useVisiblePiModels, type ModelOption } from '@/state/useModels';
+import { useSettings } from 'state/useSettings';
+import { useVisiblePiModels, type ModelOption } from 'state/useModels';
export const TaskDefaults = () => {
const { settings, saveSettings } = useSettings();
diff --git a/src/apps/officer-web/Screens/Dashboard/Settings/ProfileSettings/index.tsx b/src/apps/officer-web/Screens/Dashboard/Settings/ProfileSettings/index.tsx
index 9bafe595..7ca4af21 100644
--- a/src/apps/officer-web/Screens/Dashboard/Settings/ProfileSettings/index.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Settings/ProfileSettings/index.tsx
@@ -2,7 +2,7 @@ import { useMemo } from 'react';
import { User, Lock, Globe, ListChecks } from 'lucide-react';
import type { LayoutNode, PanelComponents } from '@/components/Workspace';
import { WorkspaceLayout } from '@/components/Workspace';
-import { appRegistry } from '../../Workspaces/app-registry';
+
import { createSettingsPanelComponents, type SettingsSection } from '../SettingsPanel';
import { UserData } from './UserData';
import { ChangePassword } from './ChangePassword';
@@ -46,7 +46,7 @@ export const ProfileSettings = () => {
return (
- {}} registry={appRegistry} components={panelComponents} />
+ {}} components={panelComponents} />
);
};
diff --git a/src/apps/officer-web/Screens/Dashboard/Settings/ResourceSettings/ResourceSidebar.tsx b/src/apps/officer-web/Screens/Dashboard/Settings/ResourceSettings/ResourceSidebar.tsx
index 730b7600..bd8e0b3b 100644
--- a/src/apps/officer-web/Screens/Dashboard/Settings/ResourceSettings/ResourceSidebar.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Settings/ResourceSettings/ResourceSidebar.tsx
@@ -3,7 +3,7 @@ import { Circle, Server, Wrench } from 'lucide-react';
import { useGlobal } from 'hooks/useGlobal';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
-import { useResources, getResourceCategory, type Resource } from '@/state/useResources';
+import { useResources, getResourceCategory, type Resource } from 'state/useResources';
type ResourceItemProps = {
resource: Resource;
diff --git a/src/apps/officer-web/Screens/Dashboard/Settings/ResourceSettings/Resources.tsx b/src/apps/officer-web/Screens/Dashboard/Settings/ResourceSettings/Resources.tsx
index 230f257b..1a84522c 100644
--- a/src/apps/officer-web/Screens/Dashboard/Settings/ResourceSettings/Resources.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Settings/ResourceSettings/Resources.tsx
@@ -15,7 +15,7 @@ import {
AlertDialogHeader,
AlertDialogTitle,
} from '@/components/ui/alert-dialog';
-import { useResources, getResourceCategory, type Resource, type PingResult } from '@/state/useResources';
+import { useResources, getResourceCategory, type Resource, type PingResult } from 'state/useResources';
import { RUN_COMMAND_CHANNEL, type RunCommandState } from './run-command-channel';
type ConnectionSectionProps = {
diff --git a/src/apps/officer-web/Screens/Dashboard/Settings/ResourceSettings/index.tsx b/src/apps/officer-web/Screens/Dashboard/Settings/ResourceSettings/index.tsx
index a70fc7ab..136bf401 100644
--- a/src/apps/officer-web/Screens/Dashboard/Settings/ResourceSettings/index.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Settings/ResourceSettings/index.tsx
@@ -7,7 +7,7 @@ import { WorkspaceLayout } from '@/components/Workspace';
import { usePanelChannel } from 'hooks/usePanelChannel';
import { useClient } from 'hooks/useClient';
import { TerminalView, FileViewerView } from 'officerdev';
-import { appRegistry } from '../../Workspaces/app-registry';
+
import { Resources } from './Resources';
import { ResourceSidebar } from './ResourceSidebar';
import {
@@ -174,7 +174,7 @@ export const ResourceSettings = () => {
return (
- {}} registry={appRegistry} components={panelComponents} />
+ {}} components={panelComponents} />
);
};
diff --git a/src/apps/officer-web/Screens/Dashboard/Settings/ServerSettings/PluginsSection.tsx b/src/apps/officer-web/Screens/Dashboard/Settings/ServerSettings/PluginsSection.tsx
index 93300ac3..40dd3b1a 100644
--- a/src/apps/officer-web/Screens/Dashboard/Settings/ServerSettings/PluginsSection.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Settings/ServerSettings/PluginsSection.tsx
@@ -1,7 +1,7 @@
import { useQuery } from '@tanstack/react-query';
import { Switch } from '@/components/ui/switch';
import { useClient } from 'hooks/useClient';
-import { useServerSettings } from '@/state/useServerSettings';
+import { useServerSettings } from 'state/useServerSettings';
type PluginInfo = {
id: string;
diff --git a/src/apps/officer-web/Screens/Dashboard/Settings/SystemSettings.tsx b/src/apps/officer-web/Screens/Dashboard/Settings/SystemSettings.tsx
index eb02071f..23ecf09b 100644
--- a/src/apps/officer-web/Screens/Dashboard/Settings/SystemSettings.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Settings/SystemSettings.tsx
@@ -12,12 +12,12 @@ import type { LayoutNode, PanelComponents } from '@/components/Workspace';
import { WorkspaceLayout } from '@/components/Workspace';
import { usePanelChannel } from 'hooks/usePanelChannel';
import { TerminalView } from 'officerdev';
-import { appRegistry } from '../Workspaces/app-registry';
+
import { createSettingsPanelComponents, type SettingsSectionGroup } from './SettingsPanel';
-import { useSettings } from '@/state/useSettings';
-import { useUserState } from '@/state/useUserState';
-import { usePiModels, useVisiblePiModels, type ModelOption } from '@/state/useModels';
-import type { UserSettings } from '@/state/types/user-settings';
+import { useSettings } from 'state/useSettings';
+import { useUserState } from 'state/useUserState';
+import { usePiModels, useVisiblePiModels, type ModelOption } from 'state/useModels';
+import type { UserSettings } from 'state/useSettings';
import { AIHarnessesSection } from './ServerSettings/AIHarnessesSection';
import { RUN_COMMAND_CHANNEL, type RunCommandState } from './ServerSettings/run-command-channel';
@@ -158,7 +158,7 @@ export const SystemSettings = () => {
return (
- {}} registry={appRegistry} components={panelComponents} />
+ {}} components={panelComponents} />
);
};
diff --git a/src/apps/officer-web/Screens/Dashboard/Terminal/TerminalScreen.tsx b/src/apps/officer-web/Screens/Dashboard/Terminal/TerminalScreen.tsx
index 46d6e377..5dc563de 100644
--- a/src/apps/officer-web/Screens/Dashboard/Terminal/TerminalScreen.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Terminal/TerminalScreen.tsx
@@ -1,20 +1,14 @@
-import { Navigate } from 'react-router';
-import { useAuth } from 'hooks/useAuth';
import type { LayoutNode } from '@/components/Workspace';
import { WorkspaceView } from '@/components/Workspace';
-import { useWorkspacesState } from '@/state/useWorkspacesState';
-import { appRegistry } from '../Workspaces/app-registry';
+import { useWorkspacesState } from 'state/useWorkspacesState';
import { defaultLayout } from './defaultLayout';
export const TerminalScreen = () => {
- const { user } = useAuth();
const workspace = useWorkspacesState('screens/terminal', defaultLayout);
- if (user?.role !== 'Super Admin') return ;
-
return (
-
+
);
};
diff --git a/src/apps/officer-web/Screens/Dashboard/Terminal/defaultLayout.ts b/src/apps/officer-web/Screens/Dashboard/Terminal/defaultLayout.ts
index 2d4af981..1daea597 100644
--- a/src/apps/officer-web/Screens/Dashboard/Terminal/defaultLayout.ts
+++ b/src/apps/officer-web/Screens/Dashboard/Terminal/defaultLayout.ts
@@ -3,5 +3,5 @@ import type { LayoutNode } from '@/components/Workspace';
export const defaultLayout: LayoutNode = {
type: 'panel',
id: 'terminal-screen',
- appType: 'terminal-host',
+ appType: 'officerdev/terminal',
};
diff --git a/src/apps/officer-web/Screens/Dashboard/Workspaces/WorkspaceScreen.tsx b/src/apps/officer-web/Screens/Dashboard/Workspaces/WorkspaceScreen.tsx
index 8c4bc729..98ffebbd 100644
--- a/src/apps/officer-web/Screens/Dashboard/Workspaces/WorkspaceScreen.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Workspaces/WorkspaceScreen.tsx
@@ -1,26 +1,14 @@
-import { useParams, Navigate } from 'react-router';
-import { useWorkspacesState } from '@/state/useWorkspacesState';
-import { WorkspaceView, createDefaultLayout } from '@/components/Workspace';
-import type { LayoutNode, WorkspaceDefinition } from '@/components/Workspace';
-import { appRegistry } from './app-registry';
+import type { LayoutNode } from '@/components/Workspace';
+import { WorkspaceView } from '@/components/Workspace';
+import { useWorkspacesState } from 'state/useWorkspacesState';
+import { defaultLayout } from './defaultLayout';
export const WorkspaceScreen = () => {
- const { id } = useParams<{ id: string }>();
- const { value: workspaces, isLoaded } = useWorkspacesState('workspaces', []);
- const workspace = workspaces.find((ws) => ws.id === id);
-
- if (!isLoaded) return null;
- if (!workspace) return ;
-
- return ;
-};
-
-const WorkspaceScreenInner = ({ workspace }: { workspace: WorkspaceDefinition }) => {
- const ws = useWorkspacesState(`ws-layout-${workspace.id}`, createDefaultLayout());
+ const workspace = useWorkspacesState('screens/workspaces', defaultLayout);
return (
-
+
);
};
diff --git a/src/apps/officer-web/Screens/Dashboard/Workspaces/app-registry.tsx b/src/apps/officer-web/Screens/Dashboard/Workspaces/app-registry.tsx
deleted file mode 100644
index fec90aeb..00000000
--- a/src/apps/officer-web/Screens/Dashboard/Workspaces/app-registry.tsx
+++ /dev/null
@@ -1,250 +0,0 @@
-import { useState, useEffect, useRef } from 'react';
-import type { ReactNode } from 'react';
-import { MessageSquare, FolderOpen, History, Music, Code, TerminalSquare } from 'lucide-react';
-import { Monitor, LayoutGrid, LayoutDashboard, Sparkles, Eye, FolderKanban, Columns2, PenLine } from 'lucide-react';
-import { useAuth } from 'hooks/useAuth';
-import type { AppRegistry } from '@/components/Workspace';
-import { useWorkspace } from '@/components/Workspace';
-import { CodeEditorView, TerminalView, FileViewerProvider, FileViewerHeader, FileViewerBody, EmbeddableChat, ChatLauncher, usePiChat, FileBrowserApp } from 'officerdev';
-import { useWorkspacesState } from '@/state/useWorkspacesState';
-import { usePanelChannel } from 'hooks/usePanelChannel';
-import { useVisiblePiModels } from '@/state/useModels';
-import { ChatHistoryApp as ChatHistory } from '../ChatHistory';
-import { Catalog } from 'sounds';
-import { WorkspaceListApp } from './WorkspaceListApp';
-import { ProjectListApp } from '../Projects/ProjectListApp';
-import { widgetRegistry } from 'widgets/widget-registry';
-import { WidgetPanel } from 'widgets/WidgetPanel';
-
-const ChatWidget = () => ;
-
-const ChatLauncherWidget = () => {
- const pi = usePiChat();
- const models = useVisiblePiModels();
- console.log(models)
- return (
- pi.sendPrompt(prompt, attachmentIds, images)}
- />
- );
-};
-
-const cwdToPath = (cwd: string) => (cwd === '~' ? '/' : cwd.slice(1));
-
-const FileBrowserWrapper = () => {
- const { cwd } = useWorkspace();
- const basePath = cwdToPath(cwd);
- return ;
-};
-
-const CodeEditorWrapper = () => ;
-
-const TerminalHeader = () => {
- const { cwd } = useWorkspace();
- return (
- <>
-
- Terminal
- {cwd}
- >
- );
-};
-
-const HostTerminalHeader = () => {
- const { cwd } = useWorkspace();
- return (
- <>
-
- Terminal
- {cwd}
- >
- );
-};
-
-const CodeEditorHeader = () => {
- const { cwd } = useWorkspace();
- return (
- <>
-
- Code Editor
- {cwd}
- >
- );
-};
-
-const EMPTY_TERMINALS: Record = {};
-
-const TerminalWrapper = ({ panelId }: { panelId: string }) => {
- const { workspaceId, cwd } = useWorkspace();
- const stateKey = workspaceId ? `ws-terminals-${workspaceId}` : 'ws-terminals-default';
- const { value: terminals, setValue: setTerminals } = useWorkspacesState>(stateKey, EMPTY_TERMINALS);
- const setTerminalsRef = useRef(setTerminals);
- setTerminalsRef.current = setTerminals;
-
- const sessionId = terminals[panelId];
-
- useEffect(() => {
- if (!sessionId) {
- setTerminals((prev) => ({ ...prev, [panelId]: crypto.randomUUID() }));
- }
- }, [panelId, sessionId, setTerminals]);
-
- useEffect(() => {
- return () => {
- setTerminalsRef.current((prev) => {
- const { [panelId]: _, ...rest } = prev;
- return rest;
- });
- };
- }, [panelId]);
-
- if (!sessionId) return null;
-
- return ;
-};
-
-const HostTerminalWrapper = ({ panelId }: { panelId: string }) => {
- const { user } = useAuth();
- const { workspaceId, cwd } = useWorkspace();
- const stateKey = workspaceId ? `ws-host-terminals-${workspaceId}` : 'ws-host-terminals-default';
- const { value: terminals, setValue: setTerminals } = useWorkspacesState>(stateKey, EMPTY_TERMINALS);
- const setTerminalsRef = useRef(setTerminals);
- setTerminalsRef.current = setTerminals;
-
- const sessionId = terminals[panelId];
-
- useEffect(() => {
- if (!sessionId) {
- setTerminals((prev) => ({ ...prev, [panelId]: crypto.randomUUID() }));
- }
- }, [panelId, sessionId, setTerminals]);
-
- useEffect(() => {
- return () => {
- setTerminalsRef.current((prev) => {
- const { [panelId]: _, ...rest } = prev;
- return rest;
- });
- };
- }, [panelId]);
-
- if (user?.role !== 'Super Admin') {
- return (
-
- Host Terminal requires Super Admin permissions.
-
- );
- }
-
- if (!sessionId) return null;
-
- return ;
-};
-
-const CommandTerminalWrapper = ({ panelId, command, statePrefix }: { panelId: string; command: string; statePrefix: string }) => {
- const { workspaceId, cwd } = useWorkspace();
- const stateKey = workspaceId ? `ws-${statePrefix}-${workspaceId}` : `ws-${statePrefix}-default`;
- const { value: terminals, setValue: setTerminals } = useWorkspacesState>(stateKey, EMPTY_TERMINALS);
- const setTerminalsRef = useRef(setTerminals);
- setTerminalsRef.current = setTerminals;
-
- const sessionId = terminals[panelId];
-
- useEffect(() => {
- if (!sessionId) {
- setTerminals((prev) => ({ ...prev, [panelId]: crypto.randomUUID() }));
- }
- }, [panelId, sessionId, setTerminals]);
-
- useEffect(() => {
- return () => {
- setTerminalsRef.current((prev) => {
- const { [panelId]: _, ...rest } = prev;
- return rest;
- });
- };
- }, [panelId]);
-
- if (!sessionId) return null;
-
- const fullCommand = cwd && cwd !== '~' ? `cd ${cwd} && ${command}` : command;
-
- return ;
-};
-
-const TmuxWrapper = ({ panelId }: { panelId: string }) => (
-
-);
-
-const NvimWrapper = ({ panelId }: { panelId: string }) => (
-
-);
-
-const TmuxHeader = () => {
- const { cwd } = useWorkspace();
- return (
- <>
-
- Tmux
- {cwd}
- >
- );
-};
-
-const NvimHeader = () => {
- const { cwd } = useWorkspace();
- return (
- <>
-
- Neovim
- {cwd}
- >
- );
-};
-
-type FileViewerChannelState = {
- filePath: string;
- fileName: string;
- root?: string;
-} | null;
-
-const FILE_VIEWER_CHANNEL = 'file-viewer';
-
-const FileViewerWorkspaceProvider = ({ panelId, children }: { panelId: string; children: ReactNode }) => {
- const [state] = usePanelChannel(`${FILE_VIEWER_CHANNEL}:${panelId}`, null);
-
- if (!state) {
- return (
-
- No file selected
-
- );
- }
-
- return (
-
- {children}
-
- );
-};
-
-export const appRegistry: AppRegistry = {
- 'chat': { name: 'Chat', icon: MessageSquare, component: ChatWidget },
- 'file-browser': { name: 'File Browser', icon: FolderOpen, component: FileBrowserWrapper },
- 'chat-history': { name: 'Chat History', icon: History, component: () => , availableOnPanel: false },
- 'sound-library': { name: 'Sound Library', icon: Music, component: () => , availableOnPanel: false },
- 'code-editor': { name: 'Code Editor', icon: Code, component: CodeEditorWrapper, header: CodeEditorHeader },
- 'terminal': { name: 'Terminal', icon: TerminalSquare, component: TerminalWrapper, header: TerminalHeader },
- 'tmux': { name: 'Tmux', icon: Columns2, component: TmuxWrapper, header: TmuxHeader },
- 'nvim': { name: 'Neovim', icon: PenLine, component: NvimWrapper, header: NvimHeader },
- 'terminal-host': { name: 'Host Terminal', icon: Monitor, component: HostTerminalWrapper, header: HostTerminalHeader, availableOnPanel: false },
- 'workspace-list': { name: 'Workspaces', icon: LayoutGrid, component: () => , availableOnPanel: false },
- 'project-list': { name: 'Projects', icon: FolderKanban, component: () => , availableOnPanel: false },
- 'file-viewer': { name: 'File Viewer', icon: Eye, component: FileViewerBody, header: FileViewerHeader, provider: FileViewerWorkspaceProvider, availableOnPanel: false },
- 'chat-launcher': { name: 'Chat Launcher', icon: Sparkles, component: ChatLauncherWidget, fixedHeight: 180, availableOnPanel: false },
- 'widget-panel': { name: 'Widget Panel', icon: LayoutDashboard, component: WidgetPanel, transparent: true },
- ...widgetRegistry,
-};
diff --git a/src/apps/officer-web/Screens/Dashboard/Workspaces/defaultLayout.ts b/src/apps/officer-web/Screens/Dashboard/Workspaces/defaultLayout.ts
new file mode 100644
index 00000000..81614cbf
--- /dev/null
+++ b/src/apps/officer-web/Screens/Dashboard/Workspaces/defaultLayout.ts
@@ -0,0 +1,11 @@
+import type { LayoutNode } from '@/components/Workspace';
+
+export const defaultLayout: LayoutNode = {
+ type: 'group',
+ id: 'ws-home-root',
+ direction: 'horizontal',
+ children: [
+ { node: { type: 'panel', id: 'ws-home-list', appType: 'workspace-list' }, size: 50 },
+ { node: { type: 'panel', id: 'ws-home-right', appType: 'workspace-preview' }, size: 50 },
+ ],
+};
diff --git a/src/apps/officer-web/Screens/Dashboard/Workspaces/index.tsx b/src/apps/officer-web/Screens/Dashboard/Workspaces/index.tsx
index 7fbf78c0..5868f861 100644
--- a/src/apps/officer-web/Screens/Dashboard/Workspaces/index.tsx
+++ b/src/apps/officer-web/Screens/Dashboard/Workspaces/index.tsx
@@ -1,2 +1 @@
-export { WorkspaceListScreen, NewWorkspaceRedirect } from './WorkspaceListScreen';
export { WorkspaceScreen } from './WorkspaceScreen';
diff --git a/src/apps/officer-web/frontend.tsx b/src/apps/officer-web/frontend.tsx
index dfc68794..3eb7190a 100644
--- a/src/apps/officer-web/frontend.tsx
+++ b/src/apps/officer-web/frontend.tsx
@@ -1,6 +1,7 @@
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { App } from './App';
+import { AppRegistry } from 'officerdev';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ColorModeProvider } from '@/components/ui/ThemeProvider';
import { I18nBridge } from '@/lib/I18nBridge';
@@ -39,6 +40,7 @@ const app = (
+
diff --git a/src/apps/officer-web/lib/I18nBridge.tsx b/src/apps/officer-web/lib/I18nBridge.tsx
index e344e7f4..22ffd3c2 100644
--- a/src/apps/officer-web/lib/I18nBridge.tsx
+++ b/src/apps/officer-web/lib/I18nBridge.tsx
@@ -1,7 +1,7 @@
import type { ReactNode } from 'react';
import type { TranslationMap } from 'i18n';
import { I18nProvider } from 'i18n';
-import { useSettings } from '@/state/useSettings';
+import { useSettings } from 'state/useSettings';
import en from '../locales/en.json';
import pt from '../locales/pt.json';
diff --git a/src/apps/officer-web/state/useInitialData.ts b/src/apps/officer-web/state/useInitialData.ts
index 1b4509c9..2f879059 100644
--- a/src/apps/officer-web/state/useInitialData.ts
+++ b/src/apps/officer-web/state/useInitialData.ts
@@ -1,6 +1,6 @@
-import { useChatSessions } from '@/state/useChatSessions';
-import { usePlans } from './usePlans';
-import { useSettings } from './useSettings';
+import { useChatSessions } from 'state/useChatSessions';
+import { usePlans } from 'state/usePlans';
+import { useSettings } from 'state/useSettings';
import { useColorModeSync } from './useThemeSync';
export const useInitialData = () => {
diff --git a/src/apps/officer-web/state/useThemeSync.ts b/src/apps/officer-web/state/useThemeSync.ts
index 1a67b3ad..cf8bdf9c 100644
--- a/src/apps/officer-web/state/useThemeSync.ts
+++ b/src/apps/officer-web/state/useThemeSync.ts
@@ -1,6 +1,6 @@
import { useEffect } from 'react';
import { useColorMode } from '@/components/ui/ThemeProvider';
-import { useSettings } from './useSettings';
+import { useSettings } from 'state/useSettings';
export const useColorModeSync = () => {
const { settings } = useSettings();
diff --git a/src/workspaces/components/Workspace/AppPicker.tsx b/src/workspaces/components/Workspace/AppPicker.tsx
index 652fed9e..96311382 100644
--- a/src/workspaces/components/Workspace/AppPicker.tsx
+++ b/src/workspaces/components/Workspace/AppPicker.tsx
@@ -6,7 +6,7 @@ type AppPickerProps = {
};
export const AppPicker = ({ registry, onSelect }: AppPickerProps) => {
- const entries = Object.entries(registry).filter(([, entry]) => !entry.widget && entry.availableOnPanel !== false);
+ const entries = Object.entries(registry).filter(([, entry]) => entry.availableOnPanel !== false);
return (
diff --git a/src/workspaces/components/Workspace/WorkspaceLayout.tsx b/src/workspaces/components/Workspace/WorkspaceLayout.tsx
index f8a33b64..ae6c20b9 100644
--- a/src/workspaces/components/Workspace/WorkspaceLayout.tsx
+++ b/src/workspaces/components/Workspace/WorkspaceLayout.tsx
@@ -3,11 +3,12 @@ import type { LayoutNode, AppRegistry, PanelComponents } from './types';
import { updateSizes } from './layout-utils';
import { WorkspaceProvider } from './WorkspaceContext';
import { WorkspaceRenderer } from './WorkspaceRenderer';
+import { useAppRegistry } from 'officerdev';
type WorkspaceLayoutProps = {
layout: LayoutNode;
onLayoutChange: (layout: LayoutNode) => void;
- registry: AppRegistry;
+ registry?: AppRegistry;
components?: PanelComponents;
workspaceId?: string;
cwd?: string;
@@ -15,7 +16,10 @@ type WorkspaceLayoutProps = {
const noop = () => {};
-export const WorkspaceLayout = ({ layout, onLayoutChange, registry, components, workspaceId, cwd }: WorkspaceLayoutProps) => {
+export const WorkspaceLayout = ({ layout, onLayoutChange, registry: registryProp, components, workspaceId, cwd }: WorkspaceLayoutProps) => {
+ const { registry: globalRegistry } = useAppRegistry();
+ const registry = registryProp ?? globalRegistry;
+
const handleResized = useCallback(
(groupId: string, sizes: number[]) => {
onLayoutChange(updateSizes(layout, groupId, sizes));
diff --git a/src/workspaces/components/Workspace/WorkspaceView.tsx b/src/workspaces/components/Workspace/WorkspaceView.tsx
index 1849a41a..7f83e926 100644
--- a/src/workspaces/components/Workspace/WorkspaceView.tsx
+++ b/src/workspaces/components/Workspace/WorkspaceView.tsx
@@ -1,25 +1,26 @@
import { useState, useCallback, useEffect } from 'react';
import { flushSync } from 'react-dom';
import { ResizablePanel, ResizablePanelGroup, ResizableHandle } from '../ui/resizable';
-import type { LayoutNode, AppRegistry, WorkspaceState, EphemeralPanels } from './types';
+import type { LayoutNode, WorkspaceState, EphemeralPanels } from './types';
import type { DropPosition } from './layout-utils';
import { splitPanel, removePanel, setApp, updateSizes, swapPanels, movePanel, countPanels } from './layout-utils';
import { WorkspaceProvider } from './WorkspaceContext';
import { WorkspaceRenderer } from './WorkspaceRenderer';
+import { useAppRegistry } from 'officerdev';
type WorkspaceViewProps = {
workspace: WorkspaceState;
- registry: AppRegistry;
cwd?: string;
ephemeral?: EphemeralPanels | null;
};
const noop = () => {};
-export const WorkspaceView = ({ workspace, registry, cwd = '~', ephemeral }: WorkspaceViewProps) => {
- if (!workspace.isLoaded) return null;
+export const WorkspaceView = ({ workspace, cwd = '~', ephemeral }: WorkspaceViewProps) => {
+ const { registry } = useAppRegistry();
- const { value: layout, setValue: onLayoutChange } = workspace;
+ const layout = workspace.value;
+ const onLayoutChange = workspace.setValue;
const [swapSourceId, setSwapSourceId] = useState
(null);
const [dragSourceId, setDragSourceId] = useState(null);
const [maximizedPanelId, setMaximizedPanelId] = useState(null);
@@ -105,6 +106,8 @@ export const WorkspaceView = ({ workspace, registry, cwd = '~', ephemeral }: Wor
return () => window.removeEventListener('keydown', onKeyDown);
}, [swapSourceId, dragSourceId, maximizedPanelId, setMaximizedAnimated]);
+ if (!workspace.isLoaded) return null;
+
const baseRenderer = (
;
transparent?: boolean;
fixedHeight?: number;
- widget?: boolean;
availableOnPanel?: boolean;
};
diff --git a/src/workspaces/officerdev/package.json b/src/workspaces/officerdev/package.json
index 6d5b2b79..71019b0f 100644
--- a/src/workspaces/officerdev/package.json
+++ b/src/workspaces/officerdev/package.json
@@ -9,6 +9,7 @@
},
"dependencies": {
"hooks": "workspace:*",
+ "state": "workspace:*",
"widgets": "workspace:*"
}
}
diff --git a/src/workspaces/officerdev/src/AppRegistry/AppRegistry.tsx b/src/workspaces/officerdev/src/AppRegistry/AppRegistry.tsx
new file mode 100644
index 00000000..b5ae0b9d
--- /dev/null
+++ b/src/workspaces/officerdev/src/AppRegistry/AppRegistry.tsx
@@ -0,0 +1,14 @@
+import { appRegistryMetas as fileBrowserMetas } from '../apps/FileBrowser';
+import { appRegistryMetas as terminalMetas } from '../apps/Terminal';
+import { appRegistryMetas as codeEditorMetas } from '../apps/CodeEditor';
+import { appRegistryMetas as chatMetas } from '../apps/Chat';
+import { appRegistryMetas as fileViewerMetas } from '../apps/FileViewer';
+import { appRegistryMetas as workspaceMetas } from '../apps/Workspaces';
+import { useAppRegistry } from './useAppRegistry';
+
+const apps = [...fileBrowserMetas, ...terminalMetas, ...codeEditorMetas, ...chatMetas, ...fileViewerMetas, ...workspaceMetas];
+
+export const AppRegistry = () => {
+ useAppRegistry(apps);
+ return null;
+};
diff --git a/src/workspaces/officerdev/src/AppRegistry/index.tsx b/src/workspaces/officerdev/src/AppRegistry/index.tsx
new file mode 100644
index 00000000..faf7550c
--- /dev/null
+++ b/src/workspaces/officerdev/src/AppRegistry/index.tsx
@@ -0,0 +1,2 @@
+export * from './AppRegistry';
+export * from './useAppRegistry';
diff --git a/src/workspaces/officerdev/src/AppRegistry/useAppRegistry/index.ts b/src/workspaces/officerdev/src/AppRegistry/useAppRegistry/index.ts
new file mode 100644
index 00000000..f5cbe731
--- /dev/null
+++ b/src/workspaces/officerdev/src/AppRegistry/useAppRegistry/index.ts
@@ -0,0 +1 @@
+export { useAppRegistry, type UseAppRegistryType, type AppRegistryMeta } from './useAppRegistry';
diff --git a/src/workspaces/officerdev/src/AppRegistry/useAppRegistry/useAppRegistry.ts b/src/workspaces/officerdev/src/AppRegistry/useAppRegistry/useAppRegistry.ts
new file mode 100644
index 00000000..03659e25
--- /dev/null
+++ b/src/workspaces/officerdev/src/AppRegistry/useAppRegistry/useAppRegistry.ts
@@ -0,0 +1,19 @@
+import type { AppRegistry, AppRegistryEntry } from '@/components/Workspace';
+import { useGlobal } from 'hooks/useGlobal';
+
+export type AppRegistryMeta = { key: string } & AppRegistryEntry;
+
+export function useAppRegistry(initialApps: AppRegistryMeta[] = []) {
+ const [registry, setRegistry] = useGlobal('APP_REGISTRY', () => metasToRegistry(initialApps));
+
+ const registerApp = (key: string, entry: AppRegistryEntry) => {
+ setRegistry((prev) => ({ ...prev, [key]: entry }));
+ };
+
+ return { registry, registerApp };
+}
+
+export type UseAppRegistryType = ReturnType;
+
+const metasToRegistry = (metas: AppRegistryMeta[]): AppRegistry =>
+ Object.fromEntries(metas.map(({ key, ...entry }) => [key, entry]));
diff --git a/src/workspaces/officerdev/src/apps/Chat/ChatList/index.tsx b/src/workspaces/officerdev/src/apps/Chat/ChatList/index.tsx
index e2ddb60c..3a37270f 100644
--- a/src/workspaces/officerdev/src/apps/Chat/ChatList/index.tsx
+++ b/src/workspaces/officerdev/src/apps/Chat/ChatList/index.tsx
@@ -1,5 +1,5 @@
import { MessageSquare } from 'lucide-react';
-import { useChatSessions } from '@/state/useChatSessions';
+import { useChatSessions } from 'state/useChatSessions';
export const ChatList = () => {
const { sessions } = useChatSessions();
diff --git a/src/workspaces/officerdev/src/apps/Chat/ChatPanelWrapper.tsx b/src/workspaces/officerdev/src/apps/Chat/ChatPanelWrapper.tsx
new file mode 100644
index 00000000..99c06481
--- /dev/null
+++ b/src/workspaces/officerdev/src/apps/Chat/ChatPanelWrapper.tsx
@@ -0,0 +1,3 @@
+import { EmbeddableChat } from './EmbeddableChat';
+
+export const ChatPanelWrapper = () => ;
diff --git a/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/useEmbeddableChat.ts b/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/useEmbeddableChat.ts
index 55531fde..5f306501 100644
--- a/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/useEmbeddableChat.ts
+++ b/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/useEmbeddableChat.ts
@@ -1,6 +1,6 @@
import type { KeyboardEvent } from 'react';
import { useState, useRef, useEffect } from 'react';
-import { useVisiblePiModels } from '@/state/useModels';
+import { useVisiblePiModels } from 'state/useModels';
import { usePiChat, type UsePiChatType } from '../../../hooks/usePiChat';
import { useAttachments } from '../useAttachments';
import { useSlashCommands } from '../useSlashCommands';
diff --git a/src/workspaces/officerdev/src/apps/Chat/components/ModelSelector.tsx b/src/workspaces/officerdev/src/apps/Chat/components/ModelSelector.tsx
index 638f6692..cc8e1d15 100644
--- a/src/workspaces/officerdev/src/apps/Chat/components/ModelSelector.tsx
+++ b/src/workspaces/officerdev/src/apps/Chat/components/ModelSelector.tsx
@@ -1,5 +1,5 @@
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
-import type { ModelOption } from '@/state/useModels';
+import type { ModelOption } from 'state/useModels';
import type { ChatMessage } from '../types';
const PROVIDER_DISPLAY: Record = {
diff --git a/src/workspaces/officerdev/src/apps/Chat/index.ts b/src/workspaces/officerdev/src/apps/Chat/index.ts
index adc04ec8..b0ab89b1 100644
--- a/src/workspaces/officerdev/src/apps/Chat/index.ts
+++ b/src/workspaces/officerdev/src/apps/Chat/index.ts
@@ -1,3 +1,7 @@
+import type { AppRegistryMeta } from '../../AppRegistry';
+import { MessageSquare } from 'lucide-react';
+import { ChatPanelWrapper } from './ChatPanelWrapper';
+
export { MessageList } from './components/MessageList';
export { MessageBubble, StreamingBubble } from './components/MessageBubble';
export { ToolActivity } from './components/ToolActivity';
@@ -18,3 +22,12 @@ export { useAttachments, type UseAttachmentsType } from './useAttachments';
export { useAudioRecording, type UseAudioRecordingType } from './useAudioRecording';
export * from './types';
+
+export const appRegistryMetas: AppRegistryMeta[] = [
+ {
+ key: 'officerdev/chat',
+ name: 'Chat',
+ icon: MessageSquare,
+ component: ChatPanelWrapper,
+ },
+];
diff --git a/src/workspaces/officerdev/src/apps/CodeEditor/CodeEditorHeader.tsx b/src/workspaces/officerdev/src/apps/CodeEditor/CodeEditorHeader.tsx
new file mode 100644
index 00000000..6c923540
--- /dev/null
+++ b/src/workspaces/officerdev/src/apps/CodeEditor/CodeEditorHeader.tsx
@@ -0,0 +1,13 @@
+import { Code } from 'lucide-react';
+import { useWorkspace } from '@/components/Workspace';
+
+export const CodeEditorHeader = () => {
+ const { cwd } = useWorkspace();
+ return (
+ <>
+
+ Code Editor
+ {cwd}
+ >
+ );
+};
diff --git a/src/workspaces/officerdev/src/apps/CodeEditor/CodeEditorPanelWrapper.tsx b/src/workspaces/officerdev/src/apps/CodeEditor/CodeEditorPanelWrapper.tsx
new file mode 100644
index 00000000..9013ca81
--- /dev/null
+++ b/src/workspaces/officerdev/src/apps/CodeEditor/CodeEditorPanelWrapper.tsx
@@ -0,0 +1,3 @@
+import { CodeEditorView } from './CodeEditor';
+
+export const CodeEditorPanelWrapper = () => ;
diff --git a/src/workspaces/officerdev/src/apps/CodeEditor/index.ts b/src/workspaces/officerdev/src/apps/CodeEditor/index.ts
index c3ba9632..69ad01e4 100644
--- a/src/workspaces/officerdev/src/apps/CodeEditor/index.ts
+++ b/src/workspaces/officerdev/src/apps/CodeEditor/index.ts
@@ -1 +1,16 @@
+import type { AppRegistryMeta } from '../../AppRegistry';
+import { Code } from 'lucide-react';
+import { CodeEditorPanelWrapper } from './CodeEditorPanelWrapper';
+import { CodeEditorHeader } from './CodeEditorHeader';
+
export { CodeEditorView } from './CodeEditor';
+
+export const appRegistryMetas: AppRegistryMeta[] = [
+ {
+ key: 'officerdev/code-editor',
+ name: 'Code Editor',
+ icon: Code,
+ component: CodeEditorPanelWrapper,
+ header: CodeEditorHeader,
+ },
+];
diff --git a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/FileBrowserApp.tsx b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/FileBrowserApp.tsx
index 26115c57..87084bd3 100644
--- a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/FileBrowserApp.tsx
+++ b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/FileBrowserApp.tsx
@@ -13,24 +13,20 @@ type FileBrowserAppProps = {
export const FileBrowserApp = ({ basePath = '/' }: FileBrowserAppProps) => {
const fileBrowserManager = useFileBrowserApp(basePath);
+ const { handleNavigate } = fileBrowserManager;
return (
-
-
-
-
-
- {/* Breadcrumb */}
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
);
};
+
diff --git a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/FileBrowserPanelWrapper.tsx b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/FileBrowserPanelWrapper.tsx
new file mode 100644
index 00000000..ffa9beb7
--- /dev/null
+++ b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/FileBrowserPanelWrapper.tsx
@@ -0,0 +1,9 @@
+import { useWorkspace } from '@/components/Workspace';
+import { FileBrowserApp } from './FileBrowserApp';
+
+const cwdToPath = (cwd: string) => (cwd === '~' ? '/' : cwd.slice(1));
+
+export const FileBrowserPanelWrapper = () => {
+ const { cwd } = useWorkspace();
+ return ;
+};
diff --git a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/Breadcrumb.tsx b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/Breadcrumb.tsx
index be85161c..1cb0724d 100644
--- a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/Breadcrumb.tsx
+++ b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/Breadcrumb.tsx
@@ -11,36 +11,38 @@ export const Breadcrumb = ({ path, onNavigate, basePath = '/' }: BreadcrumbProps
const segments = relativePath.split('/').filter(Boolean);
return (
-
);
};
-
-const registry = { ...appRegistry, 'workspace-preview': { name: 'Workspace Preview', icon: LayoutGrid, component: WorkspacePreview } };
-
-export const WorkspaceListScreen = () => {
- const workspace = useWorkspacesState('screens/homepage', defaultLayout);
-
- return (
-
-
-
- );
-};
-
-export const NewWorkspaceRedirect = () => {
- const navigate = useNavigate();
- const [params] = useSearchParams();
- const [, setName] = useGlobal(NEW_WS_NAME_KEY, '');
- const [, setDescription] = useGlobal(NEW_WS_DESC_KEY, '');
- const [, setTemplateIdx] = useGlobal(NEW_WS_TEMPLATE_KEY, 0);
- const [, setCreating] = useGlobal(CREATING_WORKSPACE_KEY, false);
- const [, setEditing] = useGlobal(EDITING_WORKSPACE_KEY, null);
- const [, setSelected] = useGlobal(SELECTED_WORKSPACE_KEY, null);
- const [, setFilePath] = useUserState('files/currentPath', '/');
-
- useEffect(() => {
- setSelected(null);
- setEditing(null);
- setName(params.get('name') || generateSlug());
- setDescription('');
- setTemplateIdx(0);
- setFilePath(params.get('cwd') || '/');
- setCreating(true);
- navigate('/workspaces', { replace: true });
- }, []);
-
- return null;
-};
diff --git a/src/apps/officer-web/Screens/Dashboard/Workspaces/constants.ts b/src/workspaces/officerdev/src/apps/Workspaces/constants.ts
similarity index 100%
rename from src/apps/officer-web/Screens/Dashboard/Workspaces/constants.ts
rename to src/workspaces/officerdev/src/apps/Workspaces/constants.ts
diff --git a/src/workspaces/officerdev/src/apps/Workspaces/index.ts b/src/workspaces/officerdev/src/apps/Workspaces/index.ts
new file mode 100644
index 00000000..c53f8e6a
--- /dev/null
+++ b/src/workspaces/officerdev/src/apps/Workspaces/index.ts
@@ -0,0 +1,25 @@
+import type { AppRegistryMeta } from '../../AppRegistry';
+import { LayoutGrid } from 'lucide-react';
+import { WorkspaceListApp } from './WorkspaceListApp';
+import { WorkspacePreview } from './WorkspacePreview';
+
+export { WorkspaceListApp };
+export { WorkspacePreview };
+export { SELECTED_WORKSPACE_KEY, CREATING_WORKSPACE_KEY, EDITING_WORKSPACE_KEY, NEW_WS_NAME_KEY, NEW_WS_DESC_KEY, NEW_WS_TEMPLATE_KEY } from './constants';
+
+export const appRegistryMetas: AppRegistryMeta[] = [
+ {
+ key: 'workspace-list',
+ name: 'Workspaces',
+ icon: LayoutGrid,
+ component: WorkspaceListApp,
+ availableOnPanel: false
+ },
+ {
+ key: 'workspace-preview',
+ name: 'Workspace Preview',
+ icon: LayoutGrid,
+ component: WorkspacePreview,
+ availableOnPanel: false
+ },
+];
diff --git a/src/workspaces/officerdev/src/hooks/appRegistry/appRegistry.ts b/src/workspaces/officerdev/src/hooks/appRegistry/appRegistry.ts
deleted file mode 100644
index 3a73800e..00000000
--- a/src/workspaces/officerdev/src/hooks/appRegistry/appRegistry.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import type { AppRegistry } from '@/components/Workspace';
-
-export function useAppRegistry(): AppRegistry {
- return {};
-}
diff --git a/src/workspaces/officerdev/src/hooks/appRegistry/index.ts b/src/workspaces/officerdev/src/hooks/appRegistry/index.ts
deleted file mode 100644
index 090ec6fb..00000000
--- a/src/workspaces/officerdev/src/hooks/appRegistry/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { useAppRegistry } from './appRegistry';
diff --git a/src/workspaces/officerdev/src/hooks/index.ts b/src/workspaces/officerdev/src/hooks/index.ts
index fc78df2b..5ccfdca9 100644
--- a/src/workspaces/officerdev/src/hooks/index.ts
+++ b/src/workspaces/officerdev/src/hooks/index.ts
@@ -1,4 +1,3 @@
-export * from './appRegistry';
export * from './useFilesAPI';
export * from './useFileViewerPanels';
export * from './usePiChat';
diff --git a/src/workspaces/officerdev/src/hooks/useFileViewerPanels/Providers.tsx b/src/workspaces/officerdev/src/hooks/useFileViewerPanels/Providers.tsx
index 729cc816..07af692f 100644
--- a/src/workspaces/officerdev/src/hooks/useFileViewerPanels/Providers.tsx
+++ b/src/workspaces/officerdev/src/hooks/useFileViewerPanels/Providers.tsx
@@ -1,6 +1,6 @@
import type { ReactNode } from 'react';
import { useSearchParams } from 'react-router';
-import { useUserState } from '@/state/useUserState';
+import { useUserState } from 'state/useUserState';
import { FileViewerProvider } from '../../apps/FileViewer';
export function ViewerProvider({ children }: { children: ReactNode }) {
diff --git a/src/workspaces/officerdev/src/hooks/usePiChat.ts b/src/workspaces/officerdev/src/hooks/usePiChat.ts
index a30ed520..5870c0f3 100644
--- a/src/workspaces/officerdev/src/hooks/usePiChat.ts
+++ b/src/workspaces/officerdev/src/hooks/usePiChat.ts
@@ -1,6 +1,6 @@
import { useState, useEffect, useRef } from 'react';
import { useChatWebSocket } from 'hooks/useChatWebSocket';
-import { useChatSessions } from '@/state/useChatSessions';
+import { useChatSessions } from 'state/useChatSessions';
import type { ChatMessage, ServerMessage, TaskInfo, Message } from '../apps/Chat/types';
const SAVE_DEBOUNCE_MS = 1000;
diff --git a/src/workspaces/officerdev/src/index.ts b/src/workspaces/officerdev/src/index.ts
index 2dfd8348..9684a77e 100644
--- a/src/workspaces/officerdev/src/index.ts
+++ b/src/workspaces/officerdev/src/index.ts
@@ -1,7 +1,16 @@
export * from './hooks';
-export * from './apps/Chat';
-export * from './apps/ChatHistory';
-export * from './apps/CodeEditor';
-export * from './apps/FileBrowser';
-export * from './apps/FileViewer';
-export * from './apps/Terminal';
+export * from './AppRegistry';
+
+// Re-export app modules (excluding appRegistryMetas to avoid name collisions)
+export { MessageList, MessageBubble, StreamingBubble, ToolActivity, QuestionActivity, ModelSelector, InputArea, ChatLauncher, AttachmentList, AttachButton, WebpageDialog, EmbeddableChat, usePiChat, ChatList, useSlashCommands, useChatSessions, useChatSession, useAttachments, useAudioRecording } from './apps/Chat';
+export type { UseEmbeddableChatType, UsePiChatType, UseChatSessionsType, UseChatSessionType, UseAttachmentsType, UseAudioRecordingType } from './apps/Chat';
+export * from './apps/Chat/types';
+export { SessionBar } from './apps/ChatHistory';
+export { CodeEditorView } from './apps/CodeEditor';
+export { useFilesAPI, useTasks, useRecentFiles, usePinnedFiles, FileBrowserApp, FileBrowserPanelWrapper, FileBrowserWidget, TaskRunnerModal } from './apps/FileBrowser';
+export type { DirEntry, TaskSummary } from './apps/FileBrowser';
+export { FileViewerView, FileViewerProvider, FileViewerHeader, FileViewerBody, FileViewerPanelProvider, useFileViewer, getFileType, getLang, getExt, getArchiveBaseName, ARCHIVE_EXTS } from './apps/FileViewer';
+export type { FileType } from './apps/FileViewer';
+export { TerminalView } from './apps/Terminal';
+export type { TerminalViewProps } from './apps/Terminal';
+export { WorkspaceListApp, WorkspacePreview, SELECTED_WORKSPACE_KEY, CREATING_WORKSPACE_KEY, EDITING_WORKSPACE_KEY, NEW_WS_NAME_KEY, NEW_WS_DESC_KEY, NEW_WS_TEMPLATE_KEY } from './apps/Workspaces';
diff --git a/src/workspaces/state/package.json b/src/workspaces/state/package.json
new file mode 100644
index 00000000..00928fec
--- /dev/null
+++ b/src/workspaces/state/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "state",
+ "version": "0.0.1",
+ "license": "MIT",
+ "type": "module",
+ "exports": {
+ ".": "./src/index.ts",
+ "./*": "./src/*.ts"
+ },
+ "dependencies": {
+ "hooks": "workspace:*",
+ "officerdev": "workspace:*"
+ }
+}
diff --git a/src/workspaces/state/src/index.ts b/src/workspaces/state/src/index.ts
new file mode 100644
index 00000000..ef2eace7
--- /dev/null
+++ b/src/workspaces/state/src/index.ts
@@ -0,0 +1,16 @@
+export { useSettings, DEFAULT_SETTINGS } from './useSettings';
+export type { UseSettingsType, UserSettings, UserState } from './useSettings';
+export { useUserState } from './useUserState';
+export { useWorkspacesState } from './useWorkspacesState';
+export { useProjectsState } from './useProjectsState';
+export { usePiModels, useVisiblePiModels, modelKey } from './useModels';
+export type { ModelOption } from './useModels';
+export { useRecentModels } from './useRecentModels';
+export { usePlans } from './usePlans';
+export { useLandingPage } from './useLandingPage';
+export { useServerSettings } from './useServerSettings';
+export { useResources, getResourceCategory } from './useResources';
+export type { Resource, ResourceCredentials, ResourceConnectionConfig, PingResult, ResourceCategory } from './useResources';
+export { useChatSessions } from './useChatSessions';
+export type { UseChatSessionsType } from './useChatSessions';
+export { useChatGroups } from './useChatGroups';
diff --git a/src/apps/officer-web/state/useChatGroups.ts b/src/workspaces/state/src/useChatGroups.ts
similarity index 100%
rename from src/apps/officer-web/state/useChatGroups.ts
rename to src/workspaces/state/src/useChatGroups.ts
diff --git a/src/apps/officer-web/state/useChatSessions.ts b/src/workspaces/state/src/useChatSessions.ts
similarity index 100%
rename from src/apps/officer-web/state/useChatSessions.ts
rename to src/workspaces/state/src/useChatSessions.ts
diff --git a/src/apps/officer-web/state/useLandingPage.ts b/src/workspaces/state/src/useLandingPage.ts
similarity index 100%
rename from src/apps/officer-web/state/useLandingPage.ts
rename to src/workspaces/state/src/useLandingPage.ts
diff --git a/src/apps/officer-web/state/useModels.ts b/src/workspaces/state/src/useModels.ts
similarity index 100%
rename from src/apps/officer-web/state/useModels.ts
rename to src/workspaces/state/src/useModels.ts
diff --git a/src/apps/officer-web/state/usePlans.ts b/src/workspaces/state/src/usePlans.ts
similarity index 100%
rename from src/apps/officer-web/state/usePlans.ts
rename to src/workspaces/state/src/usePlans.ts
diff --git a/src/apps/officer-web/state/useProjectsState.ts b/src/workspaces/state/src/useProjectsState.ts
similarity index 96%
rename from src/apps/officer-web/state/useProjectsState.ts
rename to src/workspaces/state/src/useProjectsState.ts
index fbec3ffe..201cb0fc 100644
--- a/src/apps/officer-web/state/useProjectsState.ts
+++ b/src/workspaces/state/src/useProjectsState.ts
@@ -2,7 +2,7 @@ import { useCallback, useRef } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useClient } from 'hooks/useClient';
import { useAuth } from 'hooks/useAuth';
-import type { UserState } from './types/user-settings';
+import type { UserState } from './useSettings';
const QUERY_KEY = ['PROJECTS_STATE'];
diff --git a/src/apps/officer-web/state/useRecentModels.ts b/src/workspaces/state/src/useRecentModels.ts
similarity index 100%
rename from src/apps/officer-web/state/useRecentModels.ts
rename to src/workspaces/state/src/useRecentModels.ts
diff --git a/src/apps/officer-web/state/useResources.ts b/src/workspaces/state/src/useResources.ts
similarity index 100%
rename from src/apps/officer-web/state/useResources.ts
rename to src/workspaces/state/src/useResources.ts
diff --git a/src/apps/officer-web/state/useServerSettings.ts b/src/workspaces/state/src/useServerSettings.ts
similarity index 100%
rename from src/apps/officer-web/state/useServerSettings.ts
rename to src/workspaces/state/src/useServerSettings.ts
diff --git a/src/apps/officer-web/state/useSettings.ts b/src/workspaces/state/src/useSettings.ts
similarity index 100%
rename from src/apps/officer-web/state/useSettings.ts
rename to src/workspaces/state/src/useSettings.ts
diff --git a/src/apps/officer-web/state/useUserState.ts b/src/workspaces/state/src/useUserState.ts
similarity index 96%
rename from src/apps/officer-web/state/useUserState.ts
rename to src/workspaces/state/src/useUserState.ts
index 8d745cab..354a7025 100644
--- a/src/apps/officer-web/state/useUserState.ts
+++ b/src/workspaces/state/src/useUserState.ts
@@ -2,7 +2,7 @@ import { useCallback, useRef } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useClient } from 'hooks/useClient';
import { useAuth } from 'hooks/useAuth';
-import type { UserState } from './types/user-settings';
+import type { UserState } from './useSettings';
const QUERY_KEY = ['USER_STATE'];
diff --git a/src/apps/officer-web/state/useWorkspacesState.ts b/src/workspaces/state/src/useWorkspacesState.ts
similarity index 97%
rename from src/apps/officer-web/state/useWorkspacesState.ts
rename to src/workspaces/state/src/useWorkspacesState.ts
index e777a560..b87b4836 100644
--- a/src/apps/officer-web/state/useWorkspacesState.ts
+++ b/src/workspaces/state/src/useWorkspacesState.ts
@@ -2,7 +2,7 @@ import { useCallback, useEffect, useRef } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useClient } from 'hooks/useClient';
import { useAuth } from 'hooks/useAuth';
-import type { UserState } from './types/user-settings';
+import type { UserState } from './useSettings';
const QUERY_KEY = ['WORKSPACES_STATE'];
diff --git a/src/workspaces/widgets/widget-registry.tsx b/src/workspaces/widgets/widget-registry.tsx
index e382ef88..8d4e5fe3 100644
--- a/src/workspaces/widgets/widget-registry.tsx
+++ b/src/workspaces/widgets/widget-registry.tsx
@@ -7,9 +7,9 @@ import { DailyGoals } from './DailyGoals/index';
import { QuickNotes } from './QuickNotes/index';
export const widgetRegistry: Record = {
- 'clock': { name: 'Clock', icon: ClockIcon, component: () => , widget: true },
- 'weather': { name: 'Weather', icon: CloudSun, component: () => , widget: true },
- 'pomodoro': { name: 'Pomodoro', icon: Timer, component: () => , widget: true },
- 'daily-goals': { name: 'Daily Goals', icon: Target, component: () => , widget: true },
- 'quick-notes': { name: 'Quick Notes', icon: StickyNote, component: () => , widget: true },
+ 'clock': { name: 'Clock', icon: ClockIcon, component: () => , availableOnPanel: false },
+ 'weather': { name: 'Weather', icon: CloudSun, component: () => , availableOnPanel: false },
+ 'pomodoro': { name: 'Pomodoro', icon: Timer, component: () => , availableOnPanel: false },
+ 'daily-goals': { name: 'Daily Goals', icon: Target, component: () => , availableOnPanel: false },
+ 'quick-notes': { name: 'Quick Notes', icon: StickyNote, component: () => , availableOnPanel: false },
};