From 9e9acd96310634544462746d61065f5ac7db53e0 Mon Sep 17 00:00:00 2001 From: Andre Padez Date: Sat, 21 Feb 2026 21:24:31 +0000 Subject: [PATCH] major apps and hooks refactor --- bun.lock | 10 +- package.json | 1 - .../Automation/CapabilityDetailView.tsx | 2 +- .../Screens/Dashboard/CapabilityPage.tsx | 7 +- .../Dashboard/ChatHistory/ChatDetailPanel.tsx | 6 +- .../ChatHistory/GroupContextMenu.tsx | 2 +- .../ChatHistory/SessionContextMenu.tsx | 2 +- .../Dashboard/ChatScreen/ChatScreen.tsx | 5 +- .../Screens/Dashboard/CodeEditor/index.tsx | 2 +- .../Screens/Dashboard/Files/FilesScreen.tsx | 4 +- .../Settings/ResourceSettings/index.tsx | 3 +- .../Dashboard/Settings/SystemSettings.tsx | 2 +- .../Screens/Dashboard/TaskLogs/index.tsx | 2 +- .../Workspaces/WorkspaceListScreen.tsx | 4 +- .../Dashboard/Workspaces/app-registry.tsx | 10 +- src/apps/officer-web/state/useChatGroups.ts | 2 +- src/apps/officer-web/state/useChatSessions.ts | 2 +- src/apps/officer-web/state/useModels.ts | 2 +- src/workspaces/apps/Chat/ChatLauncher.tsx | 195 ----- src/workspaces/apps/Chat/EmbeddableChat.tsx | 274 ------- src/workspaces/apps/Chat/InputArea.tsx | 253 ------ src/workspaces/apps/Chat/index.ts | 18 - src/workspaces/apps/FileBrowser/Toolbar.tsx | 225 ----- src/workspaces/apps/FileBrowser/Widget.tsx | 268 ------ src/workspaces/apps/FileBrowser/index.ts | 11 - .../apps/FileBrowser/usePinnedFiles.ts | 23 - .../apps/FileBrowser/useRecentFiles.ts | 22 - .../apps/FileViewer/FileViewerContext.tsx | 358 -------- .../apps/FileViewer/FileViewerView.tsx | 774 ------------------ src/workspaces/apps/FileViewer/index.ts | 3 - src/workspaces/apps/package.json | 12 - .../components/Workspace/WorkspaceView.tsx | 53 +- src/workspaces/components/Workspace/index.ts | 2 +- src/workspaces/components/Workspace/types.ts | 6 + src/workspaces/officerdev/APP_CONVENTIONS.md | 151 ++++ src/workspaces/officerdev/HOOK_CONVENTIONS.md | 119 +++ src/workspaces/officerdev/package.json | 4 + .../apps/Chat/ChatLauncher/ChatLauncher.tsx | 120 +++ .../src/apps/Chat/ChatLauncher/index.ts | 1 + .../src}/apps/Chat/ChatList/index.tsx | 0 .../Chat/EmbeddableChat/EmbeddableChat.tsx | 32 + .../src/apps/Chat/EmbeddableChat/index.ts | 2 + .../Chat/EmbeddableChat/useEmbeddableChat.ts | 195 +++++ .../apps/Chat/components}/AttachButton.tsx | 0 .../apps/Chat/components}/AttachmentList.tsx | 2 +- .../src/apps/Chat/components/InputArea.tsx | 130 +++ .../apps/Chat/components}/MessageBubble.tsx | 2 +- .../src/apps/Chat/components}/MessageList.tsx | 34 +- .../apps/Chat/components}/ModelSelector.tsx | 8 +- .../Chat/components}/QuestionActivity.tsx | 2 +- .../apps/Chat/components}/ToolActivity.tsx | 2 +- .../apps/Chat/components}/WebpageDialog.tsx | 0 .../officerdev/src/apps/Chat/index.ts | 20 + .../{ => officerdev/src}/apps/Chat/types.ts | 0 .../src/apps/Chat/useAttachments.ts | 102 +++ .../src/apps/Chat/useAudioRecording.ts | 124 +++ .../src}/apps/Chat/useChatSession.ts | 0 .../src}/apps/Chat/useChatSessions.ts | 0 .../src}/apps/Chat/useSlashCommands.ts | 0 .../src}/apps/ChatHistory/SessionBar.tsx | 0 .../src}/apps/ChatHistory/index.ts | 0 .../src}/apps/CodeEditor/CodeEditor.tsx | 54 +- .../src}/apps/CodeEditor/EditorTabs.tsx | 3 +- .../src}/apps/CodeEditor/FileTree.tsx | 18 +- .../src}/apps/CodeEditor/index.ts | 0 .../src}/apps/CodeEditor/language-map.ts | 0 .../src}/apps/CodeEditor/useEditorState.ts | 43 +- .../FileBrowserApp/FileBrowserApp.tsx | 36 + .../FileBrowserApp/components}/Breadcrumb.tsx | 0 .../FileBrowserApp/components}/FileGrid.tsx | 171 ++-- .../FileBrowserApp/components}/FileItem.tsx | 14 +- .../components/FileViewContainer.tsx | 126 +++ .../components/HomeDirSelector.tsx | 42 + .../components/TaskRunnerDialog.tsx | 28 + .../components}/TaskRunnerModal.tsx | 11 +- .../components/Toolbar/ActionButtons.tsx | 29 + .../components/Toolbar/DefaultActions.tsx | 71 ++ .../components/Toolbar/SelectionActions.tsx | 64 ++ .../components/Toolbar/Toolbar.tsx | 129 +++ .../components/Toolbar/index.ts | 1 + .../components/UploadProgress.tsx | 26 + .../components/VideoDownloadDialog.tsx | 69 ++ .../FileBrowserApp/components/index.ts | 5 + .../apps/FileBrowser/FileBrowserApp/index.ts | 1 + .../FileBrowserApp/useFileBrowserApp.ts} | 757 +++++------------ .../FileBrowserWidget/FileBrowserWidget.tsx | 29 + .../components/BrowseTab.tsx | 46 ++ .../FileBrowserWidget/components/EntryRow.tsx | 47 ++ .../FileBrowserWidget/components/Header.tsx | 55 ++ .../components/PinnedTab.tsx | 30 + .../components/RecentTab.tsx | 30 + .../components/SearchResults.tsx | 41 + .../FileBrowser/FileBrowserWidget/index.ts | 1 + .../FileBrowserWidget/useFileBrowserWidget.ts | 83 ++ .../officerdev/src/apps/FileBrowser/index.ts | 7 + .../src/apps/FileBrowser/usePinnedFiles.ts | 19 + .../src/apps/FileBrowser/useRecentFiles.ts | 18 + .../src}/apps/FileBrowser/useTasks.ts | 20 +- .../src/apps/FileViewer/FileViewerBody.tsx | 64 ++ .../src/apps/FileViewer/FileViewerContext.tsx | 33 + .../src/apps/FileViewer/FileViewerHeader.tsx | 108 +++ .../apps/FileViewer/FileViewerProvider.tsx | 155 ++++ .../src/apps/FileViewer/FileViewerView.tsx | 33 + .../src}/apps/FileViewer/file-types.ts | 0 .../officerdev/src/apps/FileViewer/index.ts | 6 + .../FileViewer/renderers/AudioRenderer.tsx | 144 ++++ .../FileViewer/renderers/CodeRenderer.tsx | 37 + .../FileViewer/renderers/ImageRenderer.tsx | 149 ++++ .../FileViewer/renderers/MarkdownRenderer.tsx | 114 +++ .../apps/FileViewer/renderers/PdfRenderer.tsx | 3 + .../renderers/ScrollToTopButton.tsx | 30 + .../src/apps/FileViewer/renderers/SeekBar.tsx | 56 ++ .../FileViewer/renderers/TextRenderer.tsx | 3 + .../FileViewer/renderers/VideoRenderer.tsx | 185 +++++ .../src/apps/FileViewer/renderers/index.ts | 9 + .../src}/apps/Terminal/Terminal.tsx | 0 .../src}/apps/Terminal/index.ts | 0 src/workspaces/officerdev/src/hooks/index.ts | 3 + .../hooks/useFileViewerPanels/Providers.tsx | 63 ++ .../src/hooks/useFileViewerPanels/index.ts | 1 + .../src/hooks/useFileViewerPanels/layouts.ts | 38 + .../useFileViewerPanels.tsx | 61 ++ .../src/hooks/useFilesAPI.ts} | 77 +- .../src/hooks/usePiChat.ts} | 8 +- src/workspaces/officerdev/src/index.ts | 6 + 125 files changed, 3840 insertions(+), 3285 deletions(-) delete mode 100644 src/workspaces/apps/Chat/ChatLauncher.tsx delete mode 100644 src/workspaces/apps/Chat/EmbeddableChat.tsx delete mode 100644 src/workspaces/apps/Chat/InputArea.tsx delete mode 100644 src/workspaces/apps/Chat/index.ts delete mode 100644 src/workspaces/apps/FileBrowser/Toolbar.tsx delete mode 100644 src/workspaces/apps/FileBrowser/Widget.tsx delete mode 100644 src/workspaces/apps/FileBrowser/index.ts delete mode 100644 src/workspaces/apps/FileBrowser/usePinnedFiles.ts delete mode 100644 src/workspaces/apps/FileBrowser/useRecentFiles.ts delete mode 100644 src/workspaces/apps/FileViewer/FileViewerContext.tsx delete mode 100644 src/workspaces/apps/FileViewer/FileViewerView.tsx delete mode 100644 src/workspaces/apps/FileViewer/index.ts delete mode 100644 src/workspaces/apps/package.json create mode 100644 src/workspaces/officerdev/APP_CONVENTIONS.md create mode 100644 src/workspaces/officerdev/HOOK_CONVENTIONS.md create mode 100644 src/workspaces/officerdev/src/apps/Chat/ChatLauncher/ChatLauncher.tsx create mode 100644 src/workspaces/officerdev/src/apps/Chat/ChatLauncher/index.ts rename src/workspaces/{ => officerdev/src}/apps/Chat/ChatList/index.tsx (100%) create mode 100644 src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/EmbeddableChat.tsx create mode 100644 src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/index.ts create mode 100644 src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/useEmbeddableChat.ts rename src/workspaces/{apps/Chat => officerdev/src/apps/Chat/components}/AttachButton.tsx (100%) rename src/workspaces/{apps/Chat => officerdev/src/apps/Chat/components}/AttachmentList.tsx (96%) create mode 100644 src/workspaces/officerdev/src/apps/Chat/components/InputArea.tsx rename src/workspaces/{apps/Chat => officerdev/src/apps/Chat/components}/MessageBubble.tsx (98%) rename src/workspaces/{apps/Chat => officerdev/src/apps/Chat/components}/MessageList.tsx (74%) rename src/workspaces/{apps/Chat => officerdev/src/apps/Chat/components}/ModelSelector.tsx (93%) rename src/workspaces/{apps/Chat => officerdev/src/apps/Chat/components}/QuestionActivity.tsx (99%) rename src/workspaces/{apps/Chat => officerdev/src/apps/Chat/components}/ToolActivity.tsx (99%) rename src/workspaces/{apps/Chat => officerdev/src/apps/Chat/components}/WebpageDialog.tsx (100%) create mode 100644 src/workspaces/officerdev/src/apps/Chat/index.ts rename src/workspaces/{ => officerdev/src}/apps/Chat/types.ts (100%) create mode 100644 src/workspaces/officerdev/src/apps/Chat/useAttachments.ts create mode 100644 src/workspaces/officerdev/src/apps/Chat/useAudioRecording.ts rename src/workspaces/{ => officerdev/src}/apps/Chat/useChatSession.ts (100%) rename src/workspaces/{ => officerdev/src}/apps/Chat/useChatSessions.ts (100%) rename src/workspaces/{ => officerdev/src}/apps/Chat/useSlashCommands.ts (100%) rename src/workspaces/{ => officerdev/src}/apps/ChatHistory/SessionBar.tsx (100%) rename src/workspaces/{ => officerdev/src}/apps/ChatHistory/index.ts (100%) rename src/workspaces/{ => officerdev/src}/apps/CodeEditor/CodeEditor.tsx (80%) rename src/workspaces/{ => officerdev/src}/apps/CodeEditor/EditorTabs.tsx (96%) rename src/workspaces/{ => officerdev/src}/apps/CodeEditor/FileTree.tsx (89%) rename src/workspaces/{ => officerdev/src}/apps/CodeEditor/index.ts (100%) rename src/workspaces/{ => officerdev/src}/apps/CodeEditor/language-map.ts (100%) rename src/workspaces/{ => officerdev/src}/apps/CodeEditor/useEditorState.ts (54%) create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/FileBrowserApp.tsx rename src/workspaces/{apps/FileBrowser => officerdev/src/apps/FileBrowser/FileBrowserApp/components}/Breadcrumb.tsx (100%) rename src/workspaces/{apps/FileBrowser => officerdev/src/apps/FileBrowser/FileBrowserApp/components}/FileGrid.tsx (70%) rename src/workspaces/{apps/FileBrowser => officerdev/src/apps/FileBrowser/FileBrowserApp/components}/FileItem.tsx (98%) create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/FileViewContainer.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/HomeDirSelector.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/TaskRunnerDialog.tsx rename src/workspaces/{apps/FileBrowser => officerdev/src/apps/FileBrowser/FileBrowserApp/components}/TaskRunnerModal.tsx (92%) create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/Toolbar/ActionButtons.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/Toolbar/DefaultActions.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/Toolbar/SelectionActions.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/Toolbar/Toolbar.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/Toolbar/index.ts create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/UploadProgress.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/VideoDownloadDialog.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/index.ts create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/index.ts rename src/workspaces/{apps/FileBrowser/Files.tsx => officerdev/src/apps/FileBrowser/FileBrowserApp/useFileBrowserApp.ts} (50%) create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserWidget/FileBrowserWidget.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserWidget/components/BrowseTab.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserWidget/components/EntryRow.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserWidget/components/Header.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserWidget/components/PinnedTab.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserWidget/components/RecentTab.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserWidget/components/SearchResults.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserWidget/index.ts create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserWidget/useFileBrowserWidget.ts create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/index.ts create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/usePinnedFiles.ts create mode 100644 src/workspaces/officerdev/src/apps/FileBrowser/useRecentFiles.ts rename src/workspaces/{ => officerdev/src}/apps/FileBrowser/useTasks.ts (60%) create mode 100644 src/workspaces/officerdev/src/apps/FileViewer/FileViewerBody.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileViewer/FileViewerContext.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileViewer/FileViewerHeader.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileViewer/FileViewerProvider.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileViewer/FileViewerView.tsx rename src/workspaces/{ => officerdev/src}/apps/FileViewer/file-types.ts (100%) create mode 100644 src/workspaces/officerdev/src/apps/FileViewer/index.ts create mode 100644 src/workspaces/officerdev/src/apps/FileViewer/renderers/AudioRenderer.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileViewer/renderers/CodeRenderer.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileViewer/renderers/ImageRenderer.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileViewer/renderers/MarkdownRenderer.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileViewer/renderers/PdfRenderer.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileViewer/renderers/ScrollToTopButton.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileViewer/renderers/SeekBar.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileViewer/renderers/TextRenderer.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileViewer/renderers/VideoRenderer.tsx create mode 100644 src/workspaces/officerdev/src/apps/FileViewer/renderers/index.ts rename src/workspaces/{ => officerdev/src}/apps/Terminal/Terminal.tsx (100%) rename src/workspaces/{ => officerdev/src}/apps/Terminal/index.ts (100%) create mode 100644 src/workspaces/officerdev/src/hooks/useFileViewerPanels/Providers.tsx create mode 100644 src/workspaces/officerdev/src/hooks/useFileViewerPanels/index.ts create mode 100644 src/workspaces/officerdev/src/hooks/useFileViewerPanels/layouts.ts create mode 100644 src/workspaces/officerdev/src/hooks/useFileViewerPanels/useFileViewerPanels.tsx rename src/workspaces/{apps/FileBrowser/useFiles.ts => officerdev/src/hooks/useFilesAPI.ts} (79%) rename src/workspaces/{apps/Chat/usePi.ts => officerdev/src/hooks/usePiChat.ts} (97%) diff --git a/bun.lock b/bun.lock index cce2d9ba..9a31afca 100644 --- a/bun.lock +++ b/bun.lock @@ -48,7 +48,6 @@ "@uiw/react-textarea-code-editor": "^3.1.1", "@xterm/addon-fit": "^0.11.0", "@xterm/xterm": "^6.0.0", - "apps": "workspace:*", "argon2": "^0.44.0", "bun-plugin-tailwind": "^0.1.2", "check-password-strength": "^3.0.0", @@ -146,9 +145,6 @@ "drizzle-kit": "^0.31.8", }, }, - "src/workspaces/apps": { - "name": "apps", - }, "src/workspaces/components": { "name": "components", "version": "0.0.1", @@ -247,6 +243,10 @@ "src/workspaces/officerdev": { "name": "officerdev", "version": "0.0.1", + "dependencies": { + "hooks": "workspace:*", + "widgets": "workspace:*", + }, }, "src/workspaces/sounds": { "name": "sounds", @@ -1061,8 +1061,6 @@ "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], - "apps": ["apps@workspace:src/workspaces/apps"], - "arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], "argon2": ["argon2@0.44.0", "", { "dependencies": { "@phc/format": "^1.0.0", "cross-env": "^10.0.0", "node-addon-api": "^8.5.0", "node-gyp-build": "^4.8.4" } }, "sha512-zHPGN3S55sihSQo0dBbK0A5qpi2R31z7HZDZnry3ifOyj8bZZnpZND2gpmhnRGO1V/d555RwBqIK5W4Mrmv3ig=="], diff --git a/package.json b/package.json index 01c97b26..8d055704 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,6 @@ "three": "^0.182.0", "types": "workspace:*", "vaul": "^1.1.2", - "apps": "workspace:*", "officerdev": "workspace:*", "widgets": "workspace:*", "ws": "^8.18.1", diff --git a/src/apps/officer-web/Screens/Dashboard/Automation/CapabilityDetailView.tsx b/src/apps/officer-web/Screens/Dashboard/Automation/CapabilityDetailView.tsx index 7728fa0d..d6cb1159 100644 --- a/src/apps/officer-web/Screens/Dashboard/Automation/CapabilityDetailView.tsx +++ b/src/apps/officer-web/Screens/Dashboard/Automation/CapabilityDetailView.tsx @@ -13,7 +13,7 @@ import { Card } from '@/components/Card'; import { FrontmatterBlock } from '../CapabilityPage'; import type { CapabilityDetail } from '../CapabilityPage'; import type { AutomationSelection } from './AutomationRightPanel'; -import { TaskRunnerModal } from 'apps/FileBrowser'; +import { TaskRunnerModal } from 'officerdev'; type SelectOption = { value: string; label: string }; diff --git a/src/apps/officer-web/Screens/Dashboard/CapabilityPage.tsx b/src/apps/officer-web/Screens/Dashboard/CapabilityPage.tsx index 9afaabb7..14903751 100644 --- a/src/apps/officer-web/Screens/Dashboard/CapabilityPage.tsx +++ b/src/apps/officer-web/Screens/Dashboard/CapabilityPage.tsx @@ -8,9 +8,8 @@ import { ArrowLeft, Pencil, Plus, Check, X, Trash2, Search, ChevronRight } from import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog'; import { useClient } from 'hooks/useClient'; -import { useVisiblePiModels } from '@/state/useModels'; import { Card } from '@/components/Card'; -import { usePi, EmbeddableChat } from 'apps/Chat'; +import { usePiChat, EmbeddableChat } from 'officerdev'; type CapabilitySummary = { dirName: string; name: string; @@ -63,14 +62,13 @@ export const CapabilityChat = ({ description, onResponseEnd, }: CapabilityChatProps) => { - const piModels = useVisiblePiModels(); const seedFile = `${kind.toUpperCase()}.md`; const promptFrontmatter = `\ninput file: ${filePath}\n${seedFile}: ${filePath}\ndir: ${resourceDir}\n\nBe aware of any extra files alongside the same dir as the ${kind} file we're handling, for possible extra context. You can also, if pertinent, create scripts or other files that will help you in the future.\n`; const defaultInput = isNew ? description ?? `Help me create the content for this new ${kind} file` : `Help me understand and improve this ${kind} file`; - const pi = usePi(undefined, undefined, { replaceUrl: false }); + const pi = usePiChat(undefined, undefined, { replaceUrl: false }); const onResponseEndRef = useRef(onResponseEnd); onResponseEndRef.current = onResponseEnd; @@ -86,7 +84,6 @@ export const CapabilityChat = ({ return ( @@ -99,7 +99,7 @@ function NewChat() { const [, setSelected] = usePanelChannel(CHANNEL, null); // We need connection status for DetailBar, so call usePi - const chat = usePi(); + const chat = usePiChat(); useEffect(() => { if (chat.sessionId) { diff --git a/src/apps/officer-web/Screens/Dashboard/ChatHistory/GroupContextMenu.tsx b/src/apps/officer-web/Screens/Dashboard/ChatHistory/GroupContextMenu.tsx index 93428ecd..688ed08b 100644 --- a/src/apps/officer-web/Screens/Dashboard/ChatHistory/GroupContextMenu.tsx +++ b/src/apps/officer-web/Screens/Dashboard/ChatHistory/GroupContextMenu.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import { MoreVertical, Edit2, Trash2 } from 'lucide-react'; import { useChatGroups } from '@/state/useChatGroups'; -import type { GroupEntry } from 'apps/Chat'; +import type { GroupEntry } from 'officerdev'; type GroupContextMenuProps = { group: GroupEntry; diff --git a/src/apps/officer-web/Screens/Dashboard/ChatHistory/SessionContextMenu.tsx b/src/apps/officer-web/Screens/Dashboard/ChatHistory/SessionContextMenu.tsx index 634444c3..c9161d0c 100644 --- a/src/apps/officer-web/Screens/Dashboard/ChatHistory/SessionContextMenu.tsx +++ b/src/apps/officer-web/Screens/Dashboard/ChatHistory/SessionContextMenu.tsx @@ -2,7 +2,7 @@ import { useState } from 'react'; import { MoreVertical, FolderInput, Edit2, Trash2 } from 'lucide-react'; import { useChatGroups } from '@/state/useChatGroups'; import { useChatSessions } from '@/state/useChatSessions'; -import type { SessionEntry } from 'apps/Chat'; +import type { SessionEntry } from 'officerdev'; type SessionContextMenuProps = { session: SessionEntry; diff --git a/src/apps/officer-web/Screens/Dashboard/ChatScreen/ChatScreen.tsx b/src/apps/officer-web/Screens/Dashboard/ChatScreen/ChatScreen.tsx index 141e5759..5aeb7492 100644 --- a/src/apps/officer-web/Screens/Dashboard/ChatScreen/ChatScreen.tsx +++ b/src/apps/officer-web/Screens/Dashboard/ChatScreen/ChatScreen.tsx @@ -1,14 +1,13 @@ import { useRef, useEffect, useState } from 'react'; import { useNavigate, useLocation } from 'react-router'; import { useChatSessions } from '@/state/useChatSessions'; -import { SessionBar } from 'apps/ChatHistory'; -import { EmbeddableChat, type UsePiType, type Attachment } from 'apps/Chat'; +import { SessionBar, EmbeddableChat, type UsePiChatType, type Attachment } from 'officerdev'; import { Card } from '@/components/Card'; export type { Attachment }; type ChatPanelProps = { - chat: UsePiType; + chat: UsePiChatType; }; export const ChatScreen = ({ chat }: ChatPanelProps) => { diff --git a/src/apps/officer-web/Screens/Dashboard/CodeEditor/index.tsx b/src/apps/officer-web/Screens/Dashboard/CodeEditor/index.tsx index e713d7a2..7cb4c18e 100644 --- a/src/apps/officer-web/Screens/Dashboard/CodeEditor/index.tsx +++ b/src/apps/officer-web/Screens/Dashboard/CodeEditor/index.tsx @@ -1,4 +1,4 @@ -import { CodeEditorView } from 'apps/CodeEditor'; +import { CodeEditorView } from 'officerdev'; import { Widget } from 'widgets/Widget'; export const CodeEditor = () => ( diff --git a/src/apps/officer-web/Screens/Dashboard/Files/FilesScreen.tsx b/src/apps/officer-web/Screens/Dashboard/Files/FilesScreen.tsx index 6996eac1..5f740980 100644 --- a/src/apps/officer-web/Screens/Dashboard/Files/FilesScreen.tsx +++ b/src/apps/officer-web/Screens/Dashboard/Files/FilesScreen.tsx @@ -1,15 +1,17 @@ import type { LayoutNode } from '@/components/Workspace'; import { WorkspaceView } from '@/components/Workspace'; import { useWorkspacesState } from '@/state/useWorkspacesState'; +import { useFileViewerPanels } from 'officerdev'; import { appRegistry } from '../Workspaces/app-registry'; import { defaultLayout } from './defaultLayout'; export const FilesScreen = () => { const workspace = useWorkspacesState('screens/files', defaultLayout); + const ephemeral = useFileViewerPanels(); return (
- +
); }; 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 6a8f2913..a70fc7ab 100644 --- a/src/apps/officer-web/Screens/Dashboard/Settings/ResourceSettings/index.tsx +++ b/src/apps/officer-web/Screens/Dashboard/Settings/ResourceSettings/index.tsx @@ -6,8 +6,7 @@ import type { LayoutNode, PanelComponents } from '@/components/Workspace'; import { WorkspaceLayout } from '@/components/Workspace'; import { usePanelChannel } from 'hooks/usePanelChannel'; import { useClient } from 'hooks/useClient'; -import { TerminalView } from 'apps/Terminal'; -import { FileViewerView } from 'apps/FileViewer'; +import { TerminalView, FileViewerView } from 'officerdev'; import { appRegistry } from '../../Workspaces/app-registry'; import { Resources } from './Resources'; import { ResourceSidebar } from './ResourceSidebar'; diff --git a/src/apps/officer-web/Screens/Dashboard/Settings/SystemSettings.tsx b/src/apps/officer-web/Screens/Dashboard/Settings/SystemSettings.tsx index d5ea630c..eb02071f 100644 --- a/src/apps/officer-web/Screens/Dashboard/Settings/SystemSettings.tsx +++ b/src/apps/officer-web/Screens/Dashboard/Settings/SystemSettings.tsx @@ -11,7 +11,7 @@ import { useQueryClient } from '@tanstack/react-query'; import type { LayoutNode, PanelComponents } from '@/components/Workspace'; import { WorkspaceLayout } from '@/components/Workspace'; import { usePanelChannel } from 'hooks/usePanelChannel'; -import { TerminalView } from 'apps/Terminal'; +import { TerminalView } from 'officerdev'; import { appRegistry } from '../Workspaces/app-registry'; import { createSettingsPanelComponents, type SettingsSectionGroup } from './SettingsPanel'; import { useSettings } from '@/state/useSettings'; diff --git a/src/apps/officer-web/Screens/Dashboard/TaskLogs/index.tsx b/src/apps/officer-web/Screens/Dashboard/TaskLogs/index.tsx index 993db7d0..3522d323 100644 --- a/src/apps/officer-web/Screens/Dashboard/TaskLogs/index.tsx +++ b/src/apps/officer-web/Screens/Dashboard/TaskLogs/index.tsx @@ -2,7 +2,7 @@ import { useState, useEffect } from 'react'; import { Search, AlertCircle, CheckCircle2, Clock, ArrowLeft } from 'lucide-react'; import { useClient } from 'hooks/useClient'; import { Card } from '@/components/Card'; -import { MessageBubble, type ChatMessage } from 'apps/Chat'; +import { MessageBubble, type ChatMessage } from 'officerdev'; type LogMetadata = { filename: string; diff --git a/src/apps/officer-web/Screens/Dashboard/Workspaces/WorkspaceListScreen.tsx b/src/apps/officer-web/Screens/Dashboard/Workspaces/WorkspaceListScreen.tsx index 0fa87b41..cfe96bbb 100644 --- a/src/apps/officer-web/Screens/Dashboard/Workspaces/WorkspaceListScreen.tsx +++ b/src/apps/officer-web/Screens/Dashboard/Workspaces/WorkspaceListScreen.tsx @@ -10,7 +10,7 @@ import { WorkspaceLayout, WorkspaceView, createDefaultLayout } from '@/component import type { LayoutNode, WorkspaceDefinition } from '@/components/Workspace'; import { Button } from '@/components/ui/button'; import { generateSlug, slugify } from 'helpers/slug'; -import { Files } from 'apps/FileBrowser'; +import { FileBrowserApp } from 'officerdev'; import { appRegistry } from './app-registry'; import { SELECTED_WORKSPACE_KEY, CREATING_WORKSPACE_KEY, EDITING_WORKSPACE_KEY, NEW_WS_NAME_KEY, NEW_WS_DESC_KEY, NEW_WS_TEMPLATE_KEY } from './constants'; @@ -396,7 +396,7 @@ const CreatePanel = () => { const CwdFileBrowser = () => { const [currentPath] = useUserState('files/currentPath', '/'); const [basePath] = useState(currentPath); - return ; + return ; }; // --- New Workspace Layout --- diff --git a/src/apps/officer-web/Screens/Dashboard/Workspaces/app-registry.tsx b/src/apps/officer-web/Screens/Dashboard/Workspaces/app-registry.tsx index b56f53dd..fec90aeb 100644 --- a/src/apps/officer-web/Screens/Dashboard/Workspaces/app-registry.tsx +++ b/src/apps/officer-web/Screens/Dashboard/Workspaces/app-registry.tsx @@ -5,15 +5,11 @@ import { Monitor, LayoutGrid, LayoutDashboard, Sparkles, Eye, FolderKanban, Colu import { useAuth } from 'hooks/useAuth'; import type { AppRegistry } from '@/components/Workspace'; import { useWorkspace } from '@/components/Workspace'; -import { CodeEditorView } from 'apps/CodeEditor'; -import { TerminalView } from 'apps/Terminal'; +import { CodeEditorView, TerminalView, FileViewerProvider, FileViewerHeader, FileViewerBody, EmbeddableChat, ChatLauncher, usePiChat, FileBrowserApp } from 'officerdev'; import { useWorkspacesState } from '@/state/useWorkspacesState'; import { usePanelChannel } from 'hooks/usePanelChannel'; -import { FileViewerProvider, FileViewerHeader, FileViewerBody } from 'apps/FileViewer'; -import { EmbeddableChat, ChatLauncher, usePi } from 'apps/Chat'; import { useVisiblePiModels } from '@/state/useModels'; import { ChatHistoryApp as ChatHistory } from '../ChatHistory'; -import { Files } from 'apps/FileBrowser'; import { Catalog } from 'sounds'; import { WorkspaceListApp } from './WorkspaceListApp'; import { ProjectListApp } from '../Projects/ProjectListApp'; @@ -23,7 +19,7 @@ import { WidgetPanel } from 'widgets/WidgetPanel'; const ChatWidget = () => ; const ChatLauncherWidget = () => { - const pi = usePi(); + const pi = usePiChat(); const models = useVisiblePiModels(); console.log(models) return ( @@ -41,7 +37,7 @@ const cwdToPath = (cwd: string) => (cwd === '~' ? '/' : cwd.slice(1)); const FileBrowserWrapper = () => { const { cwd } = useWorkspace(); const basePath = cwdToPath(cwd); - return ; + return ; }; const CodeEditorWrapper = () => ; diff --git a/src/apps/officer-web/state/useChatGroups.ts b/src/apps/officer-web/state/useChatGroups.ts index 3091b10d..47bd88c1 100644 --- a/src/apps/officer-web/state/useChatGroups.ts +++ b/src/apps/officer-web/state/useChatGroups.ts @@ -1,4 +1,4 @@ -import type { GroupEntry } from 'apps/Chat'; +import type { GroupEntry } from 'officerdev'; import { useAuth } from 'hooks/useAuth'; import { useClient } from 'hooks/useClient'; import { useQuery, useQueryClient } from '@tanstack/react-query'; diff --git a/src/apps/officer-web/state/useChatSessions.ts b/src/apps/officer-web/state/useChatSessions.ts index 362aba93..bf358181 100644 --- a/src/apps/officer-web/state/useChatSessions.ts +++ b/src/apps/officer-web/state/useChatSessions.ts @@ -1,4 +1,4 @@ -import type { SessionEntry, ChatMessage, Message } from 'apps/Chat'; +import type { SessionEntry, ChatMessage, Message } from 'officerdev'; import { useAuth } from 'hooks/useAuth'; import { useClient } from 'hooks/useClient'; import { useQuery, useQueryClient } from '@tanstack/react-query'; diff --git a/src/apps/officer-web/state/useModels.ts b/src/apps/officer-web/state/useModels.ts index 75c2dca3..105c3139 100644 --- a/src/apps/officer-web/state/useModels.ts +++ b/src/apps/officer-web/state/useModels.ts @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query'; import { useClient } from 'hooks/useClient'; import { useAuth } from 'hooks/useAuth'; import { useSettings } from './useSettings'; -import type { ModelOption } from 'apps/Chat'; +import type { ModelOption } from 'officerdev'; export type { ModelOption }; diff --git a/src/workspaces/apps/Chat/ChatLauncher.tsx b/src/workspaces/apps/Chat/ChatLauncher.tsx deleted file mode 100644 index d6a3b41c..00000000 --- a/src/workspaces/apps/Chat/ChatLauncher.tsx +++ /dev/null @@ -1,195 +0,0 @@ -import { useState, useMemo, useRef, useEffect, type KeyboardEvent } from 'react'; -import { Send } from 'lucide-react'; -import { toast } from 'sonner'; -import { useClient } from 'hooks/useClient'; -import { Button } from '@/components/ui/button'; -import type { ModelOption, Attachment } from './types'; -import { ModelSelector } from './ModelSelector'; -import { AttachmentList } from './AttachmentList'; -import { AttachButton } from './AttachButton'; -import { WebpageDialog } from './WebpageDialog'; - -type ChatLauncherProps = { - availableModels: ModelOption[]; - selectedModel: string | null; - onModelChange: (modelId: string) => void; - onSubmit: (data: { - prompt: string; - model: string | null; - attachmentIds?: string[]; - images?: { filename: string; dataUrl: string }[]; - }) => void; - placeholder?: string; -}; - -export function ChatLauncher({ - availableModels, - selectedModel, - onModelChange, - onSubmit, - placeholder = 'What do you want to work on now?', -}: ChatLauncherProps) { - const client = useClient(); - const [input, setInput] = useState(''); - const [attachments, setAttachments] = useState([]); - const [urlDialogOpen, setUrlDialogOpen] = useState(false); - const textareaRef = useRef(null); - - const handleAttachWebpage = async (url: string) => { - const idx = attachments.length; - setAttachments((prev) => [ - ...prev, - { type: 'webpage', url, title: '', content: '', attachmentId: '', loading: true }, - ]); - - try { - const res = await client.post<{ url: string; title: string; content: string; attachmentId: string }>('/scrape', { - url, - provider: 'pi-mono', - }); - setAttachments((prev) => - prev.map((a, i) => - i === idx - ? { ...a, title: res.title, content: res.content, attachmentId: res.attachmentId, loading: false } - : a, - ), - ); - } catch { - setAttachments((prev) => prev.filter((_, i) => i !== idx)); - toast.error('Failed to scrape webpage'); - } - }; - - const handleAttachImage = async (file: File) => { - const idx = attachments.length; - setAttachments((prev) => [ - ...prev, - { type: 'image', filename: file.name, dataUrl: '', attachmentId: '', loading: true }, - ]); - - try { - const formData = new FormData(); - formData.append('file', file); - formData.append('provider', 'pi-mono'); - - const res = await client.post<{ filename: string; dataUrl: string; attachmentId: string }>('/upload', formData); - setAttachments((prev) => - prev.map((a, i) => - i === idx ? { ...a, dataUrl: res.dataUrl, attachmentId: res.attachmentId, loading: false } : a, - ), - ); - } catch { - setAttachments((prev) => prev.filter((_, i) => i !== idx)); - toast.error('Failed to upload image'); - } - }; - - const handleSubmit = () => { - const text = input.trim(); - if (!text) return; - - let prompt = text; - const attachmentIds: string[] = []; - const images: { filename: string; dataUrl: string }[] = []; - - for (const a of attachments) { - if (a.loading) continue; - if (a.type === 'webpage' && a.content) { - prompt = `[Attached webpage: ${a.url}]\n${a.content}\n\n${prompt}`; - } else if (a.type === 'image' && a.dataUrl) { - prompt = `[Attached image: ${a.filename}]\n\n${prompt}`; - images.push({ filename: a.filename, dataUrl: a.dataUrl }); - } - attachmentIds.push(a.attachmentId); - } - - onSubmit({ - prompt, - model: selectedModel, - attachmentIds: attachmentIds.length > 0 ? attachmentIds : undefined, - images: images.length > 0 ? images : undefined, - }); - - // Reset form - setInput(''); - setAttachments([]); - }; - - const handleKeyDown = (ev: KeyboardEvent) => { - if (ev.key === 'Enter' && !ev.shiftKey) { - ev.preventDefault(); - handleSubmit(); - } - }; - - const handleImagePaste = (file: File) => { - handleAttachImage(file); - }; - - // Auto-resize textarea - useEffect(() => { - const textarea = textareaRef.current; - if (!textarea) return; - textarea.style.height = 'auto'; - textarea.style.height = Math.min(textarea.scrollHeight, 160) + 'px'; - }, [input]); - - return ( -
- setAttachments((prev) => prev.filter((_, j) => j !== i))} /> - -
- setUrlDialogOpen(true)} - /> -