create a requirements store
This commit is contained in:
147
kwa-ui/src/stores/requirements.ts
Normal file
147
kwa-ui/src/stores/requirements.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import { computed, ref } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export type RequirementStatus = 'Draft' | 'In Review' | 'Approved' | 'Blocked' | 'Delivered'
|
||||
export type RequirementPriority = 'Low' | 'Medium' | 'High' | 'Critical'
|
||||
|
||||
export interface Requirement {
|
||||
id: number
|
||||
reference: string
|
||||
title: string
|
||||
status: RequirementStatus
|
||||
priority: RequirementPriority
|
||||
owner: string
|
||||
progress: number
|
||||
dueDate: string
|
||||
description: string
|
||||
rationale: string
|
||||
acceptanceCriteria: string[]
|
||||
impactedModules: string[]
|
||||
blockers: string[]
|
||||
notes: string
|
||||
}
|
||||
|
||||
export const useRequirementsStore = defineStore('requirements', () => {
|
||||
const requirements = ref<Requirement[]>([
|
||||
{
|
||||
id: 101,
|
||||
reference: 'REQ-101',
|
||||
title: 'Full requirement traceability',
|
||||
status: 'Approved',
|
||||
priority: 'Critical',
|
||||
owner: 'Claire Martin',
|
||||
progress: 86,
|
||||
dueDate: 'May 21, 2026',
|
||||
description:
|
||||
'Each requirement must be linked to a source, a validation status, and the design or test artifacts that depend on it.',
|
||||
rationale:
|
||||
'The team must be able to audit functional decisions, reduce scope drift, and prepare compliance reviews.',
|
||||
acceptanceCriteria: [
|
||||
'The source for each requirement is visible in the detail view.',
|
||||
'The validation status is recorded in the history.',
|
||||
'Links to related test cases are available from the detail panel.',
|
||||
],
|
||||
impactedModules: ['Backlog', 'Tests', 'Audit', 'Reporting'],
|
||||
blockers: [],
|
||||
notes: 'Plan a PDF export for milestone reviews.',
|
||||
},
|
||||
{
|
||||
id: 102,
|
||||
reference: 'REQ-102',
|
||||
title: 'Business status management',
|
||||
status: 'In Review',
|
||||
priority: 'High',
|
||||
owner: 'Julien Bernard',
|
||||
progress: 54,
|
||||
dueDate: 'May 24, 2026',
|
||||
description:
|
||||
'The product must provide consistent statuses to track a requirement from creation to delivery.',
|
||||
rationale:
|
||||
'Business and product teams do not use the same words at the same time. A stable naming scheme avoids ambiguity.',
|
||||
acceptanceCriteria: [
|
||||
'Statuses are readable at a glance.',
|
||||
'The status list is consistent across the application.',
|
||||
'Blocked items are visually highlighted.',
|
||||
],
|
||||
impactedModules: ['Workflow', 'Detail', 'Dashboard'],
|
||||
blockers: ['Final label approval from the Product Owner'],
|
||||
notes: 'Can be connected to workflow transitions later.',
|
||||
},
|
||||
{
|
||||
id: 103,
|
||||
reference: 'REQ-103',
|
||||
title: 'Fast search and filtering',
|
||||
status: 'Draft',
|
||||
priority: 'Medium',
|
||||
owner: 'Nadia Petit',
|
||||
progress: 28,
|
||||
dueDate: 'May 29, 2026',
|
||||
description:
|
||||
'Users must be able to find a requirement by title, reference, owner, or functional keyword.',
|
||||
rationale:
|
||||
'Once the project reaches a moderate volume, manual navigation becomes too expensive and slows down reviews.',
|
||||
acceptanceCriteria: [
|
||||
'Search filters the list instantly.',
|
||||
'The number of visible items remains clear.',
|
||||
'No result state is displayed explicitly.',
|
||||
],
|
||||
impactedModules: ['Sidebar', 'Search', 'Performance'],
|
||||
blockers: ['Definition of the priority search criteria'],
|
||||
notes: 'To be extended with type and batch filters.',
|
||||
},
|
||||
{
|
||||
id: 104,
|
||||
reference: 'REQ-104',
|
||||
title: 'Delivery scope by release',
|
||||
status: 'Blocked',
|
||||
priority: 'Critical',
|
||||
owner: 'Sophie Laurent',
|
||||
progress: 41,
|
||||
dueDate: 'May 31, 2026',
|
||||
description:
|
||||
'Each requirement must be linked to a target release so batch and delivery decisions can be prepared.',
|
||||
rationale:
|
||||
'Decision makers need a concise view to balance load and dependencies across releases.',
|
||||
acceptanceCriteria: [
|
||||
'The target release appears in the interface.',
|
||||
'Blocked requirements are visually identified.',
|
||||
'The delivery batch is readable in the detail view.',
|
||||
],
|
||||
impactedModules: ['Release', 'Roadmap', 'Governance'],
|
||||
blockers: ['Architecture decision pending'],
|
||||
notes: 'To be linked to a milestone calendar.',
|
||||
},
|
||||
])
|
||||
|
||||
const selectedId = ref(101)
|
||||
const searchQuery = ref('')
|
||||
|
||||
const selectedRequirement = computed<Requirement>(() => {
|
||||
const fallback = requirements.value[0]
|
||||
const found = requirements.value.find((requirement) => requirement.id === selectedId.value)
|
||||
return found ?? fallback!
|
||||
})
|
||||
|
||||
const stats = computed(() => {
|
||||
const total = requirements.value.length
|
||||
const approvedCount = requirements.value.filter(
|
||||
(requirement) => requirement.status === 'Approved'
|
||||
).length
|
||||
const blockedCount = requirements.value.filter(
|
||||
(requirement) => requirement.status === 'Blocked'
|
||||
).length
|
||||
const criticalCount = requirements.value.filter(
|
||||
(requirement) => requirement.priority === 'Critical'
|
||||
).length
|
||||
|
||||
return { total, approvedCount, blockedCount, criticalCount }
|
||||
})
|
||||
|
||||
return {
|
||||
requirements,
|
||||
selectedId,
|
||||
searchQuery,
|
||||
selectedRequirement,
|
||||
stats,
|
||||
}
|
||||
})
|
||||
@@ -1,123 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
import Button from 'primevue/button'
|
||||
import RequirementsTreeList from '../components/RequirementsTreeList.vue'
|
||||
import RequirementDetail from '../components/RequirementDetail.vue'
|
||||
import { useRequirementsStore } from '../stores/requirements'
|
||||
import type { Requirement } from '../stores/requirements'
|
||||
|
||||
import type { TreeNode } from '../components/RequirementsTreeList.vue'
|
||||
|
||||
type RequirementStatus = 'Draft' | 'In Review' | 'Approved' | 'Blocked' | 'Delivered'
|
||||
type RequirementPriority = 'Low' | 'Medium' | 'High' | 'Critical'
|
||||
|
||||
interface Requirement {
|
||||
id: number
|
||||
reference: string
|
||||
title: string
|
||||
status: RequirementStatus
|
||||
priority: RequirementPriority
|
||||
owner: string
|
||||
progress: number
|
||||
dueDate: string
|
||||
description: string
|
||||
rationale: string
|
||||
acceptanceCriteria: string[]
|
||||
impactedModules: string[]
|
||||
blockers: string[]
|
||||
notes: string
|
||||
}
|
||||
|
||||
// All requirements data
|
||||
const allRequirements: Requirement[] = [
|
||||
{
|
||||
id: 101,
|
||||
reference: 'REQ-101',
|
||||
title: 'Full requirement traceability',
|
||||
status: 'Approved',
|
||||
priority: 'Critical',
|
||||
owner: 'Claire Martin',
|
||||
progress: 86,
|
||||
dueDate: 'May 21, 2026',
|
||||
description:
|
||||
'Each requirement must be linked to a source, a validation status, and the design or test artifacts that depend on it.',
|
||||
rationale:
|
||||
'The team must be able to audit functional decisions, reduce scope drift, and prepare compliance reviews.',
|
||||
acceptanceCriteria: [
|
||||
'The source for each requirement is visible in the detail view.',
|
||||
'The validation status is recorded in the history.',
|
||||
'Links to related test cases are available from the detail panel.',
|
||||
],
|
||||
impactedModules: ['Backlog', 'Tests', 'Audit', 'Reporting'],
|
||||
blockers: [],
|
||||
notes: 'Plan a PDF export for milestone reviews.',
|
||||
},
|
||||
{
|
||||
id: 102,
|
||||
reference: 'REQ-102',
|
||||
title: 'Business status management',
|
||||
status: 'In Review',
|
||||
priority: 'High',
|
||||
owner: 'Julien Bernard',
|
||||
progress: 54,
|
||||
dueDate: 'May 24, 2026',
|
||||
description:
|
||||
'The product must provide consistent statuses to track a requirement from creation to delivery.',
|
||||
rationale:
|
||||
'Business and product teams do not use the same words at the same time. A stable naming scheme avoids ambiguity.',
|
||||
acceptanceCriteria: [
|
||||
'Statuses are readable at a glance.',
|
||||
'The status list is consistent across the application.',
|
||||
'Blocked items are visually highlighted.',
|
||||
],
|
||||
impactedModules: ['Workflow', 'Detail', 'Dashboard'],
|
||||
blockers: ['Final label approval from the Product Owner'],
|
||||
notes: 'Can be connected to workflow transitions later.',
|
||||
},
|
||||
{
|
||||
id: 103,
|
||||
reference: 'REQ-103',
|
||||
title: 'Fast search and filtering',
|
||||
status: 'Draft',
|
||||
priority: 'Medium',
|
||||
owner: 'Nadia Petit',
|
||||
progress: 28,
|
||||
dueDate: 'May 29, 2026',
|
||||
description:
|
||||
'Users must be able to find a requirement by title, reference, owner, or functional keyword.',
|
||||
rationale:
|
||||
'Once the project reaches a moderate volume, manual navigation becomes too expensive and slows down reviews.',
|
||||
acceptanceCriteria: [
|
||||
'Search filters the list instantly.',
|
||||
'The number of visible items remains clear.',
|
||||
'No result state is displayed explicitly.',
|
||||
],
|
||||
impactedModules: ['Sidebar', 'Search', 'Performance'],
|
||||
blockers: ['Definition of the priority search criteria'],
|
||||
notes: 'To be extended with type and batch filters.',
|
||||
},
|
||||
{
|
||||
id: 104,
|
||||
reference: 'REQ-104',
|
||||
title: 'Delivery scope by release',
|
||||
status: 'Blocked',
|
||||
priority: 'Critical',
|
||||
owner: 'Sophie Laurent',
|
||||
progress: 41,
|
||||
dueDate: 'May 31, 2026',
|
||||
description:
|
||||
'Each requirement must be linked to a target release so batch and delivery decisions can be prepared.',
|
||||
rationale:
|
||||
'Decision makers need a concise view to balance load and dependencies across releases.',
|
||||
acceptanceCriteria: [
|
||||
'The target release appears in the interface.',
|
||||
'Blocked requirements are visually identified.',
|
||||
'The delivery batch is readable in the detail view.',
|
||||
],
|
||||
impactedModules: ['Release', 'Roadmap', 'Governance'],
|
||||
blockers: ['Architecture decision pending'],
|
||||
notes: 'To be linked to a milestone calendar.',
|
||||
},
|
||||
]
|
||||
const requirementsStore = useRequirementsStore()
|
||||
const { requirements, selectedId, searchQuery, selectedRequirement, stats } =
|
||||
storeToRefs(requirementsStore)
|
||||
|
||||
// Helper function to create tree nodes from requirements
|
||||
const buildTreeData = (): TreeNode[] => {
|
||||
@@ -129,13 +24,13 @@ const buildTreeData = (): TreeNode[] => {
|
||||
children: [
|
||||
{
|
||||
key: '101',
|
||||
label: `${allRequirements[0]!.reference} - ${allRequirements[0]!.title}`,
|
||||
data: allRequirements[0]!,
|
||||
label: `${requirements.value[0]!.reference} - ${requirements.value[0]!.title}`,
|
||||
data: requirements.value[0]!,
|
||||
},
|
||||
{
|
||||
key: '102-child',
|
||||
label: 'Sub-requirement: Power management',
|
||||
data: { ...allRequirements[1]!, id: 1021, reference: 'REQ-102.1' } as Requirement,
|
||||
data: { ...requirements.value[1]!, id: 1021, reference: 'REQ-102.1' } as Requirement,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -146,13 +41,13 @@ const buildTreeData = (): TreeNode[] => {
|
||||
children: [
|
||||
{
|
||||
key: '102',
|
||||
label: `${allRequirements[1]!.reference} - ${allRequirements[1]!.title}`,
|
||||
data: allRequirements[1]!,
|
||||
label: `${requirements.value[1]!.reference} - ${requirements.value[1]!.title}`,
|
||||
data: requirements.value[1]!,
|
||||
},
|
||||
{
|
||||
key: '103',
|
||||
label: `${allRequirements[2]!.reference} - ${allRequirements[2]!.title}`,
|
||||
data: allRequirements[2]!,
|
||||
label: `${requirements.value[2]!.reference} - ${requirements.value[2]!.title}`,
|
||||
data: requirements.value[2]!,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -163,38 +58,15 @@ const buildTreeData = (): TreeNode[] => {
|
||||
children: [
|
||||
{
|
||||
key: '104',
|
||||
label: `${allRequirements[3]!.reference} - ${allRequirements[3]!.title}`,
|
||||
data: allRequirements[3]!,
|
||||
label: `${requirements.value[3]!.reference} - ${requirements.value[3]!.title}`,
|
||||
data: requirements.value[3]!,
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
const treeData = buildTreeData()
|
||||
const searchQuery = ref('')
|
||||
const selectedId = ref(101)
|
||||
const fallbackRequirement = allRequirements[0]!
|
||||
|
||||
const selectedRequirement = computed<Requirement>(() => {
|
||||
const found = allRequirements.find((req) => req.id === selectedId.value)
|
||||
return found ?? fallbackRequirement
|
||||
})
|
||||
|
||||
const stats = computed(() => {
|
||||
const total = allRequirements.length
|
||||
const approvedCount = allRequirements.filter(
|
||||
(requirement) => requirement.status === 'Approved'
|
||||
).length
|
||||
const blockedCount = allRequirements.filter(
|
||||
(requirement) => requirement.status === 'Blocked'
|
||||
).length
|
||||
const criticalCount = allRequirements.filter(
|
||||
(requirement) => requirement.priority === 'Critical'
|
||||
).length
|
||||
|
||||
return { total, approvedCount, blockedCount, criticalCount }
|
||||
})
|
||||
const treeData = computed(() => buildTreeData())
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
Reference in New Issue
Block a user