diff --git a/src/App.tsx b/src/App.tsx index 94ef3f5..d1d5982 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -13,6 +13,7 @@ import ProjectDetailPage from '@/pages/ProjectDetailPage' import MilestonesPage from '@/pages/MilestonesPage' import MilestoneDetailPage from '@/pages/MilestoneDetailPage' import NotificationsPage from '@/pages/NotificationsPage' +import RoleEditorPage from '@/pages/RoleEditorPage' import MonitorPage from '@/pages/MonitorPage' import axios from 'axios' @@ -66,7 +67,8 @@ export default function App() {
- } /> + } /> + } /> } /> } /> @@ -91,6 +93,7 @@ export default function App() { } /> } /> } /> + } /> } /> } /> diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 5999a9e..3395448 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -31,11 +31,10 @@ export default function Sidebar({ user, onLogout }: Props) { const links = user ? [ { to: '/', icon: '๐Ÿ“Š', label: 'Dashboard' }, - { to: '/issues', icon: '๐Ÿ“‹', label: 'Issues' }, { to: '/projects', icon: '๐Ÿ“', label: 'Projects' }, - { to: '/milestones', icon: '๐Ÿ', label: 'Milestones' }, { to: '/notifications', icon: '๐Ÿ””', label: 'Notifications' + (unreadCount > 0 ? ' (' + unreadCount + ')' : '') }, { to: '/monitor', icon: '๐Ÿ“ก', label: 'Monitor' }, + ...(user.is_admin ? [{ to: '/roles', icon: '๐Ÿ”', label: 'Roles' }] : []), ] : [ { to: '/monitor', icon: '๐Ÿ“ก', label: 'Monitor' }, ] diff --git a/src/pages/CreateIssuePage.tsx b/src/pages/CreateIssuePage.tsx index 4f0cc0f..160395f 100644 --- a/src/pages/CreateIssuePage.tsx +++ b/src/pages/CreateIssuePage.tsx @@ -3,12 +3,25 @@ import { useNavigate } from 'react-router-dom' import api from '@/services/api' import type { Project } from '@/types' +const ISSUE_TYPES = [ + { value: 'story', label: 'Story', subtypes: ['feature', 'improvement', 'refactor'] }, + { value: 'issue', label: 'Issue', subtypes: ['infrastructure', 'performance', 'regression', 'security', 'user_experience', 'defect'] }, + { value: 'task', label: 'Task', subtypes: ['defect'] }, + { value: 'test', label: 'Test', subtypes: ['regression', 'security', 'smoke', 'stress'] }, + { value: 'maintenance', label: 'Maintenance', subtypes: ['deploy', 'release'] }, + { value: 'research', label: 'Research', subtypes: [] }, + { value: 'review', label: 'Review', subtypes: ['code_review', 'decision_review', 'function_review'] }, + { value: 'support', label: 'Support', subtypes: ['access', 'information'] }, + { value: 'meeting', label: 'Meeting', subtypes: ['conference', 'handover', 'recap'] }, + { value: 'resolution', label: 'Resolution', subtypes: [] }, +] + export default function CreateIssuePage() { const navigate = useNavigate() const [projects, setProjects] = useState([]) const [form, setForm] = useState({ - title: '', description: '', project_id: 0, issue_type: 'task', - priority: 'medium', tags: '', reporter_id: 1, + title: '', description: '', project_id: 0, issue_type: 'issue', + issue_subtype: '', priority: 'medium', tags: '', reporter_id: 1, }) useEffect(() => { @@ -18,9 +31,17 @@ export default function CreateIssuePage() { }) }, []) + const currentType = ISSUE_TYPES.find(t => t.value === form.issue_type) || ISSUE_TYPES[1] + const subtypes = currentType.subtypes || [] + + const handleTypeChange = (newType: string) => { + setForm(f => ({ ...f, issue_type: newType, issue_subtype: '' })) + } + const submit = async (e: React.FormEvent) => { e.preventDefault() - const payload = { ...form, tags: form.tags || null } + const payload: any = { ...form, tags: form.tags || null } + if (!form.issue_subtype) delete payload.issue_subtype await api.post('/issues', payload) navigate('/issues') } @@ -37,13 +58,18 @@ export default function CreateIssuePage() { + {subtypes.length > 0 && ( + + )}