Files
headquarter/apps/web/src/pages/ProjectSettingsPage.tsx
T
alex 1021d61be3 refactor: organize frontend components into features/ directories
Moved 43 component files into 9 feature domains:
- features/git/ — commit-dialog, commit-panel, file-editor, git-mount-editor,
  git-toolbar, merge-dialog
- features/project/ — repositories-settings-tab, repository-create-dialog
- features/terminal/ — special-keys-panel, special-keys-strip,
  terminal-session-tabs, terminal
- features/workspace/ — workspace-card, workspace-create-form,
  workspace-header, workspace-instance-chips
- features/session/ — create-session-form, session-card, session-list
- features/tool/ — instance-list, manifest-editor, start-tool-fab,
  start-tool-modal, tool-starter, tools-bottom-sheet
- features/notification/ — event-toast-bridge, notification-center,
  notification-item
- features/settings/ — settings-tab-layout
- features/mobile/ — mobile-action-sheet, mobile-detail-view, mobile-edit-view,
  mobile-fab, mobile-list-view, mobile-nav, mobile-page-header,
  mobile-terminal-header, mobile-terminal-wrapper

Updated all imports across pages and components.
Root components/ now only contains generic UI pieces:
app-shell, code-editor, data-states, icon, protected-route, syntax-highlighter.

Quality gates: verified no remaining old imports.
2026-06-04 12:37:24 +02:00

149 lines
4.3 KiB
TypeScript

import React, { useState, useEffect } from "react";
import { useParams, Link, useNavigate, Routes, Route } from "react-router-dom";
import { SettingsTabLayout } from "../components/features/settings/settings-tab-layout";
import { RepositoriesSettingsTab } from "../components/features/project/repositories-settings-tab";
import { apiClient } from "../api/client";
import { Project } from "../types";
const tabs = [
{ id: "general", label: "General", path: "general" },
{ id: "repositories", label: "Repositories", path: "repositories" },
{ id: "members", label: "Members", path: "members" },
];
const GeneralSettings: React.FC<{
project: Project;
projectId: string;
}> = ({ project, projectId }) => {
const navigate = useNavigate();
const [name, setName] = useState(project.name);
const [description, setDescription] = useState(project.description || "");
const [saving, setSaving] = useState(false);
const [error, setError] = useState("");
const handleSave = async () => {
setSaving(true);
try {
await apiClient.patch(`/projects/${projectId}`, {
name,
description,
});
} catch (err) {
setError("Failed to save changes");
} finally {
setSaving(false);
}
};
const handleDelete = async () => {
if (!window.confirm("Are you sure you want to delete this project?")) return;
try {
await apiClient.delete(`/projects/${projectId}`);
navigate("/projects");
} catch (err) {
setError("Failed to delete project");
}
};
return (
<div className="settings-panel">
<h2>General Settings</h2>
{error && <div className="error-message">{error}</div>}
<div className="form-group">
<label>Project Name</label>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
className="form-input"
/>
</div>
<div className="form-group">
<label>Description</label>
<textarea
value={description}
onChange={(e) => setDescription(e.target.value)}
className="form-textarea"
rows={4}
/>
</div>
<div className="form-actions">
<button
onClick={handleSave}
disabled={saving}
className="btn-primary"
>
{saving ? "Saving..." : "Save Changes"}
</button>
</div>
<div className="danger-zone">
<h3>Danger Zone</h3>
<button onClick={handleDelete} className="btn-danger">
Delete Project
</button>
</div>
</div>
);
};
const MembersSettingsTab: React.FC = () => (
<div className="settings-panel">
<h2>Members</h2>
<p>Team members management coming soon.</p>
</div>
);
export const ProjectSettingsPage: React.FC = () => {
const { projectId } = useParams<{ projectId: string }>();
const [project, setProject] = useState<Project | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
useEffect(() => {
const fetchProject = async () => {
try {
const response = await apiClient.get(`/projects/${projectId}`);
setProject(response.data);
} catch (err) {
setError("Failed to load project");
} finally {
setLoading(false);
}
};
fetchProject();
}, [projectId]);
if (loading) return <div>Loading...</div>;
if (error) return <div className="error-message">{error}</div>;
if (!project) return <div>Project not found</div>;
return (
<div className="project-settings-page">
<div className="settings-breadcrumb">
<Link to="/projects">Projects</Link>
<span> &gt; </span>
<Link to={`/projects/${projectId}`}>{project.name}</Link>
<span> &gt; </span>
<span>Settings</span>
</div>
<SettingsTabLayout tabs={tabs} basePath={`/projects/${projectId}/settings`}>
<Routes>
<Route
path="general"
element={<GeneralSettings project={project} projectId={projectId!} />}
/>
<Route path="repositories" element={<RepositoriesSettingsTab />} />
<Route path="members" element={<MembersSettingsTab />} />
<Route path="*" element={<GeneralSettings project={project} projectId={projectId!} />} />
</Routes>
</SettingsTabLayout>
</div>
);
};