Skip to content

feat(home): enable reordering and toggling home page widgets#91

Merged
Javenn0 merged 12 commits intomainfrom
85-implement-manage-widgets-modal-in-home-page
Apr 17, 2026
Merged

feat(home): enable reordering and toggling home page widgets#91
Javenn0 merged 12 commits intomainfrom
85-implement-manage-widgets-modal-in-home-page

Conversation

@Javenn0
Copy link
Copy Markdown
Member

@Javenn0 Javenn0 commented Apr 15, 2026

closes #85

This pull request introduces a customizable widget system for the workspace home page, allowing users to manage which home page widgets are visible and in what order. The changes include the ability to enable/disable widgets, reorder them via drag-and-drop, and persist these preferences per workspace using local storage. The home page UI is refactored to render widgets dynamically based on user preferences.

Home Page Widget Customization:

  • Added a widget management modal (Manage widgets) that allows users to enable/disable widgets and reorder them via drag-and-drop, with a new icon and UI for reordering (IconGripVertical, modal implementation, drag-and-drop logic) [1] [2] [3].
  • User widget preferences (enabled state and order) are persisted per workspace using localStorage, and are loaded and normalized on page load [1] [2].
  • The home page now renders widgets dynamically based on the enabled/ordered list from user preferences, instead of hardcoding the order and visibility [1] [2] [3] [4].

Integration and UI Enhancements:

  • Added a "Manage widgets" button in the HomeHeader that triggers the widget management modal via a custom event.
  • Refactored imports and added type annotations to support new widget management logic.

Copilot AI review requested due to automatic review settings April 15, 2026 09:27
@Javenn0 Javenn0 linked an issue Apr 15, 2026 that may be closed by this pull request
Copy link
Copy Markdown

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

Adds end-user customization for the workspace home page by allowing widgets to be reordered and toggled on/off (via a “Manage widgets” modal), with persistence per workspace.

Changes:

  • Introduces a home widget model (HomeWidgetId/HomeWidget) with normalization + localStorage persistence keyed by workspace slug.
  • Adds a “Manage widgets” modal supporting drag-and-drop reordering and enable/disable toggles.
  • Wires the PageHeader “Manage widgets” button to open the modal via a window event.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
ui/src/pages/WorkspaceHomePage.tsx Implements widget state, persistence/normalization, modal UI, DnD reorder, and enabled filtering for rendered home sections.
ui/src/components/layout/PageHeader.tsx Adds a header button click handler to open the home widgets modal via a dispatched window event.

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

<button
type="button"
role="switch"
aria-checked={widget.enabled}
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

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

The switch control has role="switch"/aria-checked but no accessible name. Screen readers will announce an unlabeled switch. Add an aria-label (e.g., including the widget label) or link it via aria-labelledby to the visible widget label text.

Suggested change
aria-checked={widget.enabled}
aria-checked={widget.enabled}
aria-label={`Toggle ${widget.label}`}

Copilot uses AI. Check for mistakes.
Comment thread ui/src/pages/WorkspaceHomePage.tsx Outdated
Comment thread ui/src/pages/WorkspaceHomePage.tsx Outdated
Copy link
Copy Markdown

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 2 out of 2 changed files in this pull request and generated 4 comments.


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

Comment thread ui/src/pages/WorkspaceHomePage.tsx Outdated
Comment thread ui/src/components/layout/PageHeader.tsx Outdated
Comment thread ui/src/pages/WorkspaceHomePage.tsx Outdated
Comment thread ui/src/pages/WorkspaceHomePage.tsx Outdated
@nazarli-shabnam nazarli-shabnam added the enhancement New feature or request label Apr 15, 2026
@nazarli-shabnam nazarli-shabnam added this to the Deadline milestone Apr 15, 2026
Copy link
Copy Markdown
Member

@nazarli-shabnam nazarli-shabnam left a comment

Choose a reason for hiding this comment

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

@Javenn0 consider copilot warnings.

Copy link
Copy Markdown

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 3 out of 3 changed files in this pull request and generated 2 comments.


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

Comment thread ui/src/pages/WorkspaceHomePage.tsx Outdated
Comment thread ui/src/pages/WorkspaceHomePage.tsx Outdated
Copy link
Copy Markdown

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 3 out of 3 changed files in this pull request and generated 2 comments.


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

Comment thread ui/src/pages/WorkspaceHomePage.tsx Outdated
Comment thread ui/src/pages/WorkspaceHomePage.tsx Outdated
@Javenn0 Javenn0 requested a review from Copilot April 17, 2026 07:55
Copy link
Copy Markdown

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 4 out of 4 changed files in this pull request and generated 4 comments.


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

Comment on lines +852 to +853
const sectionByWidgetId: Record<HomeWidgetId, ReactNode> = {
quicklinks: (
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

sectionByWidgetId is built as Record<HomeWidgetId, ReactNode>, which eagerly evaluates all widget JSX every render (including the stickies filter/sort IIFE), even when a widget is disabled. Consider storing render functions/components (e.g. Record<HomeWidgetId, () => ReactNode>) or rendering the section inline in the .map() so disabled widgets avoid the extra work.

Suggested change
const sectionByWidgetId: Record<HomeWidgetId, ReactNode> = {
quicklinks: (
const sectionByWidgetId: Record<HomeWidgetId, () => ReactNode> = {
quicklinks: () => (

Copilot uses AI. Check for mistakes.
Comment on lines +1257 to +1267
onDrop={(e) => {
e.preventDefault();
const draggedWidgetId = e.dataTransfer.getData('text/plain');
if (
draggedWidgetId &&
!widgets.some((candidate) => candidate.id === draggedWidgetId)
) {
return;
}
handleWidgetDrop(widget.id);
}}
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

The drop handler reads draggedWidgetId from dataTransfer but handleWidgetDrop reorders based on the draggingWidgetId state. This can get out of sync (e.g., state update timing) and makes the dataTransfer validation effectively unused. Consider passing the dragged id into handleWidgetDrop (or deriving it solely from dataTransfer) so reordering is driven by a single source of truth.

Copilot uses AI. Check for mistakes.
Comment thread ui/src/pages/WorkspaceHomePage.tsx Outdated
Comment thread ui/src/pages/WorkspaceHomePage.tsx Outdated
Copy link
Copy Markdown

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 4 out of 4 changed files in this pull request and generated 2 comments.


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

Comment on lines +1288 to +1292
id={`widget-toggle-label-${widget.id}`}
className="text-sm font-medium text-(--txt-primary)"
>
{widget.label}
</span>
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

The manage-widgets switch sets both aria-label and aria-labelledby. This can result in duplicate/competing accessible names and is inconsistent with the other switches in the codebase (which use aria-labelledby). Prefer keeping just aria-labelledby (or just aria-label) so the computed name is unambiguous.

Copilot uses AI. Check for mistakes.
Comment on lines +1293 to +1297
</div>
<div className="flex items-center gap-2">
<button
type="button"
role="switch"
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

The switch styling uses hard-coded Tailwind blues (border-blue-600 bg-blue-600). Elsewhere (e.g., SettingsPage switches) the app uses design tokens like bg-(--brand-default)/bg-(--neutral-400). Using the token classes here will keep the control consistent with theming (including dark mode) and future palette changes.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

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 4 out of 4 changed files in this pull request and generated 2 comments.


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

Comment on lines +1252 to +1263
{widgets.map((widget) => (
<div
key={widget.id}
draggable
onDragStart={(e) => {
e.dataTransfer.setData('text/plain', widget.id);
e.dataTransfer.effectAllowed = 'move';
setDraggingWidgetId(widget.id);
}}
onDragEnd={() => setDraggingWidgetId(null)}
onDragOver={(e) => e.preventDefault()}
onDrop={(e) => {
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

The widget reorder UI is drag-and-drop only. As implemented, there’s no keyboard-accessible way to change widget order (and HTML5 drag-and-drop is typically not usable with keyboard/screen readers), which makes this modal inaccessible for non-pointer users. Consider adding explicit “Move up / Move down” controls (or another keyboard-operable ordering mechanism) in addition to drag-and-drop, and ensure the order change is reachable via Tab/Enter/Space.

Copilot uses AI. Check for mistakes.
Comment on lines +653 to +655
const openFromHeader = () => setManageWidgetsOpen(true);
window.addEventListener(OPEN_HOME_WIDGETS, openFromHeader as EventListener);
return () => window.removeEventListener(OPEN_HOME_WIDGETS, openFromHeader as EventListener);
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

The event listener uses openFromHeader as EventListener casts when adding/removing the listener. This hides type mismatches and makes the handler signature unclear. Prefer defining openFromHeader with an Event parameter (even if unused) or typing it as an EventListener so the cast isn’t needed, while keeping the same function reference for removeEventListener.

Suggested change
const openFromHeader = () => setManageWidgetsOpen(true);
window.addEventListener(OPEN_HOME_WIDGETS, openFromHeader as EventListener);
return () => window.removeEventListener(OPEN_HOME_WIDGETS, openFromHeader as EventListener);
const openFromHeader = (_event: Event) => setManageWidgetsOpen(true);
window.addEventListener(OPEN_HOME_WIDGETS, openFromHeader);
return () => window.removeEventListener(OPEN_HOME_WIDGETS, openFromHeader);

Copilot uses AI. Check for mistakes.
…plement-manage-widgets-modal-in-home-page
Copy link
Copy Markdown
Member

@nazarli-shabnam nazarli-shabnam left a comment

Choose a reason for hiding this comment

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

good job!

@nazarli-shabnam nazarli-shabnam added the bug Something isn't working label Apr 17, 2026
@Javenn0 Javenn0 merged commit 175558c into main Apr 17, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Manage widgets modal in home page

4 participants