2247ec47c9
Use canonical profile files and writable Git working copies so editor and container changes share one source. Require confirmation before destructive Git refreshes and overlay profile files without composite snapshots.
216 lines
5.6 KiB
TypeScript
216 lines
5.6 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" | "preview";
|
|
|
|
export const ConfigProfilesPage = () => {
|
|
const isMobile = useMobileViewport();
|
|
const [mobileView, setMobileView] = useState<MobileView>("list");
|
|
const {
|
|
status,
|
|
profiles,
|
|
projects,
|
|
toolTypes,
|
|
selectedProfile,
|
|
selectedProfileId,
|
|
isCreating,
|
|
saveStatus,
|
|
error,
|
|
previewData,
|
|
previewingId,
|
|
isRefreshingGitMounts,
|
|
isReloadingWorkingCopy,
|
|
formData,
|
|
includedProfileIds,
|
|
dragOverIndex,
|
|
loadData,
|
|
handleSelectProfile,
|
|
handleCreateNew,
|
|
handleSubmit,
|
|
handleDelete,
|
|
handlePreview,
|
|
handleReloadWorkingCopy,
|
|
handleRefreshGitMounts,
|
|
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();
|
|
|
|
const handleReset = () => {
|
|
if (isCreating) {
|
|
setFormData({
|
|
name: "",
|
|
description: "",
|
|
env_vars: {},
|
|
runtime_hints: {},
|
|
mounts: [],
|
|
git_mounts: [],
|
|
files: {},
|
|
is_default: false,
|
|
});
|
|
setIncludedProfileIds([]);
|
|
setSaveStatus("idle");
|
|
} else if (selectedProfile) {
|
|
populateForm(selectedProfile);
|
|
}
|
|
};
|
|
|
|
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}
|
|
projects={projects}
|
|
toolTypes={toolTypes}
|
|
selectedProfile={selectedProfile}
|
|
mobileView={mobileView}
|
|
isCreating={isCreating}
|
|
formData={formData}
|
|
includedProfileIds={includedProfileIds}
|
|
availableProfiles={availableProfilesForInclude()}
|
|
previewData={previewData}
|
|
previewingId={previewingId}
|
|
isRefreshingGitMounts={isRefreshingGitMounts}
|
|
isReloadingWorkingCopy={isReloadingWorkingCopy}
|
|
saveStatus={saveStatus}
|
|
error={error}
|
|
onViewChange={setMobileView}
|
|
onSelect={handleSelectProfile}
|
|
onCreate={handleCreateNew}
|
|
onDelete={handleDelete}
|
|
onFormChange={updateFormField}
|
|
onSubmit={handleSubmit}
|
|
getScopeLabel={getScopeLabel}
|
|
getIncludedProfile={getIncludedProfile}
|
|
onAddInclude={addInclude}
|
|
onRemoveInclude={removeInclude}
|
|
onAddEnvVar={addEnvVar}
|
|
onUpdateEnvVar={updateEnvVar}
|
|
onRemoveEnvVar={removeEnvVar}
|
|
onAddFile={addFile}
|
|
onUpdateFile={updateFile}
|
|
onRemoveFile={removeFile}
|
|
onAddMount={addMount}
|
|
onUpdateMount={updateMount}
|
|
onRemoveMount={removeMount}
|
|
onAddMountFile={addMountFile}
|
|
onUpdateMountFile={updateMountFile}
|
|
onRemoveMountFile={removeMountFile}
|
|
onPreview={handlePreview}
|
|
onReloadWorkingCopy={() => void handleReloadWorkingCopy()}
|
|
onRefreshGitMounts={(id) => void handleRefreshGitMounts(id)}
|
|
onClosePreview={() => setPreviewData(null)}
|
|
/>
|
|
);
|
|
}
|
|
|
|
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}
|
|
isRefreshingGitMounts={isRefreshingGitMounts}
|
|
isReloadingWorkingCopy={isReloadingWorkingCopy}
|
|
projects={projects}
|
|
toolTypes={toolTypes}
|
|
availableProfiles={availableProfilesForInclude()}
|
|
getIncludedProfile={getIncludedProfile}
|
|
getScopeLabel={getScopeLabel}
|
|
onFormChange={updateFormField}
|
|
onSubmit={handleSubmit}
|
|
onReset={handleReset}
|
|
onPreview={() => selectedProfile && handlePreview(selectedProfile.id)}
|
|
onReloadWorkingCopy={() => void handleReloadWorkingCopy()}
|
|
onRefreshGitMounts={() =>
|
|
selectedProfile && handleRefreshGitMounts(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>
|
|
);
|
|
};
|