Skip to content
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

[WEB-2500] feat: Product updates modal (What's new in Plane) #5690

Draft
wants to merge 7 commits into
base: preview
Choose a base branch
from

Conversation

prateekshourya29
Copy link
Collaborator

@prateekshourya29 prateekshourya29 commented Sep 24, 2024

Media

image

Issue link - WEB-2500

Summary by CodeRabbit

  • New Features

    • Introduced a new endpoint for accessing instance changelogs.
    • Added a new environment variable INSTANCE_CHANGELOG_URL for configuration.
    • Implemented a ProductUpdatesHeader component displaying the current version and updates.
    • Created a ProductUpdatesModal for viewing product updates.
    • Added a ProductUpdatesFooter with links to documentation and support.
    • Enhanced the SidebarHelpSection for improved user interaction with updates.
  • Bug Fixes

    • Removed outdated components related to product updates to streamline the user interface.
  • Documentation

    • Updated components to improve accessibility and user experience.

Copy link
Contributor

coderabbitai bot commented Sep 24, 2024

Walkthrough

The changes introduce a new environment variable INSTANCE_CHANGELOG_URL across multiple Dockerfiles and settings, enabling the application to access changelog data. A new endpoint, ChangeLogEndpoint, is added to handle HTTP GET requests for fetching changelog information. Additionally, several components related to product updates are restructured, including the introduction of a ProductUpdatesModal and a ProductUpdatesHeader, while some older components are removed. The modifications enhance the application's ability to display changelog data and improve the organization of related components.

Changes

File Path Change Summary
apiserver/Dockerfile.api, apiserver/Dockerfile.dev Added new environment variable INSTANCE_CHANGELOG_URL set to a specific URL.
apiserver/plane/license/api/views/__init__.py Introduced import for ChangeLogEndpoint to expand available endpoints.
apiserver/plane/license/api/views/changelog.py Added ChangeLogEndpoint class to handle GET requests for changelog data.
apiserver/plane/license/api/views/instance.py Added instance_changelog_url key to the response data dictionary.
apiserver/plane/license/urls.py Added new URL path changelog/ associated with ChangeLogEndpoint.
apiserver/plane/settings/common.py Added new environment variable INSTANCE_CHANGELOG_URL to settings, defaulting to an empty string.
web/app/profile/page.tsx Activated import for FileService.
web/ce/components/global/index.ts Removed exports for product-updates and product-updates-modal, added product-updates-header.
web/ce/components/global/product-updates-header.tsx Introduced ProductUpdatesHeader component to display updates header.
web/ce/components/global/product-updates-modal.tsx Removed ProductUpdatesModal component.
web/ce/components/global/product-updates.tsx Removed ProductUpdates component and its associated prop type.
web/core/components/common/index.ts Removed export for product-updates-modal.
web/core/components/common/product-updates-modal.tsx Removed ProductUpdatesModal component.
web/core/components/global/index.ts Exported all entities from the product-updates module.
web/core/components/global/product-updates/footer.tsx Introduced ProductUpdatesFooter component for footer links.
web/core/components/global/product-updates/index.ts Exported all entities from modal and footer modules.
web/core/components/global/product-updates/modal.tsx Introduced ProductUpdatesModal component for displaying product updates in a modal.
web/core/components/workspace/sidebar/help-section.tsx Updated to replace ProductUpdates component with a button to trigger ProductUpdatesModal.
web/core/services/instance.service.ts Added getInstanceChangeLog method to retrieve changelog data from the API.

Possibly related PRs

Suggested labels

✨feature, 🌐frontend, 🛠️refactor

Suggested reviewers

  • sriramveeraghanta
  • SatishGandham

🐇 In the code where changes hop,
A new URL, we can't stop!
Changelogs now have a place,
In modals, they find their space.
With headers bright and updates clear,
Our app's new look will bring good cheer! 🎉


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

Outside diff range and nitpick comments (17)
web/core/components/global/index.ts (1)

1-1: LGTM! Consider named exports for better maintainability.

The export statement aligns with the PR objectives by making the product updates functionality available to other parts of the application. This change effectively introduces the new feature for the product updates modal.

While the current implementation works, consider using named exports instead of a wildcard export for better maintainability and clarity. This approach allows for better tracking of which specific entities are being used elsewhere in the codebase and can prevent potential naming conflicts.

Example of named exports:

export { ProductUpdatesModal, useProductUpdates } from "./product-updates";

This suggestion is optional and depends on your team's coding standards and preferences.

web/core/components/global/product-updates/index.ts (1)

1-2: LGTM! Consider adding a brief comment.

The export statements look good and align with the PR objective of implementing a product updates modal. This index file will make it easier to import the modal and footer components related to product updates in other parts of the application.

Consider adding a brief comment at the top of the file to describe its purpose:

// Index file for product updates components
export * from "./modal";
export * from "./footer";

This comment would provide quick context for developers who might work on this file in the future.

web/core/services/instance.service.ts (1)

29-35: LGTM: New method implemented correctly with a minor suggestion.

The getInstanceChangeLog method is well-implemented and consistent with the existing code style and error handling pattern. It aligns with the PR objectives of implementing a feature for product updates.

Consider enhancing the error handling to provide more context:

 async getInstanceChangeLog(): Promise<TPage> {
   return this.get("/api/instances/changelog/")
     .then((response) => response.data)
     .catch((error) => {
-      throw error;
+      throw new Error(`Failed to fetch instance changelog: ${error.message}`);
     });
 }

This change would make debugging easier by providing more specific error information.

web/ce/components/global/product-updates-header.tsx (2)

1-7: Consider reordering imports for consistency.

To improve code organization and address the static analysis hint, consider reordering the imports. Place the package.json import after the image import.

Here's the suggested order:

import { observer } from "mobx-react";
import Image from "next/image";
// assets
import PlaneLogo from "@/public/plane-logos/blue-without-text.png";
import packageJson from "package.json";
// helpers
import { cn } from "@/helpers/common.helper";
Tools
GitHub Check: lint-web

[failure] 3-3:
package.json import should occur after import of @/public/plane-logos/blue-without-text.png


9-25: Approve implementation with a minor accessibility suggestion.

The component is well-structured, uses appropriate React and Next.js features, and implements a responsive design. Good job on using the observer wrapper for reactive updates and dynamically displaying the version number.

For improved accessibility, consider adding an aria-label to the outer div to describe the purpose of this section.

Here's a suggested modification for line 10:

<div className="flex gap-2 mx-6 my-4 items-center justify-between flex-shrink-0" aria-label="Product updates header">
apiserver/plane/license/urls.py (1)

23-27: LGTM: New URL pattern is correctly implemented.

The new URL pattern for the changelog feature has been properly added and follows the existing structure in the file. The path and naming are appropriate and consistent with other patterns.

For consistency with other URL patterns in this file, consider adding a trailing comma after the closing parenthesis of name="instance-changelog",. This is a minor style suggestion and doesn't affect functionality.

 path(
     "changelog/",
     ChangeLogEndpoint.as_view(),
-    name="instance-changelog",
+    name="instance-changelog",
 ),
web/core/components/global/product-updates/footer.tsx (4)

1-7: LGTM! Consider grouping imports for better organization.

The imports are appropriate for the component's functionality. The use of Next.js Image component is good for optimized image loading, and the custom UI utility and helper function promote code reuse.

Consider grouping the imports for better organization:

import Image from "next/image";

// ui
import { getButtonStyling } from "@plane/ui";

// helpers
import { cn } from "@/helpers/common.helper";

// assets
import PlaneLogo from "@/public/plane-logos/blue-without-text.png";

9-10: LGTM! Consider adding ARIA roles for improved accessibility.

The component structure is clean and follows React best practices. The use of Tailwind CSS classes provides a consistent styling approach.

Consider adding ARIA roles to improve accessibility:

-  <div className="flex items-center justify-between flex-shrink-0 gap-4 m-6 mb-4">
+  <div className="flex items-center justify-between flex-shrink-0 gap-4 m-6 mb-4" role="contentinfo">

11-49: LGTM! Consider adding security attributes and improving accessibility for links.

The links section is well-structured and provides useful resources for users. The use of SVG circles as separators is a nice visual touch.

Consider the following improvements:

  1. Add rel="noopener noreferrer" to links with target="_blank" for security:
-        target="_blank"
+        target="_blank" rel="noopener noreferrer"
  1. Improve accessibility by adding aria-label to the SVG separators:
-      <svg viewBox="0 0 2 2" className="h-0.5 w-0.5 fill-current">
+      <svg viewBox="0 0 2 2" className="h-0.5 w-0.5 fill-current" aria-label="separator">
  1. Consider using a semantic list structure for better accessibility:
<nav aria-label="Footer links">
  <ul className="flex items-center gap-2">
    <li>
      <a href="https://go.plane.so/p-docs" target="_blank" rel="noopener noreferrer" className="text-sm text-custom-text-200 hover:text-custom-text-100 hover:underline underline-offset-1 outline-none">
        Docs
      </a>
    </li>
    <li aria-hidden="true">
      <svg viewBox="0 0 2 2" className="h-0.5 w-0.5 fill-current" aria-label="separator">
        <circle cx={1} cy={1} r={1} />
      </svg>
    </li>
    {/* Repeat for other links */}
  </ul>
</nav>

50-61: LGTM! Consider adding alt text and improving button accessibility.

The "Powered by Plane Pages" button is well-implemented, using a custom styling utility for consistency and the Next.js Image component for performance.

Consider the following improvements:

  1. Add a more descriptive alt text for the logo image:
-      <Image src={PlaneLogo} alt="Plane" width={12} height={12} />
+      <Image src={PlaneLogo} alt="Plane logo" width={12} height={12} />
  1. Add rel="noopener noreferrer" for security:
-      target="_blank"
+      target="_blank" rel="noopener noreferrer"
  1. Improve accessibility by adding an aria-label to the anchor tag:
       className={cn(
         getButtonStyling("accent-primary", "sm"),
         "flex gap-1.5 items-center text-center font-medium hover:underline underline-offset-2 outline-none"
       )}
+      aria-label="Visit Plane Pages website"
     >
web/core/components/global/product-updates/modal.tsx (2)

23-28: LGTM with a minor suggestion: Component declaration and hooks usage are well-implemented.

The component is correctly defined as a functional component, wrapped with MobX's observer HOC for reactive updates. The use of useRef for the editor reference and useSWR for data fetching are good practices.

Consider destructuring the props in the function parameters for cleaner code:

-export const ProductUpdatesModal: FC<ProductUpdatesModalProps> = observer((props) => {
-  const { isOpen, handleClose } = props;
+export const ProductUpdatesModal: FC<ProductUpdatesModalProps> = observer(({ isOpen, handleClose }) => {

30-76: LGTM with a minor suggestion: Component structure and conditional rendering are well-implemented.

The component's structure is well-organized, using modular components and handling different states appropriately. The conditional rendering for loading and error states enhances the user experience.

Consider adding an aria-label to the modal for better accessibility:

-<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXL}>
+<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXL} aria-label="Product Updates">
web/core/components/workspace/sidebar/help-section.tsx (2)

Line range hint 32-32: LGTM: New state and modal for product updates

The introduction of isChangeLogOpen state and the ProductUpdatesModal component is well-implemented. The modal is correctly placed and its props are properly set.

For consistency, consider renaming isChangeLogOpen to isProductUpdatesModalOpen to match the component name and its purpose more closely.

-const [isChangeLogOpen, setIsChangeLogOpen] = useState(false);
+const [isProductUpdatesModalOpen, setIsProductUpdatesModalOpen] = useState(false);

-<ProductUpdatesModal isOpen={isChangeLogOpen} handleClose={() => setIsChangeLogOpen(false)} />
+<ProductUpdatesModal isOpen={isProductUpdatesModalOpen} handleClose={() => setIsProductUpdatesModalOpen(false)} />

Also applies to: 41-41


119-127: LGTM: New menu item for "What's new" feature

The addition of the "What's new" button as a CustomMenu.MenuItem is well-implemented. It correctly triggers the product updates modal when clicked.

To improve accessibility, consider adding an aria-label to the button.

 <button
   type="button"
   onClick={() => setIsChangeLogOpen(true)}
-  className="flex w-full items-center justify-start text-xs hover:bg-custom-background-80"
+  className="flex w-full items-center justify-start text-xs hover:bg-custom-background-80"
+  aria-label="Open product updates"
 >
   <span className="text-xs">What&apos;s new</span>
 </button>
apiserver/plane/license/api/views/instance.py (2)

180-181: LGTM! Consider adding a fallback value for INSTANCE_CHANGELOG_URL.

The addition of instance_changelog_url to the response data is consistent with the existing code structure and aligns with the PR objective of implementing a "What's new" feature. Good job!

Consider adding a fallback value for settings.INSTANCE_CHANGELOG_URL in case it's not defined in the settings. This would make the code more robust:

-        data["instance_changelog_url"] = settings.INSTANCE_CHANGELOG_URL
+        data["instance_changelog_url"] = getattr(settings, 'INSTANCE_CHANGELOG_URL', '')

This ensures that even if INSTANCE_CHANGELOG_URL is not defined in the settings, the code won't raise an AttributeError.


Line range hint 1-181: Overall, the change is well-integrated. Consider adding a comment for clarity.

The addition of instance_changelog_url to the response data is minimal and doesn't affect the overall structure or logic of the file. It enhances the API response with information needed for the "What's new" feature, which aligns well with the PR objectives.

Consider adding a brief comment above the new line to explain its purpose:

+        # Add changelog URL for the "What's new" feature
         data["instance_changelog_url"] = settings.INSTANCE_CHANGELOG_URL

This would improve code readability and make the purpose of this addition clear to other developers.

apiserver/plane/settings/common.py (1)

362-364: LGTM! Consider adding a comment for consistency.

The addition of INSTANCE_CHANGELOG_URL is well-implemented and aligns with the PR objectives. It follows the existing pattern for environment variables in this file.

For consistency with other similar configurations in this file, consider adding a brief comment explaining the purpose of this variable. For example:

# Instance Changelog URL
INSTANCE_CHANGELOG_URL = os.environ.get("INSTANCE_CHANGELOG_URL", "")

This will help maintain the documentation standard throughout the configuration file.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 117afdb and 2b0f835.

Files selected for processing (20)
  • apiserver/Dockerfile.api (1 hunks)
  • apiserver/Dockerfile.dev (1 hunks)
  • apiserver/plane/license/api/views/init.py (1 hunks)
  • apiserver/plane/license/api/views/changelog.py (1 hunks)
  • apiserver/plane/license/api/views/instance.py (1 hunks)
  • apiserver/plane/license/urls.py (2 hunks)
  • apiserver/plane/settings/common.py (1 hunks)
  • web/app/profile/page.tsx (1 hunks)
  • web/ce/components/global/index.ts (1 hunks)
  • web/ce/components/global/product-updates-header.tsx (1 hunks)
  • web/ce/components/global/product-updates-modal.tsx (0 hunks)
  • web/ce/components/global/product-updates.tsx (0 hunks)
  • web/core/components/common/index.ts (0 hunks)
  • web/core/components/common/product-updates-modal.tsx (0 hunks)
  • web/core/components/global/index.ts (1 hunks)
  • web/core/components/global/product-updates/footer.tsx (1 hunks)
  • web/core/components/global/product-updates/index.ts (1 hunks)
  • web/core/components/global/product-updates/modal.tsx (1 hunks)
  • web/core/components/workspace/sidebar/help-section.tsx (2 hunks)
  • web/core/services/instance.service.ts (2 hunks)
Files not reviewed due to no reviewable changes (4)
  • web/ce/components/global/product-updates-modal.tsx
  • web/ce/components/global/product-updates.tsx
  • web/core/components/common/index.ts
  • web/core/components/common/product-updates-modal.tsx
Additional context used
Ruff
apiserver/plane/license/api/views/__init__.py

22-22: .changelog.ChangeLogEndpoint imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)

GitHub Check: lint-web
web/ce/components/global/product-updates-header.tsx

[failure] 3-3:
package.json import should occur after import of @/public/plane-logos/blue-without-text.png

Additional comments not posted (17)
web/ce/components/global/index.ts (1)

1-2: LGTM! Component exports updated.

The changes look good and align with the PR objectives. The new export for product-updates-header has been added, which seems to be part of the new product updates modal feature.

However, please note that the exports for product-updates and product-updates-modal have been removed. Ensure that this doesn't break any existing imports in other parts of the codebase.

To verify that no imports are broken due to the removed exports, run the following script:

Also, consider updating the PR description to mention the component restructuring (removal of product-updates and product-updates-modal, addition of product-updates-header) for better clarity on the changes made.

apiserver/plane/license/api/views/__init__.py (1)

22-22: ⚠️ Potential issue

Address the unused import of ChangeLogEndpoint

The newly added import of ChangeLogEndpoint is currently flagged as unused by the static analysis tool. This could lead to potential issues or confusion in the future.

Consider one of the following actions:

  1. If ChangeLogEndpoint is intended to be used elsewhere in the codebase, ensure it's properly utilized or re-exported in this init.py file.
  2. If it's meant to be available at the package level, add it to the __all__ list (if one exists) or re-export it explicitly.
  3. If the import is premature and not yet needed, consider removing it until it's actually used to avoid confusion.

To resolve this, you could either remove the import if it's not needed yet:

-from .changelog import ChangeLogEndpoint

Or, if it should be available at the package level, re-export it:

from .changelog import ChangeLogEndpoint
+__all__ = [..., 'ChangeLogEndpoint']  # Add to existing __all__ or create one if it doesn't exist

Please clarify the intended use of ChangeLogEndpoint and update the code accordingly.

To help verify the usage of ChangeLogEndpoint in the codebase, you can run the following script:

This script will help determine if ChangeLogEndpoint is used elsewhere in the codebase or if it's re-exported in the init.py file.

Tools
Ruff

22-22: .changelog.ChangeLogEndpoint imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)

web/core/services/instance.service.ts (2)

2-2: LGTM: Import statement updated correctly.

The import statement has been properly updated to include the TPage type, which is used in the new getInstanceChangeLog method. This change is consistent with the new functionality being added.


2-2: Summary: Changes align well with PR objectives.

The modifications to this file, including the new getInstanceChangeLog method and the updated import statement, are well-implemented and consistent with the existing codebase. These changes directly support the PR objective of implementing a feature for product updates in the Plane application.

The new method provides a way to fetch changelog information, which can be used to populate the "What's new in Plane" modal mentioned in the PR summary. This implementation forms a crucial backend service component for the feature.

Also applies to: 29-35

apiserver/plane/license/api/views/changelog.py (3)

1-13: LGTM: Imports are well-organized and appropriate.

The imports are correctly grouped, separated by comments, and all seem necessary for the functionality of this file. This organization improves readability and maintainability.


16-19: Verify security implications of AllowAny permission.

The ChangeLogEndpoint is currently accessible to all users due to the AllowAny permission setting. While this may be intentional, it's important to ensure that the changelog doesn't contain any sensitive information that should be restricted to authenticated users or specific user roles.

Please confirm if this level of access is appropriate for the changelog content. If the changelog contains any sensitive information, consider implementing appropriate authentication and authorization measures.


1-35: Overall assessment: Good implementation with room for improvement.

The ChangeLogEndpoint class provides a solid foundation for fetching and serving changelog data. The code is well-structured and follows Django REST framework conventions. However, there are a few areas where it can be improved:

  1. Consider the security implications of using AllowAny permission.
  2. Enhance error handling and logging in the fetch_change_logs method.
  3. Improve error handling and status code usage in the get method.
  4. Consider using ImproperlyConfigured exception for missing settings.

Implementing these suggestions will result in more robust, maintainable, and easier to debug code. Great job on the initial implementation!

apiserver/plane/license/urls.py (2)

14-14: LGTM: Import statement addition is correct.

The ChangeLogEndpoint import has been properly added to the existing list of view imports. It follows the established naming convention and is placed appropriately.


Line range hint 1-78: Summary: Changes align well with PR objectives.

The additions to this file successfully implement the URL routing for the new changelog feature, which aligns with the PR objective of introducing a product updates modal. The changes are minimal, focused, and consistent with the existing code structure and conventions.

Key points:

  1. A new ChangeLogEndpoint has been imported.
  2. A new URL pattern for "changelog/" has been added, using the ChangeLogEndpoint.

These changes provide the necessary backend routing to support the new "What's new in Plane" feature described in the PR objectives.

web/core/components/global/product-updates/footer.tsx (1)

1-62: Overall, the implementation looks good with room for minor improvements.

The ProductUpdatesFooter component is well-structured and follows React best practices. It effectively renders a footer section with useful links and a call-to-action button for Plane Pages. The use of Tailwind CSS for styling and custom utility functions promotes consistency.

To further enhance the component:

  1. Group imports for better organization.
  2. Improve accessibility by adding ARIA roles, labels, and using semantic HTML structure.
  3. Enhance security for external links.
  4. Provide more descriptive alt text for images.

These changes will make the component more robust, accessible, and maintainable.

web/core/components/global/product-updates/modal.tsx (2)

1-16: LGTM: Imports and service initialization look good.

The imports cover all necessary dependencies for the component's functionality. Creating the InstanceService instance outside the component is a good practice to avoid unnecessary recreations.


18-21: LGTM: Props type definition is clear and appropriate.

The ProductUpdatesModalProps type is well-defined with isOpen and handleClose properties, which align with the component's functionality. This type definition enhances code readability and type safety.

web/core/components/workspace/sidebar/help-section.tsx (3)

9-9: LGTM: New import for ProductUpdatesModal

The import for ProductUpdatesModal is correctly placed and appropriately sourced from the global components. This is suitable for a feature that might be used across different parts of the application.


Line range hint 1-165: Summary: Successfully implemented product updates modal

The changes in this file successfully implement the new feature for displaying product updates, as outlined in the PR objectives. The "What's new" button has been added to the help section sidebar, and it triggers a modal to show the latest product updates.

Key points:

  1. The ProductUpdatesModal component is properly imported and integrated.
  2. State management for the modal's visibility is implemented correctly.
  3. The UI changes are minimal and non-disruptive to the existing sidebar structure.

These changes align well with the PR's goal of enhancing user experience by informing users about recent updates in the Plane application through a dedicated modal interface.


16-16: Verify the new import path for PlaneVersionNumber

The import for PlaneVersionNumber has been moved to a new location. While this change appears to be part of a component reorganization, it's important to ensure that the new import path is correct and consistent with the project's structure.

To verify the correctness of the new import path, please run the following command:

web/app/profile/page.tsx (2)

38-38: LGTM: FileService import uncommented

The uncommented import of FileService is necessary for the component's functionality, particularly for handling file-related operations such as deleting user avatars. This change aligns with the component's requirements and doesn't introduce any conflicts or issues.


38-38: Minimal impact: FileService import enables existing functionality

Uncommenting the FileService import doesn't introduce new functionality but enables the existing handleDelete function to work correctly. This change has minimal impact on the overall structure and behavior of the component, ensuring that file-related operations (such as deleting user avatars) function as intended.

@@ -4,6 +4,7 @@ FROM python:3.12.5-alpine AS backend
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
ENV INSTANCE_CHANGELOG_URL https://api.plane.so/api/public/anchor/8e1c2e4c7bc5493eb7731be3862f6960/pages/
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Hardcoded INSTANCE_CHANGELOG_URL detected in Dockerfiles

The INSTANCE_CHANGELOG_URL environment variable is hardcoded in the following Dockerfiles, which may pose security risks and reduce flexibility across different environments:

  • apiserver/Dockerfile.dev
  • apiserver/Dockerfile.api

Recommendations:

  1. Replace the hardcoded URL with environment variable placeholders to allow configuration at runtime:
    ENV INSTANCE_CHANGELOG_URL ${INSTANCE_CHANGELOG_URL}
  2. Store the actual URL in environment-specific configuration files or secure storage solutions such as Kubernetes Secrets or CI/CD pipeline variables.
  3. Ensure that sensitive tokens or identifiers within URLs are managed securely and are not exposed in the codebase.
Analysis chain

Approve with suggestions: Consider security and flexibility for INSTANCE_CHANGELOG_URL

The addition of the INSTANCE_CHANGELOG_URL environment variable aligns well with the PR objectives for implementing the "What's new in Plane" feature. However, there are some considerations to improve security and flexibility:

  1. Instead of hardcoding the actual URL in the Dockerfile, consider using a placeholder value:

    ENV INSTANCE_CHANGELOG_URL ${INSTANCE_CHANGELOG_URL:-https://api.example.com/changelog}

    This allows for easy overriding of the URL at runtime or through environment-specific configurations.

  2. Move the actual URL setting to a more secure and flexible method, such as:

    • Environment-specific .env files
    • Kubernetes ConfigMaps or Secrets
    • CI/CD pipeline variables
  3. Please verify:

    • Is this URL sensitive? The long alphanumeric string might be a token or identifier.
    • Does this URL change across different environments (dev, staging, production)?

These changes will enhance security and make the configuration more adaptable to different deployment scenarios.

To ensure this URL isn't used elsewhere in the codebase, run:

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for hardcoded instances of the changelog URL
rg --type-not dockerfile "https://api.plane.so/api/public/anchor/8e1c2e4c7bc5493eb7731be3862f6960/pages/"

Length of output: 140


Script:

#!/bin/bash
# Search for hardcoded instances of the changelog URL excluding Dockerfiles
rg --ignore-file Dockerfile "https://api.plane.so/api/public/anchor/8e1c2e4c7bc5493eb7731be3862f6960/pages/"

Length of output: 421

Comment on lines +21 to +24
def fetch_change_logs(self):
response = requests.get(settings.INSTANCE_CHANGELOG_URL)
response.raise_for_status()
return response.json()
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling and logging to fetch_change_logs method.

While the method correctly raises an exception for HTTP errors, it lacks specific error handling and logging. This could make debugging issues more difficult in production.

Consider adding try-except blocks to handle potential exceptions and log errors. Here's a suggested implementation:

import logging

logger = logging.getLogger(__name__)

def fetch_change_logs(self):
    try:
        response = requests.get(settings.INSTANCE_CHANGELOG_URL)
        response.raise_for_status()
        return response.json()
    except requests.RequestException as e:
        logger.error(f"Error fetching changelog: {str(e)}")
        raise

This change will log any errors that occur during the request, making it easier to diagnose issues in production.

Comment on lines +26 to +35
def get(self, request):
# Fetch the changelog
if settings.INSTANCE_CHANGELOG_URL:
data = self.fetch_change_logs()
return Response(data, status=status.HTTP_200_OK)
else:
return Response(
{"error": "could not fetch changelog please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling and status codes in get method.

The current implementation has a few areas that could be improved:

  1. The error message when INSTANCE_CHANGELOG_URL is not set could be more specific.
  2. Returning HTTP 400 (Bad Request) when the URL is not set might not be the most appropriate status code.
  3. There's no error handling for potential exceptions from fetch_change_logs.

Consider the following improvements:

from django.core.exceptions import ImproperlyConfigured

def get(self, request):
    if not settings.INSTANCE_CHANGELOG_URL:
        raise ImproperlyConfigured("INSTANCE_CHANGELOG_URL is not set in settings.")
    
    try:
        data = self.fetch_change_logs()
        return Response(data, status=status.HTTP_200_OK)
    except requests.RequestException as e:
        return Response(
            {"error": f"Failed to fetch changelog: {str(e)}"},
            status=status.HTTP_503_SERVICE_UNAVAILABLE
        )

This implementation:

  1. Raises an ImproperlyConfigured exception if the URL is not set, which is more appropriate for configuration issues.
  2. Handles potential exceptions from fetch_change_logs.
  3. Returns a more appropriate HTTP 503 (Service Unavailable) status when the changelog fetch fails.

@@ -4,6 +4,7 @@ FROM python:3.12.5-alpine AS backend
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
ENV INSTANCE_CHANGELOG_URL https://api.plane.so/api/public/anchor/8e1c2e4c7bc5493eb7731be3862f6960/pages/
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

⚠️ Potential issue

Hardcoding INSTANCE_CHANGELOG_URL May Expose Sensitive Information

The environment variable INSTANCE_CHANGELOG_URL is currently hardcoded in the Dockerfile with a URL containing an identifier (8e1c2e4c7bc5493eb7731be3862f6960) that appears to be sensitive. To enhance security and flexibility, consider the following changes:

  • Use a Placeholder for the URL: Replace the hardcoded URL with a placeholder in the Dockerfile.
  • Inject the Actual URL at Runtime: Set the real URL through environment variables during container deployment or runtime configuration.

Suggested Change:

- ENV INSTANCE_CHANGELOG_URL https://api.plane.so/api/public/anchor/8e1c2e4c7bc5493eb7731be3862f6960/pages/
+ ENV INSTANCE_CHANGELOG_URL ${INSTANCE_CHANGELOG_URL:-https://api.plane.so/api/public/anchor/PLACEHOLDER/pages/}

Benefits:

  1. Security: Prevents exposure of sensitive identifiers in the codebase.
  2. Flexibility: Allows different environments (development, staging, production) to use unique URLs without modifying the Dockerfile.
  3. Maintainability: Simplifies updates to the URL without needing to rebuild the Docker image.
Analysis chain

Consider using a placeholder for the INSTANCE_CHANGELOG_URL

While adding this environment variable aligns with the PR objectives for implementing a product updates modal, hardcoding the full URL in the Dockerfile might pose a security risk, especially since it contains what appears to be an API key or identifier (8e1c2e4c7bc5493eb7731be3862f6960).

Consider replacing the hardcoded URL with a placeholder and injecting the actual URL at runtime or during deployment. This approach enhances security and flexibility. Here's a suggested change:

-ENV INSTANCE_CHANGELOG_URL https://api.plane.so/api/public/anchor/8e1c2e4c7bc5493eb7731be3862f6960/pages/
+ENV INSTANCE_CHANGELOG_URL ${INSTANCE_CHANGELOG_URL:-https://api.plane.so/api/public/anchor/PLACEHOLDER/pages/}

This change allows you to:

  1. Set a default placeholder URL in the Dockerfile.
  2. Override it with the actual URL during container runtime or in your deployment configuration.
  3. Avoid exposing potentially sensitive information in your Dockerfile.

To ensure this environment variable is used correctly in the application code, please run the following command:

This will help verify that the application is properly configured to use this new environment variable.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usage of INSTANCE_CHANGELOG_URL in Python files
rg --type python 'INSTANCE_CHANGELOG_URL' -C 3

Length of output: 77


Script:

#!/bin/bash
# Search for usage of INSTANCE_CHANGELOG_URL in Python files using the correct file type alias
rg --type py 'INSTANCE_CHANGELOG_URL' -C 3

Length of output: 1986

Comment on lines +34 to +52
{!isLoading && !!error ? (
<div className="flex flex-col items-center justify-center w-full h-full mb-8">
<div className="text-lg font-medium">We are having trouble fetching the updates.</div>
<div className="text-sm text-custom-text-200">
Please visit{" "}
<a
href="https://go.plane.so/p-changelog"
target="_blank"
className="text-sm text-custom-primary-100 font-medium hover:text-custom-primary-200 underline underline-offset-1 outline-none"
>
our changelogs
</a>{" "}
for the latest updates.
</div>
</div>
) : isLoading ? (
<div className="flex items-center justify-center w-full h-full">
<LogoSpinner />
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Improve error handling and accessibility for loading state.

While the error and loading states are handled, there are opportunities for improvement:

  1. The error message could be more specific about the nature of the error.
  2. The loading spinner lacks an accessibility label.

Consider the following improvements:

  1. Enhance the error message:
-<div className="text-lg font-medium">We are having trouble fetching the updates.</div>
+<div className="text-lg font-medium">Error: Unable to fetch product updates. {error.message}</div>
  1. Add an accessibility label to the loading spinner:
-<LogoSpinner />
+<LogoSpinner aria-label="Loading product updates" />

These changes will provide more context for errors and improve accessibility for screen reader users.

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
{!isLoading && !!error ? (
<div className="flex flex-col items-center justify-center w-full h-full mb-8">
<div className="text-lg font-medium">We are having trouble fetching the updates.</div>
<div className="text-sm text-custom-text-200">
Please visit{" "}
<a
href="https://go.plane.so/p-changelog"
target="_blank"
className="text-sm text-custom-primary-100 font-medium hover:text-custom-primary-200 underline underline-offset-1 outline-none"
>
our changelogs
</a>{" "}
for the latest updates.
</div>
</div>
) : isLoading ? (
<div className="flex items-center justify-center w-full h-full">
<LogoSpinner />
</div>
{!isLoading && !!error ? (
<div className="flex flex-col items-center justify-center w-full h-full mb-8">
<div className="text-lg font-medium">Error: Unable to fetch product updates. {error.message}</div>
<div className="text-sm text-custom-text-200">
Please visit{" "}
<a
href="https://go.plane.so/p-changelog"
target="_blank"
className="text-sm text-custom-primary-100 font-medium hover:text-custom-primary-200 underline underline-offset-1 outline-none"
>
our changelogs
</a>{" "}
for the latest updates.
</div>
</div>
) : isLoading ? (
<div className="flex items-center justify-center w-full h-full">
<LogoSpinner aria-label="Loading product updates" />
</div>

@pushya22 pushya22 marked this pull request as draft October 3, 2024 12:07
@prateekshourya29 prateekshourya29 marked this pull request as ready for review October 4, 2024 08:40
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: 2

🧹 Outside diff range and nitpick comments (8)
web/ce/components/global/product-updates-header.tsx (1)

15-17: Consider simplifying the cn function usage.

The cn function is typically used for conditional class names, but in this case, it's being used with a single string argument. You could simplify this by removing the cn function call.

You could replace:

className={cn(
  "px-2 mx-2 py-0.5 text-center text-xs font-medium rounded-full bg-custom-primary-100/20 text-custom-primary-100"
)}

with:

className="px-2 mx-2 py-0.5 text-center text-xs font-medium rounded-full bg-custom-primary-100/20 text-custom-primary-100"

Unless you plan to add conditional classes in the future, this simplification would be more straightforward.

web/core/components/workspace/sidebar/help-section.tsx (3)

140-148: LGTM: "What's new" feature implemented as per PR objectives.

The addition of the "What's new" button within the CustomMenu.MenuItem structure effectively implements the feature described in the PR objectives. The placement and functionality are appropriate for a help section item.

Consider adding an aria-label to the button for improved accessibility:

 <button
   type="button"
   onClick={() => setIsChangeLogOpen(true)}
+  aria-label="Open changelog"
   className="flex w-full items-center justify-start text-xs hover:bg-custom-background-80"
 >
   <span className="text-xs">What&apos;s new</span>
 </button>

176-177: LGTM: Improved flexibility in sidebar toggle button styling.

The use of template literals for conditional class application enhances the button's ability to adapt to different collapse states. This is a good practice in React for dynamic styling.

Consider extracting the className logic into a separate variable for improved readability:

+ const toggleButtonClassName = cn(
+   "grid place-items-center rounded-md p-1 text-custom-text-200 outline-none hover:bg-custom-background-90 hover:text-custom-text-100",
+   {
+     "w-full": isCollapsed
+   }
+ );

 <button
   type="button"
-  className={`grid place-items-center rounded-md p-1 text-custom-text-200 outline-none hover:bg-custom-background-90 hover:text-custom-text-100 ${isCollapsed ? "w-full" : ""
-    }`}
+  className={toggleButtonClassName}
   onClick={() => toggleSidebar()}
 >

This refactoring would make the component more readable and easier to maintain.


Line range hint 39-39: LGTM: ProductUpdatesModal implementation aligns with PR objectives.

The ProductUpdatesModal is correctly implemented and tied to the isChangeLogOpen state, which is toggled by the "What's new" button. This directly fulfills the PR objective of introducing a product updates modal.

Consider adding a loading state to improve user experience:

+ const [isLoading, setIsLoading] = useState(false);

 // ... other code

 <ProductUpdatesModal
   isOpen={isChangeLogOpen}
-  handleClose={() => setIsChangeLogOpen(false)}
+  handleClose={() => {
+    setIsChangeLogOpen(false);
+    setIsLoading(false);
+  }}
+  onOpenChange={(open) => {
+    if (open) setIsLoading(true);
+  }}
+  isLoading={isLoading}
 />

 // ... in the "What's new" button onClick handler
 onClick={() => {
   setIsChangeLogOpen(true);
+  setIsLoading(true);
 }}

This enhancement would provide visual feedback to users while the changelog content is being loaded.

web/app/profile/page.tsx (1)

289-290: LGTM! Minor suggestion for readability.

The changes to the email input's className improve consistency and maintain the existing functionality. The error styling is preserved, and the input remains disabled as before.

For improved readability, consider using a template literal for the className:

-                      className={`w-full cursor-not-allowed rounded-md !bg-custom-background-80 ${errors.email ? "border-red-500" : ""
-                        }`}
+                      className={`w-full cursor-not-allowed rounded-md !bg-custom-background-80 ${
+                        errors.email ? "border-red-500" : ""
+                      }`}

This change would make the conditional styling easier to read and maintain.

web/core/components/global/product-updates/modal.tsx (3)

23-23: Consider removing the observer wrapper if not using MobX observables

The ProductUpdatesModal component is wrapped with observer, but it doesn't appear to utilize any MobX observable state within this component. If there are no observables being used, you might remove the observer wrapper to reduce unnecessary overhead.


28-32: Review SWR revalidation settings to ensure data freshness

The useSWR hook is configured with:

  • revalidateIfStale: false
  • revalidateOnFocus: false

This means the data won't be revalidated when it becomes stale or when the window gains focus. If it's important for users to see the most recent product updates, consider enabling these options or implementing a manual refresh mechanism to ensure data stays current.


40-50: Localize user-facing strings for internationalization

The strings displayed to users, such as error messages and informational text, are hardcoded in English:

  • Line 40: "We are having trouble fetching the updates."
  • Lines 42-51: "Please visit our changelogs for the latest updates."

If your application supports multiple languages or might in the future, consider wrapping these strings with a localization function to support internationalization.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 2b0f835 and 9c3f825.

📒 Files selected for processing (4)
  • web/app/profile/page.tsx (1 hunks)
  • web/ce/components/global/product-updates-header.tsx (1 hunks)
  • web/core/components/global/product-updates/modal.tsx (1 hunks)
  • web/core/components/workspace/sidebar/help-section.tsx (3 hunks)
🔇 Additional comments (7)
web/ce/components/global/product-updates-header.tsx (3)

10-26: Component structure looks good!

The ProductUpdatesHeader component is well-structured. It's a functional component wrapped with observer, which is appropriate for components that need to react to observable state changes. The use of an arrow function with an implicit return is suitable for this simple component.


11-25: Styling approach looks good!

The use of Tailwind CSS for styling is consistent with modern React practices. The layout seems responsive and well-structured, using flexbox appropriately. The custom color classes (custom-primary-100) provide a good way to maintain consistent branding.


1-26: Overall, the ProductUpdatesHeader component is well-implemented.

This component aligns well with the PR objectives of implementing a modal for product updates. It provides a clean and informative header for the "What's new" feature, displaying the application version and branding effectively. The code is well-structured and follows React best practices.

A few minor suggestions have been made to improve robustness and simplify the code slightly, but these are not critical issues. Good job on implementing this feature!

web/core/components/workspace/sidebar/help-section.tsx (2)

8-10: LGTM: Import changes align with new feature implementation.

The changes in the import statements are consistent with the PR objectives of introducing a new product updates modal. The addition of UI components like CustomMenu and Tooltip, along with the shift from ProductUpdates to ProductUpdatesModal, indicates an enhancement in how product updates are presented to the user. The inclusion of PlaneVersionNumber also suggests an improvement in displaying version information.

Also applies to: 17-17


Line range hint 1-185: Overall assessment: Changes successfully implement the "What's new" feature.

The modifications in this file effectively implement the product updates modal and "What's new" feature as described in the PR objectives. The code quality is good, and the changes are well-integrated into the existing component structure. Minor suggestions for accessibility and user experience improvements have been provided, but these are not critical for the functionality of the new feature.

Great job on implementing this new feature! The changes are well-structured and align perfectly with the PR objectives. Consider the minor suggestions for further enhancements, but overall, this is ready for merging.

web/app/profile/page.tsx (2)

Line range hint 1-478: LGTM! Changes improve code consistency without altering core functionality.

The modifications to this file are minimal and focused on improving code cleanliness and consistency. The core functionality of the ProfileSettingsPage component remains intact, with only minor adjustments to the email input field styling and the removal of the getLayout function.

These changes align with good coding practices and don't introduce any apparent issues. The component continues to handle user profile settings effectively, including form management, image uploads, and account deactivation options.


Line range hint 1-1: Verify the impact of removing the getLayout function.

The getLayout function has been removed as mentioned in the AI-generated summary. This simplifies the component structure, but we should ensure that this change doesn't negatively impact the page layout or routing.

Please confirm that:

  1. The page still renders correctly within the desired layout.
  2. Any layout-related functionality previously handled by getLayout is now properly managed elsewhere.
  3. This change is consistent with the project's current architecture and routing setup.

Run the following script to check for any remaining references to getLayout in the codebase:

If any results are found, please review them to ensure that the removal of getLayout from this component doesn't cause any inconsistencies.

✅ Verification successful

Verified: getLayout function removal

The getLayout function has been successfully removed with no remaining references found in the codebase. The component structure is simplified, and there are no impacts on page layout or routing.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining references to getLayout
rg 'getLayout' --type tsx --type ts

Length of output: 63


Script:

#!/bin/bash
# Search for any remaining references to getLayout using ast-grep
ast-grep --lang typescript --pattern '$_.getLayout($$$)' --pattern '$$_.getLayout$$' 

Length of output: 253


Script:

#!/bin/bash
# Search for any remaining references to getLayout using a combined pattern in ast-grep
ast-grep --lang typescript --pattern '$_.getLayout($$$) | $_.getLayout$$' 

Length of output: 75

Comment on lines +1 to +8
import { observer } from "mobx-react";
import Image from "next/image";
// helpers
import { cn } from "@/helpers/common.helper";
// assets
import PlaneLogo from "@/public/plane-logos/blue-without-text.png";
// package.json
import packageJson from "package.json";
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider using an environment variable for the package version.

The direct import of package.json might cause issues in certain build configurations, especially in production environments. Consider using an environment variable to store and access the package version instead.

You could set up an environment variable in your build process and access it like this:

const version = process.env.NEXT_PUBLIC_APP_VERSION || 'unknown';

Then use version instead of packageJson.version in your component.

Comment on lines +58 to +75
<div className="ml-5">
{data?.id && (
<DocumentReadOnlyEditorWithRef
ref={editorRef}
id={data.id}
initialValue={data.description_html ?? "<p></p>"}
containerClassName="p-0 border-none"
mentionHandler={{
highlights: () => Promise.resolve([]),
}}
embedHandler={{
issue: {
widgetCallback: () => <></>,
},
}}
/>
)}
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle cases where no product updates are available

If data exists but data.id is falsy, the content area renders nothing, which might confuse users. To enhance user experience, consider displaying a message indicating that no product updates are available.

Apply this diff to address the issue:

-            {data?.id && (
+            {data?.id ? (
               <DocumentReadOnlyEditorWithRef
                 ref={editorRef}
                 id={data.id}
                 initialValue={data.description_html ?? "<p></p>"}
                 containerClassName="p-0 border-none"
                 mentionHandler={{
                   highlights: () => Promise.resolve([]),
                 }}
                 embedHandler={{
                   issue: {
                     widgetCallback: () => <></>,
                   },
                 }}
               />
+            ) : (
+              <div className="text-lg font-medium">No product updates are available at this time.</div>
             )}
📝 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
<div className="ml-5">
{data?.id && (
<DocumentReadOnlyEditorWithRef
ref={editorRef}
id={data.id}
initialValue={data.description_html ?? "<p></p>"}
containerClassName="p-0 border-none"
mentionHandler={{
highlights: () => Promise.resolve([]),
}}
embedHandler={{
issue: {
widgetCallback: () => <></>,
},
}}
/>
)}
</div>
<div className="ml-5">
{data?.id ? (
<DocumentReadOnlyEditorWithRef
ref={editorRef}
id={data.id}
initialValue={data.description_html ?? "<p></p>"}
containerClassName="p-0 border-none"
mentionHandler={{
highlights: () => Promise.resolve([]),
}}
embedHandler={{
issue: {
widgetCallback: () => <></>,
},
}}
/>
) : (
<div className="text-lg font-medium">No product updates are available at this time.</div>
)}
</div>

@pushya22 pushya22 marked this pull request as draft October 4, 2024 10:34
@sriramveeraghanta sriramveeraghanta added this to the v0.24.0 milestone Oct 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🌟enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants