Spaces:
Sleeping
Sleeping
| 'use client' | |
| import { useState } from 'react' | |
| import { MetricsInput } from '@/lib/types' | |
| interface MetricsFormProps { | |
| onSubmit: (metrics: MetricsInput) => void | |
| initialValues?: MetricsInput | |
| } | |
| export const defaultMetrics: MetricsInput = { | |
| deploymentFrequency: 'weekly', | |
| leadTimeDays: 0, | |
| changeFailureRate: 0, | |
| mttrHours: 0, | |
| pipelineDurationMinutes: 0, | |
| prReviewTimeHours: 0, | |
| engineerCount: 1, | |
| serviceCount: 1, | |
| } | |
| export default function MetricsForm({ onSubmit, initialValues }: MetricsFormProps) { | |
| const [metrics, setMetrics] = useState<MetricsInput>(initialValues ?? defaultMetrics) | |
| function handleSubmit(e: React.FormEvent) { | |
| e.preventDefault() | |
| onSubmit(metrics) | |
| } | |
| function setField<K extends keyof MetricsInput>(key: K, value: MetricsInput[K]) { | |
| setMetrics((prev) => ({ ...prev, [key]: value })) | |
| } | |
| return ( | |
| <form onSubmit={handleSubmit} className="space-y-6"> | |
| <div> | |
| <label htmlFor="deploymentFrequency" className="block text-sm font-medium text-gray-700 mb-1"> | |
| Deployment Frequency | |
| </label> | |
| <select | |
| id="deploymentFrequency" | |
| value={metrics.deploymentFrequency} | |
| onChange={(e) => | |
| setField('deploymentFrequency', e.target.value as MetricsInput['deploymentFrequency']) | |
| } | |
| className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500" | |
| > | |
| <option value="multiple_per_day">Multiple times per day</option> | |
| <option value="daily">Once per day</option> | |
| <option value="weekly">Once per week</option> | |
| <option value="monthly">Once per month</option> | |
| <option value="less_than_monthly">Less than once per month</option> | |
| </select> | |
| </div> | |
| <div className="grid grid-cols-1 gap-6 sm:grid-cols-2"> | |
| <div> | |
| <label htmlFor="leadTimeDays" className="block text-sm font-medium text-gray-700 mb-1"> | |
| Lead Time (days) | |
| </label> | |
| <input | |
| id="leadTimeDays" | |
| type="number" | |
| min={0} | |
| step={0.5} | |
| value={metrics.leadTimeDays} | |
| onChange={(e) => setField('leadTimeDays', parseFloat(e.target.value) || 0)} | |
| className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500" | |
| /> | |
| </div> | |
| <div> | |
| <label htmlFor="changeFailureRate" className="block text-sm font-medium text-gray-700 mb-1"> | |
| Change Failure Rate (%) | |
| </label> | |
| <input | |
| id="changeFailureRate" | |
| type="number" | |
| min={0} | |
| max={100} | |
| step={1} | |
| value={metrics.changeFailureRate} | |
| onChange={(e) => setField('changeFailureRate', parseFloat(e.target.value) || 0)} | |
| className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500" | |
| /> | |
| </div> | |
| <div> | |
| <label htmlFor="mttrHours" className="block text-sm font-medium text-gray-700 mb-1"> | |
| MTTR (hours) | |
| </label> | |
| <input | |
| id="mttrHours" | |
| type="number" | |
| min={0} | |
| step={0.5} | |
| value={metrics.mttrHours} | |
| onChange={(e) => setField('mttrHours', parseFloat(e.target.value) || 0)} | |
| className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500" | |
| /> | |
| </div> | |
| <div> | |
| <label htmlFor="pipelineDurationMinutes" className="block text-sm font-medium text-gray-700 mb-1"> | |
| Pipeline Duration (minutes) | |
| </label> | |
| <input | |
| id="pipelineDurationMinutes" | |
| type="number" | |
| min={0} | |
| value={metrics.pipelineDurationMinutes} | |
| onChange={(e) => setField('pipelineDurationMinutes', parseFloat(e.target.value) || 0)} | |
| className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500" | |
| /> | |
| </div> | |
| <div> | |
| <label htmlFor="prReviewTimeHours" className="block text-sm font-medium text-gray-700 mb-1"> | |
| PR Review Time (hours) | |
| </label> | |
| <input | |
| id="prReviewTimeHours" | |
| type="number" | |
| min={0} | |
| step={0.5} | |
| value={metrics.prReviewTimeHours} | |
| onChange={(e) => setField('prReviewTimeHours', parseFloat(e.target.value) || 0)} | |
| className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500" | |
| /> | |
| </div> | |
| <div> | |
| <label htmlFor="engineerCount" className="block text-sm font-medium text-gray-700 mb-1"> | |
| Engineer Count | |
| </label> | |
| <input | |
| id="engineerCount" | |
| type="number" | |
| min={1} | |
| step={1} | |
| value={metrics.engineerCount} | |
| onChange={(e) => setField('engineerCount', parseInt(e.target.value) || 1)} | |
| className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500" | |
| /> | |
| </div> | |
| <div> | |
| <label htmlFor="serviceCount" className="block text-sm font-medium text-gray-700 mb-1"> | |
| Service Count | |
| </label> | |
| <input | |
| id="serviceCount" | |
| type="number" | |
| min={1} | |
| step={1} | |
| value={metrics.serviceCount} | |
| onChange={(e) => setField('serviceCount', parseInt(e.target.value) || 1)} | |
| className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500" | |
| /> | |
| </div> | |
| </div> | |
| <div className="pt-2"> | |
| <button | |
| type="submit" | |
| className="w-full rounded-md bg-indigo-600 px-4 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2" | |
| > | |
| Next: Team Context | |
| </button> | |
| </div> | |
| </form> | |
| ) | |
| } | |