Files
headquarter/apps/web/src/pages/ConfigProfilesPage.tsx
T
Developer d7d5baa41a refactor: extract ConfigProfilesPage components
- Extract use-config-profiles hook for state management
- Extract ConfigProfileListSidebar, ConfigProfileEditorPanel, ConfigProfilesMobileView
- Slim ConfigProfilesPage from 1,611 to 170 lines

Quality gates: tsc --noEmit passes, npm run build passes
2026-06-05 19:09:09 +00:00

171 lines
4.2 KiB
TypeScript

import { useState } from "react";
import { ErrorState, LoadingState } from "../components/data-states";
import { useMobileViewport } from "../hooks/use-mobile-viewport";
import { useConfigProfiles } from "../hooks/use-config-profiles";
import { ConfigProfileListSidebar } from "../components/features/config-profiles/ConfigProfileListSidebar";
import { ConfigProfileEditorPanel } from "../components/features/config-profiles/ConfigProfileEditorPanel";
import { ConfigProfilesMobileView } from "../components/features/config-profiles/ConfigProfilesMobileView";
type MobileView = "list" | "detail" | "edit";
export const ConfigProfilesPage = () => {
const isMobile = useMobileViewport();
const [mobileView, setMobileView] = useState<MobileView>("list");
const {
status,
profiles,
projects,
toolTypes,
selectedProfile,
selectedProfileId,
isCreating,
saveStatus,
error,
previewData,
previewingId,
formData,
includedProfileIds,
dragOverIndex,
loadData,
handleSelectProfile,
handleCreateNew,
handleSubmit,
handleDelete,
handlePreview,
updateFormField,
addEnvVar,
updateEnvVar,
removeEnvVar,
addFile,
updateFile,
removeFile,
addMount,
updateMount,
removeMount,
addMountFile,
updateMountFile,
removeMountFile,
getIncludedProfile,
getScopeLabel,
availableProfilesForInclude,
addInclude,
removeInclude,
handleDragStart,
handleDragOver,
handleDragLeave,
handleDrop,
setPreviewData,
setFormData,
setSaveStatus,
setIncludedProfileIds,
populateForm,
} = useConfigProfiles();
if (status === "loading") {
return (
<div className="container">
<LoadingState message="Loading Config Profiles..." />
</div>
);
}
if (status === "error") {
return (
<div className="container">
<ErrorState message="Failed to load Config Profiles." onRetry={loadData} />
</div>
);
}
if (isMobile) {
return (
<ConfigProfilesMobileView
profiles={profiles}
selectedProfile={selectedProfile}
mobileView={mobileView}
isCreating={isCreating}
formData={formData}
saveStatus={saveStatus}
onViewChange={setMobileView}
onSelect={handleSelectProfile}
onCreate={handleCreateNew}
onDelete={handleDelete}
onFormChange={updateFormField}
onSubmit={handleSubmit}
getScopeLabel={getScopeLabel}
/>
);
}
return (
<div
className="container"
style={{ display: "flex", height: "calc(100vh - 4rem)", gap: 0, padding: 0 }}
>
<ConfigProfileListSidebar
profiles={profiles}
selectedProfileId={selectedProfileId}
onSelect={handleSelectProfile}
onCreate={handleCreateNew}
onDelete={handleDelete}
/>
<ConfigProfileEditorPanel
isCreating={isCreating}
selectedProfile={selectedProfile}
formData={formData}
includedProfileIds={includedProfileIds}
dragOverIndex={dragOverIndex}
error={error}
saveStatus={saveStatus}
previewData={previewData}
previewingId={previewingId}
projects={projects}
toolTypes={toolTypes}
availableProfiles={availableProfilesForInclude()}
getIncludedProfile={getIncludedProfile}
getScopeLabel={getScopeLabel}
onFormChange={updateFormField}
onSubmit={handleSubmit}
onReset={() => {
if (isCreating) {
setFormData({
name: "",
description: "",
env_vars: {},
runtime_hints: {},
mounts: [],
git_mounts: [],
files: {},
is_default: false,
});
setIncludedProfileIds([]);
setSaveStatus("idle");
} else if (selectedProfile) {
populateForm(selectedProfile);
}
}}
onPreview={() => selectedProfile && handlePreview(selectedProfile.id)}
onAddInclude={addInclude}
onRemoveInclude={removeInclude}
onDragStart={handleDragStart}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
onAddEnvVar={addEnvVar}
onUpdateEnvVar={updateEnvVar}
onRemoveEnvVar={removeEnvVar}
onAddFile={addFile}
onUpdateFile={updateFile}
onRemoveFile={removeFile}
onAddMount={addMount}
onUpdateMount={updateMount}
onRemoveMount={removeMount}
onAddMountFile={addMountFile}
onUpdateMountFile={updateMountFile}
onRemoveMountFile={removeMountFile}
onClosePreview={() => setPreviewData(null)}
/>
</div>
);
};