Skip to content

Conversation

@kaochannel154
Copy link
Contributor

@kaochannel154 kaochannel154 commented Sep 11, 2025

User description

Summary

Add Updates notification button to the stage navigation rail with consistent styling and clickable functionality.

Related Issue

N/A

Changes

  • Add UpdateNotificationButton integration to stage navigation items
  • Add notification type support to NavigationListItem component
  • Make entire Updates navigation item clickable (both icon and text)
  • Maintain consistent styling with existing navigation items
  • Show blue notification dot when unread updates exist

Testing

  • Verified Updates button appears in both expanded and collapsed navigation states
  • Confirmed clicking both icon and text opens the notification dialog
  • Tested notification dot visibility with unread updates
  • Ensured consistent hover effects with other navigation items

Other Information

Implementation maintains existing design system and follows established patterns in the navigation rail components.

I'll update the dialog content during the merge. Hopefully the agent will be ready for the update by then...

スクリーンショット 2025-09-11 16 07 19 スクリーンショット 2025-09-11 16 42 54 スクリーンショット 2025-09-11 16 43 27 スクリーンショット 2025-09-11 16 43 34

PR Type

Enhancement


Description

  • Add update notification button to navigation systems

  • Implement global state management for notifications

  • Integrate notification UI across Studio and Editor

  • Update README with enhanced branding and features


Diagram Walkthrough

flowchart LR
  A["UpdateNotificationProvider"] --> B["Navigation Rail"]
  A --> C["Studio Header"]
  A --> D["Editor Header"]
  B --> E["MegaphoneIcon + Dot"]
  C --> E
  D --> E
  E --> F["Notification Dialog"]
  F --> G["Latest Updates List"]
Loading

File Walkthrough

Relevant files
Enhancement
10 files
navigation-items.ts
Add notification navigation item type                                       
+17/-2   
index.ts
Export update notification components                                       
+5/-0     
index.ts
Add components export to v2 module                                             
+1/-0     
layout.tsx
Integrate notification provider and button                             
+35/-28 
navigation-list-item.tsx
Add notification item rendering support                                   
+38/-19 
navigation-rail.tsx
Wrap navigation rail with provider                                             
+3/-2     
page.tsx
Add notification provider to workspace                                     
+9/-4     
index.tsx
Export notification components from editor                             
+2/-0     
update-notification-button.tsx
Implement complete notification system component                 
+208/-0 
v2-header.tsx
Add notification button to header                                               
+6/-2     
Documentation
1 files
README.md
Complete README redesign with enhanced branding                   
+112/-16

Summary by CodeRabbit

  • New Features

    • Added an Updates notification in the navigation rail and editor header with an unread indicator.
    • Clicking opens a “Latest Updates” dialog showing recent improvements and new features; notifications are marked as read after viewing.
    • Includes a “View all” link to the full updates page.
  • UI

    • Consistent availability of update notifications across the Studio and Editor screens.
  • Chores

    • Minor internal cleanup with no user-facing impact.

- Add custom megaphone icon using Lucide v0.15.31 SVG design
- Implement unread state management with conditional dot display
- Position button left of Run button in V2Header
- Add hover effect with opacity transition
- Include accessibility support with proper aria-label and title
- Add Dialog components from @giselle-internal/ui
- Implement full dialog with header, content, and footer sections
- Add 3 update items with NEW/IMPROVED labels and descriptions
- Use consistent color palette (#DAFF09, #08F4EE, #1663F3)
- Add hover effects and chevron navigation icons
- Optimize padding by using negative margin (-m-3) approach
- Remove unnecessary border lines and margins for cleaner look
- Include proper accessibility attributes and keyboard navigation
- Add individual dates (Dec 15, 12, 10, 2024) to each update item
- Replace 'Got it!' button with 'View all' link directing to blog updates
- Improve code formatting consistency (tabs to spaces)
- Enhance content structure for better readability
- Maintain accessibility and hover effects
- Add UpdateNotificationButton to studio.giselles.ai main layout header
- Export UpdateNotificationButton through proper module export chain
- Position notification icon between Docs link and UserButton
- Maintain consistent UI spacing and styling in header
- Follow 'less is more' philosophy with minimal, obvious implementation
- Move UpdateNotificationButton to the left of Docs link in header navigation
- Maintain consistent spacing and visual hierarchy
- Follow user's requested positioning preference
- Add UpdateNotificationProvider with React Context for global state
- Implement safe hook that works with/without provider (graceful fallback)
- Sync notification state across all instances (Studio, Playground, Editor)
- One-click update to dialog content reflects everywhere
- Maintain existing UI/UX while eliminating duplicate state management

✅ Single source of truth - update once, reflects everywhere
✅ Graceful degradation when provider missing
✅ Maintains all existing functionality
✅ Zero breaking changes to existing code
…vider cleanup

- Extract notification data to structured constants for easier maintenance
- Remove complex fallback logic in favor of clear provider requirement
- Eliminate redundant UpdateNotificationProvider in V2Placeholder
- Generate notification items dynamically with .map() for better scalability
- Reduce code complexity while maintaining full functionality
- Improve readability and maintainability without breaking changes
- Add UpdateNotificationButton integration to navigation items
- Add notification type support to NavigationListItem
- Make entire Updates navigation item clickable (both icon and text)
- Maintain consistent styling with other navigation items
- Show notification dot when unread updates exist
@kaochannel154 kaochannel154 self-assigned this Sep 11, 2025
Copilot AI review requested due to automatic review settings September 11, 2025 07:54
@changeset-bot
Copy link

changeset-bot bot commented Sep 11, 2025

⚠️ No Changeset found

Latest commit: 4e97be6

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

💥 An error occurred when fetching the changed packages and changesets in this PR
Some errors occurred when validating the changesets config:
The package or glob expression "giselle-sdk" is specified in the `ignore` option but it is not found in the project. You may have misspelled the package name or provided an invalid glob expression. Note that glob expressions must be defined according to https://www.npmjs.com/package/micromatch.

@giselles-ai
Copy link

giselles-ai bot commented Sep 11, 2025

Finished running flow.

Step Status Updated(UTC)
1 Sep 11, 2025 7:54am
2 Sep 11, 2025 7:55am
3 Sep 11, 2025 7:55am
4 Sep 11, 2025 7:55am

@vercel
Copy link

vercel bot commented Sep 11, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
giselle Ready Ready Preview Comment Sep 11, 2025 8:51am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 11, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Introduces an Update Notification feature: new notification-type nav item, a context provider, and a button that opens a dialog listing hard-coded updates. Integrates the button into the editor header and navigation rail. Adds re-exports to surface provider/button in the workflow-designer-ui package. Minor import cleanup elsewhere.

Changes

Cohort / File(s) Summary
Navigation item model & data
apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-items.ts
Adds NotificationNavigationItem type, expands NavigationItem union, and appends a "Updates" notification item using MegaphoneIcon with onClick stub.
Navigation list rendering
apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx
Renders notification-type as a button hosting UpdateNotificationButton; maintains link rendering; adds exhaustive type handling and click forwarding to inner button.
Provider wrapping (stage rail)
apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-rail.tsx
Wraps rail UI with UpdateNotificationProvider context.
Provider wrapping (workspace page)
apps/studio.giselles.ai/app/workspaces/[workspaceId]/page.tsx
Wraps Editor with UpdateNotificationProvider.
Public API re-exports (editor root)
internal-packages/workflow-designer-ui/src/editor/index.tsx
Re-exports UpdateNotificationButton and UpdateNotificationProvider from v2.
Public API re-exports (v2)
internal-packages/workflow-designer-ui/src/editor/v2/index.ts, .../components/index.ts
Re-exports components, including UpdateNotificationButton and UpdateNotificationProvider.
New notification feature component
internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx
Adds client-side UpdateNotificationProvider (context) and UpdateNotificationButton; manages unread state, dialog open/close, hard-coded updates list, and mark-as-read.
Header integration
internal-packages/workflow-designer-ui/src/editor/v2/components/v2-header.tsx
Adds UpdateNotificationButton next to RunButton.
Minor cleanup
packages/giselle/src/react/act/use-act-controller.tsx
Removes unused Generation type import.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant NR as NavigationListItem (notification)
  participant UNB as UpdateNotificationButton
  participant C as UpdateNotificationProvider (Context)
  participant D as Dialog

  U->>NR: Click "Updates" nav item
  NR->>UNB: Forward click to inner button
  UNB->>C: set isOpen = true, markAsRead()
  C-->>UNB: Context state updated (hasUnread=false)
  UNB->>D: Render Dialog (open)
  U->>D: Interact with list / View all
  D-->>UNB: Close request
  UNB->>C: set isOpen = false
Loading
sequenceDiagram
  autonumber
  actor U as User
  participant VH as V2Header
  participant UNB as UpdateNotificationButton
  participant C as UpdateNotificationProvider
  participant D as Dialog

  U->>VH: Click bell/megaphone
  VH->>UNB: Event
  UNB->>C: Toggle isOpen, markAsRead()
  UNB->>D: Show Latest Updates
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • shige
  • toyamarinyon

Pre-merge checks (3 passed)

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title "Feat/update announcement" is on-topic and concisely reflects the primary change—adding an updates/announcement notification UI (UpdateNotificationButton, provider, and navigation item) across the app—so it is suitable for reviewers scanning PR history. It is short and avoids noisy file lists or emojis. For consistency with repository conventions you may optionally prefer a more explicit phrasing like "Add Updates notification to navigation rail" or use a "feat:" prefix.
Description Check ✅ Passed The PR description follows the repository template and includes the required sections: Summary, Related Issue, Changes, Testing, and Other Information, along with a detailed file walkthrough, diagram, and screenshots, giving reviewers adequate context for the changes. The testing notes are present and the author clearly documents next steps (dialog content update). If the dialog content is required for this review, ask the author to provide it or mark it as post-merge work.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Poem

A rabbit thumps: “Hear ye, new news!” 📣
Little dots blink—unread hues.
I hop to the header, then down the rail,
A dialog blooms with a carrot-tale. 🥕
Click, click—all read, no backlog fright—
Megaphone quiet, we sleep well tonight.

✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/update-announcement

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@giselles-ai
Copy link

giselles-ai bot commented Sep 11, 2025

  • Expanded Navigation Rail:
    1. Ensure the side navigation rail is expanded.
    2. Verify that a new "Updates" item with a megaphone icon is visible below the "Acts" item.
    3. Confirm that a small blue notification dot is visible on the top-right corner of the megaphone icon.
  • Collapsed Navigation Rail:
    1. Collapse the side navigation rail.
    2. Verify that the megaphone icon for "Updates" is visible.
    3. Confirm that the blue notification dot is still present on the icon.
  • Clicking in Expanded View:
    1. Expand the navigation rail.
    2. Click directly on the "Updates" text (not the icon).
    3. Expected Result: The "Latest Updates" dialog opens.
    4. Observe the "Updates" item in the navigation rail.
    5. Expected Result: The blue notification dot has disappeared.
    6. Close the dialog and click on the megaphone icon this time.
    7. Expected Result: The dialog opens again, and the blue dot remains gone.
  • Clicking in Collapsed View:
    1. After completing the test above (so the notification is marked as read), refresh the page to simulate a new session with unread updates. The blue dot should reappear.
    2. Collapse the navigation rail.
    3. Click on the megaphone icon.
    4. Expected Result: The "Latest Updates" dialog opens, and the blue dot on the icon in the background disappears.
  • Dialog Content Verification:
    1. With the "Latest Updates" dialog open, verify the title is "Latest Updates".
    2. Confirm that a list of recent updates is displayed.
    3. Check that each update item shows:
      • A colored badge (e.g., "NEW" or "IMPROVED").
      • A title, date, and description.
    4. Verify that each update item in the list has a > icon on the right.
  • Dialog Interactions:
    1. Hover the cursor over any of the update items in the list.
    2. Expected Result: The item's background color should change, and the cursor should turn into a pointer, indicating it's clickable.
    3. Find and click the "View all" link at the bottom of the dialog.
    4. Expected Result: A new browser tab opens to the Giselle blog/updates page.
    5. Verify you can close the dialog by clicking the 'X' icon (if present) or by clicking on the faded area outside the dialog.
  • Hover Effect:
    1. In both the expanded and collapsed navigation rail, hover your mouse over the "Updates" item.
    2. Expected Result: The hover background style should be identical to the hover style of other items like "Plays" and "Agents".
  • Visual Alignment and Style:
    1. With the navigation rail expanded, visually compare the "Updates" item to its neighbors ("Plays", "Agents").
    2. Expected Result: The icon size, font size, color, and spacing should be consistent with the other navigation items.
📝 E2E Test Generation Prompt
**Objective:** Generate a comprehensive E2E test suite using Playwright and TypeScript for the new "Updates Notification" feature. The tests should cover all user-facing changes introduced in the PR, be maintainable, and ready for CI integration.

### 1. Context Summary

The PR introduces an "Updates" notification feature. A new clickable "Updates" button, represented by a megaphone icon, has been added to the application's UI in two primary locations:

1.  **Stage Navigation Rail:** A vertical navigation bar on the `stage` pages.
2.  **Main Header:** The top-level header of the application.

**Key User Flow:**
A user sees a blue notification dot on the megaphone icon, indicating unread updates. The user clicks the button (either the icon or the text in the expanded nav rail), which opens a dialog modal containing the latest updates. Upon clicking, the blue dot disappears, marking the updates as read for the current session.

**Critical Paths to Test:**
- Verifying the presence and initial state (with dot) of the notification button.
- The click-to-open-dialog and mark-as-read functionality.
- The button's behavior in both expanded and collapsed states of the side navigation rail.
- Ensuring the feature does not break existing navigation or header functionality.

### 2. Test Scenarios

Create a new Playwright test file named `updates-notification.spec.ts`. Structure the tests within a `describe('Updates Notification Feature', () => { ... })` block.

**Setup:**
- Use a `test.beforeEach` hook to navigate to a relevant page where the side navigation rail is visible, for example, `/stage/willi`. This will ensure a clean state for each test.

**Scenario 1: Expanded Navigation Rail**
- **Test 1.1: Initial State & Visibility**
  - **Given** the user is on the `/stage/willi` page and the navigation rail is expanded.
  - **Then** assert that the "Updates" navigation item is visible.
  - **And** assert that the blue notification dot is visible on the icon.

- **Test 1.2: Functionality on Click**
  - **Given** the user is on the `/stage/willi` page.
  - **When** the user clicks the "Updates" navigation item (the entire button area).
  - **Then** assert that the "Latest Updates" dialog modal becomes visible.
  - **And** assert that the blue notification dot is no longer visible on the icon.
  - **When** the user closes the dialog (e.g., by pressing the 'Escape' key or clicking a close button if available).
  - **Then** assert that the dialog is no longer visible.
  - **And** assert that the blue dot remains hidden.

- **Test 1.3: State Persistence on Reload**
  - **Given** the user has opened the updates dialog once.
  - **When** the user reloads the page.
  - **Then** assert that the "Updates" navigation item is visible.
  - **And** assert that the blue notification dot is **not** visible.

**Scenario 2: Collapsed Navigation Rail**
- **Test 2.1: Functionality in Collapsed State**
  - **Given** the user is on the `/stage/willi` page.
  - **When** the user collapses the navigation rail.
  - **Then** assert that the "Updates" icon is still visible.
  - **And** assert that the blue notification dot is visible.
  - **When** the user clicks the "Updates" icon.
  - **Then** assert that the "Latest Updates" dialog modal becomes visible.
  - **And** assert that the blue notification dot is no longer visible.

**Scenario 3: Dialog Content Verification**
- **Test 3.1: Verify Dialog Content**
  - **Given** the user has clicked the "Updates" button.
  - **Then** assert the dialog is visible.
  - **And** assert the dialog contains the title "Latest Updates".
  - **And** assert there is at least one notification item with the text "Enhanced Anthropic Web Search Integration".
  - **And** assert there is a link with the text "View all".

**Scenario 4: Regression Testing**
- **Test 4.1: Other Navigation Items**
  - **Given** the user is on the `/stage/willi` page.
  - **When** the user clicks the "Library" navigation item.
  - **Then** assert that the URL path changes to include `/stage/library`.
  - **And** assert the "Updates" dialog is not triggered.

### 3. Playwright Implementation Instructions

Use the following locators and methods to implement the tests. Prefer role-based and `aria-label` locators for robustness.

- **Navigation:**
  - `await page.goto('/stage/willi');`

- **Locators:**
  - **Stage Nav Rail "Updates" Button:** The feature is implemented as a button containing the text "Updates" when expanded. This wrapper button forwards the click. Target this wrapper.
    ```typescript
    const updatesNavItem = page.locator('nav').getByRole('button', { name: 'Updates' });
    ```
  - **Notification Dot:** The dot is a `div` element inside the button. It has a specific background color. A selector targeting its class or position relative to the icon is needed.
    ```typescript
    const notificationDot = updatesNavItem.locator('div[class*="bg-[#6B8FF0]"]');
    // Or, more robustly, targeting the button with the aria-label that contains the dot.
    const updateButtonCore = page.getByRole('button', { name: 'View updates' });
    const notificationDotOnCore = updateButtonCore.locator('div[class*="bg-[#6B8FF0]"]');
    ```
  - **Updates Dialog:**
    ```typescript
    const updatesDialog = page.getByRole('dialog');
    ```
  - **Dialog Title:**
    ```typescript
    const dialogTitle = updatesDialog.getByRole('heading', { name: 'Latest Updates' });
    ```
  - **"View all" Link:**
    ```typescript
    const viewAllLink = updatesDialog.getByRole('link', { name: 'View all' });
    ```
  - **Nav Rail Collapse/Expand Button:** Assume there's a button to control this. You may need to inspect the live app to find the correct selector. A placeholder is:
    ```typescript
    const collapseButton = page.getByRole('button', { name: 'Collapse navigation' });
    ```

- **User Interactions:**
  - `await updatesNavItem.click();`
  - `await collapseButton.click();`
  - `await page.reload();`
  - To close a dialog: `await page.keyboard.press('Escape');`

- **Assertions:**
  - `await expect(updatesNavItem).toBeVisible();`
  - `await expect(notificationDotOnCore).toBeVisible();`
  - `await expect(notificationDotOnCore).toBeHidden();` or `await expect(notificationDotOnCore).toHaveCount(0);`
  - `await expect(updatesDialog).toBeVisible();`
  - `await expect(dialogTitle).toBeVisible();`
  - `await expect(page).toHaveURL(/.*\/stage\/library/);`

- **Example Test Structure:**
  ```typescript
  import { test, expect } from '@playwright/test';

  test.describe('Updates Notification Feature', () => {
    test.beforeEach(async ({ page }) => {
      await page.goto('/stage/willi');
    });

    test('should display the notification dot on initial load', async ({ page }) => {
      const updateButtonCore = page.getByRole('button', { name: 'View updates' });
      await expect(updateButtonCore).toBeVisible();
      const notificationDot = updateButtonCore.locator('div[class*="bg-[#6B8FF0]"]');
      await expect(notificationDot).toBeVisible();
    });
    
    // ... more tests
  });

4. MCP Integration Guidelines (Optional)

Playwright tests are executed via a command-line interface. If a proprietary "Playwright MCP" tool is used, it likely wraps the standard Playwright CLI.

  • Standard Execution Command:
    npx playwright test tests/updates-notification.spec.ts
  • MCP Execution Command (Assumed Structure):
    # Execute a specific test file
    mcp playwright test --test-file tests/updates-notification.spec.ts
    
    # Run tests in headed mode for debugging
    mcp playwright test --test-file tests/updates-notification.spec.ts --headed
    
    # Set base URL via environment variable if needed
    BASE_URL=http://localhost:3000 mcp playwright test

5. CI-Ready Code Requirements

  • File Structure: Place the new test file updates-notification.spec.ts in the project's designated E2E test directory (e.g., tests/ or e2e/).
  • Naming Conventions:
    • Test files should end with .spec.ts.
    • Use describe blocks for feature suites and test (or it) for individual test cases with clear, descriptive names (e.g., test('should open dialog on click and hide notification dot')).
  • Atomicity: Each test should be independent and runnable on its own. Use beforeEach to set up a consistent state and avoid dependencies between tests. This is critical for parallel execution in CI.
  • Error Handling: Rely on Playwright's built-in assertions (expect). They provide clear error messages upon failure, which is ideal for CI logs. Avoid generic try/catch blocks.
  • Parallelization: By making tests atomic, they are automatically ready for Playwright's default parallel execution, significantly speeding up CI runs. No special configuration is needed if the tests are written correctly.

</details>

Copy link
Contributor

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 an Updates notification button to the stage navigation rail with consistent styling and clickable functionality. The implementation introduces a notification system that shows a blue dot when unread updates exist and opens a dialog with the latest feature announcements.

  • Add UpdateNotificationButton component with notification management context
  • Integrate notifications into stage navigation rail and main layout header
  • Update navigation system to support notification-type items alongside existing link items

Reviewed Changes

Copilot reviewed 11 out of 22 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx New component implementing notification button with dialog and state management
apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx Extended to support notification type navigation items
apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-items.ts Added Updates notification item to navigation configuration
internal-packages/workflow-designer-ui/src/editor/v2/components/v2-header.tsx Integrated notification button into editor header
apps/studio.giselles.ai/app/(main)/layout.tsx Added notification button to main layout header
README.md Major restructuring with enhanced styling and feature showcase

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

useUpdateNotification();

const handleClick = () => {
console.log("Update notification clicked!");
Copy link

Copilot AI Sep 11, 2025

Choose a reason for hiding this comment

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

Remove console.log statements from production code. These debug statements should be removed or replaced with proper logging if needed.

Suggested change
console.log("Update notification clicked!");

Copilot uses AI. Check for mistakes.
Comment on lines 154 to 156
onClick={() =>
console.log(`Navigate to ${notification.title} details`)
}
Copy link

Copilot AI Sep 11, 2025

Choose a reason for hiding this comment

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

Remove console.log statements from production code. These debug statements should be removed or replaced with proper logging if needed.

Suggested change
onClick={() =>
console.log(`Navigate to ${notification.title} details`)
}
onClick={() => {}}

Copilot uses AI. Check for mistakes.
type: "notification",
icon: MegaphoneIcon,
label: "Updates",
onClick: () => {},
Copy link

Copilot AI Sep 11, 2025

Choose a reason for hiding this comment

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

The onClick handler is empty. This should either implement the intended functionality or be removed if the notification behavior is handled elsewhere.

Suggested change
onClick: () => {},
onClick: () => { console.log("Updates notification clicked"); },

Copilot uses AI. Check for mistakes.
Comment on lines 26 to 31
onClick={(e) => {
const updateButton = e.currentTarget.querySelector("button");
if (updateButton) {
updateButton.click();
}
}}
Copy link

Copilot AI Sep 11, 2025

Choose a reason for hiding this comment

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

Using querySelector to find and programmatically click a button creates fragile coupling. Consider passing the click handler directly or using a more explicit event delegation pattern.

Copilot uses AI. Check for mistakes.
@qodo-merge-for-open-source
Copy link

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

State Duplication

Multiple UpdateNotificationProvider instances are introduced (e.g., in the navigation rail and higher-level layout/pages). This will isolate context state between header and rail buttons (dots/open state won’t stay in sync). Consider a single app-level provider to share state across all update buttons.

	<UpdateNotificationProvider>
		<AnimatePresence initial={false}>
			{state === "expanded" && (
				<motion.div
					className="hidden md:block fixed top-0 left-0 h-full"
					exit={{
						opacity: 0,
						width: "var(--spacing-navigation-rail-collapsed)",
					}}
					initial={{
						opacity: 0,
						width: "var(--spacing-navigation-rail-collapsed)",
					}}
					animate={{
						opacity: 1,
						width: "var(--spacing-navigation-rail-expanded)",
					}}
				>
					<NavigationRailExpanded
						user={userPromise}
						onCollapseButtonClick={() => setState("collapsed")}
					/>
				</motion.div>
			)}
		</AnimatePresence>
		<AnimatePresence initial={false}>
			{state === "collapsed" && (
				<motion.div
					className="hidden md:block fixed top-0 left-0 h-full"
					initial={{
						opacity: 1,
						width: "var(--spacing-navigation-rail-collapsed)",
					}}
					exit={{
						opacity: 0,
						width: "var(--spacing-navigation-rail-collapsed)",
					}}
					animate={{
						opacity: 1,
						width: "var(--spacing-navigation-rail-collapsed)",
					}}
				>
					<NavigationRailCollapsed
						user={userPromise}
						onExpandButtonClick={() => setState("expanded")}
					/>
				</motion.div>
			)}
		</AnimatePresence>
		<motion.div
			initial={{
				width: "var(--spacing-navigation-rail-expanded)",
			}}
			animate={spacingAnimationControls}
			className="border-r border-white/10"
		/>
	</UpdateNotificationProvider>
);
A11y Bug

The notification list item renders a button containing another button (UpdateNotificationButton). Nested interactive elements are invalid HTML and can cause click/keyboard issues. Make the outer container a non-button element or refactor the trigger so the whole row is the trigger without nesting buttons.

<button
  type="button"
  onClick={(e) => {
    const updateButton = e.currentTarget.querySelector("button");
    if (updateButton) {
      updateButton.click();
    }
  }}
  className="text-text-muted text-sm flex items-center py-0.5 hover:bg-ghost-element-hover rounded-lg px-1 w-full text-left"
>
  <div className="size-8 flex items-center justify-center">
    <UpdateNotificationButton />
  </div>
  {props.variant === "expanded" && props.label}
</button>
Formatting Error

Stray closing tag '' was added, which will render incorrectly in GitHub and may confuse readers. Remove it.

</thinking>

cursor[bot]

This comment was marked as outdated.

@qodo-merge-for-open-source
Copy link

qodo-merge-for-open-source bot commented Sep 11, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Centralize provider and triggers

The suggestion advises centralizing the UpdateNotificationProvider at the
application root to unify state management and refactoring the
NavigationListItem to avoid nested buttons and fragile click handlers by
directly using the notification context.

Examples:

apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx [22-39]
    case "notification":
      return (
        <button
          type="button"
          onClick={(e) => {
            const updateButton = e.currentTarget.querySelector("button");
            if (updateButton) {
              updateButton.click();
            }
          }}

 ... (clipped 8 lines)
apps/studio.giselles.ai/app/(main)/layout.tsx [14-47]
		<UpdateNotificationProvider>
			<div className="h-screen overflow-y-hidden bg-black-900 flex flex-col">
				<header className="flex flex-col">
					{/* Top row: Logo, Team Selection, User Icon */}
					<div className="h-[50px] flex items-center px-[24px] justify-between">
						<div className="flex items-center gap-2">
							<Link href="/" aria-label="Giselle logo">
								<GiselleLogo className="w-[70px] h-auto fill-white mt-[4px]" />
							</Link>
							<span className="text-black-70">/</span>

 ... (clipped 24 lines)

Solution Walkthrough:

Before:

// Multiple providers create isolated states
// apps/studio.giselles.ai/app/(main)/layout.tsx
export default function Layout({ children }) {
  return (
    <UpdateNotificationProvider>
      {/* ... header with UpdateNotificationButton ... */}
    </UpdateNotificationProvider>
  );
}

// apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-rail.tsx
export function NavigationRail() {
  return (
    <UpdateNotificationProvider>
      {/* ... navigation rail content ... */}
    </UpdateNotificationProvider>
  );
}

// apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx
// Nested button with fragile click handler
function NavigationListItem(props) {
  // ...
  case "notification":
    return (
      <button onClick={(e) => e.currentTarget.querySelector("button")?.click()}>
        <UpdateNotificationButton />
        {props.label}
      </button>
    );
  // ...
}

After:

// A single provider at the root ensures unified state
// app/layout.tsx (hypothetical root layout)
export default function RootLayout({ children }) {
  return (
    <UpdateNotificationProvider>
      {children}
    </UpdateNotificationProvider>
  );
}
// Other layouts no longer need the provider.

// apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx
// The list item itself becomes the trigger, removing nesting and hacks.
function NavigationListItem(props) {
  const { markAsRead } = useUpdateNotification();
  // ...
  case "notification":
    return (
      <button onClick={markAsRead} className="w-full text-left ...">
        <div className="size-8 ...">
          <UpdateNotificationButton />
        </div>
        {props.label}
      </button>
    );
  // ...
}
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a critical architectural flaw by pointing out multiple UpdateNotificationProvider instances, which would cause inconsistent state, and also highlights a severe implementation anti-pattern with nested buttons and programmatic clicks, which is bad for accessibility and robustness.

High
Possible issue
Remove nested interactive elements

Avoid nesting a button within another button, which is invalid HTML and can
break click/keyboard behavior. Replace the outer button with a div that acts
like a button and add keyboard handling for accessibility. This preserves
full-row click while delegating the actual dialog open to the inner trigger.

apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx [22-39]

 case "notification":
   return (
-    <button
-      type="button"
+    <div
+      role="button"
+      tabIndex={0}
       onClick={(e) => {
         const updateButton = e.currentTarget.querySelector("button");
         if (updateButton) {
           updateButton.click();
         }
       }}
-      className="text-text-muted text-sm flex items-center py-0.5 hover:bg-ghost-element-hover rounded-lg px-1 w-full text-left"
+      onKeyDown={(e) => {
+        if (e.key === "Enter" || e.key === " ") {
+          e.preventDefault();
+          const updateButton = (e.currentTarget as HTMLElement).querySelector("button") as HTMLButtonElement | null;
+          updateButton?.click();
+        }
+      }}
+      className="text-text-muted text-sm flex items-center py-0.5 hover:bg-ghost-element-hover rounded-lg px-1 w-full"
     >
       <div className="size-8 flex items-center justify-center">
         <UpdateNotificationButton />
       </div>
       {props.variant === "expanded" && props.label}
-    </button>
+    </div>
   );
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies invalid nested interactive elements (<button> inside <button>) and proposes a fix using a div with appropriate ARIA roles and keyboard handlers, which improves HTML validity and accessibility.

Low
Learned
best practice
Remove debug logging

Remove debug logging from production code. Drop the console.log and directly
invoke the state update; also scan and remove similar logs in this file (e.g.,
notification item clicks).

internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx [118-121]

 const handleClick = () => {
-  console.log("Update notification clicked!");
   markAsRead();
 };
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why:
Relevant best practice - Remove debug logging and dead code from production modules to avoid noise and accidental data leakage.

Low
  • Update

- Changed from switch statement to if-else chain for better type narrowing
- TypeScript now properly narrows the NavigationItem union type
- Fixes Vercel deployment build error

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx (1)

113-116: Remove console.log in production paths

Drop debug logs in the trigger and item clicks; wire real navigation later.

-  console.log("Update notification clicked!");
   markAsRead();
-                onClick={() =>
-                  console.log(`Navigate to ${notification.title} details`)
-                }
+                onClick={() => {
+                  /* TODO: navigate to notification details when available */
+                }}

Also applies to: 146-152

apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx (1)

23-40: Critical: Nested button + querySelector click-forwarding breaks HTML/a11y

A button inside a button is invalid and harms accessibility. Programmatic forwarding via querySelector is brittle. Render the update trigger as the row itself.

-  if (props.type === "notification") {
-    return (
-      <button
-        type="button"
-        onClick={(e) => {
-          const updateButton = e.currentTarget.querySelector("button");
-          if (updateButton) {
-            updateButton.click();
-          }
-        }}
-        className="text-text-muted text-sm flex items-center py-0.5 hover:bg-ghost-element-hover rounded-lg px-1 w-full text-left"
-      >
-        <div className="size-8 flex items-center justify-center">
-          <UpdateNotificationButton />
-        </div>
-        {props.variant === "expanded" && props.label}
-      </button>
-    );
-  }
+  if (props.type === "notification") {
+    return (
+      <UpdateNotificationButton variant="nav-item">
+        {props.variant === "expanded" && props.label}
+      </UpdateNotificationButton>
+    );
+  }
🧹 Nitpick comments (4)
internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx (4)

111-111: Ensure unread badge clears on any open path

When the dialog opens via other triggers, also clear unread to prevent stale dots.

-  const { hasUnreadUpdates, isOpen, setIsOpen, markAsRead } = context;
+  const {
+    hasUnreadUpdates,
+    isOpen,
+    setIsOpen,
+    setHasUnreadUpdates,
+    markAsRead,
+  } = context;
@@
-    <Dialog open={isOpen} onOpenChange={setIsOpen}>
+    <Dialog
+      open={isOpen}
+      onOpenChange={(open) => {
+        setIsOpen(open);
+        if (open) setHasUnreadUpdates(false);
+      }}
+    >

Also applies to: 119-121


72-101: Export a small hook for context access (future-proofing consumers)

A useUpdateNotification() hook lets other components open the dialog without DOM querying.

 const UpdateNotificationContext = createContext<UpdateNotificationState | null>(
   null,
 );
 
 export function UpdateNotificationProvider({
@@
 }
 
+export function useUpdateNotification() {
+  const ctx = useContext(UpdateNotificationContext);
+  if (!ctx) {
+    throw new Error(
+      "useUpdateNotification must be used within UpdateNotificationProvider",
+    );
+  }
+  return ctx;
+}

130-130: Prefer design tokens over hard-coded hex

Use a theme token/utility (e.g., accent/brand color) for the dot to keep dark/light modes consistent.


41-61: Consider using lucide-react’s Megaphone to reduce custom SVG

Keeps iconography consistent and reduces maintenance surface.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf3a94d and 4e97be6.

📒 Files selected for processing (4)
  • apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx (1 hunks)
  • internal-packages/workflow-designer-ui/src/editor/v2/components/index.ts (1 hunks)
  • internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx (1 hunks)
  • packages/giselle/src/react/act/use-act-controller.tsx (0 hunks)
💤 Files with no reviewable changes (1)
  • packages/giselle/src/react/act/use-act-controller.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal-packages/workflow-designer-ui/src/editor/v2/components/index.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development-guide.mdc)

**/*.{ts,tsx}: Use Biome for formatting with tab indentation and double quotes
Follow organized imports pattern (enabled in biome.json)
Use TypeScript for type safety; avoid any types
Use Next.js patterns for web applications
Use async/await for asynchronous code rather than promises
Error handling: use try/catch blocks and propagate errors appropriately
Use kebab-case for all filenames (e.g., user-profile.ts)
Use camelCase for variables, functions, and methods (e.g., userEmail)
Use prefixes like is, has, can, should for boolean variables and functions for clarity
Use verbs or verb phrases that clearly indicate purpose for function naming (e.g., calculateTotalPrice(), not process())

If breaking changes are introduced in new AI SDK versions, update code to accommodate those changes

**/*.{ts,tsx}: Use TypeScript and avoid any
Use async/await and proper error handling
Variables and functions should use camelCase
Boolean variables and functions should use is/has/can/should prefixes
Function names should clearly indicate purpose

Files:

  • apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx
  • internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/development-guide.mdc)

**/*.tsx: Use functional components with React hooks
Use PascalCase for React components and classes (e.g., UserProfile)

**/*.tsx: Components should use React hooks and Next.js patterns
Component identifiers should use PascalCase

Files:

  • apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx
  • internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx
**/*

📄 CodeRabbit inference engine (.cursor/rules/naming-guide.mdc)

All filenames should use kebab-case (lowercase with hyphens)

Files:

  • apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx
  • internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/naming-guide.mdc)

**/*.{js,jsx,ts,tsx}: React components and classes should use PascalCase
Variables, functions, and methods should use camelCase
Use verbs or verb phrases for function names; names should clearly indicate what the function does; avoid ambiguous names that could lead to misuse
Use nouns or noun phrases for variable names; names should describe what the variable represents; avoid single-letter variables except in very short scopes
Use prefixes like 'is', 'has', 'can', 'should' for both variables and functions returning boolean values; make the true/false meaning clear

Files:

  • apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx
  • internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx
apps/studio.giselles.ai/app/stage/ui/navigation-rail/**/navigation-list*.tsx

📄 CodeRabbit inference engine (apps/studio.giselles.ai/app/stage/ui/navigation-rail/AGENTS.md)

apps/studio.giselles.ai/app/stage/ui/navigation-rail/**/navigation-list*.tsx: If you need non-link behaviors, extend NavigationListItem to support additional item types
Compute the current pathname in NavigationListItem and apply active styles when navigationItem.isActive?.(pathname) is true
Alternatively, pass the active pathname down from the page/layout and style items in NavigationListItem accordingly

Files:

  • apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx
🧠 Learnings (14)
📓 Common learnings
Learnt from: CR
PR: giselles-ai/giselle#0
File: internal-packages/workflow-designer-ui/src/new-editor/AGENTS.md:0-0
Timestamp: 2025-09-02T05:50:06.317Z
Learning: Applies to internal-packages/workflow-designer-ui/src/new-editor/**/*.ts : Lift actions into the store (e.g., expose updateNode) and invoke them from components performing mutations.
📚 Learning: 2025-09-01T00:43:10.540Z
Learnt from: CR
PR: giselles-ai/giselle#0
File: apps/studio.giselles.ai/app/stage/ui/navigation-rail/AGENTS.md:0-0
Timestamp: 2025-09-01T00:43:10.540Z
Learning: Applies to apps/studio.giselles.ai/app/stage/ui/navigation-rail/**/navigation-list*.tsx : If you need non-link behaviors, extend NavigationListItem to support additional item types

Applied to files:

  • apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx
📚 Learning: 2025-09-01T00:43:10.540Z
Learnt from: CR
PR: giselles-ai/giselle#0
File: apps/studio.giselles.ai/app/stage/ui/navigation-rail/AGENTS.md:0-0
Timestamp: 2025-09-01T00:43:10.540Z
Learning: Applies to apps/studio.giselles.ai/app/stage/ui/navigation-rail/**/{navigation-rail-collapsed.tsx,menu-button.tsx} : Update collapsed header toggle icons or hover behavior

Applied to files:

  • apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx
📚 Learning: 2025-09-01T00:43:10.540Z
Learnt from: CR
PR: giselles-ai/giselle#0
File: apps/studio.giselles.ai/app/stage/ui/navigation-rail/AGENTS.md:0-0
Timestamp: 2025-09-01T00:43:10.540Z
Learning: Applies to apps/studio.giselles.ai/app/stage/ui/navigation-rail/**/navigation-list*.tsx : Alternatively, pass the active pathname down from the page/layout and style items in NavigationListItem accordingly

Applied to files:

  • apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx
📚 Learning: 2025-09-01T00:43:10.540Z
Learnt from: CR
PR: giselles-ai/giselle#0
File: apps/studio.giselles.ai/app/stage/ui/navigation-rail/AGENTS.md:0-0
Timestamp: 2025-09-01T00:43:10.540Z
Learning: Applies to apps/studio.giselles.ai/app/stage/ui/navigation-rail/**/navigation-items.ts : To change labels, icons, or routes, update the corresponding fields in the nav item objects

Applied to files:

  • apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx
📚 Learning: 2025-09-01T00:43:10.540Z
Learnt from: CR
PR: giselles-ai/giselle#0
File: apps/studio.giselles.ai/app/stage/ui/navigation-rail/AGENTS.md:0-0
Timestamp: 2025-09-01T00:43:10.540Z
Learning: Applies to apps/studio.giselles.ai/app/stage/ui/navigation-rail/**/navigation-items.ts : Define navigation destinations by appending objects shaped { id, type: "link", icon, label, href, isActive? }

Applied to files:

  • apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx
📚 Learning: 2025-09-01T00:43:10.540Z
Learnt from: CR
PR: giselles-ai/giselle#0
File: apps/studio.giselles.ai/app/stage/ui/navigation-rail/AGENTS.md:0-0
Timestamp: 2025-09-01T00:43:10.540Z
Learning: Applies to apps/studio.giselles.ai/app/stage/ui/navigation-rail/**/navigation-rail.tsx : Adjust the default rail state by changing useState<NavigationRailState>("expanded") to "collapsed" (or vice versa)

Applied to files:

  • apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx
📚 Learning: 2025-09-01T00:43:10.540Z
Learnt from: CR
PR: giselles-ai/giselle#0
File: apps/studio.giselles.ai/app/stage/ui/navigation-rail/AGENTS.md:0-0
Timestamp: 2025-09-01T00:43:10.540Z
Learning: Applies to apps/studio.giselles.ai/app/stage/ui/navigation-rail/**/navigation-rail.tsx : If moving away from Suspense-based user loading, change prop to user: UserDataForNavigationRail

Applied to files:

  • apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx
📚 Learning: 2025-09-01T00:43:10.540Z
Learnt from: CR
PR: giselles-ai/giselle#0
File: apps/studio.giselles.ai/app/stage/ui/navigation-rail/AGENTS.md:0-0
Timestamp: 2025-09-01T00:43:10.540Z
Learning: Applies to apps/studio.giselles.ai/app/stage/ui/navigation-rail/**/navigation-list*.tsx : Compute the current pathname in NavigationListItem and apply active styles when navigationItem.isActive?.(pathname) is true

Applied to files:

  • apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx
📚 Learning: 2025-09-01T00:43:10.540Z
Learnt from: CR
PR: giselles-ai/giselle#0
File: apps/studio.giselles.ai/app/stage/ui/navigation-rail/AGENTS.md:0-0
Timestamp: 2025-09-01T00:43:10.540Z
Learning: Applies to apps/studio.giselles.ai/app/stage/ui/navigation-rail/**/navigation-rail-footer-menu.tsx : Modify footer/account menu by editing the items array; set external: true for external links (renders <a target="_blank" rel="noopener">); the value: "log-out" item renders SignOutButton via renderItem

Applied to files:

  • apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx
📚 Learning: 2025-09-01T00:43:10.540Z
Learnt from: CR
PR: giselles-ai/giselle#0
File: apps/studio.giselles.ai/app/stage/ui/navigation-rail/AGENTS.md:0-0
Timestamp: 2025-09-01T00:43:10.540Z
Learning: Applies to apps/studio.giselles.ai/app/stage/ui/navigation-rail/**/navigation-items.ts : Import icons for navigation items from lucide-react or the internal icon set when adding/updating items

Applied to files:

  • apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx
📚 Learning: 2025-09-02T05:50:06.317Z
Learnt from: CR
PR: giselles-ai/giselle#0
File: internal-packages/workflow-designer-ui/src/new-editor/AGENTS.md:0-0
Timestamp: 2025-09-02T05:50:06.317Z
Learning: Applies to internal-packages/workflow-designer-ui/src/new-editor/**/*.ts : Lift actions into the store (e.g., expose updateNode) and invoke them from components performing mutations.

Applied to files:

  • internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx
📚 Learning: 2025-07-21T22:29:07.662Z
Learnt from: CR
PR: giselles-ai/giselle#0
File: .cursor/rules/edit-workspace-tour.mdc:0-0
Timestamp: 2025-07-21T22:29:07.662Z
Learning: Applies to internal-packages/workflow-designer-ui/src/editor/workspace-tour/workspace-tour.tsx : Update the `TourGlobalStyles` component in `workspace-tour.tsx` for animation changes

Applied to files:

  • internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx
📚 Learning: 2025-09-02T05:50:06.317Z
Learnt from: CR
PR: giselles-ai/giselle#0
File: internal-packages/workflow-designer-ui/src/new-editor/AGENTS.md:0-0
Timestamp: 2025-09-02T05:50:06.317Z
Learning: Applies to internal-packages/workflow-designer-ui/src/new-editor/**/*.tsx : Use selective subscriptions: selectors must pick only the minimal state needed for render (e.g., s.nodesById[id], specific UI flags).

Applied to files:

  • internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx
🧬 Code graph analysis (2)
apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-list-item.tsx (4)
apps/studio.giselles.ai/app/stage/ui/navigation-rail/navigation-items.ts (1)
  • NavigationItem (21-21)
apps/studio.giselles.ai/app/stage/ui/navigation-rail/types.ts (1)
  • NavigationRailState (1-1)
internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx (1)
  • UpdateNotificationButton (104-203)
internal-packages/workflow-designer-ui/src/editor/v2/components/index.ts (1)
  • UpdateNotificationButton (2-2)
internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx (2)
internal-packages/workflow-designer-ui/src/editor/v2/components/index.ts (2)
  • UpdateNotificationProvider (3-3)
  • UpdateNotificationButton (2-2)
internal-packages/workflow-designer-ui/src/editor/index.tsx (2)
  • UpdateNotificationProvider (24-24)
  • UpdateNotificationButton (24-24)

Comment on lines +104 to +133
export function UpdateNotificationButton() {
const context = useContext(UpdateNotificationContext);
if (!context) {
throw new Error(
"UpdateNotificationButton must be used within UpdateNotificationProvider",
);
}
const { hasUnreadUpdates, isOpen, setIsOpen, markAsRead } = context;

const handleClick = () => {
console.log("Update notification clicked!");
markAsRead();
};

return (
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogTrigger asChild>
<button
type="button"
onClick={handleClick}
className="relative"
aria-label="View updates"
>
<MegaphoneIcon className="size-4 text-text-muted" />
{/* Notification dot - only show when there are unread updates */}
{hasUnreadUpdates && (
<div className="absolute -top-[2px] -right-[2px] w-[8px] h-[8px] bg-[#6B8FF0] rounded-full" />
)}
</button>
</DialogTrigger>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid nested-button integrations: Add a full-width “nav-item” trigger variant

Expose a variant and children to let consumers render the entire navigation row as the trigger, eliminating the need to wrap this component in another button.

-export function UpdateNotificationButton() {
+export function UpdateNotificationButton({
+  variant = "icon",
+  className,
+  children,
+}: {
+  variant?: "icon" | "nav-item";
+  className?: string;
+  children?: ReactNode;
+}) {
@@
-  const { hasUnreadUpdates, isOpen, setIsOpen, markAsRead } = context;
+  const { hasUnreadUpdates, isOpen, setIsOpen, markAsRead } = context;
@@
-      <DialogTrigger asChild>
-        <button
-          type="button"
-          onClick={handleClick}
-          className="relative"
-          aria-label="View updates"
-        >
-          <MegaphoneIcon className="size-4 text-text-muted" />
-          {/* Notification dot - only show when there are unread updates */}
-          {hasUnreadUpdates && (
-            <div className="absolute -top-[2px] -right-[2px] w-[8px] h-[8px] bg-[#6B8FF0] rounded-full" />
-          )}
-        </button>
-      </DialogTrigger>
+      <DialogTrigger asChild>
+        <button
+          type="button"
+          onClick={handleClick}
+          className={`${variant === "nav-item"
+            ? "text-text-muted text-sm flex items-center py-0.5 hover:bg-ghost-element-hover rounded-lg px-1 w-full text-left"
+            : "relative"} ${className ?? ""}`}
+          aria-label="View updates"
+        >
+          {variant === "nav-item" ? (
+            <>
+              <div className="size-8 flex items-center justify-center relative">
+                <MegaphoneIcon className="size-4 text-text-muted" />
+                {hasUnreadUpdates && (
+                  <div className="absolute -top-[2px] -right-[2px] w-[8px] h-[8px] bg-[#6B8FF0] rounded-full" />
+                )}
+              </div>
+              {children}
+            </>
+          ) : (
+            <>
+              <MegaphoneIcon className="size-4 text-text-muted" />
+              {hasUnreadUpdates && (
+                <div className="absolute -top-[2px] -right-[2px] w-[8px] h-[8px] bg-[#6B8FF0] rounded-full" />
+              )}
+            </>
+          )}
+        </button>
+      </DialogTrigger>

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx
lines 104-133: the component currently renders an internal <button> inside
DialogTrigger which forces consumers to wrap it in another button for full-width
nav rows; add a variant prop (e.g., variant?: 'icon' | 'nav-item') and children
prop, and when variant === 'nav-item' render DialogTrigger with asChild and
forward the provided children (no internal button) so consumers can supply the
full-width nav row element as the trigger; when variant === 'icon' keep the
existing internal button and attach handleClick/aria-label/notification-dot to
it; ensure types support children and variant, and that markAsRead/onClick are
only called once by wiring handleClick to the consumed child via cloning or
letting consumers call it (document in prop types).

Copy link
Member

@shige shige left a comment

Choose a reason for hiding this comment

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

The following concerns me:

  • Clicking on each notification element does nothing.
  • The Latest Updates section contains dummy content. I'd like it to be mergeable.

@shige shige requested a review from toyamarinyon September 12, 2025 01:34
@shige
Copy link
Member

shige commented Sep 12, 2025

@toyamarinyon
Could you review codes when you have a time?

@kaochannel154
Copy link
Contributor Author

@shige
Thanks for reviewing!
As noted in the other update, I'll swap this out for the most current version once it's ready to merge. The content will focus on things that directly impact users (like additional available models, new tool functionality that's been added, etc.).

@toyamarinyon
Copy link
Contributor

It looks good overall, but there are some areas that need some adjustment, so I will check and adjust them at the start of next week.

const { hasUnreadUpdates, isOpen, setIsOpen, markAsRead } = context;

const handleClick = () => {
console.log("Update notification clicked!");

Choose a reason for hiding this comment

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

🟡 MEDIUM - Debug console.log left in production code

Category: quality

| Agent: General Code Review

Description:
console.log statement appears to be debug leftover code

Suggestion:
Remove debug console.log or use proper logger if intentional logging is needed

Confidence: 95%
Rule: general_console_log_committed

key={notification.id}
type="button"
onClick={() =>
console.log(`Navigate to ${notification.title} details`)

Choose a reason for hiding this comment

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

🟡 MEDIUM - Debug console.log left in production code

Category: quality

| Agent: General Code Review

Description:
console.log statement appears to be debug leftover code

Suggestion:
Remove debug console.log or use proper logger if intentional logging is needed

Confidence: 95%
Rule: general_console_log_committed

Comment on lines +41 to +61
function MegaphoneIcon({ className }: { className?: string }) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className={className}
>
<title>Megaphone icon</title>
<path d="M11 6a13 13 0 0 0 8.4-2.8A1 1 0 0 1 21 4v12a1 1 0 0 1-1.6.8A13 13 0 0 0 11 14H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2z" />
<path d="M6 14a12 12 0 0 0 2.4 7.2 2 2 0 0 0 3.2-2.4A8 8 0 0 1 10 14" />
<path d="M8 6v8" />
</svg>
);
}

Choose a reason for hiding this comment

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

🟡 MEDIUM - Custom MegaphoneIcon reimplements lucide-react icon

Category: quality

| Agent: Code Consistency & Reuse Check

Description:
Creating custom SVG component when MegaphoneIcon already exists in lucide-react library

Suggestion:
Import MegaphoneIcon from 'lucide-react' instead of defining a custom component. The file already imports ChevronRightIcon from the same library (line 9), and navigation-items.ts (line 2) shows MegaphoneIcon is available from lucide-react.

Confidence: 90%
Rule: quality_reinventing_wheel

@diffray-bot
Copy link

diffray diffray code review

Free public review - Want AI code reviews on your PRs? Check out diffray.ai

Summary

Validated 6 issues: 3 kept (console.log statements, custom icon reimplementation), 3 filtered (hardcoded URL follows codebase pattern, magic numbers too minor, SRP violation subjective)

Issues Found: 3

See 3 individual line comment(s) for details.

Full issue list (click to expand)

🟡 MEDIUM - Debug console.log left in production code

File: internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx:114

Category: quality

| Agent: General Code Review

Description: console.log statement appears to be debug leftover code

Suggestion: Remove debug console.log or use proper logger if intentional logging is needed

Confidence: 95%

Rule: general_console_log_committed


🟡 MEDIUM - Debug console.log left in production code

File: internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx:150

Category: quality

| Agent: General Code Review

Description: console.log statement appears to be debug leftover code

Suggestion: Remove debug console.log or use proper logger if intentional logging is needed

Confidence: 95%

Rule: general_console_log_committed


🟡 MEDIUM - Custom MegaphoneIcon reimplements lucide-react icon

File: internal-packages/workflow-designer-ui/src/editor/v2/components/update-notification-button.tsx:41-61

Category: quality

| Agent: Code Consistency & Reuse Check

Description: Creating custom SVG component when MegaphoneIcon already exists in lucide-react library

Suggestion: Import MegaphoneIcon from 'lucide-react' instead of defining a custom component. The file already imports ChevronRightIcon from the same library (line 9), and navigation-items.ts (line 2) shows MegaphoneIcon is available from lucide-react.

Confidence: 90%

Rule: quality_reinventing_wheel



Powered by diffray - AI Code Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants