Added status to the requirements

This commit is contained in:
gulimabr
2025-12-02 11:47:45 -03:00
parent 459ceaa162
commit 9428c4d2de
12 changed files with 340 additions and 15 deletions

View File

@@ -1,13 +1,13 @@
import { useState, useEffect } from 'react'
import { useAuth, useProject } from '@/hooks'
import { useParams, Link } from 'react-router-dom'
import { requirementService, validationService, relationshipService, commentService, tagService, priorityService, groupService } from '@/services'
import { requirementService, validationService, relationshipService, commentService, tagService, priorityService, groupService, requirementStatusService } from '@/services'
import type { Requirement } from '@/services/requirementService'
import type { RelationshipType, RequirementLink, RequirementSearchResult } from '@/services/relationshipService'
import type { Tag } from '@/services/tagService'
import type { Priority } from '@/services/priorityService'
import type { Group } from '@/services/groupService'
import type { ValidationStatus, ValidationHistory, Comment, RequirementHistory } from '@/types'
import type { ValidationStatus, ValidationHistory, Comment, RequirementHistory, RequirementStatus } from '@/types'
// Tab types
type TabType = 'description' | 'relationships' | 'acceptance-criteria' | 'shared-comments' | 'validate' | 'history'
@@ -64,9 +64,11 @@ export default function RequirementDetailPage() {
const [editTagId, setEditTagId] = useState<number | ''>('')
const [editPriorityId, setEditPriorityId] = useState<number | ''>('')
const [editGroupIds, setEditGroupIds] = useState<number[]>([])
const [editStatusId, setEditStatusId] = useState<number | ''>(1)
const [availableTags, setAvailableTags] = useState<Tag[]>([])
const [availablePriorities, setAvailablePriorities] = useState<Priority[]>([])
const [availableGroups, setAvailableGroups] = useState<Group[]>([])
const [availableStatuses, setAvailableStatuses] = useState<RequirementStatus[]>([])
const [editOptionsLoading, setEditOptionsLoading] = useState(false)
// Requirement history state
@@ -429,21 +431,24 @@ export default function RequirementDetailPage() {
setEditTagId(requirement.tag.id)
setEditPriorityId(requirement.priority?.id || '')
setEditGroupIds(requirement.groups.map(g => g.id))
setEditStatusId(requirement.status?.id || 1)
setEditError(null)
setShowEditModal(true)
// Fetch options if not already loaded
if (availableTags.length === 0 || availablePriorities.length === 0 || availableGroups.length === 0) {
if (availableTags.length === 0 || availablePriorities.length === 0 || availableGroups.length === 0 || availableStatuses.length === 0) {
try {
setEditOptionsLoading(true)
const [tags, priorities, groups] = await Promise.all([
const [tags, priorities, groups, statuses] = await Promise.all([
tagService.getTags(),
priorityService.getPriorities(),
groupService.getGroups()
groupService.getGroups(),
requirementStatusService.getStatuses()
])
setAvailableTags(tags)
setAvailablePriorities(priorities)
setAvailableGroups(groups)
setAvailableStatuses(statuses)
} catch (err) {
console.error('Failed to fetch edit options:', err)
setEditError('Failed to load options. Please try again.')
@@ -475,7 +480,8 @@ export default function RequirementDetailPage() {
req_desc: editReqDesc.trim() || undefined,
tag_id: editTagId as number,
priority_id: editPriorityId ? editPriorityId as number : undefined,
group_ids: editGroupIds
group_ids: editGroupIds,
status_id: editStatusId ? editStatusId as number : undefined,
})
// Refetch to ensure consistency (trigger updates version)
@@ -515,6 +521,9 @@ export default function RequirementDetailPage() {
}
}
// Check if requirement is in draft status
const isDraftStatus = requirement?.status?.status_code === 'DRAFT'
if (loading) {
return (
<div className="min-h-screen bg-white flex items-center justify-center">
@@ -561,9 +570,33 @@ export default function RequirementDetailPage() {
return (
<div>
<h3 className="text-xl font-bold text-gray-800 mb-2">Description</h3>
{/* Draft indicator banner */}
{isDraftStatus && (
<div className="mb-4 p-3 bg-amber-50 border border-amber-300 border-dashed rounded-lg">
<div className="flex items-center gap-2">
<span className="text-amber-600 text-lg">📝</span>
<div>
<p className="font-semibold text-amber-800">Draft Requirement</p>
<p className="text-sm text-amber-700">This requirement is still in draft status and is not finalized. It may be subject to changes.</p>
</div>
</div>
</div>
)}
<p className="text-sm text-gray-700 mb-2">
<span className="font-semibold">Version:</span> {requirement.version}
</p>
<p className="text-sm text-gray-700 mb-2">
<span className="font-semibold">Status:</span>{' '}
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${
isDraftStatus
? 'bg-amber-100 text-amber-800 border border-amber-300'
: 'bg-blue-100 text-blue-800'
}`}>
{requirement.status?.status_name || 'Unknown'}
</span>
</p>
<p className="text-sm text-gray-700 mb-2">
<span className="font-semibold">Validation Status:</span>{' '}
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${getValidationStatusStyle(validationStatus)}`}>
@@ -1220,6 +1253,14 @@ export default function RequirementDetailPage() {
<div className="max-w-5xl mx-auto px-8 py-8">
{/* Requirement Header */}
<div className="text-center mb-8">
{/* Draft Status Indicator */}
{isDraftStatus && (
<div className="mb-4 inline-flex items-center gap-2 px-4 py-2 bg-amber-100 border-2 border-dashed border-amber-400 rounded-lg">
<span className="text-amber-600 text-lg">📝</span>
<span className="text-amber-800 font-medium">Draft - Not Finalized</span>
</div>
)}
{/* Tag */}
<h2 className="text-2xl font-bold text-gray-800 mb-2">{tagCode}</h2>
@@ -1491,6 +1532,28 @@ export default function RequirementDetailPage() {
</select>
</div>
{/* Status */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Status
</label>
<select
value={editStatusId}
onChange={(e) => setEditStatusId(e.target.value ? Number(e.target.value) : '')}
className="w-full px-3 py-2 border border-gray-300 rounded text-sm focus:outline-none focus:ring-2 focus:ring-teal-500 focus:border-transparent"
disabled={editLoading}
>
{availableStatuses.map((status) => (
<option key={status.id} value={status.id}>
{status.status_name} {status.description ? `- ${status.description}` : ''}
</option>
))}
</select>
<p className="mt-1 text-xs text-gray-500">
Draft requirements are not finalized and marked with a visual indicator.
</p>
</div>
{/* Description */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">

View File

@@ -22,6 +22,11 @@ const getValidationStatusStyle = (status: string): { bgColor: string; textColor:
}
}
// Check if requirement is in draft status
const isDraftStatus = (statusCode: string | undefined): boolean => {
return statusCode === 'DRAFT'
}
export default function RequirementsPage() {
const { user, logout, isAuditor } = useAuth()
const { currentProject, isLoading: projectLoading } = useProject()
@@ -426,17 +431,32 @@ export default function RequirementsPage() {
const validationStatus = req.validation_status || 'Not Validated'
const validationStyle = getValidationStatusStyle(validationStatus)
const isStale = req.validation_version !== null && req.validation_version !== req.version
const isDraft = isDraftStatus(req.status?.status_code)
return (
<div
key={req.id}
className="flex items-center rounded overflow-hidden border border-gray-300 bg-white"
className={`flex items-center rounded overflow-hidden border bg-white ${
isDraft
? 'border-amber-400 border-dashed border-2'
: 'border-gray-300'
}`}
>
{/* Tag and name section */}
<div className="px-4 py-4 min-w-[280px]">
<span className="font-bold text-gray-800">
{tagLabel} - {req.req_name}
</span>
<div className="flex items-center gap-2">
{isDraft && (
<span
className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-amber-100 text-amber-800 border border-amber-300"
title="This requirement is still in draft and not finalized"
>
📝 Draft
</span>
)}
<span className="font-bold text-gray-800">
{tagLabel} - {req.req_name}
</span>
</div>
</div>
{/* Group chips */}