Skip to content

Conversation

@ConnorNeed
Copy link
Member

Nothing benefits more from me procrastinating from exams than this webUI.
Screenshot from 2025-12-16 14-26-35
Screenshot from 2025-12-16 14-26-57
Screenshot from 2025-12-16 14-27-21
Screenshot from 2025-12-16 14-27-35

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds dynamic tile creation functionality to the MosaicDashboard component, allowing users to add new panels on-the-fly in horizontal (right) or vertical (below) directions. The feature includes interactive buttons in each tile's toolbar that open a dropdown for selecting which panel to add.

Key changes:

  • Added Controls component with buttons to dynamically add tiles in different directions
  • Implemented dropdown UI for selecting which tile type to add
  • Fixed typo in TODO comment ("paramaterize" → "parameterize")

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 144 to 148
{ALL_TILES.filter((t) => t !== id).map((t) => (
<option key={t} value={t}>
{t}
</option>
))}
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

The tile names displayed in the dropdown and button labels are camelCase identifiers (e.g., 'mapView', 'rosMonitor') which are not user-friendly. Consider creating a mapping to display human-readable names (e.g., 'Map View', 'ROS Monitor') to improve the user experience.

Copilot uses AI. Check for mistakes.
Comment on lines 109 to 129
<button
className="tile-btn"
title="Add tile to the right"
onClick={(e) => {
e.stopPropagation();
setPendingAdd({ pathKey, path, direction: 'row' });
}}
>
➕ (Right)
</button>

<button
className="tile-btn"
title="Add tile below"
onClick={(e) => {
e.stopPropagation();
setPendingAdd({ pathKey, path, direction: 'column' });
}}
>
➕ (Below)
</button>
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

The buttons lack proper aria-label attributes for screen readers. While the title attribute is present, it only provides tooltip text on hover and is not accessible to assistive technologies. Add aria-label attributes to ensure screen reader users can understand the purpose of these buttons.

Copilot uses AI. Check for mistakes.
Comment on lines 132 to 140
<select
className="tile-select"
onClick={(e) => e.stopPropagation()}
onChange={(e) => {
const value = e.target.value as MosaicKey;
splitAndAdd(pendingAdd!.direction, value);
}}
defaultValue=""
>
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

The select dropdown appears immediately when either button is clicked, but lacks an accessible label. Add an aria-label attribute to the select element to describe its purpose for screen reader users, such as "Select tile to add".

Copilot uses AI. Check for mistakes.
.tile-btn {
background: transparent;
border: 1px solid #444;
color: #2d2d2d;
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

The button text color is set to a very dark color (#2d2d2d) on a dark background (#2d2d2d for the title bar), making the buttons nearly invisible to users. The color should be changed to a lighter color (such as #f1f1f1) to provide sufficient contrast and ensure the buttons are visible and accessible.

Copilot uses AI. Check for mistakes.
Comment on lines 90 to 153
const Controls: React.FC<{ id: MosaicKey; path: MosaicPath }> = ({ id, path }) => {
const { mosaicActions } = useContext(MosaicContext);
const pathKey = JSON.stringify(path);
const showDropdown = pendingAdd?.pathKey === pathKey;

const splitAndAdd = (direction: 'row' | 'column', newTile: MosaicKey) => {
const splitNode: MosaicNode<MosaicKey> = {
direction,
first: id, // keep current tile
second: newTile,
splitPercentage: 60,
};

mosaicActions.replaceWith(path, splitNode);
setPendingAdd(null);
};

return (
<div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
<button
className="tile-btn"
title="Add tile to the right"
onClick={(e) => {
e.stopPropagation();
setPendingAdd({ pathKey, path, direction: 'row' });
}}
>
➕ (Right)
</button>

<button
className="tile-btn"
title="Add tile below"
onClick={(e) => {
e.stopPropagation();
setPendingAdd({ pathKey, path, direction: 'column' });
}}
>
➕ (Below)
</button>

{showDropdown ? (
<select
className="tile-select"
onClick={(e) => e.stopPropagation()}
onChange={(e) => {
const value = e.target.value as MosaicKey;
splitAndAdd(pendingAdd!.direction, value);
}}
defaultValue=""
>
<option value="" disabled>
Pick tile…
</option>
{ALL_TILES.filter((t) => t !== id).map((t) => (
<option key={t} value={t}>
{t}
</option>
))}
</select>
) : null}
</div>
);
};
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

The Controls component is defined inside the render function of MosaicDashboard. This will cause the Controls component to be recreated on every render, which can lead to unnecessary re-renders and potential performance issues. The Controls component should be moved outside of the MosaicDashboard component or memoized to prevent this issue.

Copilot uses AI. Check for mistakes.
Comment on lines 69 to 81
const ALL_TILES = useMemo<MosaicKey[]>(
() => [
'mapView',
'rosMonitor',
'networkHealthMonitor',
'orientationDisplay',
'videoControls',
'waypointList',
'gasSensor',
'goalSetter',
],
[]
);
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

The ALL_TILES constant is wrapped in useMemo with an empty dependency array, but since it contains a static array of string literals that never changes, useMemo adds unnecessary overhead without any benefit. Consider removing useMemo and declaring ALL_TILES as a const array outside the component, or at minimum as a regular const inside the component.

Copilot uses AI. Check for mistakes.
Comment on lines 135 to 138
onChange={(e) => {
const value = e.target.value as MosaicKey;
splitAndAdd(pendingAdd!.direction, value);
}}
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

The onChange handler directly casts the value without validation and uses the non-null assertion operator (pendingAdd!). If pendingAdd becomes null between the time showDropdown is evaluated and onChange is triggered, this could cause a runtime error. Consider adding a null check before calling splitAndAdd.

Copilot uses AI. Check for mistakes.
Comment on lines 131 to 150
{showDropdown ? (
<select
className="tile-select"
onClick={(e) => e.stopPropagation()}
onChange={(e) => {
const value = e.target.value as MosaicKey;
splitAndAdd(pendingAdd!.direction, value);
}}
defaultValue=""
>
<option value="" disabled>
Pick tile…
</option>
{ALL_TILES.filter((t) => t !== id).map((t) => (
<option key={t} value={t}>
{t}
</option>
))}
</select>
) : null}
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

The dropdown is only closed when a tile is selected via splitAndAdd. If a user clicks elsewhere on the page, the dropdown remains open and shows for that specific tile. Consider adding an onBlur handler or a click-outside handler to close the dropdown when the user clicks elsewhere, improving the user experience.

Copilot uses AI. Check for mistakes.
@ConnorNeed
Copy link
Member Author

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link

Copilot AI commented Dec 16, 2025

@ConnorNeed I've opened a new pull request, #10, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

const value = e.target.value as MosaicKey;
// Validate pendingAdd state and selected value before proceeding
if (pendingAdd && value) {
splitAndAdd(pendingAdd.direction, value);
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

The onChange handler doesn't reset the select element's value after selection. This means after selecting a tile, the dropdown will show the last selected tile instead of the placeholder "Pick tile…". Consider adding e.target.value = '' after calling splitAndAdd to reset the selection, or use a controlled component with value state.

Suggested change
splitAndAdd(pendingAdd.direction, value);
splitAndAdd(pendingAdd.direction, value);
e.target.value = '';

Copilot uses AI. Check for mistakes.
@ConnorNeed
Copy link
Member Author

Code still has some bugs. Closing for now

@ConnorNeed ConnorNeed closed this Dec 16, 2025
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