6b118307eb
- Extract use-repo-workspace hook for data loading - Extract WorkspaceLayout and FileBrowser components - Slim RepoWorkspacePage from 505 to ~80 lines Quality gates: tsc --noEmit passes, npm run build passes
215 lines
6.6 KiB
TypeScript
215 lines
6.6 KiB
TypeScript
import { Icon } from "../../icon";
|
|
import { FileBrowser } from "./FileBrowser";
|
|
import { FileEditor } from "../git/file-editor";
|
|
import { CommitPanel } from "../git/commit-panel";
|
|
import { GitToolbar } from "../git/git-toolbar";
|
|
import { InstanceList } from "../tool/instance-list";
|
|
import type { GitRepository, GitStatus } from "../../../api/git-repositories";
|
|
import type { ToolType } from "../../../api/tool-types";
|
|
import type { Project } from "../../../hooks/use-repo-workspace";
|
|
|
|
type MobileTab = "files" | "editor" | "git" | "terminal";
|
|
|
|
interface Props {
|
|
projectId: string;
|
|
project: Project | null;
|
|
isMobile: boolean;
|
|
mobileTab: MobileTab;
|
|
selectedRepoId: string | null;
|
|
selectedRepo: GitRepository | undefined;
|
|
branches: string[];
|
|
currentBranch: string;
|
|
gitStatus: GitStatus | null;
|
|
toolTypes: ToolType[];
|
|
repositories: GitRepository[];
|
|
onMobileTabChange: (tab: MobileTab) => void;
|
|
onRepoChange: (repoId: string) => void;
|
|
onBranchChange: (branch: string) => void;
|
|
onRefresh: () => void;
|
|
}
|
|
|
|
export const WorkspaceLayout = ({
|
|
projectId,
|
|
project,
|
|
isMobile,
|
|
mobileTab,
|
|
selectedRepoId,
|
|
selectedRepo,
|
|
branches,
|
|
currentBranch,
|
|
gitStatus,
|
|
toolTypes,
|
|
repositories,
|
|
onMobileTabChange,
|
|
onRepoChange,
|
|
onBranchChange,
|
|
onRefresh,
|
|
}: Props) => {
|
|
if (isMobile) {
|
|
return (
|
|
<div className="mobile-workspace">
|
|
<div className="mobile-workspace-header">
|
|
<select
|
|
value={selectedRepoId || ""}
|
|
onChange={(e) => onRepoChange(e.target.value)}
|
|
className="mobile-repo-selector"
|
|
>
|
|
{repositories.map((repo) => (
|
|
<option key={repo.id} value={repo.id}>
|
|
{repo.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
{selectedRepoId && (
|
|
<select
|
|
value={currentBranch}
|
|
onChange={(e) => onBranchChange(e.target.value)}
|
|
className="mobile-branch-selector"
|
|
>
|
|
{branches.map((branch) => (
|
|
<option key={branch} value={branch}>
|
|
{branch}
|
|
</option>
|
|
))}
|
|
</select>
|
|
)}
|
|
</div>
|
|
|
|
<div className="mobile-workspace-content">
|
|
{mobileTab === "files" && selectedRepoId && (
|
|
<FileBrowser projectId={projectId} repoId={selectedRepoId} gitStatus={gitStatus} />
|
|
)}
|
|
{mobileTab === "editor" && selectedRepoId && (
|
|
<FileEditor projectId={projectId} repoId={selectedRepoId} />
|
|
)}
|
|
{mobileTab === "git" && selectedRepoId && gitStatus && (
|
|
<div className="mobile-git-view">
|
|
<CommitPanel
|
|
projectId={projectId}
|
|
repoId={selectedRepoId}
|
|
modified={gitStatus.modified}
|
|
added={gitStatus.added}
|
|
deleted={gitStatus.deleted}
|
|
untracked={gitStatus.untracked}
|
|
onCommit={() => {
|
|
onRefresh();
|
|
}}
|
|
/>
|
|
</div>
|
|
)}
|
|
{mobileTab === "terminal" && selectedRepoId && (
|
|
<InstanceList
|
|
projectId={projectId}
|
|
repoId={selectedRepoId}
|
|
projectName={project?.name}
|
|
repoName={selectedRepo?.name}
|
|
toolTypes={toolTypes}
|
|
/>
|
|
)}
|
|
</div>
|
|
|
|
<div className="mobile-workspace-tabs">
|
|
<button
|
|
className={`mobile-workspace-tab ${mobileTab === "files" ? "active" : ""}`}
|
|
onClick={() => onMobileTabChange("files")}
|
|
type="button"
|
|
>
|
|
<Icon name="folder" size="sm" />
|
|
<span>Files</span>
|
|
</button>
|
|
<button
|
|
className={`mobile-workspace-tab ${mobileTab === "editor" ? "active" : ""}`}
|
|
onClick={() => onMobileTabChange("editor")}
|
|
type="button"
|
|
>
|
|
<Icon name="edit" size="sm" />
|
|
<span>Editor</span>
|
|
</button>
|
|
<button
|
|
className={`mobile-workspace-tab ${mobileTab === "git" ? "active" : ""}`}
|
|
onClick={() => onMobileTabChange("git")}
|
|
type="button"
|
|
>
|
|
<Icon name="branch" size="sm" />
|
|
<span>Git</span>
|
|
</button>
|
|
<button
|
|
className={`mobile-workspace-tab ${mobileTab === "terminal" ? "active" : ""}`}
|
|
onClick={() => onMobileTabChange("terminal")}
|
|
type="button"
|
|
>
|
|
<Icon name="terminal" size="sm" />
|
|
<span>Terminal</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
{selectedRepoId && (
|
|
<GitToolbar
|
|
projectId={projectId}
|
|
repoId={selectedRepoId}
|
|
currentBranch={currentBranch}
|
|
branches={branches}
|
|
hasRemote={Boolean(selectedRepo?.remote_url)}
|
|
isMirror={Boolean(selectedRepo?.is_mirror)}
|
|
onBranchChange={onBranchChange}
|
|
onRefresh={onRefresh}
|
|
/>
|
|
)}
|
|
<div className="workspace-layout">
|
|
<aside className="workspace-sidebar">
|
|
<div className="sidebar-section">
|
|
<label className="form-field">
|
|
Repository
|
|
<select
|
|
value={selectedRepoId || ""}
|
|
onChange={(e) => onRepoChange(e.target.value)}
|
|
>
|
|
{repositories.map((repo) => (
|
|
<option key={repo.id} value={repo.id}>
|
|
{repo.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
</div>
|
|
|
|
{selectedRepoId && (
|
|
<>
|
|
<FileBrowser projectId={projectId} repoId={selectedRepoId} gitStatus={gitStatus} />
|
|
{gitStatus && (
|
|
<CommitPanel
|
|
projectId={projectId}
|
|
repoId={selectedRepoId}
|
|
modified={gitStatus.modified}
|
|
added={gitStatus.added}
|
|
deleted={gitStatus.deleted}
|
|
untracked={gitStatus.untracked}
|
|
onCommit={onRefresh}
|
|
/>
|
|
)}
|
|
<InstanceList
|
|
projectId={projectId}
|
|
repoId={selectedRepoId}
|
|
projectName={project?.name}
|
|
repoName={selectedRepo?.name}
|
|
toolTypes={toolTypes}
|
|
/>
|
|
</>
|
|
)}
|
|
</aside>
|
|
|
|
<main className="workspace-main">
|
|
{selectedRepoId && (
|
|
<FileEditor projectId={projectId} repoId={selectedRepoId} />
|
|
)}
|
|
</main>
|
|
</div>
|
|
</>
|
|
);
|
|
};
|