Skip to content

dashboard changes #1362

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

nikhilsinhaparseable
Copy link
Contributor

@nikhilsinhaparseable nikhilsinhaparseable commented Jun 30, 2025

  1. add below fields to dashboard creation -

    • tags - list of strings
    • created - created datetime c.
    • is favorite - true/false, default false
  2. ensure title is unique

  3. add API to get all tags - GET /api/v1/dashboards/list_tags

Summary by CodeRabbit

  • New Features

    • Added endpoints to list all dashboard tags and to list dashboards filtered by a tag.
    • Dashboards now include metadata such as creation date, tags, and favorite status.
  • Improvements

    • Dashboard titles are now required to be unique.
    • Partial updates to dashboards are supported via query parameters for select fields.
    • Enhanced ownership verification with more descriptive error messages.

    1. add below fields to dashboard creation -
       a. tags - list of strings
       b. created - created datetime
       c. is favorite - true/false, default false

    2. ensure title is unique
    3. add API to get all tags - `GET /api/v1/dashboards/list_tags`
Copy link
Contributor

coderabbitai bot commented Jun 30, 2025

"""

Walkthrough

Two new GET endpoints /dashboards/list_tags and /dashboards/list_by_tag/{tag} were added with authorization requirements. The dashboard data model was extended with metadata fields (created, tags, is_favorite), and logic was enhanced for tag management, partial updates via query parameters, title uniqueness enforcement, and improved ownership verification returning dashboard data.

Changes

File(s) Change Summary
src/handlers/http/modal/server.rs Added GET routes /dashboards/list_tags and /dashboards/list_by_tag/{tag} with authorization for listing tags and dashboards by tag.
src/handlers/http/users/dashboards.rs Added list_tags and list_dashboards_by_tag async handlers; enhanced update_dashboard for partial updates via query parameters; added error variant.
src/users/dashboards.rs Extended Dashboard struct with created, tags, is_favorite; added methods for listing tags and dashboards by tag; enforced title uniqueness; preserved created on update; improved ownership checks returning dashboard data.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Server
    participant Dashboards

    Client->>Server: GET /dashboards/list_tags (with auth)
    Server->>Dashboards: list_tags()
    Dashboards-->>Server: Sorted, deduplicated tag list
    Server-->>Client: 200 OK + JSON(tag list)
Loading
sequenceDiagram
    participant Client
    participant Server
    participant Dashboards

    Client->>Server: GET /dashboards/list_by_tag/{tag} (with auth)
    Server->>Dashboards: list_dashboards_by_tag(tag)
    Dashboards-->>Server: Filtered dashboard summaries
    Server-->>Client: 200 OK + JSON(dashboard summaries)
Loading

Poem

In the warren, tags now hop and play,
Dashboards keep their titles unique each day.
Created dates and favorites, too,
All in camelCase, fresh and new!
Now list your tags with a single call—
This bunny’s code will fetch them all! 🐇✨
"""


📜 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 be97b21 and f6e625f.

📒 Files selected for processing (2)
  • src/handlers/http/users/dashboards.rs (5 hunks)
  • src/users/dashboards.rs (9 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/handlers/http/users/dashboards.rs
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:63-71
Timestamp: 2025-05-01T10:22:45.695Z
Learning: Dashboard design in Parseable follows a sharing model where any user can read (list/get) any dashboard, enabling dashboard sharing functionality, but only the dashboard author can modify (update/delete) their own dashboards.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1348
File: src/prism/home/mod.rs:366-368
Timestamp: 2025-06-15T18:18:14.590Z
Learning: In the Parseable dashboard system, dashboard_id is guaranteed to always be present (never None) because IDs are generated at dashboard creation time, and there are no pre-v1 dashboards that could lack IDs.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/users/dashboards.rs:154-165
Timestamp: 2025-05-01T12:22:42.363Z
Learning: Title validation for dashboards is performed in the `create_dashboard` HTTP handler function rather than in the `DASHBOARDS.create` method, avoiding redundant validation.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:0-0
Timestamp: 2025-05-01T10:27:56.858Z
Learning: The `add_tile()` function in `src/handlers/http/users/dashboards.rs` should use `get_dashboard_by_user(dashboard_id, &user_id)` instead of `get_dashboard(dashboard_id)` to ensure proper authorization checks when modifying a dashboard.
src/users/dashboards.rs (4)
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:0-0
Timestamp: 2025-05-01T10:27:56.858Z
Learning: The `add_tile()` function in `src/handlers/http/users/dashboards.rs` should use `get_dashboard_by_user(dashboard_id, &user_id)` instead of `get_dashboard(dashboard_id)` to ensure proper authorization checks when modifying a dashboard.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:63-71
Timestamp: 2025-05-01T10:22:45.695Z
Learning: Dashboard design in Parseable follows a sharing model where any user can read (list/get) any dashboard, enabling dashboard sharing functionality, but only the dashboard author can modify (update/delete) their own dashboards.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/users/dashboards.rs:154-165
Timestamp: 2025-05-01T12:22:42.363Z
Learning: Title validation for dashboards is performed in the `create_dashboard` HTTP handler function rather than in the `DASHBOARDS.create` method, avoiding redundant validation.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1348
File: src/prism/home/mod.rs:366-368
Timestamp: 2025-06-15T18:18:14.590Z
Learning: In the Parseable dashboard system, dashboard_id is guaranteed to always be present (never None) because IDs are generated at dashboard creation time, and there are no pre-v1 dashboards that could lack IDs.
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: Build Default x86_64-apple-darwin
  • GitHub Check: Quest Smoke and Load Tests for Standalone deployments
  • GitHub Check: Build Default x86_64-pc-windows-msvc
  • GitHub Check: Quest Smoke and Load Tests for Distributed deployments
  • GitHub Check: Build Default aarch64-apple-darwin
  • GitHub Check: Build Kafka aarch64-apple-darwin
  • GitHub Check: Build Default x86_64-unknown-linux-gnu
  • GitHub Check: Build Kafka x86_64-unknown-linux-gnu
  • GitHub Check: Build Default aarch64-unknown-linux-gnu
  • GitHub Check: coverage
🔇 Additional comments (7)
src/users/dashboards.rs (7)

55-67: LGTM: Dashboard struct enhancements look good.

The addition of created, tags, and is_favorite fields with camelCase serialization properly extends the dashboard metadata capabilities. The optional field types are appropriate for backward compatibility.


85-87: LGTM: Proper default initialization for is_favorite field.

The logic correctly initializes is_favorite to false when it's None, maintaining the expected default behavior.


106-142: LGTM: Summary serialization properly includes new fields.

The to_summary method correctly includes the new created, tags, and is_favorite fields in the serialized output, with proper camelCase naming for dashboardId and isFavorite.


237-237: LGTM: Proper timestamp initialization for new dashboards.

Setting the created timestamp to the current time when creating a new dashboard is the correct behavior.


255-260: LGTM: Proper preservation of created timestamp during updates.

The update method correctly preserves the original created timestamp from the existing dashboard while updating other metadata. This maintains the audit trail of when the dashboard was originally created.


334-361: LGTM: Well-implemented tag management methods.

Both list_tags and list_dashboards_by_tag methods are implemented correctly:

  • Proper use of read locks for performance
  • Efficient filtering and deduplication in list_tags
  • Correct tag matching logic in list_dashboards_by_tag

371-379: LGTM: Improved ownership verification with dashboard return.

Changing the return type from Result<(), DashboardError> to Result<Dashboard, DashboardError> is a good improvement that allows callers to access the dashboard data after verification, reducing the need for additional lookups.

✨ Finishing Touches
  • 📝 Generate Docstrings

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

🧹 Nitpick comments (2)
src/users/dashboards.rs (2)

85-88: Remove redundant comment.

The comment on line 87 duplicates the information already provided on line 85.

        // if is_favorite is None, set it to false, else set it to the current value
        self.is_favorite = Some(
-            self.is_favorite.unwrap_or(false), // default to false if not set
+            self.is_favorite.unwrap_or(false),
        );

336-348: Consider future optimization for tag listing.

While the implementation is correct and consistent with the current in-memory architecture, loading all dashboards to extract tags may become inefficient as the system scales. Consider maintaining a separate index of tags in the future for better performance.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b8a9bd0 and 87c3892.

📒 Files selected for processing (3)
  • src/handlers/http/modal/server.rs (1 hunks)
  • src/handlers/http/users/dashboards.rs (1 hunks)
  • src/users/dashboards.rs (9 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:63-71
Timestamp: 2025-05-01T10:22:45.695Z
Learning: Dashboard design in Parseable follows a sharing model where any user can read (list/get) any dashboard, enabling dashboard sharing functionality, but only the dashboard author can modify (update/delete) their own dashboards.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1348
File: src/prism/home/mod.rs:366-368
Timestamp: 2025-06-15T18:18:14.590Z
Learning: In the Parseable dashboard system, dashboard_id is guaranteed to always be present (never None) because IDs are generated at dashboard creation time, and there are no pre-v1 dashboards that could lack IDs.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/users/dashboards.rs:154-165
Timestamp: 2025-05-01T12:22:42.363Z
Learning: Title validation for dashboards is performed in the `create_dashboard` HTTP handler function rather than in the `DASHBOARDS.create` method, avoiding redundant validation.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:0-0
Timestamp: 2025-05-01T10:27:56.858Z
Learning: The `add_tile()` function in `src/handlers/http/users/dashboards.rs` should use `get_dashboard_by_user(dashboard_id, &user_id)` instead of `get_dashboard(dashboard_id)` to ensure proper authorization checks when modifying a dashboard.
src/handlers/http/users/dashboards.rs (2)
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:0-0
Timestamp: 2025-05-01T10:27:56.858Z
Learning: The `add_tile()` function in `src/handlers/http/users/dashboards.rs` should use `get_dashboard_by_user(dashboard_id, &user_id)` instead of `get_dashboard(dashboard_id)` to ensure proper authorization checks when modifying a dashboard.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/users/dashboards.rs:154-165
Timestamp: 2025-05-01T12:22:42.363Z
Learning: Title validation for dashboards is performed in the `create_dashboard` HTTP handler function rather than in the `DASHBOARDS.create` method, avoiding redundant validation.
src/handlers/http/modal/server.rs (3)
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:0-0
Timestamp: 2025-05-01T10:27:56.858Z
Learning: The `add_tile()` function in `src/handlers/http/users/dashboards.rs` should use `get_dashboard_by_user(dashboard_id, &user_id)` instead of `get_dashboard(dashboard_id)` to ensure proper authorization checks when modifying a dashboard.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/users/dashboards.rs:154-165
Timestamp: 2025-05-01T12:22:42.363Z
Learning: Title validation for dashboards is performed in the `create_dashboard` HTTP handler function rather than in the `DASHBOARDS.create` method, avoiding redundant validation.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:63-71
Timestamp: 2025-05-01T10:22:45.695Z
Learning: Dashboard design in Parseable follows a sharing model where any user can read (list/get) any dashboard, enabling dashboard sharing functionality, but only the dashboard author can modify (update/delete) their own dashboards.
src/users/dashboards.rs (4)
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:0-0
Timestamp: 2025-05-01T10:27:56.858Z
Learning: The `add_tile()` function in `src/handlers/http/users/dashboards.rs` should use `get_dashboard_by_user(dashboard_id, &user_id)` instead of `get_dashboard(dashboard_id)` to ensure proper authorization checks when modifying a dashboard.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:63-71
Timestamp: 2025-05-01T10:22:45.695Z
Learning: Dashboard design in Parseable follows a sharing model where any user can read (list/get) any dashboard, enabling dashboard sharing functionality, but only the dashboard author can modify (update/delete) their own dashboards.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/users/dashboards.rs:154-165
Timestamp: 2025-05-01T12:22:42.363Z
Learning: Title validation for dashboards is performed in the `create_dashboard` HTTP handler function rather than in the `DASHBOARDS.create` method, avoiding redundant validation.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1348
File: src/prism/home/mod.rs:366-368
Timestamp: 2025-06-15T18:18:14.590Z
Learning: In the Parseable dashboard system, dashboard_id is guaranteed to always be present (never None) because IDs are generated at dashboard creation time, and there are no pre-v1 dashboards that could lack IDs.
🧬 Code Graph Analysis (1)
src/handlers/http/users/dashboards.rs (1)
src/users/dashboards.rs (1)
  • list_tags (338-348)
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: Build Default x86_64-unknown-linux-gnu
  • GitHub Check: coverage
  • GitHub Check: Quest Smoke and Load Tests for Distributed deployments
  • GitHub Check: Build Default x86_64-pc-windows-msvc
  • GitHub Check: Build Default aarch64-apple-darwin
  • GitHub Check: Quest Smoke and Load Tests for Standalone deployments
  • GitHub Check: Build Default x86_64-apple-darwin
  • GitHub Check: Build Default aarch64-unknown-linux-gnu
  • GitHub Check: Build Kafka aarch64-apple-darwin
  • GitHub Check: Build Kafka x86_64-unknown-linux-gnu
🔇 Additional comments (5)
src/users/dashboards.rs (3)

211-219: LGTM! Title uniqueness check is well implemented.

The implementation correctly enforces title uniqueness while properly handling updates by excluding the current dashboard from the duplicate check.


239-239: Excellent timestamp handling!

The implementation correctly sets the created timestamp during creation and preserves it during updates, maintaining proper audit trail integrity.

Also applies to: 257-262


55-55: Verify API consumers & docs for camelCase serialization change

Adding #[serde(rename_all = "camelCase")] on the Dashboard struct in src/users/dashboards.rs changes all JSON fields from snake_case to camelCase (e.g. dashboard_iddashboardId, is_favoriteisFavorite). We didn’t find any in-repo tests or JSON fixtures expecting the old names, but downstream clients, SDKs, OpenAPI specs or README examples may still rely on snake_case. Please ensure:

  • src/users/dashboards.rs – the Dashboard struct now uses camelCase.
  • Any OpenAPI/Swagger definitions or generated clients are updated to use camelCase property names.
  • Frontend/mobile apps and SDKs that consume the dashboard API handle dashboardId, isFavorite, etc.
  • README.md examples and JSON test fixtures reflect the new naming.
  • New tests are added (or existing ones updated) to assert camelCase serialization.
src/handlers/http/users/dashboards.rs (1)

148-151: LGTM! Clean handler implementation.

The handler correctly delegates to the business logic layer and returns the appropriate response.

src/handlers/http/modal/server.rs (1)

282-288: Route properly configured with appropriate authorization.

The /list_tags endpoint is correctly added with Action::ListDashboard authorization, which aligns with the dashboard sharing model where any user can read dashboard information.

coderabbitai[bot]
coderabbitai bot previously approved these changes Jun 30, 2025
1. is_favorite=true/false -- to set dashboard to favorite
2. rename_to=<updated title> -- to update the title of the dashboard
3. tags=<comma separated tags> -- to update tags

add validation -
body and query params both cannot co-exist in PUT request
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)
src/handlers/http/users/dashboards.rs (1)

97-123: Consider optimizing the dashboard retrieval pattern.

The current implementation retrieves the existing dashboard even when performing full updates via request body. This could be optimized by only fetching the existing dashboard when query parameters are used for partial updates.

Additionally, consider adding validation to ensure the rename_to parameter respects the same uniqueness constraints as the title validation in the create function.

-    let mut existing_dashboard = DASHBOARDS
-        .get_dashboard_by_user(dashboard_id, &user_id)
-        .await
-        .ok_or(DashboardError::Metadata(
-            "Dashboard does not exist or user is not authorized",
-        ))?;
-
-    let query_map = web::Query::<HashMap<String, String>>::from_query(req.query_string())
-        .map_err(|_| DashboardError::InvalidQueryParameter)?;
-
-    // Validate: either query params OR body, not both
-    let has_query_params = !query_map.is_empty();
-    let has_body_update = dashboard.title != existing_dashboard.title || dashboard.tiles.is_some();
+    let query_map = web::Query::<HashMap<String, String>>::from_query(req.query_string())
+        .map_err(|_| DashboardError::InvalidQueryParameter)?;
+
+    let has_query_params = !query_map.is_empty();
+    
+    // Only fetch existing dashboard if we need it for partial updates
+    let existing_dashboard = if has_query_params {
+        Some(DASHBOARDS
+            .get_dashboard_by_user(dashboard_id, &user_id)
+            .await
+            .ok_or(DashboardError::Metadata(
+                "Dashboard does not exist or user is not authorized",
+            ))?)
+    } else {
+        None
+    };
+
+    // Validate: either query params OR body, not both
+    let has_body_update = has_query_params || dashboard.title.is_empty() || dashboard.tiles.is_some();
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 87c3892 and 8c235e0.

📒 Files selected for processing (2)
  • src/handlers/http/users/dashboards.rs (5 hunks)
  • src/users/dashboards.rs (9 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/users/dashboards.rs
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:63-71
Timestamp: 2025-05-01T10:22:45.695Z
Learning: Dashboard design in Parseable follows a sharing model where any user can read (list/get) any dashboard, enabling dashboard sharing functionality, but only the dashboard author can modify (update/delete) their own dashboards.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1348
File: src/prism/home/mod.rs:366-368
Timestamp: 2025-06-15T18:18:14.590Z
Learning: In the Parseable dashboard system, dashboard_id is guaranteed to always be present (never None) because IDs are generated at dashboard creation time, and there are no pre-v1 dashboards that could lack IDs.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/users/dashboards.rs:154-165
Timestamp: 2025-05-01T12:22:42.363Z
Learning: Title validation for dashboards is performed in the `create_dashboard` HTTP handler function rather than in the `DASHBOARDS.create` method, avoiding redundant validation.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:0-0
Timestamp: 2025-05-01T10:27:56.858Z
Learning: The `add_tile()` function in `src/handlers/http/users/dashboards.rs` should use `get_dashboard_by_user(dashboard_id, &user_id)` instead of `get_dashboard(dashboard_id)` to ensure proper authorization checks when modifying a dashboard.
src/handlers/http/users/dashboards.rs (3)
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:0-0
Timestamp: 2025-05-01T10:27:56.858Z
Learning: The `add_tile()` function in `src/handlers/http/users/dashboards.rs` should use `get_dashboard_by_user(dashboard_id, &user_id)` instead of `get_dashboard(dashboard_id)` to ensure proper authorization checks when modifying a dashboard.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/users/dashboards.rs:154-165
Timestamp: 2025-05-01T12:22:42.363Z
Learning: Title validation for dashboards is performed in the `create_dashboard` HTTP handler function rather than in the `DASHBOARDS.create` method, avoiding redundant validation.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:63-71
Timestamp: 2025-05-01T10:22:45.695Z
Learning: Dashboard design in Parseable follows a sharing model where any user can read (list/get) any dashboard, enabling dashboard sharing functionality, but only the dashboard author can modify (update/delete) their own dashboards.
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: Build Default aarch64-apple-darwin
  • GitHub Check: Quest Smoke and Load Tests for Standalone deployments
  • GitHub Check: Quest Smoke and Load Tests for Distributed deployments
  • GitHub Check: Build Default x86_64-unknown-linux-gnu
  • GitHub Check: Build Default aarch64-unknown-linux-gnu
  • GitHub Check: Build Default x86_64-pc-windows-msvc
  • GitHub Check: Build Default x86_64-apple-darwin
  • GitHub Check: Build Kafka x86_64-unknown-linux-gnu
  • GitHub Check: Build Kafka aarch64-apple-darwin
  • GitHub Check: coverage
🔇 Additional comments (6)
src/handlers/http/users/dashboards.rs (6)

19-19: LGTM!

The HashMap import is necessary for the new query parameter handling functionality.


77-82: Authorization approach follows established patterns.

The use of get_dashboard_by_user for authorization checks aligns with the established pattern for dashboard operations, ensuring only the dashboard author can modify their dashboards.


84-95: Robust validation prevents conflicting update approaches.

The logic to prevent simultaneous use of query parameters and request body for updates is well-implemented and prevents potential conflicts or confusion in the API behavior.


124-140: Excellent tile validation logic.

The validation for tile IDs (checking for nil values and uniqueness) is comprehensive and prevents common data integrity issues. The use of HashSet for uniqueness checking is efficient.


196-199: Simple and effective tag listing implementation.

The function correctly delegates to the DASHBOARDS service and returns the expected JSON response. Based on the dashboard sharing model, this endpoint should be accessible to all users for reading dashboard metadata.


215-216: Appropriate error handling for query parameter validation.

The new InvalidQueryParameter error variant with BAD_REQUEST status code correctly handles malformed query parameters and provides clear error responses to clients.

Also applies to: 228-228

coderabbitai[bot]
coderabbitai bot previously approved these changes Jun 30, 2025
coderabbitai[bot]
coderabbitai bot previously approved these changes Jul 1, 2025
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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3ca8f87 and 0fb2180.

📒 Files selected for processing (1)
  • src/users/dashboards.rs (9 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:63-71
Timestamp: 2025-05-01T10:22:45.695Z
Learning: Dashboard design in Parseable follows a sharing model where any user can read (list/get) any dashboard, enabling dashboard sharing functionality, but only the dashboard author can modify (update/delete) their own dashboards.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1348
File: src/prism/home/mod.rs:366-368
Timestamp: 2025-06-15T18:18:14.590Z
Learning: In the Parseable dashboard system, dashboard_id is guaranteed to always be present (never None) because IDs are generated at dashboard creation time, and there are no pre-v1 dashboards that could lack IDs.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/users/dashboards.rs:154-165
Timestamp: 2025-05-01T12:22:42.363Z
Learning: Title validation for dashboards is performed in the `create_dashboard` HTTP handler function rather than in the `DASHBOARDS.create` method, avoiding redundant validation.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:0-0
Timestamp: 2025-05-01T10:27:56.858Z
Learning: The `add_tile()` function in `src/handlers/http/users/dashboards.rs` should use `get_dashboard_by_user(dashboard_id, &user_id)` instead of `get_dashboard(dashboard_id)` to ensure proper authorization checks when modifying a dashboard.
src/users/dashboards.rs (4)
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:0-0
Timestamp: 2025-05-01T10:27:56.858Z
Learning: The `add_tile()` function in `src/handlers/http/users/dashboards.rs` should use `get_dashboard_by_user(dashboard_id, &user_id)` instead of `get_dashboard(dashboard_id)` to ensure proper authorization checks when modifying a dashboard.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/handlers/http/users/dashboards.rs:63-71
Timestamp: 2025-05-01T10:22:45.695Z
Learning: Dashboard design in Parseable follows a sharing model where any user can read (list/get) any dashboard, enabling dashboard sharing functionality, but only the dashboard author can modify (update/delete) their own dashboards.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1305
File: src/users/dashboards.rs:154-165
Timestamp: 2025-05-01T12:22:42.363Z
Learning: Title validation for dashboards is performed in the `create_dashboard` HTTP handler function rather than in the `DASHBOARDS.create` method, avoiding redundant validation.
Learnt from: nikhilsinhaparseable
PR: parseablehq/parseable#1348
File: src/prism/home/mod.rs:366-368
Timestamp: 2025-06-15T18:18:14.590Z
Learning: In the Parseable dashboard system, dashboard_id is guaranteed to always be present (never None) because IDs are generated at dashboard creation time, and there are no pre-v1 dashboards that could lack IDs.
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: coverage
  • GitHub Check: Build Default x86_64-apple-darwin
  • GitHub Check: Build Default x86_64-unknown-linux-gnu
  • GitHub Check: Build Kafka x86_64-unknown-linux-gnu
  • GitHub Check: Build Default x86_64-pc-windows-msvc
  • GitHub Check: Build Default aarch64-apple-darwin
  • GitHub Check: Build Default aarch64-unknown-linux-gnu
  • GitHub Check: Build Kafka aarch64-apple-darwin
  • GitHub Check: Quest Smoke and Load Tests for Distributed deployments
  • GitHub Check: Quest Smoke and Load Tests for Standalone deployments
🔇 Additional comments (9)
src/users/dashboards.rs (9)

55-55: LGTM: CamelCase serialization added for API consistency.

The camelCase serialization aligns with JavaScript/JSON naming conventions commonly used in web APIs.


61-64: LGTM: New metadata fields enhance dashboard functionality.

The new fields created, tags, and is_favorite provide valuable metadata tracking capabilities. The optional nature maintains backward compatibility with existing dashboards.


85-86: LGTM: Default value initialization for is_favorite field.

The logic correctly initializes is_favorite to false when unset, matching the documented default behavior.


106-111: LGTM: Summary method updated to include new metadata fields.

The new fields are properly included in the dashboard summary with appropriate camelCase naming for API consistency.

Also applies to: 127-141


122-122: LGTM: Field name updated to camelCase for consistency.

The dashboardId naming matches the camelCase serialization pattern applied to the struct.


237-237: LGTM: Created timestamp set during dashboard creation.

The created field is properly initialized to the current time when creating new dashboards.


255-257: LGTM: Improved ownership verification with timestamp preservation.

The refactored approach efficiently combines ownership verification with retrieving the existing dashboard, allowing the created timestamp to be preserved during updates.

Also applies to: 260-260


334-346: LGTM: Efficient tag aggregation implementation.

The list_tags method correctly:

  • Flattens tags from all dashboards
  • Removes duplicates with dedup()
  • Returns a sorted list
  • Handles the case where dashboards may not have tags

The implementation is efficient and follows Rust best practices.


356-356: LGTM: Enhanced ownership verification with improved error messaging.

The method now returns the Dashboard instead of just success/failure, enabling efficient data reuse. The error message is more descriptive and user-friendly compared to the previous Unauthorized variant.

This change aligns with the usage pattern in the update method where the existing dashboard data is needed.

Also applies to: 359-363

Comment on lines +209 to +217
// ensure the dashboard has unique title
let dashboards = self.0.read().await;
let has_duplicate = dashboards
.iter()
.any(|d| d.title == dashboard.title && d.dashboard_id != dashboard.dashboard_id);

if has_duplicate {
return Err(DashboardError::Metadata("Dashboard title must be unique"));
}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Potential race condition in title uniqueness validation.

The uniqueness check has a race condition where concurrent operations could both pass validation and create duplicate titles. However, this may be acceptable given the typical usage patterns of dashboard creation.

The validation logic correctly excludes the same dashboard when checking for duplicates during updates.

Consider if stricter concurrency control is needed:


🏁 Script executed:

#!/bin/bash
# Description: Check if there are other places where concurrent dashboard operations might conflict
# Expected: Find patterns of concurrent dashboard access that might need synchronization

rg -A 5 -B 5 "dashboards.*write.*await|write.*await.*dashboards" --type rust

Length of output: 707


Hold write lock during title‐uniqueness check and insertion

Currently, in src/users/dashboards.rs (around lines 209–217), the code does:

// ensure the dashboard has unique title
let dashboards = self.0.read().await;
let has_duplicate = dashboards
    .iter()
    .any(|d| d.title == dashboard.title && d.dashboard_id != dashboard.dashboard_id);

if has_duplicate {
    return Err(DashboardError::Metadata("Dashboard title must be unique"));
}

// …later…
let mut dashboards = self.0.write().await;
dashboards.retain(|d| d.dashboard_id != dashboard.dashboard_id);
dashboards.push(dashboard.clone());

Between the read lock and the write lock, another concurrent create/update can slip in, leading to duplicate titles. To eliminate this window:

  • Acquire the write lock first, then do both the duplicate check and the insertion under that guard.
  • Example diff:
- // ensure the dashboard has unique title
- let dashboards = self.0.read().await;
- let has_duplicate = dashboards
-     .iter()
-     .any(|d| d.title == dashboard.title && d.dashboard_id != dashboard.dashboard_id);
+ // atomically check and insert under write lock
+ let mut dashboards = self.0.write().await;
+ let has_duplicate = dashboards
+     .iter()
+     .any(|d| d.title == dashboard.title && d.dashboard_id != dashboard.dashboard_id);

  if has_duplicate {
      return Err(DashboardError::Metadata("Dashboard title must be unique"));
  }

- // …later under a separate write lock…
- let mut dashboards = self.0.write().await;
- dashboards.retain(|d| d.dashboard_id != dashboard.dashboard_id);
- dashboards.push(dashboard.clone());
+ // now that we've validated under the same lock:
+ dashboards.retain(|d| d.dashboard_id != dashboard.dashboard_id);
+ dashboards.push(dashboard.clone());

Apply this pattern to both the create and update code paths so that checking for duplicates and modifying the collection is a single atomic operation.

🤖 Prompt for AI Agents
In src/users/dashboards.rs around lines 209 to 217, the uniqueness check for
dashboard titles is done under a read lock, but the insertion happens later
under a write lock, allowing a race condition. To fix this, acquire the write
lock before checking for duplicates and perform both the duplicate check and the
insertion while holding the write lock, ensuring atomicity and preventing
concurrent modifications from causing duplicate titles.

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.

1 participant