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 HealthDashboard from './pages/HealthDashboard';
|
||||||
import PilotChecklist from './pages/PilotChecklist';
|
import PilotChecklist from './pages/PilotChecklist';
|
||||||
import ReadinessDashboard from './pages/ReadinessDashboard';
|
import ReadinessDashboard from './pages/ReadinessDashboard';
|
||||||
|
import KillList from './pages/KillList';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [developerMode, setDeveloperMode] = useState(false);
|
const [developerMode, setDeveloperMode] = useState(false);
|
||||||
@@ -37,6 +38,7 @@ function App() {
|
|||||||
<Link to="/health">Health</Link>
|
<Link to="/health">Health</Link>
|
||||||
<Link to="/pilot">Pilot</Link>
|
<Link to="/pilot">Pilot</Link>
|
||||||
<Link to="/readiness">Ready</Link>
|
<Link to="/readiness">Ready</Link>
|
||||||
|
<Link to="/kill">Kill</Link>
|
||||||
{developerMode && (
|
{developerMode && (
|
||||||
<>
|
<>
|
||||||
<Link to="/datasets">Data</Link>
|
<Link to="/datasets">Data</Link>
|
||||||
@@ -55,6 +57,7 @@ function App() {
|
|||||||
<Route path="/health" element={<HealthDashboard />} />
|
<Route path="/health" element={<HealthDashboard />} />
|
||||||
<Route path="/pilot" element={<PilotChecklist />} />
|
<Route path="/pilot" element={<PilotChecklist />} />
|
||||||
<Route path="/readiness" element={<ReadinessDashboard />} />
|
<Route path="/readiness" element={<ReadinessDashboard />} />
|
||||||
|
<Route path="/kill" element={<KillList />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</div>
|
</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