fix: address final review issues - promise handling, error scoping, controlled inputs, SortHeader
This commit is contained in:
@@ -41,7 +41,7 @@ export default function LlmSettings({ settings, onSave, saveError }: LlmSettings
|
|||||||
setTemperature(value);
|
setTemperature(value);
|
||||||
if (tempTimerRef.current) clearTimeout(tempTimerRef.current);
|
if (tempTimerRef.current) clearTimeout(tempTimerRef.current);
|
||||||
tempTimerRef.current = setTimeout(() => {
|
tempTimerRef.current = setTimeout(() => {
|
||||||
onSave("llm.temperature", value);
|
onSave("llm.temperature", value).catch((e) => console.error("Failed to save temperature:", e));
|
||||||
}, 300);
|
}, 300);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,24 @@ interface StockTableProps {
|
|||||||
type SortField = "ticker" | "createdAt" | "updatedAt";
|
type SortField = "ticker" | "createdAt" | "updatedAt";
|
||||||
type SortDirection = "asc" | "desc";
|
type SortDirection = "asc" | "desc";
|
||||||
|
|
||||||
|
function SortHeader({ field, children, sortField, sortDirection, onSort }: {
|
||||||
|
field: SortField;
|
||||||
|
children: ReactNode;
|
||||||
|
sortField: SortField;
|
||||||
|
sortDirection: SortDirection;
|
||||||
|
onSort: (field: SortField) => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<th
|
||||||
|
className="text-left py-2 px-3 font-medium text-gray-700 cursor-pointer hover:text-gray-900 select-none"
|
||||||
|
onClick={() => onSort(field)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
{sortField === field && <span className="ml-1">{sortDirection === "asc" ? "↑" : "↓"}</span>}
|
||||||
|
</th>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default function StockTable({ stocks, onNotesSave, saveError }: StockTableProps) {
|
export default function StockTable({ stocks, onNotesSave, saveError }: StockTableProps) {
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const [sortField, setSortField] = useState<SortField>("ticker");
|
const [sortField, setSortField] = useState<SortField>("ticker");
|
||||||
@@ -72,16 +90,6 @@ export default function StockTable({ stocks, onNotesSave, saveError }: StockTabl
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const SortHeader = ({ field, children }: { field: SortField; children: ReactNode }) => (
|
|
||||||
<th
|
|
||||||
className="text-left py-2 px-3 font-medium text-gray-700 cursor-pointer hover:text-gray-900 select-none"
|
|
||||||
onClick={() => handleSort(field)}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
{sortField === field && <span className="ml-1">{sortDirection === "asc" ? "↑" : "↓"}</span>}
|
|
||||||
</th>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (stocks.length === 0) {
|
if (stocks.length === 0) {
|
||||||
return (
|
return (
|
||||||
<p className="text-gray-500 py-8">No stocks tracked yet. Visit the stocks page to add some.</p>
|
<p className="text-gray-500 py-8">No stocks tracked yet. Visit the stocks page to add some.</p>
|
||||||
@@ -109,12 +117,12 @@ export default function StockTable({ stocks, onNotesSave, saveError }: StockTabl
|
|||||||
<table className="w-full text-sm">
|
<table className="w-full text-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="border-b border-gray-200">
|
<tr className="border-b border-gray-200">
|
||||||
<SortHeader field="ticker">Ticker</SortHeader>
|
<SortHeader field="ticker" sortField={sortField} sortDirection={sortDirection} onSort={handleSort}>Ticker</SortHeader>
|
||||||
<th className="text-left py-2 px-3 font-medium text-gray-700">Notes</th>
|
<th className="text-left py-2 px-3 font-medium text-gray-700">Notes</th>
|
||||||
<th className="text-left py-2 px-3 font-medium text-gray-700">Last Decision</th>
|
<th className="text-left py-2 px-3 font-medium text-gray-700">Last Decision</th>
|
||||||
<th className="text-left py-2 px-3 font-medium text-gray-700">Last Job</th>
|
<th className="text-left py-2 px-3 font-medium text-gray-700">Last Job</th>
|
||||||
<SortHeader field="createdAt">Created</SortHeader>
|
<SortHeader field="createdAt" sortField={sortField} sortDirection={sortDirection} onSort={handleSort}>Created</SortHeader>
|
||||||
<SortHeader field="updatedAt">Updated</SortHeader>
|
<SortHeader field="updatedAt" sortField={sortField} sortDirection={sortDirection} onSort={handleSort}>Updated</SortHeader>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export default function SystemSettings({ settings, alpacaMode, onSave, saveError
|
|||||||
<div key={setting.key} className="flex items-start gap-4">
|
<div key={setting.key} className="flex items-start gap-4">
|
||||||
<div className="font-mono text-sm text-gray-600 w-48 shrink-0 pt-2">{setting.key}</div>
|
<div className="font-mono text-sm text-gray-600 w-48 shrink-0 pt-2">{setting.key}</div>
|
||||||
<textarea
|
<textarea
|
||||||
|
key={setting.key + setting.value}
|
||||||
className="flex-1 border border-gray-300 rounded-lg px-3 py-2 text-sm font-mono focus:ring-2 focus:ring-blue-500"
|
className="flex-1 border border-gray-300 rounded-lg px-3 py-2 text-sm font-mono focus:ring-2 focus:ring-blue-500"
|
||||||
rows={2}
|
rows={2}
|
||||||
defaultValue={setting.value}
|
defaultValue={setting.value}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export default function TradingSettings({ settings, onSave, saveError }: Trading
|
|||||||
clearTimeout(saveTimersRef.current.get(key)!);
|
clearTimeout(saveTimersRef.current.get(key)!);
|
||||||
}
|
}
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
onSave(key, value);
|
onSave(key, value).catch((e) => console.error(`Failed to save ${key}:`, e));
|
||||||
saveTimersRef.current.delete(key);
|
saveTimersRef.current.delete(key);
|
||||||
}, 300);
|
}, 300);
|
||||||
saveTimersRef.current.set(key, timer);
|
saveTimersRef.current.set(key, timer);
|
||||||
|
|||||||
Reference in New Issue
Block a user