feat: add project settings page with tabbed layout

- Create SettingsTabLayout component with sidebar navigation
- Create ProjectSettingsPage with General settings tab
- Create RepositoriesSettingsTab for repo management
- Add Members placeholder tab
- Update router with settings routes
- Add CSS styles for settings layout
- Navigate to /projects/:id/settings from workspace header
This commit is contained in:
Fusion
2026-05-19 15:26:57 +02:00
parent 965f6f6585
commit 0bc0d99c21
17 changed files with 1136 additions and 16 deletions
+33 -15
View File
@@ -11,6 +11,7 @@ import {
} from "../api/git_repositories";
import { CommitPanel } from "../components/commit-panel";
import { GitToolbar } from "../components/git-toolbar";
import { WorkspaceHeader } from "../components/workspace-header";
type WorkspaceStatus = "loading" | "ready" | "error" | "empty";
@@ -28,11 +29,18 @@ interface FileTreeEntry {
} | null;
}
interface Project {
id: string;
name: string;
description?: string | null;
}
export const RepoWorkspace = () => {
const { projectId } = useParams<{ projectId: string }>();
const [searchParams, setSearchParams] = useSearchParams();
const [status, setStatus] = useState<WorkspaceStatus>("loading");
const [project, setProject] = useState<Project | null>(null);
const [repositories, setRepositories] = useState<GitRepository[]>([]);
const [selectedRepoId, setSelectedRepoId] = useState<string | null>(
searchParams.get("repo")
@@ -41,6 +49,16 @@ export const RepoWorkspace = () => {
const [currentBranch, setCurrentBranch] = useState<string>("main");
const [gitStatus, setGitStatus] = useState<GitStatus | null>(null);
const loadProject = useCallback(async () => {
if (!projectId) return;
try {
const response = await apiClient.get(`/projects/${projectId}`);
setProject(response.data);
} catch {
setProject(null);
}
}, [projectId]);
const loadRepositories = useCallback(async () => {
if (!projectId) return;
@@ -95,8 +113,9 @@ export const RepoWorkspace = () => {
}, [projectId, selectedRepoId]);
useEffect(() => {
void loadProject();
void loadRepositories();
}, [loadRepositories]);
}, [loadProject, loadRepositories]);
useEffect(() => {
void loadBranches();
@@ -116,20 +135,12 @@ export const RepoWorkspace = () => {
return (
<section className="repo-workspace">
<div className="workspace-header">
<div className="workspace-title">
<h1>Repository Workspace</h1>
{selectedRepo && <span className="repo-name">{selectedRepo.name}</span>}
</div>
<div className="workspace-actions">
<Link
className="secondary-button"
to={`/projects/${projectId}/repositories`}
>
Manage Repositories
</Link>
</div>
</div>
{project && (
<WorkspaceHeader
project={project}
currentRepo={selectedRepo || null}
/>
)}
{status === "loading" && (
<p className="muted">Loading repositories...</p>
@@ -160,6 +171,13 @@ export const RepoWorkspace = () => {
</div>
)}
{project && (
<WorkspaceHeader
project={project}
currentRepo={selectedRepo || null}
/>
)}
{status === "ready" && repositories.length > 0 && (
<div className="workspace-layout">
<aside className="workspace-sidebar">