Spaces:
Running
Running
| import type { Stream, StreamType } from '../../types/stream'; | |
| import './StreamEditor.css'; | |
| interface Props { | |
| id?: string; | |
| stream: Stream; | |
| onChange: (updated: Stream) => void; | |
| onDelete: () => void; | |
| } | |
| const ALL_VARS = [ | |
| 'Tin', | |
| 'Tout', | |
| 'ṁ', | |
| 'cp', | |
| 'CP', | |
| 'Water Content In', | |
| 'Water Content Out', | |
| 'Density', | |
| 'Pressure', | |
| ]; | |
| const DEFAULT_VARS: Record<StreamType, string[]> = { | |
| product: ['Tin', 'Tout', 'ṁ', 'cp'], | |
| steam: ['Tin', 'ṁ'], | |
| water: ['Tin', 'ṁ', 'Water Content In', 'Water Content Out'], | |
| air: ['Tin', 'ṁ'], | |
| }; | |
| const STREAM_TYPES: StreamType[] = ['product', 'steam', 'air', 'water']; | |
| export default function StreamEditor({ id, stream, onChange, onDelete }: Props) { | |
| const displayVars = stream.display_vars?.length | |
| ? stream.display_vars | |
| : DEFAULT_VARS[stream.type] || DEFAULT_VARS.product; | |
| const update = (partial: Partial<Stream>) => { | |
| onChange({ ...stream, ...partial }); | |
| }; | |
| const handleTypeChange = (type: StreamType) => { | |
| update({ | |
| type, | |
| display_vars: DEFAULT_VARS[type], | |
| }); | |
| }; | |
| const toggleVar = (varName: string) => { | |
| const current = [...displayVars]; | |
| const idx = current.indexOf(varName); | |
| if (idx >= 0) { | |
| current.splice(idx, 1); | |
| } else { | |
| current.push(varName); | |
| } | |
| update({ display_vars: current }); | |
| }; | |
| const updateValue = (key: string, value: string) => { | |
| const sv = { ...(stream.stream_values || {}) }; | |
| sv[key] = value; | |
| update({ stream_values: sv }); | |
| }; | |
| return ( | |
| <div className="se-card" id={id}> | |
| {/* Header row */} | |
| <div className="se-header"> | |
| <input | |
| type="text" | |
| className="se-name" | |
| value={stream.name} | |
| onChange={(e) => update({ name: e.target.value })} | |
| placeholder="Stream name" | |
| /> | |
| <select | |
| className="se-type" | |
| value={stream.type} | |
| onChange={(e) => handleTypeChange(e.target.value as StreamType)} | |
| > | |
| {STREAM_TYPES.map((t) => ( | |
| <option key={t} value={t}> | |
| {t} | |
| </option> | |
| ))} | |
| </select> | |
| <button className="btn btn-sm" onClick={onDelete} title="Delete stream"> | |
| ✕ | |
| </button> | |
| </div> | |
| {/* Variable selector */} | |
| <div className="se-var-selector"> | |
| {ALL_VARS.map((v) => { | |
| const isSelected = displayVars.includes(v); | |
| return ( | |
| <button | |
| key={v} | |
| className={`se-var-pill ${isSelected ? 'active' : ''}`} | |
| onClick={() => toggleVar(v)} | |
| > | |
| {v} | |
| </button> | |
| ); | |
| })} | |
| </div> | |
| {/* Value inputs */} | |
| <div className="se-values"> | |
| {displayVars.map((v) => ( | |
| <div key={v} className="se-value-field"> | |
| <label>{v}</label> | |
| <input | |
| type="text" | |
| value={stream.stream_values?.[v] || ''} | |
| onChange={(e) => updateValue(v, e.target.value)} | |
| placeholder="—" | |
| /> | |
| </div> | |
| ))} | |
| </div> | |
| </div> | |
| ); | |
| } | |