Files
Aperant/apps/frontend/src/renderer/components/settings/ProjectSettingsContent.tsx
T
Mitsu 9d43abedde refactor: remove deprecated code across backend and frontend (#348)
## Backend
- Delete `agents/auto_claude_tools.py` (compatibility shim)
- Delete `implementation_plan/main.py` (compatibility shim)
- Remove `--dev` flag and `dev_mode` parameter from:
  - cli/main.py, cli/utils.py, cli/spec_commands.py
  - runners/spec_runner.py
  - spec/pipeline/models.py, orchestrator.py
  - spec/complexity.py
- Remove `ClaudeSimilarityDetector` class from batch_issues.py
- Remove unused `self.detector` alias

## Frontend
- Remove `PROJECT_UPDATE_AUTOBUILD` IPC channel
- Remove `updateProjectAutoBuild` from:
  - project-handlers.ts (IPC handler)
  - project-api.ts (preload API)
  - project-store.ts (store function)
  - project-mock.ts (mock)
- Remove deprecated `appendOutput`/`clearOutputBuffer` from terminal-store
- Update useTerminalEvents to use terminalBufferManager directly
- Remove deprecated "Update Auto Claude" dialog from Sidebar
- Remove `handleUpdate` from useProjectSettings hook

## Tests
- Remove `test_dev_mode_param_ignored` test
2025-12-27 16:33:26 +01:00

169 lines
4.8 KiB
TypeScript

import { useEffect, useRef } from 'react';
import { LinearTaskImportModal } from '../LinearTaskImportModal';
import { SettingsSection } from './SettingsSection';
import { useProjectSettings, UseProjectSettingsReturn } from '../project-settings/hooks/useProjectSettings';
import { loadTasks } from '../../stores/task-store';
import { EmptyProjectState } from './common/EmptyProjectState';
import { ErrorDisplay } from './common/ErrorDisplay';
import { SectionRouter } from './sections/SectionRouter';
import { createHookProxy } from './utils/hookProxyFactory';
import type { Project } from '../../../shared/types';
export type ProjectSettingsSection = 'general' | 'claude' | 'linear' | 'github' | 'memory';
interface ProjectSettingsContentProps {
project: Project | undefined;
activeSection: ProjectSettingsSection;
isOpen: boolean;
onHookReady: (hook: UseProjectSettingsReturn | null) => void;
}
/**
* Renders project settings content based on the active section.
* Exposes hook state to parent for save coordination.
*/
export function ProjectSettingsContent({
project,
activeSection,
isOpen,
onHookReady
}: ProjectSettingsContentProps) {
// Show empty state if no project selected
if (!project) {
return (
<SettingsSection
title="No Project Selected"
description="Select a project from the dropdown above to configure its settings"
>
<EmptyProjectState />
</SettingsSection>
);
}
return (
<ProjectSettingsContentInner
project={project}
activeSection={activeSection}
isOpen={isOpen}
onHookReady={onHookReady}
/>
);
}
/**
* Inner component that uses the project settings hook.
* Separated to ensure the hook is only called when a project is selected.
*/
function ProjectSettingsContentInner({
project,
activeSection,
isOpen,
onHookReady
}: {
project: Project;
activeSection: ProjectSettingsSection;
isOpen: boolean;
onHookReady: (hook: UseProjectSettingsReturn | null) => void;
}) {
const hook = useProjectSettings(project, isOpen);
// Keep a stable ref to the hook for the parent
const hookRef = useRef(hook);
hookRef.current = hook;
const {
settings,
setSettings,
versionInfo,
isCheckingVersion,
isUpdating,
envConfig,
isLoadingEnv,
envError,
updateEnvConfig,
showClaudeToken,
setShowClaudeToken,
showLinearKey,
setShowLinearKey,
showOpenAIKey,
setShowOpenAIKey,
showGitHubToken,
setShowGitHubToken,
expandedSections: _expandedSections,
toggleSection: _toggleSection,
gitHubConnectionStatus,
isCheckingGitHub,
isCheckingClaudeAuth,
claudeAuthStatus,
showLinearImportModal,
setShowLinearImportModal,
linearConnectionStatus,
isCheckingLinear,
handleInitialize,
handleClaudeSetup,
error
} = hook;
// Expose hook to parent for save coordination - only once when dialog opens
// We use hookRef to avoid infinite loops (hook object is recreated each render)
useEffect(() => {
if (isOpen) {
const hookProxy = createHookProxy(hookRef);
onHookReady(hookProxy);
}
return () => {
onHookReady(null);
};
}, [isOpen, onHookReady]);
return (
<>
<SectionRouter
activeSection={activeSection}
project={project}
settings={settings}
setSettings={setSettings}
versionInfo={versionInfo}
isCheckingVersion={isCheckingVersion}
isUpdating={isUpdating}
envConfig={envConfig}
isLoadingEnv={isLoadingEnv}
envError={envError}
updateEnvConfig={updateEnvConfig}
showClaudeToken={showClaudeToken}
setShowClaudeToken={setShowClaudeToken}
showLinearKey={showLinearKey}
setShowLinearKey={setShowLinearKey}
showOpenAIKey={showOpenAIKey}
setShowOpenAIKey={setShowOpenAIKey}
showGitHubToken={showGitHubToken}
setShowGitHubToken={setShowGitHubToken}
gitHubConnectionStatus={gitHubConnectionStatus}
isCheckingGitHub={isCheckingGitHub}
isCheckingClaudeAuth={isCheckingClaudeAuth}
claudeAuthStatus={claudeAuthStatus}
linearConnectionStatus={linearConnectionStatus}
isCheckingLinear={isCheckingLinear}
handleInitialize={handleInitialize}
handleClaudeSetup={handleClaudeSetup}
onOpenLinearImport={() => setShowLinearImportModal(true)}
/>
<ErrorDisplay error={error} envError={envError} />
{/* Linear Task Import Modal */}
<LinearTaskImportModal
projectId={project.id}
open={showLinearImportModal}
onOpenChange={setShowLinearImportModal}
onImportComplete={async (result) => {
// Refresh task list to show imported tasks (even on partial success)
if (result.imported > 0) {
await loadTasks(project.id);
}
}}
/>
</>
);
}