Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RecorderView: FieldView Replay #162

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

ericwooshem
Copy link

A feature to review past runs on FieldView. Data is stored locally in browser, or can be downloaded and uploaded.

A feature to review past runs on FieldView. Data is stored locally in browser, or can be downloaded and uploaded.
Comment on lines +77 to +79
replayOverlay?: {
ops: DrawOp[];
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think replayOverlay should be separate from TelemetryItem. Live telemetry received from the server comes in batches which complicates the handling logic. Field recording playback should include one overlay at a time and that overlay should live outside of the telemetry item array.

Comment on lines +30 to +37
this.overlay = this.props.telemetry.reduce((acc, { field, replayOverlay, fieldOverlay }) => ({
ops: [
...acc.ops,
...(field?.ops || []),
...(replayOverlay?.ops || []),
...(fieldOverlay?.ops || []),
],
}), { ops: [] });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think live overlays and replayed overlays should be displayed simultaneously. I think it probably makes sense to favor replays over live. In that case, the old logic for setting this.overlay should be preserved with a separate switch between this.overlay and the replay overlay from this.props.

Comment on lines +338 to +340
<div className="canvas-container" style={{ marginBottom: '.5em' }}>
<AutoFitCanvas ref={this.canvasRef} containerHeight="calc(100% - 3em)" />
</div>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this canvas do?

);
this.setState({ savedReplays: keys }, () => {
if (this.state.autoSelect) {
this.handleLoadTelemetryByFilename({ target: { selectedOptions: Array.from(this.state.savedReplays.map(filename => ({ value: filename }))) } });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why Array.from() here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer new code to be written in TS. No need to update this whole file at this point though.

Comment on lines +96 to +102
const maxStorageSize = 5 * 1024 * 1024;
if (totalSize + newDataSize > maxStorageSize) {
alert("Cannot save replay: LocalStorage quota exceeded.");
return;
} else {
localStorage.setItem(storageKey, dataToSave);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to set a per-replay limit and truncate recordings that exceed it. This should probably be done with a limit on the size of this.telemetryRecording; I commented elsewhere about that.

Comment on lines +295 to +298
this.telemetryRecording.push({
timestamp: relativeTimestamp,
ops: overlay.ops,
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The length of this array should be limited. It should probably also be implemented with a circular buffer to avoid allocating / shifting items around.

};

handleLoadTelemetryByFilename = (event) => {
const selectedFiles = Array.from(event.target.selectedOptions, (option) => option.value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why Array.from() here instead of map()?

Comment on lines +114 to +122
this.telemetryReplay = [];

selectedFiles.forEach((filename) => {
const savedTelemetry = localStorage.getItem(filename);
if (savedTelemetry) {
const parsedTelemetry = JSON.parse(savedTelemetry);
this.telemetryReplay.push(parsedTelemetry);
}
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this go in the setState() callback?


handleLoadTelemetryByFilename = (event) => {
const selectedFiles = Array.from(event.target.selectedOptions, (option) => option.value);
if (selectedFiles.length === 0) return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this special-cased?

@rbrott
Copy link
Member

rbrott commented Feb 16, 2025

Very cool. Do you happen to have a video of this in operation?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants