This commit is contained in:
2025-09-17 17:29:57 -04:00
parent 0fa6025514
commit 47f631fedb
3 changed files with 187 additions and 85 deletions

View File

@@ -15,6 +15,7 @@ function App() {
const [statusMessages, setStatusMessages] = useState([]); const [statusMessages, setStatusMessages] = useState([]);
const [markerTime, setMarkerTime] = useState(0); const [markerTime, setMarkerTime] = useState(0);
const playerRef = useRef(null); const playerRef = useRef(null);
const [drawerOpen, setDrawerOpen] = useState(false);
const playerInstanceRef = useRef(null); const playerInstanceRef = useRef(null);
// State for the values // State for the values
window.chartRef = chartRef; window.chartRef = chartRef;
@@ -22,6 +23,8 @@ function App() {
window.playerInstanceRef = playerInstanceRef; window.playerInstanceRef = playerInstanceRef;
// Slider states // Slider states
const inputRef = useRef(null);
const [sliderMin, setSliderMin] = useState(0.0); const [sliderMin, setSliderMin] = useState(0.0);
const [sliderMax, setSliderMax] = useState(1.0); const [sliderMax, setSliderMax] = useState(1.0);
// Date range states // Date range states
@@ -39,16 +42,25 @@ function App() {
const [lastSubmitted, setLastSubmitted] = useState({ const [lastSubmitted, setLastSubmitted] = useState({
startRange, startRange,
endRange, endRange,
sliderValue,
queryText, queryText,
}); });
// Check if any value has changed // // Check if any value has changed
const hasChanged = // const queryChanged =
startRange !== lastSubmitted.startRange || // startRange !== lastSubmitted.startRange ||
endRange !== lastSubmitted.endRange || // endRange !== lastSubmitted.endRange ||
sliderValue !== lastSubmitted.sliderValue || // queryText !== lastSubmitted.queryText;
queryText !== lastSubmitted.queryText;
// Check if queryText is different from lastSubmitted.queryText
const textChanged = queryText !== lastSubmitted.queryText;
const startChanged =
startRange.getTime() !== new Date(lastSubmitted.startRange).getTime();
const endChanged =
endRange.getTime() !== new Date(lastSubmitted.endRange).getTime();
const queryChanged = textChanged || startChanged || endChanged;
const streamComputeStatus = () => { const streamComputeStatus = () => {
fetch("api/return_status") fetch("api/return_status")
@@ -78,7 +90,6 @@ function App() {
let c_line = JSON.parse(line); let c_line = JSON.parse(line);
if (c_line["task"] !== "DONE_QUIT") { if (c_line["task"] !== "DONE_QUIT") {
console.log(c_line);
setStatusMessages((msgs) => [ setStatusMessages((msgs) => [
...msgs, ...msgs,
c_line, c_line,
@@ -98,8 +109,6 @@ function App() {
}; };
// Function to resubmit fetch // Function to resubmit fetch
const handleResubmit = (doTestMode = false) => { const handleResubmit = (doTestMode = false) => {
console.log("startRange, endRange:", startRange, endRange);
console.log("test mode:", doTestMode);
let startRangeUse; let startRangeUse;
let endRangeUse; let endRangeUse;
if (doTestMode == true) { if (doTestMode == true) {
@@ -114,7 +123,6 @@ function App() {
endRangeUse = endRange; endRangeUse = endRange;
} }
console.log("Using date range:", startRangeUse, endRangeUse);
setStartRange(startRangeUse); setStartRange(startRangeUse);
setEndRange(endRangeUse); setEndRange(endRangeUse);
@@ -134,9 +142,8 @@ function App() {
}); });
setLastSubmitted({ setLastSubmitted({
startRangeUse, startRange: startRangeUse,
endRangeUse, endRange: endRangeUse,
sliderValue,
queryText, queryText,
}); });
}; };
@@ -256,7 +263,11 @@ function App() {
return ( return (
<div className="app-container"> <div className="app-container">
<div className="section-box-horiz"> <div
className={`section-box-horiz${
drawerOpen ? " drawer-open" : ""
}`}
>
<div className="flex-group"> <div className="flex-group">
<CustomDateRangePicker <CustomDateRangePicker
startDate={startRange} startDate={startRange}
@@ -266,23 +277,38 @@ function App() {
/> />
</div> </div>
<div className="flex-group"> <div className="flex-group">
<input <div style={{ position: "relative", width: "100%" }}>
type="text" <input
placeholder="Enter query" type="text"
value={queryText} placeholder="Enter query"
onChange={(e) => setQueryText(e.target.value)} value={queryText}
style={{ onChange={(e) => setQueryText(e.target.value)}
marginLeft: "16px", onKeyDown={(e) => {
marginRight: "16px", if (e.key === "Enter") handleResubmit();
padding: "8px", }}
borderRadius: "4px", style={{
border: "1px solid #343a40", marginLeft: "16px",
color: "#fff", // Text white marginRight: "16px",
backgroundColor: "#23272f", // Optional: dark background for contrast padding: "8px",
}} borderRadius: "4px",
/> border: "1px solid #343a40",
color: "#fff",
backgroundColor: "#23272f",
width: "100%",
minWidth: 0,
boxSizing: "border-box",
fontSize: "1.1em",
transition: "width 0.2s",
}}
ref={inputRef}
size={Math.max(queryText.length, 1)}
/>
</div>
</div> </div>
<div className="flex-group"> <div
className="flex-group"
style={{ visibility: queryChanged ? "hidden" : "visible" }}
>
<label <label
style={{ style={{
marginLeft: "8px", marginLeft: "8px",
@@ -293,7 +319,10 @@ function App() {
Threshold: Threshold:
</label> </label>
</div> </div>
<div className="flex-group"> <div
className="flex-group"
style={{ visibility: queryChanged ? "hidden" : "visible" }}
>
<input <input
type="range" type="range"
min={sliderMin} min={sliderMin}
@@ -302,19 +331,36 @@ function App() {
value={sliderValue} value={sliderValue}
onChange={(e) => updateDataAndValue(e.target.value)} onChange={(e) => updateDataAndValue(e.target.value)}
style={{ style={{
width: "120px", width: "100%",
color: "#fff", // Text white color: "#fff",
backgroundColor: "#23272f", // Optional: dark background for contrast backgroundColor: "#23272f",
minWidth: 0,
}} }}
/> />
</div> </div>
<div className="flex-group"> <div
className="flex-group"
style={{ visibility: queryChanged ? "hidden" : "visible" }}
>
<span style={{ marginLeft: "8px", color: "#fff" }}> <span style={{ marginLeft: "8px", color: "#fff" }}>
{sliderValue.toFixed(2)} {sliderValue.toFixed(2)}
</span> </span>
</div> </div>
<div className="flex-group"> <div
<button onClick={handleResubmit}>Resubmit</button> className="flex-group"
style={{ visibility: queryChanged ? "visible" : "hidden" }}
>
<button
onClick={handleResubmit}
style={{
width: "100%",
padding: "12px 0",
fontSize: "1.1em",
marginTop: "8px",
}}
>
Resubmit
</button>
</div> </div>
</div> </div>
<div> <div>

View File

@@ -443,16 +443,30 @@ const EmbedTimeline = React.memo(function EmbedTimeline({
// --- Chart Event Handlers --- // --- Chart Event Handlers ---
async function onChartClick(params, echarts) { async function onChartClick(params, echarts) {
let pixel;
const nativeEvent = params.event.event; const nativeEvent = params.event.event;
const pixel = [nativeEvent.offsetX, nativeEvent.offsetY];
// Support both mouse and touch events
if (nativeEvent.touches && nativeEvent.touches.length > 0) {
// Touch event
const rect = nativeEvent.target.getBoundingClientRect();
const touch = nativeEvent.touches[0];
pixel = [
touch.clientX - rect.left,
touch.clientY - rect.top
];
} else {
// Mouse event
pixel = [nativeEvent.offsetX, nativeEvent.offsetY];
}
const dataCoord = echarts.convertFromPixel({ seriesIndex: 0 }, pixel); const dataCoord = echarts.convertFromPixel({ seriesIndex: 0 }, pixel);
const res = await fetch("/api/events/click", { const res = await fetch("/api/events/click", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ body: JSON.stringify({
timestamp: timestamp: mapVirtualToRealTime(dataCoord[0], breaks, virtualTime) / 1000,
mapVirtualToRealTime(dataCoord[0], breaks, virtualTime) / 1000,
}), }),
}); });
if (!res.ok) throw new Error(`HTTP error: ${res.status}`); if (!res.ok) throw new Error(`HTTP error: ${res.status}`);

View File

@@ -2,6 +2,37 @@ import { useTable } from "react-table";
import { useMemo } from "react"; import { useMemo } from "react";
import "./StatusDisplay.css"; import "./StatusDisplay.css";
function ProgressBar({ progress, total }) {
const percent = total ? Math.round((progress / total) * 100) : 0;
return (
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
<div
style={{
background: "#181a20",
borderRadius: 6,
width: 80,
height: 14,
overflow: "hidden",
border: "1px solid #3a7afe",
marginRight: 8,
}}
>
<div
style={{
width: `${percent}%`,
height: "100%",
background: "#3a7afe",
transition: "width 0.3s",
}}
/>
</div>
<span style={{ color: "#e0e6ed", fontSize: 13 }}>
{progress}/{total} ({percent}%)
</span>
</div>
);
}
export default function StatusesDisplayHUD({ statusMessages }) { export default function StatusesDisplayHUD({ statusMessages }) {
const msg = {}; const msg = {};
const dataPre = {}; const dataPre = {};
@@ -9,7 +40,19 @@ export default function StatusesDisplayHUD({ statusMessages }) {
{ Header: "When", accessor: "WHEN" }, { Header: "When", accessor: "WHEN" },
{ Header: "Scheduled", accessor: "SCHEDULED" }, { Header: "Scheduled", accessor: "SCHEDULED" },
{ Header: "Queued", accessor: "QUEUED" }, { Header: "Queued", accessor: "QUEUED" },
{ Header: "Processing", accessor: "VECTOR_CALC" }, {
Header: "Processing",
accessor: "VECTOR_CALC",
Cell: ({ value }) =>
value && value.type === "progress" ? (
<ProgressBar
progress={value.progress}
total={value.how_many}
/>
) : (
value || ""
),
},
{ Header: "Calculating", accessor: "SCORE_CALC" }, { Header: "Calculating", accessor: "SCORE_CALC" },
{ Header: "Status", accessor: "STATUS" }, { Header: "Status", accessor: "STATUS" },
]; ];
@@ -55,8 +98,13 @@ export default function StatusesDisplayHUD({ statusMessages }) {
m["progress"] + m["progress"] +
"/" + "/" +
m["how_many"]; m["how_many"];
dataPre[when_key]["VECTOR_CALC"] = // dataPre[when_key]["VECTOR_CALC"] =
m["progress"] + "/" + m["how_many"]; // m["progress"] + "/" + m["how_many"];
dataPre[when_key]["VECTOR_CALC"] = {
progress: m["progress"],
how_many: m["how_many"],
type: "progress",
};
break; break;
case "VECTOR_CALC_IN_FOLDER_DONE": case "VECTOR_CALC_IN_FOLDER_DONE":
msg_show = "Finished processing videos"; msg_show = "Finished processing videos";
@@ -72,7 +120,7 @@ export default function StatusesDisplayHUD({ statusMessages }) {
msg_show = c_task; msg_show = c_task;
} }
msg[when_key] = msg_show; msg[when_key] = msg_show;
console.log(when_key); // console.log(when_key);
dataPre[when_key]["STATUS"] = msg_show; dataPre[when_key]["STATUS"] = msg_show;
} }
}); });
@@ -86,48 +134,42 @@ export default function StatusesDisplayHUD({ statusMessages }) {
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } =
useTable({ columns: columnsMemo, data }); useTable({ columns: columnsMemo, data });
return (
<div className="table-container">
<table
{...getTableProps()}
style={{ "--col-count": columns.length - 1 }}
>
{rows.length > 0 && (
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th {...column.getHeaderProps()}>
{column.render("Header")}
</th>
))}
</tr>
))}
</thead>
)}
<tbody {...getTableBodyProps()}>
{rows.map((row) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => (
<td {...cell.getCellProps()}>
{cell.render("Cell")}
</td>
))}
</tr>
);
})}
</tbody>
</table>
</div>
);
return ( return (
<div> <div>
{Object.entries(msg).map(([when, messages], idx) => ( {rows.length > 0 && (
<StatusDisplay key={when} when={when} message={messages} /> <div className="table-container">
))} <table
{...getTableProps()}
style={{ "--col-count": columns.length - 1 }}
>
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th {...column.getHeaderProps()}>
{column.render("Header")}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => (
<td {...cell.getCellProps()}>
{cell.render("Cell")}
</td>
))}
</tr>
);
})}
</tbody>
</table>
</div>
)}
</div> </div>
); );
} }