✏️ 메인 대시보드에 프로젝트 이름 수정 기능 추가
Some checks failed
SonarQube Analysis / SonarQube Scan (push) Has been cancelled

- App.jsx dashboard에 프로젝트 이름 수정 기능 구현
- 프로젝트 선택 시 '✏️ 이름 수정' 버튼 표시
- 실제 API에서 프로젝트 목록 로드 (더미 데이터는 fallback)
- 편집 폼: 파란색 박스로 명확하게 구분
- Enter 키로 빠른 저장
- 💾 저장 / ✕ 취소 버튼
- 저장 후 드롭다운 자동 갱신
This commit is contained in:
Hyungi Ahn
2025-10-14 06:58:14 +09:00
parent aca00cf3cb
commit 433d894175

View File

@@ -9,6 +9,7 @@ import SystemLogsPage from './pages/SystemLogsPage';
import LogMonitoringPage from './pages/LogMonitoringPage';
import ErrorBoundary from './components/ErrorBoundary';
import errorLogger from './utils/errorLogger';
import api from './api';
import './App.css';
function App() {
@@ -19,6 +20,48 @@ function App() {
const [pageParams, setPageParams] = useState({});
const [selectedProject, setSelectedProject] = useState(null);
const [showUserMenu, setShowUserMenu] = useState(false);
const [projects, setProjects] = useState([]);
const [editingProject, setEditingProject] = useState(null);
const [editedProjectName, setEditedProjectName] = useState('');
// 프로젝트 목록 로드
const loadProjects = async () => {
try {
const response = await api.get('/projects');
if (response.data && response.data.projects) {
setProjects(response.data.projects);
}
} catch (error) {
console.error('프로젝트 목록 로드 실패:', error);
}
};
// 프로젝트 이름 수정
const updateProjectName = async (projectId) => {
try {
const response = await api.patch(`/dashboard/projects/${projectId}?job_name=${encodeURIComponent(editedProjectName)}`);
if (response.data.success) {
// 프로젝트 목록 갱신
await loadProjects();
// 선택된 프로젝트 업데이트
if (selectedProject && selectedProject.id === projectId) {
setSelectedProject({
...selectedProject,
project_name: editedProjectName
});
}
setEditingProject(null);
setEditedProjectName('');
alert('프로젝트 이름이 수정되었습니다.');
}
} catch (error) {
console.error('프로젝트 이름 수정 실패:', error);
alert('프로젝트 이름 수정에 실패했습니다.');
}
};
useEffect(() => {
// 저장된 토큰 확인
@@ -28,6 +71,7 @@ function App() {
if (token && userData) {
setIsAuthenticated(true);
setUser(JSON.parse(userData));
loadProjects(); // 프로젝트 목록 로드
}
setIsLoading(false);
@@ -313,15 +357,43 @@ function App() {
{/* 프로젝트 선택 */}
<div style={{ marginBottom: '32px' }}>
<h2 style={{ fontSize: '18px', fontWeight: '600', color: '#2d3748', marginBottom: '12px' }}>
📁 프로젝트 선택
</h2>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '12px' }}>
<h2 style={{ fontSize: '18px', fontWeight: '600', color: '#2d3748', margin: 0 }}>
📁 프로젝트 선택
</h2>
{selectedProject && (
<button
onClick={() => {
setEditingProject(selectedProject);
setEditedProjectName(selectedProject.project_name || '');
}}
style={{
padding: '6px 12px',
background: '#10b981',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: 'pointer',
fontSize: '13px',
fontWeight: '600',
display: 'flex',
alignItems: 'center',
gap: '4px'
}}
title="프로젝트 이름 수정"
>
이름 수정
</button>
)}
</div>
<select
value={selectedProject?.official_project_code || ''}
onChange={(e) => {
const projectCode = e.target.value;
if (projectCode) {
setSelectedProject({
const project = projects.find(p => p.official_project_code === projectCode);
setSelectedProject(project || {
official_project_code: projectCode,
project_name: e.target.options[e.target.selectedIndex].text.split(' - ')[1]
});
@@ -339,10 +411,87 @@ function App() {
}}
>
<option value="">프로젝트를 선택하세요</option>
<option value="J24-001">J24-001 - 테스트 프로젝트 A</option>
<option value="J24-002">J24-002 - 테스트 프로젝트 B</option>
<option value="J24-003">J24-003 - 테스트 프로젝트 C</option>
{projects.length > 0 ? (
projects.map(project => (
<option key={project.id || project.official_project_code} value={project.official_project_code}>
{project.official_project_code} - {project.project_name || project.job_name}
</option>
))
) : (
<>
<option value="J24-001">J24-001 - 테스트 프로젝트 A</option>
<option value="J24-002">J24-002 - 테스트 프로젝트 B</option>
<option value="J24-003">J24-003 - 테스트 프로젝트 C</option>
</>
)}
</select>
{/* 프로젝트 이름 편집 폼 */}
{editingProject && (
<div style={{
marginTop: '16px',
background: '#eff6ff',
border: '2px solid #3b82f6',
borderRadius: '8px',
padding: '16px'
}}>
<div style={{ marginBottom: '12px', fontWeight: '600', color: '#1e40af', fontSize: '14px' }}>
프로젝트 이름 수정: {editingProject.official_project_code}
</div>
<div style={{ display: 'flex', gap: '8px' }}>
<input
type="text"
value={editedProjectName}
onChange={(e) => setEditedProjectName(e.target.value)}
onKeyPress={(e) => {
if (e.key === 'Enter') updateProjectName(editingProject.id);
}}
placeholder="새 프로젝트 이름"
autoFocus
style={{
flex: 1,
padding: '10px 12px',
border: '2px solid #3b82f6',
borderRadius: '6px',
fontSize: '14px'
}}
/>
<button
onClick={() => updateProjectName(editingProject.id)}
style={{
padding: '10px 20px',
background: '#10b981',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: 'pointer',
fontSize: '14px',
fontWeight: '600'
}}
>
💾 저장
</button>
<button
onClick={() => {
setEditingProject(null);
setEditedProjectName('');
}}
style={{
padding: '10px 20px',
background: '#ef4444',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: 'pointer',
fontSize: '14px',
fontWeight: '600'
}}
>
취소
</button>
</div>
</div>
)}
</div>
{/* 핵심 기능 */}