diff --git a/apps/web/src/components/mobile-workspace/mobile-flow-page.tsx b/apps/web/src/components/mobile-workspace/mobile-flow-page.tsx index f7d38e2..11fb163 100644 --- a/apps/web/src/components/mobile-workspace/mobile-flow-page.tsx +++ b/apps/web/src/components/mobile-workspace/mobile-flow-page.tsx @@ -58,6 +58,8 @@ export const MobileFlowPage = ({ screen }: MobileFlowPageProps) => { assistantError: projectWorkspace.error?.message, localStatus: workspace.statusMessage, }); + const handleRepositoryChange = + projectWorkspace.projectWorkspace.setRepository; const handleOpenUnit = (selectedWorkUnitId?: string) => { const targetId = @@ -135,6 +137,7 @@ export const MobileFlowPage = ({ screen }: MobileFlowPageProps) => { data={projectWorkspace.data} modelId={MODEL_ID} modelLabel={MODEL_LABEL} + onAddProject={() => workspace.setProjectManagerOpen(true)} onComposerChange={workspace.handleComposerChange} onComposerSubmit={workspace.handleComposerSubmit} onOpenUnit={(selectedWorkUnitId) => @@ -145,6 +148,12 @@ export const MobileFlowPage = ({ screen }: MobileFlowPageProps) => { projectId as Id<"projects"> ) } + onProjectManagerClose={() => workspace.setProjectManagerOpen(false)} + onRepositoryChange={handleRepositoryChange} + onRepositoryConnect={(event) => { + event.preventDefault(); + void projectWorkspace.projectWorkspace.connectRepository(); + }} onRestoreChecked={handleRestoreChecked} onSettingsClose={() => workspace.setSettingsOpen(false)} onSettingsOpen={() => workspace.setSettingsOpen(true)} @@ -153,6 +162,9 @@ export const MobileFlowPage = ({ screen }: MobileFlowPageProps) => { }} onWorkUnitChecked={handleWorkUnitChecked} onWorkUnitSentBack={handleWorkUnitSentBack} + pendingAction={projectWorkspace.projectWorkspace.pendingAction} + projectManagerOpen={workspace.projectManagerOpen} + repositoryValue={projectWorkspace.projectWorkspace.repository} settingsOpen={workspace.settingsOpen} statusMessage={statusMessage} userEmail={user?.email} diff --git a/packages/ui/src/components/mobile-workspace/mobile-project-manager-panel.tsx b/packages/ui/src/components/mobile-workspace/mobile-project-manager-panel.tsx new file mode 100644 index 0000000..6562bef --- /dev/null +++ b/packages/ui/src/components/mobile-workspace/mobile-project-manager-panel.tsx @@ -0,0 +1,118 @@ +import { LoaderCircle, X } from "lucide-react"; +import type { FormEvent } from "react"; + +import type { MobileWorkspaceView } from "./models"; + +export interface MobileProjectManagerPanelProps { + readonly data: MobileWorkspaceView; + readonly onClose: () => void; + readonly onProjectSelect: (projectId: string) => void; + readonly onRepositoryChange: (value: string) => void; + readonly onRepositoryConnect: (event: FormEvent) => void; + readonly pendingAction?: string | null; + readonly repositoryValue: string; + readonly statusMessage?: string; +} + +export const MobileProjectManagerPanel = ({ + data, + onClose, + onProjectSelect, + onRepositoryChange, + onRepositoryConnect, + pendingAction, + repositoryValue, + statusMessage, +}: MobileProjectManagerPanelProps) => { + const connecting = pendingAction === "connect"; + + return ( +
+
+
+

Projects

+

+ Connect a repository to Zopu. +

+
+ +
+ +
+
+ + + +
+ + + onRepositoryChange(event.currentTarget.value) + } + placeholder="https://git.openputer.com/owner/repo.git" + required + type="url" + value={repositoryValue} + /> + +
+
+ + {statusMessage ? ( +

+ {statusMessage} +

+ ) : null} +
+
+ ); +}; diff --git a/packages/ui/src/components/mobile-workspace/mobile-project-select.tsx b/packages/ui/src/components/mobile-workspace/mobile-project-select.tsx index bf6e9d9..1039878 100644 --- a/packages/ui/src/components/mobile-workspace/mobile-project-select.tsx +++ b/packages/ui/src/components/mobile-workspace/mobile-project-select.tsx @@ -1,11 +1,12 @@ import { cn } from "@code/ui/lib/utils"; -import { ChevronDown } from "lucide-react"; +import { ChevronDown, Plus } from "lucide-react"; import type { MobileProjectView } from "./models"; export interface MobileProjectSelectProps { readonly activeCount: number; readonly className?: string; + readonly onAddProject: () => void; readonly onProjectSelect: (projectId: string) => void; readonly projects: readonly MobileProjectView[]; readonly selectedProjectId?: string; @@ -14,6 +15,7 @@ export interface MobileProjectSelectProps { export const MobileProjectSelect = ({ activeCount, className, + onAddProject, onProjectSelect, projects, selectedProjectId, @@ -49,5 +51,14 @@ export const MobileProjectSelect = ({ {activeCount} active + ); diff --git a/packages/ui/src/components/mobile-workspace/mobile-work-stack-screen.tsx b/packages/ui/src/components/mobile-workspace/mobile-work-stack-screen.tsx index 70bbc2e..425ba59 100644 --- a/packages/ui/src/components/mobile-workspace/mobile-work-stack-screen.tsx +++ b/packages/ui/src/components/mobile-workspace/mobile-work-stack-screen.tsx @@ -10,6 +10,7 @@ import { } from "lucide-react"; import type { FormEvent, MouseEvent } from "react"; +import { MobileProjectManagerPanel } from "./mobile-project-manager-panel"; import { MobileProjectSelect } from "./mobile-project-select"; import { MobileSettingsPanel } from "./mobile-settings-panel"; import type { @@ -42,6 +43,7 @@ const dateLabel = new Intl.DateTimeFormat("en", { interface WorkStackHeaderProps { readonly activeCount: number; + readonly onAddProject: () => void; readonly onOpenSettings?: () => void; readonly onProjectSelect: (projectId: string) => void; readonly projects: readonly MobileProjectView[]; @@ -51,6 +53,7 @@ interface WorkStackHeaderProps { const WorkStackHeader = ({ activeCount, + onAddProject, onOpenSettings, onProjectSelect, projects, @@ -67,6 +70,7 @@ const WorkStackHeader = ({ void; readonly onComposerChange: (value: string) => void; readonly onComposerSubmit: (event: FormEvent) => void; readonly onOpenUnit: (workUnitId: string) => void; readonly onProjectSelect: (projectId: string) => void; + readonly onProjectManagerClose: () => void; + readonly onRepositoryChange: (value: string) => void; + readonly onRepositoryConnect: (event: FormEvent) => void; readonly onRestoreChecked: () => void; readonly onSettingsClose: () => void; readonly onSettingsOpen: () => void; readonly onSignOut?: () => void; readonly onWorkUnitChecked: (workUnitId: string) => void; readonly onWorkUnitSentBack: (workUnitId: string) => void; + readonly pendingAction?: string | null; + readonly projectManagerOpen: boolean; + readonly repositoryValue: string; readonly settingsOpen: boolean; readonly statusMessage?: string; readonly userEmail?: string; @@ -322,16 +333,23 @@ export const MobileWorkStackScreen = ({ data, modelId, modelLabel, + onAddProject, onComposerChange, onComposerSubmit, onOpenUnit, + onProjectManagerClose, onProjectSelect, + onRepositoryChange, + onRepositoryConnect, onRestoreChecked, onSettingsClose, onSettingsOpen, onSignOut, onWorkUnitChecked, onWorkUnitSentBack, + pendingAction, + projectManagerOpen, + repositoryValue, settingsOpen, statusMessage, userEmail, @@ -350,6 +368,7 @@ export const MobileWorkStackScreen = ({
+ {projectManagerOpen ? ( + + ) : null} {settingsOpen ? (