Skip to content

feat: toggles for binary labels in report#3296

Merged
johanneskoester merged 9 commits intomainfrom
feat/report-toggle
Feb 19, 2025
Merged

feat: toggles for binary labels in report#3296
johanneskoester merged 9 commits intomainfrom
feat/report-toggle

Conversation

@johanneskoester
Copy link
Copy Markdown
Contributor

@johanneskoester johanneskoester commented Feb 16, 2025

QC

  • The PR contains a test case for the changes or the changes are already covered by an existing test case.
  • The documentation (docs/) is updated to reflect the changes or this is not necessary (e.g. if the change does neither modify the language nor the behavior or functionalities of Snakemake).

Summary by CodeRabbit

  • New Features

    • Introduced interactive toggle switches that let users dynamically filter and adjust result displays.
    • Added a new Toggle component for selecting between values using radio buttons.
    • Enhanced result display management with the ToggleViewManager and ButtonViewManager classes.
    • Integrated new JavaScript components into the report's HTML template for improved functionality.
  • Bug Fixes

    • Updated asset specifications for tailwindcss to ensure correct versioning and URL retrieval.
  • Documentation

    • Enhanced reporting documentation with recommendations for using labels and showcasing toggle switch functionality.
  • Refactor

    • Optimized the result view button behavior for a more intuitive and consistent user experience.

@johanneskoester johanneskoester added the WIP Work in progress. Not meant for merging. label Feb 16, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 16, 2025

📝 Walkthrough

Walkthrough

This pull request introduces new functionality to support dynamic toggle controls in the results reporting component. Key modifications include the addition of a new ToggleViewManager class for handling various content types, updates to the AbstractResults class for improved data processing and toggle state management, and the introduction of a new Toggle React component. Additionally, the ResultViewButton class has been refactored to utilize the new ButtonViewManager, and the main HTML template now includes scripts for the new components.

Changes

File(s) Change Summary
snakemake/.../components/abstract_results.js Added arrayKey, ToggleViewManager class, and methods for handling toggles; updated AbstractResults constructor and methods to work with new data structures.
snakemake/.../components/result_view_button.js Introduced ButtonViewManager class; refactored ResultViewButton to utilize the new manager for handling content types.
snakemake/.../components/toggle.js Introduced a new Toggle React component for selecting between two values using radio buttons.
snakemake/.../template/index.html.jinja2 Added script inclusions for toggle.js and abstract_view_manager.js.
snakemake/.../components/abstract_view_manager.js Added AbstractViewManager class with methods for handling different MIME types.
snakemake/.../components/common.js Added getResultMimeType function for retrieving MIME type based on result path.
docs/snakefiles/reporting.rst Updated documentation to include recommendations for using labels and introduced toggle switch functionality in reports.
snakemake/assets/__init__.py Updated specifications for the tailwindcss/tailwind.css asset URL and version.

Possibly related PRs


📜 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 3093ffd and f23b817.

📒 Files selected for processing (1)
  • docs/snakefiles/reporting.rst (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/snakefiles/reporting.rst
⏰ Context from checks skipped due to timeout of 90000ms (30)
  • GitHub Check: testing (10, 3.12)
  • GitHub Check: testing (10, 3.11)
  • GitHub Check: testing (9, 3.12)
  • GitHub Check: testing (9, 3.11)
  • GitHub Check: testing (8, 3.12)
  • GitHub Check: testing (8, 3.11)
  • GitHub Check: testing (7, 3.12)
  • GitHub Check: testing (7, 3.11)
  • GitHub Check: testing (6, 3.12)
  • GitHub Check: testing (6, 3.11)
  • GitHub Check: testing-windows (10)
  • GitHub Check: testing (5, 3.12)
  • GitHub Check: testing (5, 3.11)
  • GitHub Check: testing-windows (9)
  • GitHub Check: testing-windows (8)
  • GitHub Check: testing (4, 3.12)
  • GitHub Check: testing-windows (7)
  • GitHub Check: testing (4, 3.11)
  • GitHub Check: testing (3, 3.12)
  • GitHub Check: testing-windows (6)
  • GitHub Check: testing (3, 3.11)
  • GitHub Check: testing-windows (5)
  • GitHub Check: testing (2, 3.12)
  • GitHub Check: testing-windows (4)
  • GitHub Check: testing (2, 3.11)
  • GitHub Check: testing-windows (3)
  • GitHub Check: testing (1, 3.12)
  • GitHub Check: testing-windows (2)
  • GitHub Check: testing (1, 3.11)
  • GitHub Check: testing-windows (1)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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. (Beta)
  • @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.

@johanneskoester johanneskoester marked this pull request as draft February 16, 2025 21:34
Copy link
Copy Markdown
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: 3

🧹 Nitpick comments (6)
snakemake/report/html_reporter/template/components/abstract_results.js (6)

1-3: Consider renaming or documenting arrayKey for clarity
This utility function is straightforward, but calling it arrayKey may not fully convey its role in creating a unique identifier from label arrays. Consider adding a short docstring or a more descriptive name for easier comprehension.


38-53: Add a unique key for each toggle control
When mapping over toggleLabels.entries(), each returned element should have a stable key prop to avoid React’s "missing key" warnings.

return toggleLabels.entries().map(function(entry) {
    let [name, values] = entry;
    return e(
        Toggle,
+       { key: name,
          label: name,
          values: values,
          callback: function(selected) { ... }
        }
    );
});

55-62: Optimize setState usage
Assigning data from this.state.data again during every toggle may be redundant if data does not change. You can omit re-storing data or store it outside state to reduce unnecessary re-renders.

toggleCallback(name, selected) {
    let data = this.state.data;
    this.setState(prevState => {
        let toggles = new Map(prevState.toggles);
        toggles.set(name, selected);
-       return { data: data, toggles };
+       return { toggles };
    });
}

115-192: Consider optimizing the toggle detection loop for large data
Multiple filter calls on potentially large arrays can degrade performance. A single pass counting approach can be more efficient. Also consider short-circuiting if results is empty.


200-216: Add unique keys for rendered headers
When mapping over data.entryLabels to create <th> elements, each should have a key prop to avoid React warnings about missing keys.

data.entryLabels.map(function (label) {
    return e(
        "th",
+       { key: label, className: "text-left p-1 uppercase" },
        label
    )
})

218-273: Remove or guard the console.log calls
Repeated console logging in renderEntries can clutter production console output. Either remove these statements or wrap them in a development-check condition to keep logs out of production.

console.log({
-   toggleLabels,
-   entryPath,
-   entryLabels,
});
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a19a0ac and edc4285.

📒 Files selected for processing (4)
  • snakemake/report/html_reporter/template/components/abstract_results.js (4 hunks)
  • snakemake/report/html_reporter/template/components/result_view_button.js (0 hunks)
  • snakemake/report/html_reporter/template/components/toggle.js (1 hunks)
  • snakemake/report/html_reporter/template/index.html.jinja2 (1 hunks)
💤 Files with no reviewable changes (1)
  • snakemake/report/html_reporter/template/components/result_view_button.js
⏰ Context from checks skipped due to timeout of 90000ms (30)
  • GitHub Check: testing (10, 3.12)
  • GitHub Check: testing (10, 3.11)
  • GitHub Check: testing (9, 3.12)
  • GitHub Check: testing (9, 3.11)
  • GitHub Check: testing (8, 3.12)
  • GitHub Check: testing (8, 3.11)
  • GitHub Check: testing (7, 3.12)
  • GitHub Check: testing (7, 3.11)
  • GitHub Check: testing (6, 3.12)
  • GitHub Check: testing (6, 3.11)
  • GitHub Check: testing (5, 3.12)
  • GitHub Check: testing-windows (10)
  • GitHub Check: testing (5, 3.11)
  • GitHub Check: testing-windows (9)
  • GitHub Check: testing (4, 3.12)
  • GitHub Check: testing-windows (8)
  • GitHub Check: testing (4, 3.11)
  • GitHub Check: testing-windows (7)
  • GitHub Check: testing (3, 3.12)
  • GitHub Check: testing-windows (6)
  • GitHub Check: testing (3, 3.11)
  • GitHub Check: testing-windows (5)
  • GitHub Check: testing (2, 3.12)
  • GitHub Check: testing-windows (4)
  • GitHub Check: testing (2, 3.11)
  • GitHub Check: testing-windows (3)
  • GitHub Check: testing (1, 3.12)
  • GitHub Check: testing-windows (2)
  • GitHub Check: testing (1, 3.11)
  • GitHub Check: testing-windows (1)
🔇 Additional comments (4)
snakemake/report/html_reporter/template/components/abstract_results.js (3)

6-10: Ensure getData() does not introduce side effects or async calls
Initializing state from getData() within the constructor is acceptable for synchronous data. If the data is fetched asynchronously or if side effects occur, consider moving data retrieval into a React lifecycle method like componentDidMount.


64-79: Overall table rendering logic looks good
The table structure and composition are consistent. Passing data to helper methods is clear and maintainable.


194-198: isLabelled approach confirmed
This concise helper is straightforward and appears correct for checking if every result has labels.

snakemake/report/html_reporter/template/index.html.jinja2 (1)

82-82: Script inclusion for toggle component looks correct
Including components/toggle.js is consistent and ensures the Toggle is available for the report.

@johanneskoester johanneskoester marked this pull request as ready for review February 18, 2025 15:38
Copy link
Copy Markdown
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: 3

🧹 Nitpick comments (6)
snakemake/report/html_reporter/template/components/abstract_view_manager.js (2)

2-21: Remove unnecessary break statements after return.

The break statements after return are unreachable and should be removed.

Apply this diff to remove unreachable code:

     handleSelectedResult(resultPath) {
         let entry = results[resultPath];
         const mimeType = getResultMimeType(resultPath);

         switch (mimeType) {
             case "image/svg+xml":
             case "image/png":
             case "image/jpeg":
                 return this.handleImg(entry, resultPath);
-                break;
             case "text/html":
                 return this.handleHtml(entry, resultPath);
-                break;
             case "application/pdf":
                 return this.handlePdf(entry, resultPath);
-                break;
             default:
                 return this.handleDefault(entry, resultPath);
         }
     }

23-37: Make abstract methods truly abstract using static error messages.

The error messages should indicate that these are abstract methods that must be implemented by subclasses.

Apply this diff to improve error messages:

     handleImg(entry, resultPath) {
-        throw new Error("Unimplemented!");
+        throw new Error("Abstract method 'handleImg' must be implemented by subclass");
     }

     handleHtml(entry, resultPath) {
-        throw new Error("Unimplemented!");
+        throw new Error("Abstract method 'handleHtml' must be implemented by subclass");
     }

     handlePdf(entry, resultPath) {
-        throw new Error("Unimplemented!");
+        throw new Error("Abstract method 'handlePdf' must be implemented by subclass");
     }

     handleDefault(entry, resultPath) {
-        throw new Error("Unimplemented!");
+        throw new Error("Abstract method 'handleDefault' must be implemented by subclass");
     }
snakemake/report/html_reporter/template/components/result_view_button.js (1)

10-62: Reduce code duplication in handler methods.

The handler methods share similar prop creation logic with slight variations. Consider extracting common logic into a helper method.

Apply this diff to reduce duplication:

+    createViewProps(content, entry, resultPath) {
+        let app = this.app;
+        return {
+            href: "#",
+            onClick: function() {
+                app.setView({
+                    content: content,
+                    contentPath: entry.data_uri,
+                    resultPath: resultPath
+                });
+            }
+        };
+    }
+
     handleImg(entry, resultPath) {
-        let app = this.app;
-        let props = {
-            href: "#",
-            onClick: function() {
-                app.setView({
-                    content: "img",
-                    contentPath: entry.data_uri,
-                    resultPath: resultPath
-                });
-            }
-        };
+        let props = this.createViewProps("img", entry, resultPath);
         return this.renderButton(props);
     }

     handleHtml(entry, resultPath) {
-        let app = this.app;
-        let props = {
-            href: "#",
-            onClick: function() {
-                app.setView({
-                    content: "html",
-                    contentPath: entry.data_uri,
-                    resultPath: resultPath
-                });
-            }
-        };
+        let props = this.createViewProps("html", entry, resultPath);
         return this.renderButton(props);
     }

     handlePdf(entry, resultPath) {
-        let app = this.app;
-        let props = {
-            href: "#",
-            onClick: function() {
-                app.setView({
-                    content: "pdf",
-                    contentPath: entry.data_uri,
-                    resultPath: resultPath
-                });
-            }
-        };
+        let props = this.createViewProps("pdf", entry, resultPath);
         return this.renderButton(props);
     }
snakemake/report/html_reporter/template/components/toggle.js (2)

11-16: Remove console.log statement.

The console.log statement should be removed from production code.

 selectValue(selected) {
-    // swap the value
-    console.log(selected);
     this.setState({ value: selected });
     this.props.callback(selected);
 }

78-110: Remove commented out code.

The commented out render2 method should be removed as it's not being used.

snakemake/report/html_reporter/template/components/abstract_results.js (1)

92-107: Optimize state updates and improve readability.

The toggleCallback method can be optimized for better readability and performance.

 toggleCallback(name, selected) {
-    let data = this.state.data;
-    let _this = this;
-    this.setState(function (prevState) {
-        let toggles = new Map(prevState.toggles);
-        toggles.set(name, selected);
-        return { data: data, toggles };
-    }, function () {
-        if (_this.state.data.resultPathsToEntryLabels.has(_this.props.app.state.resultPath)) {
-            let toggleLabels = Array.from(data.toggleLabels.keys().map((label) => _this.state.toggles.get(label)));
-            let entryLabels = _this.state.data.resultPathsToEntryLabels.get(_this.props.app.state.resultPath);
-            let targetPath = _this.state.data.entries.get(arrayKey(entryLabels)).get(arrayKey(toggleLabels));
-            _this.toggleViewManager.handleSelectedResult(targetPath);
-        }
-    });
+    this.setState(
+        prevState => {
+            const toggles = new Map(prevState.toggles);
+            toggles.set(name, selected);
+            return { toggles };
+        },
+        () => {
+            const { data, toggles } = this.state;
+            const { resultPath } = this.props.app.state;
+            
+            if (data.resultPathsToEntryLabels.has(resultPath)) {
+                const toggleLabels = Array.from(data.toggleLabels.keys().map(label => toggles.get(label)));
+                const entryLabels = data.resultPathsToEntryLabels.get(resultPath);
+                const targetPath = data.entries.get(arrayKey(entryLabels)).get(arrayKey(toggleLabels));
+                this.toggleViewManager.handleSelectedResult(targetPath);
+            }
+        }
+    );
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between edc4285 and 032c2dd.

⛔ Files ignored due to path filters (1)
  • docs/snakefiles/images/report-toggles.png is excluded by !**/*.png
📒 Files selected for processing (8)
  • docs/snakefiles/reporting.rst (2 hunks)
  • snakemake/assets/__init__.py (1 hunks)
  • snakemake/report/html_reporter/template/components/abstract_results.js (4 hunks)
  • snakemake/report/html_reporter/template/components/abstract_view_manager.js (1 hunks)
  • snakemake/report/html_reporter/template/components/common.js (1 hunks)
  • snakemake/report/html_reporter/template/components/result_view_button.js (1 hunks)
  • snakemake/report/html_reporter/template/components/toggle.js (1 hunks)
  • snakemake/report/html_reporter/template/index.html.jinja2 (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.py`: Do not try to improve formatting. Do not suggest ...

**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of the self argument of methods.
Do not suggest type annotation of the cls argument of classmethods.
Do not suggest return type annotation if a function or method does not contain a return statement.

  • snakemake/assets/__init__.py
🔇 Additional comments (6)
snakemake/report/html_reporter/template/components/result_view_button.js (1)

73-81: LGTM! Clean React component implementation.

The ResultViewButton component follows React best practices:

  • Good separation of concerns by delegating to ButtonViewManager
  • Proper prop types validation
  • Clean and focused render method
snakemake/report/html_reporter/template/index.html.jinja2 (1)

82-83: LGTM! Proper script inclusion.

The new scripts are:

  • Added in the correct order (before dependent components)
  • Follow the same template pattern as other script includes
snakemake/report/html_reporter/template/components/toggle.js (1)

42-42: Use htmlFor instead of for attribute.

In React, the label attribute should be htmlFor instead of for.

-    {for: valueId(0), className: `${labelClasses} rounded-l`},
+    {htmlFor: valueId(0), className: `${labelClasses} rounded-l`},

-    {for: valueId(1), className: `${labelClasses} rounded-r`},
+    {htmlFor: valueId(1), className: `${labelClasses} rounded-r`},

Also applies to: 59-59

snakemake/assets/__init__.py (1)

66-66:

Details

❓ Verification inconclusive

Verify Tailwind CSS and plugin versions.

The update includes:

  • Tailwind CSS version: 3.4.16
  • Forms plugin version: 0.5.9

Let's verify these versions are stable and compatible.

Also applies to: 69-69


🌐 Web query:

What is the latest version of Tailwind CSS and its forms plugin?

💡 Result:

Tailwind CSS v4.0 is its latest major release as of February 2025[1][4]. This version introduces significant performance improvements (full builds up to 5x faster, incremental builds 100x faster), modern CSS features like cascade layers and container queries[1][4], and a shift to CSS-first configuration instead of JavaScript[3][4].

For forms styling:

  • The @tailwindcss/forms plugin’s latest npm release is v0.5.10[2].
  • In Tailwind CSS v4.x projects:
    • Plugins are now imported directly into your main CSS file using @plugin syntax[3].
    • Example usage:
      @import "tailwindcss";
      @plugin "@tailwindcss/forms";
      This replaces traditional JavaScript-based configuration[3].

Key changes impacting forms:

  • Automatic content detection removes manual template configuration[1][3]
  • Dynamic variants/data attributes allow utilities like data-checked:* without custom config[1][4]
  • form-input, form-checkbox, etc., classes remain supported via strategy: 'class'[2][8]

For new projects:

npm install tailwindcss@latest

Citations:


Tailwind CSS and Plugin Version Compatibility Check

The current CDN URL in snakemake/assets/__init__.py (lines 66 and 69) uses version placeholders that are tied to an older release—specifically, Tailwind CSS is presently set to 3.4.16 and the forms plugin to 0.5.9. However, as of February 2025, Tailwind CSS v4.0 is available and the latest release of the @tailwindcss/forms plugin is v0.5.10. Additionally, Tailwind CSS v4.0 now favors a CSS-first configuration for plugins (using @plugin imports in your CSS) over the older JavaScript configuration via URL query parameters.

Please verify whether:

  • You intend to lock the project to Tailwind CSS 3.4.16 and forms plugin 0.5.9, or if an upgrade to Tailwind CSS v4.0 (and correspondingly updating the forms plugin to 0.5.10) is desired.
  • The current CDN-based plugin configuration still meets your project requirements or if switching to the new CSS-based plugin import is needed.
snakemake/report/html_reporter/template/components/abstract_results.js (1)

5-38: LGTM! Well-structured view manager.

The ToggleViewManager class is well-organized with clear separation of concerns for different content types.

docs/snakefiles/reporting.rst (1)

99-131: LGTM! Clear and comprehensive documentation.

The documentation effectively explains:

  • The purpose and benefits of using labels
  • How to implement toggles for binary labels
  • Visual example with the toggle switch image

The changes are well-structured and provide clear guidance for users.

Comment on lines +19 to +20
function getResultMimeType(resultPath) {
return results[resultPath].mime_type
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for missing paths and mime types.

The function should handle cases where resultPath is not found in results or mime_type is undefined.

Apply this diff to add error handling:

 function getResultMimeType(resultPath) {
-    return results[resultPath].mime_type
+    if (!(resultPath in results)) {
+        throw new Error(`Result path '${resultPath}' not found`);
+    }
+    const result = results[resultPath];
+    if (!result.mime_type) {
+        throw new Error(`No mime_type found for result '${resultPath}'`);
+    }
+    return result.mime_type;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function getResultMimeType(resultPath) {
return results[resultPath].mime_type
function getResultMimeType(resultPath) {
if (!(resultPath in results)) {
throw new Error(`Result path '${resultPath}' not found`);
}
const result = results[resultPath];
if (!result.mime_type) {
throw new Error(`No mime_type found for result '${resultPath}'`);
}
return result.mime_type;
}

Comment on lines +3 to +9
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { value: this.props.values[0] };
this.selectValue = this.selectValue.bind(this);

}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add PropTypes validation and handle potential empty values.

The component should validate its props and handle cases where values array might be empty.

Add PropTypes validation:

Toggle.propTypes = {
  label: PropTypes.string.isRequired,
  values: PropTypes.arrayOf(PropTypes.string).isRequired,
  callback: PropTypes.func.isRequired,
};

Add defensive check in constructor:

 constructor(props) {
     super(props);
+    if (!props.values || props.values.length === 0) {
+      throw new Error('Toggle component requires non-empty values array');
+    }
     this.state = { value: this.props.values[0] };
     this.selectValue = this.selectValue.bind(this);
 }

Comment on lines +273 to +276
AbstractResults.propTypes = {
app: PropTypes.object.isRequired,
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Move PropTypes outside of render method.

PropTypes should be defined at the class level, not inside the render method.

-    renderEntries(data) {
-        AbstractResults.propTypes = {
-            app: PropTypes.object.isRequired,
-        };

+    static propTypes = {
+        app: PropTypes.object.isRequired,
+    };
+
+    renderEntries(data) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
AbstractResults.propTypes = {
app: PropTypes.object.isRequired,
};
class AbstractResults extends React.Component {
static propTypes = {
app: PropTypes.object.isRequired,
};
renderEntries(data) {
// ... rest of the renderEntries implementation
}
// ... other methods and component code
}

Copy link
Copy Markdown
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 (2)
snakemake/report/html_reporter/template/components/abstract_view_manager.js (2)

1-1: Enforce abstract class behavior.

Since this is an abstract class, consider adding a constructor that prevents direct instantiation:

 class AbstractViewManager {
+    constructor() {
+        if (this.constructor === AbstractViewManager) {
+            throw new Error('Abstract class "AbstractViewManager" cannot be instantiated directly.');
+        }
+    }

20-34: Add JSDoc documentation and improve error messages.

The handler methods need documentation to guide implementers and more descriptive error messages.

+    /**
+     * Handles image type results (svg, png, jpeg)
+     * @param {Object} entry - The result entry
+     * @param {string} resultPath - Path to the result
+     * @returns {void}
+     * @abstract
+     */
     handleImg(entry, resultPath) {
-        throw new Error("Unimplemented!");
+        throw new Error("AbstractViewManager.handleImg() must be implemented by subclass");
     }

+    /**
+     * Handles HTML type results
+     * @param {Object} entry - The result entry
+     * @param {string} resultPath - Path to the result
+     * @returns {void}
+     * @abstract
+     */
     handleHtml(entry, resultPath) {
-        throw new Error("Unimplemented!");
+        throw new Error("AbstractViewManager.handleHtml() must be implemented by subclass");
     }

+    /**
+     * Handles PDF type results
+     * @param {Object} entry - The result entry
+     * @param {string} resultPath - Path to the result
+     * @returns {void}
+     * @abstract
+     */
     handlePdf(entry, resultPath) {
-        throw new Error("Unimplemented!");
+        throw new Error("AbstractViewManager.handlePdf() must be implemented by subclass");
     }

+    /**
+     * Handles results with unsupported MIME types
+     * @param {Object} entry - The result entry
+     * @param {string} resultPath - Path to the result
+     * @returns {void}
+     * @abstract
+     */
     handleDefault(entry, resultPath) {
-        throw new Error("Unimplemented!");
+        throw new Error("AbstractViewManager.handleDefault() must be implemented by subclass");
     }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 032c2dd and 3093ffd.

📒 Files selected for processing (1)
  • snakemake/report/html_reporter/template/components/abstract_view_manager.js (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: testing-windows (10)
  • GitHub Check: testing-windows (9)
  • GitHub Check: testing-windows (8)
  • GitHub Check: testing-windows (7)
  • GitHub Check: testing-windows (3)

@sonarqubecloud
Copy link
Copy Markdown

@johanneskoester johanneskoester merged commit 7690998 into main Feb 19, 2025
40 checks passed
@johanneskoester johanneskoester deleted the feat/report-toggle branch February 19, 2025 15:21
johanneskoester pushed a commit that referenced this pull request Feb 27, 2025
🤖 I have created a release *beep* *boop*
---


##
[8.29.0](v8.28.0...v8.29.0)
(2025-02-27)


### Features

* provide mechanism to link between report items (snakemake.report_href,
see docs) ([#3224](#3224))
([a024e60](a024e60))
* toggles for binary labels in report
([#3296](#3296))
([7690998](7690998))


### Bug Fixes

* add missing [@conda](https://github.com/conda) annotations
([#3298](#3298))
([0b541cc](0b541cc))
* properly handle remote storage when waiting for pipes
([#3317](#3317))
([9f7e092](9f7e092))
* provide proper error messages if output file preparation (pipe, mkdir)
fails ([#3309](#3309))
([77ef176](77ef176))
* record file extension (e.g. .tsv) in between workflow cache records in
order to avoid that files of the wrong format are erroneously returned
by the cache. This will lead to some cache misses. But avoiding errors
induced by the previous behavior of ignoring file extensions when
seeking for cache records is more important.
([#3314](#3314))
([4912f00](4912f00))
* sort results lexicographically by labels in their order of appearance
([#3293](#3293))
([a19a0ac](a19a0ac))


### Documentation

* update best practices
([7270eb3](7270eb3))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
kjohnsen pushed a commit to kjohnsen/snakemake that referenced this pull request Dec 15, 2025
<!--Add a description of your PR here-->

### QC
<!-- Make sure that you can tick the boxes below. -->

* [x] The PR contains a test case for the changes or the changes are
already covered by an existing test case.
* [x] The documentation (`docs/`) is updated to reflect the changes or
this is not necessary (e.g. if the change does neither modify the
language nor the behavior or functionalities of Snakemake).


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Introduced interactive toggle switches that let users dynamically
filter and adjust result displays.
- Added a new `Toggle` component for selecting between values using
radio buttons.
- Enhanced result display management with the `ToggleViewManager` and
`ButtonViewManager` classes.
- Integrated new JavaScript components into the report's HTML template
for improved functionality.

- **Bug Fixes**
- Updated asset specifications for `tailwindcss` to ensure correct
versioning and URL retrieval.

- **Documentation**
- Enhanced reporting documentation with recommendations for using labels
and showcasing toggle switch functionality.

- **Refactor**
- Optimized the result view button behavior for a more intuitive and
consistent user experience.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
kjohnsen pushed a commit to kjohnsen/snakemake that referenced this pull request Dec 15, 2025
🤖 I have created a release *beep* *boop*
---


##
[8.29.0](snakemake/snakemake@v8.28.0...v8.29.0)
(2025-02-27)


### Features

* provide mechanism to link between report items (snakemake.report_href,
see docs) ([snakemake#3224](snakemake#3224))
([a024e60](snakemake@a024e60))
* toggles for binary labels in report
([snakemake#3296](snakemake#3296))
([7690998](snakemake@7690998))


### Bug Fixes

* add missing [@conda](https://github.com/conda) annotations
([snakemake#3298](snakemake#3298))
([0b541cc](snakemake@0b541cc))
* properly handle remote storage when waiting for pipes
([snakemake#3317](snakemake#3317))
([9f7e092](snakemake@9f7e092))
* provide proper error messages if output file preparation (pipe, mkdir)
fails ([snakemake#3309](snakemake#3309))
([77ef176](snakemake@77ef176))
* record file extension (e.g. .tsv) in between workflow cache records in
order to avoid that files of the wrong format are erroneously returned
by the cache. This will lead to some cache misses. But avoiding errors
induced by the previous behavior of ignoring file extensions when
seeking for cache records is more important.
([snakemake#3314](snakemake#3314))
([4912f00](snakemake@4912f00))
* sort results lexicographically by labels in their order of appearance
([snakemake#3293](snakemake#3293))
([a19a0ac](snakemake@a19a0ac))


### Documentation

* update best practices
([7270eb3](snakemake@7270eb3))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

WIP Work in progress. Not meant for merging.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant