Skip to content

Conversation

@nikochiko
Copy link
Member

@nikochiko nikochiko commented Jul 17, 2025

Q/A checklist

  • I have tested my UI changes on mobile and they look acceptable
  • I have tested changes to the workflows in both the API and the UI
  • I have done a code review of my changes and looked at each line of the diff + the references of each function I have changed
  • My changes have not increased the import time of the server
How to check import time?

time python -c 'import server'

You can visualize this using tuna:

python3 -X importtime -c 'import server' 2> out.log && tuna out.log

To measure import time for a specific library:

$ time python -c 'import pandas'

________________________________________________________
Executed in    1.15 secs    fish           external
   usr time    2.22 secs   86.00 micros    2.22 secs
   sys time    0.72 secs  613.00 micros    0.72 secs

To reduce import times, import libraries that take a long time inside the functions that use them instead of at the top of the file:

def my_function():
    import pandas as pd
    ...

Legal Boilerplate

Look, I get it. The entity doing business as “Gooey.AI” and/or “Dara.network” was incorporated in the State of Delaware in 2020 as Dara Network Inc. and is gonna need some rights from me in order to utilize my contributions in this PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Dara Network Inc can use, modify, copy, and redistribute my contributions, under its choice of terms.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 17, 2025

📝 Walkthrough

"""

Walkthrough

This set of changes introduces enhancements to the search and navigation experience, primarily within the explore and header components. The explore page is refactored to use a unified SearchFilters model, now supporting dynamic sorting via a new SortOptions enum, improved workspace filtering, and responsive UI elements. The search bar and filter UI are restructured for better responsiveness and usability, including mobile-specific behaviors. Several new FontAwesome icons are added. The saved workflow preview logic is updated to conditionally show run counts based on new parameters. Navigation links and dropdowns are refactored for consistency and responsiveness, and the Google sign-in button receives a responsive redesign for desktop and mobile. Minor CSS formatting fixes and route handler improvements are also included.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes
This PR spans multiple modules and templates, introduces new models and enums, updates function signatures, and refactors UI logic and rendering across several files. The changes are interconnected and require careful review of search/filter logic, UI/UX adjustments, and backward compatibility.

Possibly related PRs

Suggested reviewers

  • devxpy
    """

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f47dc37 and d5fe760.

📒 Files selected for processing (4)
  • routers/root.py (9 hunks)
  • widgets/explore.py (2 hunks)
  • widgets/workflow_search.py (9 hunks)
  • workspaces/widgets.py (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • widgets/explore.py
  • workspaces/widgets.py
🧰 Additional context used
🧠 Learnings (1)
routers/root.py (1)

Learnt from: nikochiko
PR: #703
File: workspaces/widgets.py:161-166
Timestamp: 2025-06-16T11:43:04.972Z
Learning: In workspaces/widgets.py header links rendering, the gui.columns([2, 10]) layout should be maintained consistently even when no icon exists, leaving empty space in the first column for visual alignment purposes. This prioritizes consistent alignment over space optimization.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (python)
  • GitHub Check: test (3.10.12, 1.8.3)
🔇 Additional comments (16)
routers/root.py (7)

12-12: LGTM!

The new imports are appropriately added to support the enhanced search functionality and workspace selector integration.

Also applies to: 48-49


248-260: Well-structured parameter consolidation.

Excellent refactor to consolidate individual query parameters into the typed SearchFilters model. The use of FastAPI's Query() annotation ensures proper parameter binding while maintaining clean type safety.


697-705: Well-designed function signature extension.

The addition of optional parameters with sensible defaults maintains backwards compatibility while enabling the new search functionality. The type hints are properly specified.


714-748: Improved responsive header structure.

The header reorganization with proper flex layout and conditional rendering based on show_search_bar enhances the user experience. The mobile search integration is well-structured.


778-823: Well-implemented mobile search functionality.

The mobile search implementation is excellent:

  • Proper function scoping with private naming convention
  • Clean JavaScript for DOM manipulation with appropriate event handling
  • Good responsive design with proper CSS class management
  • User-friendly cancel functionality

The focus management (document.querySelector('#search_bar').focus()) enhances the mobile user experience.


837-860: Good refactor to use shared helper functions.

Excellent consolidation to use workspace_selector_link instead of manual GUI construction. This reduces code duplication and ensures consistent styling across components. The breakpoint alignment with header changes maintains visual consistency.


862-868: Excellent helper function design.

The render_header_link helper function is well-designed with clear responsibilities:

  • Handles optional icon parameter gracefully
  • Consistent responsive classes and styling
  • Proper semantic HTML structure
  • Good code reuse potential

This promotes maintainability and consistency across header links.

widgets/workflow_search.py (9)

1-3: LGTM!

All new imports are appropriately used and well-organized to support the enhanced search and sorting functionality.

Also applies to: 14-14, 19-21, 23-23


26-60: Well-designed sorting options implementation.

Excellent structure using NamedTuple for type safety and GooeyEnum for functionality:

  • Consistent icon styling with fixed width for proper alignment
  • Meaningful sort criteria covering key user needs
  • Appropriate default selection (FEATURED)
  • Clean enum design with proper inheritance

The implementation provides a solid foundation for the sorting functionality.


62-70: Good enhancement to SearchFilters model.

The migration to Pydantic BaseModel and addition of the sort field is well-executed:

  • Provides built-in validation and serialization for FastAPI
  • Boolean evaluation correctly includes all filter fields
  • Default values maintain backwards compatibility

This aligns perfectly with the FastAPI Query parameter usage in the router.


72-152: Sophisticated responsive filter UI design.

Excellent implementation of adaptive layout with intelligent responsive behavior:

  • Dynamic column classes based on filter state and user authentication
  • Smart CSS media queries for label visibility on different screen sizes
  • Clean conditional rendering that maintains UI clarity
  • Proper use of flexbox for alignment

The complexity is well-managed and the user experience considerations are thoughtful.


154-178: Clean implementation of search redirect functionality.

Well-structured approach to handling search input changes:

  • Clear separation between rendering and redirect logic
  • Proper change detection prevents unnecessary redirects
  • Good use of model_dump(exclude_defaults=True) for clean query parameters
  • Appropriate use of gui.RedirectException for navigation

This provides a smooth user experience with immediate search result updates.


180-290: Thoughtful search bar enhancements with contextual placeholders.

Excellent improvements to the search experience:

  • Dynamic placeholder text provides clear context about current filtering scope
  • Proper handling of different workspace types (personal vs. regular)
  • Workflow information integration in placeholders enhances user understanding
  • Maintained backwards compatibility in function signatures

The contextual guidance helps users understand their current search scope.


314-329: Well-designed workspace conversion helpers.

Clean implementation of bidirectional workspace conversion:

  • Clear separation of concerns for filter value mapping
  • Proper preference for human-readable handle names over IDs
  • Safe handling of edge cases with None returns
  • Good type hints for function safety

These utilities enable consistent workspace filtering across the application.


368-391: Smart conditional display logic in search results.

Excellent refinement of search result rendering:

  • Intelligent show_run_count logic that displays counts when relevant (sorting by "Most Runs" or for workspace members)
  • Proper workspace author display based on current filtering context
  • Clean UI with hide_visibility_pill parameter

The conditional display balances information density with user relevance effectively.


393-509: Comprehensive query filtering improvements.

Excellent enhancement of the filtering system:

  • build_sort_filter provides appropriate ordering strategies for each sort option
  • Featured sorting uses intelligent prioritization (approved examples, priorities, root workflows)
  • Proper integration of workspace helper functions in search filtering
  • User context is correctly threaded through the filtering pipeline

The database query structure should provide good performance while supporting the new sorting requirements.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch search-sort

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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

🧹 Nitpick comments (4)
templates/google_one_tap_button.html (1)

24-29: Consider increasing mobile button width for better touch target.

The mobile sign-in button width of 60px might be smaller than optimal for touch interactions. Consider increasing it to at least 64px to meet accessibility guidelines.

-        google.accounts.id.renderButton(document.getElementById("g_id_signin_mobile"), {
-            shape: "rectangular",
-            width: 60,
-            type: "icon",
-            size: "large",
-        });
+        google.accounts.id.renderButton(document.getElementById("g_id_signin_mobile"), {
+            shape: "rectangular",
+            width: 64,
+            type: "icon",
+            size: "large",
+        });
daras_ai_v2/base.py (2)

357-363: Potential indentation issue with dedent and f-string.

The f-string inside dedent() might produce unexpected indentation. Consider moving string formatting outside dedent.

-                gui.write(
-                    dedent(f"""
-                You currently don't have access to this resource. Please request access from the
-                {owner_workspace.display_name(current_user=self.request.user)} admin or sign in with another account. 
-                You are logged in as {self.request.user.email or self.request.user.phone_number}.
-                """)
-                )
+                workspace_name = owner_workspace.display_name(current_user=self.request.user)
+                user_identifier = self.request.user.email or self.request.user.phone_number
+                gui.write(
+                    dedent(f"""
+                    You currently don't have access to this resource. Please request access from the
+                    {workspace_name} admin or sign in with another account. 
+                    You are logged in as {user_identifier}.
+                    """).strip()
+                )

2454-2481: Consider refactoring complex authorization logic for better maintainability.

The authorization logic is comprehensive but complex. Consider breaking it down into smaller, more focused methods for better readability and testability.

 def is_user_authorized(self, user: AppUser | None = None) -> bool:
     if self.is_user_admin(user):
         return True
 
     sr, pr = self.current_sr_pr
     if pr.saved_run_id != sr.id:
-        # not published run
-        return (
-            # free workspace: allow anyone
-            not sr.workspace.subscription_id
-            or (
-                PricingPlan.from_sub(sr.workspace.subscription)
-                == PricingPlan.STARTER
-            )
-            # paid workspace: allow members
-            or bool(user and sr.workspace in user.cached_workspaces)
-        )
+        return self._is_unpublished_run_authorized(user, sr)
+    
+    return self._is_published_run_authorized(user, pr)
 
-    # published run
-    return (
-        pr.is_approved_example
-        or (
-            WorkflowAccessLevel(pr.public_access)
-            in (WorkflowAccessLevel.FIND_AND_VIEW, WorkflowAccessLevel.EDIT)
-        )
-        # current user is in the same workspace
-        or bool(user and pr.workspace in user.cached_workspaces)
-    )
+def _is_unpublished_run_authorized(self, user: AppUser | None, sr: SavedRun) -> bool:
+    """Check authorization for unpublished runs."""
+    # Free/starter workspace: allow anyone
+    if not sr.workspace.subscription_id:
+        return True
+    if PricingPlan.from_sub(sr.workspace.subscription) == PricingPlan.STARTER:
+        return True
+    # Paid workspace: allow members only
+    return bool(user and sr.workspace in user.cached_workspaces)
+
+def _is_published_run_authorized(self, user: AppUser | None, pr: PublishedRun) -> bool:
+    """Check authorization for published runs."""
+    if pr.is_approved_example:
+        return True
+    if WorkflowAccessLevel(pr.public_access) in (WorkflowAccessLevel.FIND_AND_VIEW, WorkflowAccessLevel.EDIT):
+        return True
+    # Allow workspace members
+    return bool(user and pr.workspace in user.cached_workspaces)
routers/root.py (1)

715-734: Consider using CSS classes instead of inline styles for better maintainability.

While the current implementation works, toggling CSS classes would be more maintainable than directly setting display properties.

Instead of manipulating inline styles directly, consider adding/removing CSS classes:

 def get_js_hide_mobile_search():
     return dedent("""
     event.preventDefault();
     const hide_on_mobile_search = document.querySelectorAll('.hide_on_mobile_search');
     const show_on_mobile_search = document.querySelectorAll('.show_on_mobile_search');
-    hide_on_mobile_search.forEach(el => el.style.setProperty('display', 'flex'));
-    show_on_mobile_search.forEach(el => el.style.setProperty('display', 'none'));
+    hide_on_mobile_search.forEach(el => el.classList.remove('d-none'));
+    show_on_mobile_search.forEach(el => el.classList.add('d-none'));
     """)

This approach would be more consistent with the Bootstrap utility classes used elsewhere in the code.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fc02923 and 7c7249b.

📒 Files selected for processing (13)
  • daras_ai_v2/base.py (7 hunks)
  • daras_ai_v2/icons.py (2 hunks)
  • daras_ai_v2/meta_content.py (1 hunks)
  • daras_ai_v2/paypal.py (2 hunks)
  • daras_ai_v2/settings.py (2 hunks)
  • recipes/VideoBots.py (0 hunks)
  • routers/account.py (2 hunks)
  • routers/root.py (9 hunks)
  • templates/google_one_tap_button.html (2 hunks)
  • widgets/explore.py (5 hunks)
  • widgets/saved_workflow.py (5 hunks)
  • widgets/workflow_search.py (9 hunks)
  • workspaces/widgets.py (6 hunks)
💤 Files with no reviewable changes (1)
  • recipes/VideoBots.py
🧰 Additional context used
🧠 Learnings (6)
daras_ai_v2/settings.py (1)
Learnt from: nikochiko
PR: GooeyAI/gooey-server#703
File: daras_ai_v2/settings.py:301-308
Timestamp: 2025-06-16T11:42:40.993Z
Learning: In daras_ai_v2/settings.py, when using a localhost frontend with api.gooey.ai backend deployment, hard-coded "/explore/" paths work correctly as relative URLs, but EXPLORE_URL computed from APP_BASE_URL may point to the wrong domain (localhost instead of api.gooey.ai).
daras_ai_v2/icons.py (1)
Learnt from: nikochiko
PR: GooeyAI/gooey-server#703
File: daras_ai_v2/settings.py:309-309
Timestamp: 2025-06-16T11:40:10.683Z
Learning: The FontAwesome icon `fa-magnifying-glass` is available in both `fa-solid` and `fa-regular` styles. The user nikochiko confirmed this with documentation link https://fontawesome.com/icons/magnifying-glass?f=classic&s=regular
routers/account.py (1)
Learnt from: nikochiko
PR: GooeyAI/gooey-server#703
File: daras_ai_v2/settings.py:301-308
Timestamp: 2025-06-16T11:42:40.993Z
Learning: In daras_ai_v2/settings.py, when using a localhost frontend with api.gooey.ai backend deployment, hard-coded "/explore/" paths work correctly as relative URLs, but EXPLORE_URL computed from APP_BASE_URL may point to the wrong domain (localhost instead of api.gooey.ai).
workspaces/widgets.py (1)
Learnt from: nikochiko
PR: GooeyAI/gooey-server#703
File: workspaces/widgets.py:161-166
Timestamp: 2025-06-16T11:43:04.972Z
Learning: In workspaces/widgets.py header links rendering, the gui.columns([2, 10]) layout should be maintained consistently even when no icon exists, leaving empty space in the first column for visual alignment purposes. This prioritizes consistent alignment over space optimization.
routers/root.py (1)
Learnt from: nikochiko
PR: GooeyAI/gooey-server#703
File: workspaces/widgets.py:161-166
Timestamp: 2025-06-16T11:43:04.972Z
Learning: In workspaces/widgets.py header links rendering, the gui.columns([2, 10]) layout should be maintained consistently even when no icon exists, leaving empty space in the first column for visual alignment purposes. This prioritizes consistent alignment over space optimization.
widgets/saved_workflow.py (1)
Learnt from: nikochiko
PR: GooeyAI/gooey-server#703
File: workspaces/widgets.py:161-166
Timestamp: 2025-06-16T11:43:04.972Z
Learning: In workspaces/widgets.py header links rendering, the gui.columns([2, 10]) layout should be maintained consistently even when no icon exists, leaving empty space in the first column for visual alignment purposes. This prioritizes consistent alignment over space optimization.
🧬 Code Graph Analysis (1)
routers/account.py (5)
daras_ai_v2/fastapi_tricks.py (2)
  • get_app_route_url (68-74)
  • get_route_path (77-80)
widgets/workflow_search.py (2)
  • SearchFilters (60-67)
  • get_filter_value_from_workspace (271-272)
daras_ai_v2/base.py (1)
  • current_workspace (1420-1425)
workspaces/widgets.py (1)
  • get_current_workspace (192-203)
routers/root.py (1)
  • explore_page (250-262)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (python)
  • GitHub Check: test (3.10.12, 1.8.3)
🔇 Additional comments (32)
daras_ai_v2/icons.py (1)

25-25: LGTM! Icon additions support new UI features.

The new icons are properly formatted with correct FontAwesome classes and are positioned logically within the file structure. The search icon uses fa-solid fa-magnifying-glass which is appropriate for UI elements.

Also applies to: 28-28, 50-53

daras_ai_v2/paypal.py (1)

6-6: LGTM! Type annotation improvements enhance code clarity.

The consolidated imports and explicit ClassVar annotations for class-level constants are excellent improvements that enhance type safety without changing functionality.

Also applies to: 21-22, 27-27

daras_ai_v2/settings.py (1)

309-309: LGTM! Removal of static explore link supports dynamic navigation.

Clearing the HEADER_ICONS dictionary aligns with the refactoring of explore page navigation to be more dynamic and context-aware, as mentioned in the PR objectives.

routers/account.py (2)

16-16: LGTM! Import addition supports URL generation with query parameters.

The get_app_route_url import is necessary for constructing URLs with query parameters in the new redirect logic.


139-156: LGTM! Well-implemented workspace-scoped explore redirect.

The new route handler correctly:

  • Performs authentication checks with appropriate redirect to login
  • Retrieves the current workspace for the authenticated user
  • Creates search filters scoped to that workspace
  • Redirects to the explore page with properly encoded filters

This implementation aligns with the PR objective of redirecting from the saved tab to the explore page with workspace filtering.

daras_ai_v2/meta_content.py (1)

220-238: LGTM! Authorization check enhances SEO and security.

The new authorization check correctly prevents search engines from following or indexing pages that require authentication, while preserving the original tab-based logic for publicly accessible content. This aligns with the broader authorization improvements introduced in the PR.

templates/google_one_tap_button.html (1)

1-3: Good responsive design implementation.

The separation of desktop and mobile sign-in buttons with responsive classes (d-none d-md-inline and d-md-none) is a clean approach for device-specific rendering.

workspaces/widgets.py (5)

2-2: Good security practice with HTML escaping.

Adding the html module import to properly escape user-generated content prevents XSS vulnerabilities.


22-27: Excellent security and code quality improvements.

The changes improve the code in multiple ways:

  • Proper HTML escaping prevents XSS vulnerabilities
  • Structured div approach is more maintainable than string concatenation
  • Responsive styling with text truncation improves UI on smaller screens

Also applies to: 38-39, 60-67, 118-119


143-143: Appropriate breakpoint adjustment for better UX.

Changing from d-lg-none to d-xl-none allows header links to display on large screens, improving navigation accessibility.


133-158: Excellent refactoring to reduce code duplication.

The refactoring to use render_link_in_dropdown helper function improves code maintainability while preserving the consistent column layout pattern.


163-190: Well-designed helper function following DRY principle.

The render_link_in_dropdown function excellently encapsulates the repeated dropdown link pattern while maintaining the required gui.columns([2, 10]) layout for visual consistency. The optional parameters provide good flexibility.

widgets/explore.py (3)

26-51: Well-structured meta tag generation with good SEO practices.

The build_meta_tags function uses clean pattern matching and generates contextual titles that improve SEO. The defensive programming with default SearchFilters instance prevents null reference errors.


54-68: Smart UI improvements and defensive programming.

Good improvements:

  • Responsive heading visibility based on search context
  • Copying search_filters prevents mutation side effects
  • Cleaner redirect logic with default exclusion reduces URL clutter

88-88: Good style consistency and UI enhancements.

The changes improve code consistency by using gui.div instead of gui.tag("div") and enhance the run count display with better styling and layout.

Also applies to: 129-129, 148-154

daras_ai_v2/base.py (2)

366-368: Proper authorization gate implementation.

The authorization check is correctly placed at the beginning of the render method with an early return pattern, preventing any unauthorized access to sensitive operations.


1477-1477: Good improvements for type safety and performance.

Adding type hints improves code clarity, and using select_related for the PublishedRun query reduces database queries by eagerly loading related objects.

Also applies to: 1487-1488

routers/root.py (5)

8-8: LGTM!

The imports are properly organized and all appear to be used in the code.

Also applies to: 13-13, 38-40, 50-51


250-262: Good refactoring to consolidate query parameters!

The use of a Pydantic model with FastAPI's Query() annotation improves parameter handling and validation while making the code more maintainable.


698-713: Well-implemented search redirect logic!

The function properly handles search state changes and URL updates using the framework's redirect mechanism.


737-741: LGTM!

The addition of the optional search_filters parameter maintains backward compatibility while enabling search functionality.


808-809: Good improvements to header navigation!

The breakpoint adjustments and refactoring to use the render_link_in_dropdown helper improve consistency and user experience.

Also applies to: 815-822, 852-852, 862-869

widgets/saved_workflow.py (3)

27-27: Good use of keyword-only arguments!

The addition of * enforces keyword-only arguments, improving API clarity and preventing positional argument mistakes.

Also applies to: 33-33, 87-87


135-161: Good CSS improvements for better layout flexibility!

The flexbox approach and increased max-width for author names improve the responsive behavior and accommodate longer content.


166-228: Well-structured footer rendering improvements!

The conditional display based on membership status and consistent muted text styling improve the UI hierarchy and information disclosure.

widgets/workflow_search.py (7)

60-68: LGTM!

The SearchFilters model properly includes the new sort field and the boolean evaluation correctly considers all filter fields.


271-286: Well-designed workspace filter helpers!

The functions provide a clean abstraction for converting between workspaces and filter values, properly handling both handle names and IDs.


76-133: Excellent responsive UI implementation!

The conditional rendering based on login status and dynamic sort option display provide a clean, context-aware interface.


217-247: Smart placeholder text generation!

The dynamic placeholder provides helpful context about the current search scope, improving user understanding.


363-382: Well-implemented sorting logic!

The sort filter provides comprehensive ordering strategies for each sort option, with appropriate fallback ordering.


31-33: Fix incorrect decorator usage - cannot use @classmethod and @Property together.

Using both decorators will cause a runtime error. Choose one approach:

Option 1 - Use @classmethod:

-    @classmethod
-    @property
-    def default(cls) -> "SortOptions":
+    @classmethod
+    def default(cls) -> "SortOptions":
         return cls.FEATURED

Option 2 - Use class attribute:

-    @classmethod
-    @property
-    def default(cls) -> "SortOptions":
-        return cls.FEATURED
+    DEFAULT = "featured"

Then update usage from SortOptions.default to SortOptions.default() or SortOptions.DEFAULT.

Likely an incorrect or invalid review comment.


329-344: Verification Complete: is_member Is Properly Annotated

I’ve confirmed that in build_workflow_access_filter we annotate

  • is_member=Q(membership__role__isnull=False) for authenticated users
  • default is_member=False for anonymous users

No further changes are required here.

@nikochiko nikochiko force-pushed the search-sort branch 2 times, most recently from a7888fa to ea18713 Compare July 23, 2025 13:06
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: 0

♻️ Duplicate comments (4)
widgets/workflow_search.py (4)

30-33: Fix the decorator syntax issue on the default property.

The code combines @classmethod and @property decorators incorrectly. A property cannot be a classmethod - these decorators are mutually exclusive.

-    @classmethod
-    @property
-    def default(cls) -> "SortOptions":
-        return cls.FEATURED
+    @classmethod
+    def default(cls) -> "SortOptions":
+        return cls.FEATURED

289-291: Fix the SortOptions.default reference after correcting the decorator.

This code references SortOptions.default which has the decorator issue identified earlier.

    sort_options = dict(
-        (opt.value if opt != SortOptions.default else "", opt) for opt in SortOptions
+        (opt.value if opt != SortOptions.default() else "", opt) for opt in SortOptions
    )

294-294: Fix the SortOptions.default reference in format_func.

This line also references the problematic SortOptions.default property.

    def format_func(v: str | None) -> str:
-        opt = sort_options.get(v, SortOptions.default)
+        opt = sort_options.get(v, SortOptions.default())

371-374: Fix the SortOptions.default reference in query building.

Another instance of the decorator issue that needs to be addressed.

    qs = build_sort_filter(
        qs,
-        search_filters.sort and SortOptions(search_filters.sort) or SortOptions.default,
+        search_filters.sort and SortOptions(search_filters.sort) or SortOptions.default(),
    )
🧹 Nitpick comments (2)
widgets/workflow_search.py (2)

207-228: Consider caching workspace lookups in placeholder generation.

The function calls get_workspace_from_filter_value and performs workspace display name generation on every invocation, which could be expensive if called frequently.

Consider memoizing or caching the workspace lookup result:

def get_placeholder_by_search_filters(
    search_filters: SearchFilters,
    current_user: AppUser | None,
    fallback_workspace_text: str = "Gooey.AI",
) -> str:
    from daras_ai_v2.all_pages import page_slug_map, normalize_slug

    text = "Search"
-    workspace = current_user and get_workspace_from_filter_value(
-        current_user, search_filters.workspace
-    )
+    workspace = None
+    if current_user and search_filters.workspace:
+        # Consider caching this lookup if called frequently
+        workspace = get_workspace_from_filter_value(
+            current_user, search_filters.workspace
+        )

253-267: Optimize workspace lookup with early return and better iteration.

The function iterates through all cached workspaces on every call. Consider using a dictionary lookup for better performance.

def get_workspace_from_filter_value(
    user: AppUser, value: str
) -> typing.Optional["Workspace"]:
    if not value:
        return None

+    # Try direct ID lookup first if value is numeric
+    if value.isdigit():
+        workspace_id = int(value)
+        for w in user.cached_workspaces:
+            if w.id == workspace_id:
+                return w
+    
+    # Then try handle name lookup
    for w in user.cached_workspaces:
-        if str(w.id) == value or (w.handle_id and w.handle.name == value):
+        if w.handle_id and w.handle.name == value:
            return w

    return None
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a7888fa and ea18713.

📒 Files selected for processing (5)
  • daras_ai_v2/icons.py (2 hunks)
  • routers/root.py (9 hunks)
  • widgets/explore.py (4 hunks)
  • widgets/workflow_search.py (9 hunks)
  • workspaces/widgets.py (6 hunks)
🧬 Code Graph Analysis (1)
widgets/workflow_search.py (7)
app_users/models.py (2)
  • AppUser (90-262)
  • cached_workspaces (242-249)
bots/models/published_run.py (1)
  • PublishedRun (118-346)
bots/models/workflow.py (5)
  • Workflow (189-257)
  • short_title (230-232)
  • page_cls (240-243)
  • get_or_create_metadata (245-257)
  • emoji (235-237)
daras_ai_v2/grid_layout_widget.py (1)
  • grid_layout (25-38)
widgets/saved_workflow.py (1)
  • render_saved_workflow_preview (24-91)
workspaces/models.py (4)
  • Workspace (105-449)
  • display_name (392-402)
  • display_html (47-57)
  • display_html (387-390)
daras_ai_v2/all_pages.py (1)
  • normalize_slug (109-110)
✅ Files skipped from review due to trivial changes (1)
  • daras_ai_v2/icons.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • widgets/explore.py
  • workspaces/widgets.py
  • routers/root.py
🧰 Additional context used
🧬 Code Graph Analysis (1)
widgets/workflow_search.py (7)
app_users/models.py (2)
  • AppUser (90-262)
  • cached_workspaces (242-249)
bots/models/published_run.py (1)
  • PublishedRun (118-346)
bots/models/workflow.py (5)
  • Workflow (189-257)
  • short_title (230-232)
  • page_cls (240-243)
  • get_or_create_metadata (245-257)
  • emoji (235-237)
daras_ai_v2/grid_layout_widget.py (1)
  • grid_layout (25-38)
widgets/saved_workflow.py (1)
  • render_saved_workflow_preview (24-91)
workspaces/models.py (4)
  • Workspace (105-449)
  • display_name (392-402)
  • display_html (47-57)
  • display_html (387-390)
daras_ai_v2/all_pages.py (1)
  • normalize_slug (109-110)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (python)
  • GitHub Check: test (3.10.12, 1.8.3)
🔇 Additional comments (6)
widgets/workflow_search.py (6)

76-85: Good refactoring of the conditional UI layout logic.

The dynamic column class assignment based on filter visibility states improves the responsive layout handling.


369-369: Good refactoring to pass user context to search filter builder.

Adding the user parameter to build_search_filter enables proper workspace filtering based on user permissions.


379-398: Well-structured sorting implementation with comprehensive options.

The sort filtering function provides good coverage of different sorting criteria with appropriate fallback ordering for each case.


442-444: Good integration of workspace filtering with user context.

The workspace filter now properly uses the helper function to resolve workspace objects from filter values.


375-375: Confirm Clearing of Default Ordering on PublishedRun

The PublishedRun model defines a default ordering (Meta.ordering = ["-updated_at"]) in bots/models/published_run.py (around line 181). The call at widgets/workflow_search.py:375:

qs = qs.order_by()

will strip out that default ordering before any subsequent sorts. Please verify this is intentional. If you need to preserve the model’s default sort, either remove the order_by() call or explicitly apply the desired fields after clearing.

Locations to review:

  • bots/models/published_run.py (class Meta → ordering = ["-updated_at"])
  • widgets/workflow_search.py line 375 (qs = qs.order_by())

162-164: No performance issues detected in placeholder generation

I’ve reviewed get_placeholder_by_search_filters and its helper get_workspace_from_filter_value. Both perform only:

  • A cached import (Python memoizes modules after the first load)
  • A simple O(n) loop over current_user.cached_workspaces (n is typically small)
  • A dictionary lookup and string concatenations

These operations are millisecond-scale even for dozens of workspaces, so calling this on each render won’t introduce noticeable lag. No changes required.

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: 0

🧹 Nitpick comments (1)
routers/root.py (1)

742-743: Import placement should be optimized.

The import is placed inside the function, which can impact performance if called frequently. Consider moving this to the module level.

+from routers.account import explore_in_current_workspace
+
 @contextmanager
 def page_wrapper(
     request: Request,
     className="",
     search_filters: typing.Optional[SearchFilters] = None,
     show_search_bar: bool = True,
 ):
-    from routers.account import explore_in_current_workspace
-
     context = {"request": request, "block_incognito": True}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ea18713 and 1ec4503.

📒 Files selected for processing (2)
  • routers/root.py (9 hunks)
  • widgets/explore.py (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • widgets/explore.py
🧰 Additional context used
🧠 Learnings (1)
routers/root.py (1)

Learnt from: nikochiko
PR: #703
File: workspaces/widgets.py:161-166
Timestamp: 2025-06-16T11:43:04.972Z
Learning: In workspaces/widgets.py header links rendering, the gui.columns([2, 10]) layout should be maintained consistently even when no icon exists, leaving empty space in the first column for visual alignment purposes. This prioritizes consistent alignment over space optimization.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (python)
  • GitHub Check: test (3.10.12, 1.8.3)
🔇 Additional comments (18)
routers/root.py (18)

8-8: Import addition looks good.

The textwrap.dedent import is used appropriately in the new JavaScript helper functions below.


13-13: Import addition looks good.

The Query import from FastAPI is correctly used in the updated explore_page function signature.


38-38: Import addition looks good.

The get_app_route_url import is used appropriately in the new search redirect functionality.


50-51: Import additions look good.

Both imports are used correctly - render_link_in_dropdown for consistent dropdown link rendering and SearchFilters, render_search_bar for the new unified search functionality.


698-712: Search bar redirect helper function is well implemented.

The function correctly handles search query changes and redirects using the FastAPI route URL generation. The logic is sound and follows the expected pattern.


714-733: JavaScript helper functions look good.

Both mobile search show/hide functions correctly manipulate DOM classes and handle focus management. The use of dedent improves readability and the logic is sound.


736-741: Function signature enhancement looks good.

The addition of search_filters and show_search_bar parameters provides the necessary flexibility for the new search functionality while maintaining backward compatibility with defaults.


753-756: Header container styling looks good.

The position-relative and flexbox classes provide proper layout structure for the responsive header design.


757-775: Logo container structure is well organized.

The responsive logo display logic correctly shows different logos for different screen sizes using Bootstrap classes.


776-806: Mobile search implementation is comprehensive.

The conditional rendering, responsive classes, and JavaScript integration provide a solid mobile search experience. The toggle functionality and focus management are properly implemented.


807-812: Header container styling looks good.

The max-width constraint and flexbox layout provide proper structure for header elements while preventing overflow from long workspace names.


813-819: Conditional explore link rendering looks good.

The logic correctly shows the explore link when the search bar is hidden, maintaining consistent navigation options.


821-824: Header links refactoring looks good.

The use of the new render_header_link helper function provides consistent rendering and includes icon support from settings.


826-831: Saved link addition looks good.

The new "Saved" link for authenticated users provides direct access to workspace-scoped saved runs, enhancing user experience.


860-861: Responsive class change looks good.

The change from d-lg-none to d-xl-none aligns with the consistent breakpoint adjustments mentioned in the AI summary.


870-883: Dropdown link refactoring is well implemented.

The use of render_link_in_dropdown helper function provides consistent styling and behavior across all dropdown links, improving maintainability.


885-890: New header link helper function is well designed.

The function provides consistent link rendering with optional icon support and proper responsive classes. The structure and implementation are sound.


250-262: Explore_page signature change is safe
I verified there are no direct calls to explore_page—it’s only referenced by route helpers in:

  • routers/root.py
  • workspaces/widgets.py
  • routers/account.py

Since these use get_route_path/get_app_route_url and rely on the router’s dependency injection to supply SearchFilters, no further updates are needed.

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)
widgets/workflow_search.py (2)

286-317: Update usage after fixing the SortOptions.default decorator issue.

The responsive sort menu implementation is well-designed, but lines 290 and 294 reference SortOptions.default which has the decorator issue. After fixing the decorator problem, update these references accordingly.

The responsive design with icons on mobile and full labels on desktop is excellent for UX.


372-375: Update usage after fixing the SortOptions.default decorator issue.

Line 374 references SortOptions.default which has the decorator issue. After fixing the decorator problem, update this reference accordingly.

🧹 Nitpick comments (1)
widgets/workflow_search.py (1)

70-116: Consider refactoring for better readability.

The function works correctly but has complex conditional logic for determining column classes and rendering different UI components. The logic is sound but could benefit from extraction into smaller helper functions.

Consider extracting the column class determination logic:

def _get_filter_column_classes(show_workspace_filter: bool, show_sort_option: bool) -> tuple[str, str]:
    if not show_sort_option:
        return "col-12 col-md-7", ""
    elif show_workspace_filter:
        return "col-9 col-md-7", "col-3 col-md-5"
    else:
        return "col-7", "col-5"

This would make the main function logic clearer and easier to test.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ec4503 and b2a8f13.

📒 Files selected for processing (2)
  • widgets/saved_workflow.py (5 hunks)
  • widgets/workflow_search.py (9 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • widgets/saved_workflow.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test (3.10.12, 1.8.3)
🔇 Additional comments (7)
widgets/workflow_search.py (7)

60-67: LGTM!

The SearchFilters model is well-structured with appropriate field types and the __bool__ method correctly includes the new sort field for comprehensive filter state checking.


119-196: LGTM!

The updated function signature and integration with SearchFilters improves the API design. The dynamic placeholder generation enhances user experience by providing contextual search hints.


199-228: Excellent UX enhancement!

This function provides contextual search placeholders that help users understand their current search scope. The error handling for invalid workflow slugs and special handling for personal workspaces improves the user experience.


253-267: LGTM!

These helper functions provide clean abstraction for workspace filtering, handling both workspace handles and IDs appropriately. The bidirectional conversion ensures consistency across the filtering system.


341-363: LGTM!

The conditional display logic appropriately handles privacy concerns and provides relevant information based on user membership and current filters. The inline _render_run function keeps the logic contained and readable.


379-398: Excellent sorting implementation with comprehensive fallback criteria.

The sorting logic is well-designed with appropriate fallback criteria for each sort option. The FEATURED sort particularly shows thoughtful prioritization of approved examples, root workflows, and user-created content.


437-485: LGTM!

The search filter implementation is robust with proper text search tokenization and sanitization. The integration with workspace helpers and full-text search using SearchVector provides comprehensive search capabilities.

@nikochiko nikochiko force-pushed the search-sort branch 2 times, most recently from e3b88eb to 77e2272 Compare July 28, 2025 12:53
@nikochiko nikochiko mentioned this pull request Jul 28, 2025
4 tasks
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: 0

♻️ Duplicate comments (3)
widgets/workflow_search.py (3)

116-116: Update usage of SortOptions.default after fixing the decorator issue.

This code references SortOptions.default which has the decorator issue. Update based on the chosen fix approach.


379-379: Update usage of SortOptions.default after fixing the decorator issue.

This code references SortOptions.default which has the decorator issue. Update based on the chosen fix approach.


30-33: Fix the incompatible decorator combination.

The @classmethod and @property decorators cannot be combined. This will cause an AttributeError when trying to access SortOptions.default.

Choose one of these solutions:

Solution 1 (Recommended): Use a simple class method

-    @classmethod
-    @property
-    def default(cls) -> "SortOptions":
+    @classmethod
+    def default(cls) -> "SortOptions":
         return cls.FEATURED

Solution 2: Use a class attribute

-    @classmethod
-    @property
-    def default(cls) -> "SortOptions":
-        return cls.FEATURED
+    default = FEATURED  # Define after the enum values

Then update the usage in lines 116 and 379 to call SortOptions.default() (for solution 1) or access SortOptions.default (for solution 2).

🧹 Nitpick comments (1)
widgets/workflow_search.py (1)

292-306: Good abstraction for workspace filtering.

The helper functions provide clean separation of concerns for workspace filter value handling. The logic correctly supports both handle names and workspace IDs.

Consider adding a null check for safety:

def get_filter_value_from_workspace(workspace: "Workspace") -> str:
-    return (workspace.handle_id and workspace.handle.name) or str(workspace.id)
+    return (workspace.handle_id and workspace.handle and workspace.handle.name) or str(workspace.id)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8af8d75 and f47dc37.

📒 Files selected for processing (1)
  • widgets/workflow_search.py (9 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (python)
  • GitHub Check: test (3.10.12, 1.8.3)
🔇 Additional comments (6)
widgets/workflow_search.py (6)

60-67: LGTM! Clean model extension.

The addition of the sort field to SearchFilters and its inclusion in the __bool__ method is well-implemented and maintains consistency with the existing pattern.


157-235: Excellent enhancement to search bar functionality.

The addition of dynamic placeholder text via get_placeholder_by_search_filters significantly improves user experience by providing contextual search hints. The parameter handling and props management are well-implemented.


238-267: Well-designed helper function with clear logic.

The dynamic placeholder generation enhances UX by providing contextual search hints. The fallback logic, workspace handling, and local import to avoid circular dependencies are all well-implemented.


346-368: Smart conditional display logic for run counts.

The updated logic to show run counts when sorting by "Most Runs" even for non-members makes perfect sense from a UX perspective - users should see the data they're sorting by.


384-403: Comprehensive and well-designed sorting implementation.

The sorting logic is thoughtfully implemented with appropriate fallback criteria for each option. The FEATURED sorting's multi-criteria approach prioritizing approved examples and root workflows is particularly well-designed.


442-490: Good integration of workspace filtering with existing search logic.

The updated function signature and use of workspace helper functions integrates well with the existing comprehensive search implementation. The search logic remains robust with proper token sanitization and multi-field SearchVector coverage.

@devxpy devxpy closed this Jul 29, 2025
@devxpy devxpy reopened this Jul 29, 2025
…_search, use GooeyEnum for enums, tweak workspace popper button padding
@devxpy devxpy assigned nikochiko and unassigned devxpy Jul 31, 2025
@nikochiko nikochiko merged commit 1479c97 into master Jul 31, 2025
8 checks passed
@nikochiko nikochiko deleted the search-sort branch July 31, 2025 10:29
@coderabbitai coderabbitai bot mentioned this pull request Aug 12, 2025
4 tasks
@coderabbitai coderabbitai bot mentioned this pull request Sep 4, 2025
4 tasks
@coderabbitai coderabbitai bot mentioned this pull request Sep 15, 2025
4 tasks
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.

3 participants