Kill List: Operations phase tool
- After each pilot day: identify 3 biggest irritations - Fix only those before next pilot day - Progress tracking with visual indicator - Add new irritations on the fly Part of OR-001 Operational Readiness. Next: Pilot 001 — Break the system!
This commit is contained in:
@@ -7,6 +7,7 @@ import FieldConsole from './pages/FieldConsole';
|
||||
import HealthDashboard from './pages/HealthDashboard';
|
||||
import PilotChecklist from './pages/PilotChecklist';
|
||||
import ReadinessDashboard from './pages/ReadinessDashboard';
|
||||
import KillList from './pages/KillList';
|
||||
|
||||
function App() {
|
||||
const [developerMode, setDeveloperMode] = useState(false);
|
||||
@@ -37,6 +38,7 @@ function App() {
|
||||
<Link to="/health">Health</Link>
|
||||
<Link to="/pilot">Pilot</Link>
|
||||
<Link to="/readiness">Ready</Link>
|
||||
<Link to="/kill">Kill</Link>
|
||||
{developerMode && (
|
||||
<>
|
||||
<Link to="/datasets">Data</Link>
|
||||
@@ -55,6 +57,7 @@ function App() {
|
||||
<Route path="/health" element={<HealthDashboard />} />
|
||||
<Route path="/pilot" element={<PilotChecklist />} />
|
||||
<Route path="/readiness" element={<ReadinessDashboard />} />
|
||||
<Route path="/kill" element={<KillList />} />
|
||||
</Routes>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Kill List
|
||||
*
|
||||
* After each pilot day: identify the 3 biggest irritations
|
||||
* and fix only those before next pilot day.
|
||||
*/
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
interface KillItem {
|
||||
id: string;
|
||||
text: string;
|
||||
priority: number;
|
||||
fixed: boolean;
|
||||
}
|
||||
|
||||
function KillList() {
|
||||
const [items, setItems] = useState<KillItem[]>([
|
||||
{ id: '1', text: 'Upload takes too long on slow connection', priority: 1, fixed: false },
|
||||
{ id: '2', text: 'GPS accuracy drops in urban canyons', priority: 2, fixed: false },
|
||||
{ id: '3', text: 'Cannot review mission after upload', priority: 3, fixed: false },
|
||||
]);
|
||||
|
||||
const toggleFixed = (id: string) => {
|
||||
setItems(items.map(item =>
|
||||
item.id === id ? { ...item, fixed: !item.fixed } : item
|
||||
));
|
||||
};
|
||||
|
||||
const addItem = (text: string) => {
|
||||
const newItem: KillItem = {
|
||||
id: Date.now().toString(),
|
||||
text,
|
||||
priority: items.length + 1,
|
||||
fixed: false,
|
||||
};
|
||||
setItems([...items, newItem]);
|
||||
};
|
||||
|
||||
const fixedCount = items.filter(i => i.fixed).length;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>Kill List</h2>
|
||||
<p style={{ color: '#666', marginBottom: 20 }}>
|
||||
After each pilot day: identify the 3 biggest irritations.
|
||||
Fix only those before next pilot day.
|
||||
</p>
|
||||
|
||||
<div style={{ marginBottom: 20 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8 }}>
|
||||
<span>Progress</span>
|
||||
<span>{fixedCount}/{items.length}</span>
|
||||
</div>
|
||||
<div style={{ height: 8, background: '#f0f0f0', borderRadius: 4, overflow: 'hidden' }}>
|
||||
<div style={{
|
||||
width: `${(fixedCount / items.length) * 100}%`,
|
||||
height: '100%',
|
||||
background: fixedCount === items.length ? '#32cd32' : '#dc143c',
|
||||
transition: 'width 0.3s',
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gap: 12 }}>
|
||||
{items.map(item => (
|
||||
<div key={item.id} style={{
|
||||
border: '1px solid #ccc',
|
||||
padding: 16,
|
||||
borderRadius: 8,
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
background: item.fixed ? '#f0fff0' : '#fff',
|
||||
}}>
|
||||
<div>
|
||||
<span style={{
|
||||
textDecoration: item.fixed ? 'line-through' : 'none',
|
||||
color: item.fixed ? '#999' : '#333',
|
||||
}}>
|
||||
#{item.priority} {item.text}
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => toggleFixed(item.id)}
|
||||
style={{
|
||||
padding: '6px 12px',
|
||||
background: item.fixed ? '#32cd32' : '#f0f0f0',
|
||||
border: '1px solid #ccc',
|
||||
borderRadius: 4,
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
{item.fixed ? '✅ Fixed' : '🔧 Fix'}
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ marginTop: 20 }}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="New irritation..."
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
addItem(e.currentTarget.value);
|
||||
e.currentTarget.value = '';
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: 12,
|
||||
border: '1px solid #ccc',
|
||||
borderRadius: 8,
|
||||
fontSize: 16,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default KillList;
|
||||
Reference in New Issue
Block a user