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

chore: Update markdown component + create avatar component + refactor #36832

Open
wants to merge 17 commits into
base: release
Choose a base branch
from

Conversation

jsartisan
Copy link
Contributor

@jsartisan jsartisan commented Oct 11, 2024

Summary by CodeRabbit

  • New Features

    • Introduced the Avatar component for displaying user avatars.
    • Added the Markdown component for rendering Markdown content with GitHub Flavored Markdown support.
    • Enhanced AIChat component with a new modular input system and improved message display.
  • Bug Fixes

    • Updated CSS for better styling consistency across components.
  • Refactor

    • Removed outdated components (ChatDescriptionModal and ThreadMessage) to streamline the codebase.
    • Simplified the structure of AIChat by incorporating new components.
  • Documentation

    • Updated Storybook stories for AIChat, Avatar, and Markdown components to showcase new features.

Warning

Tests have not run on the HEAD db2bc5c yet


Fri, 11 Oct 2024 13:08:01 UTC

Copy link
Contributor

coderabbitai bot commented Oct 11, 2024

Walkthrough

The pull request introduces several changes to the @appsmith/wds package, including the addition of the remark-gfm dependency in package.json. The AIChat component has undergone significant modifications, replacing certain imports and altering its structure. The ChatDescriptionModal and ThreadMessage components have been removed, along with their associated files. New components, Avatar and Markdown, have been added to enhance functionality. Additionally, updates have been made to CSS styles and Storybook stories to reflect these changes.

Changes

File Path Change Summary
app/client/packages/design-system/widgets/package.json Added dependency: "remark-gfm": "^4.0.0"
app/client/packages/design-system/widgets/jest.config.js Added constant esModules for Jest configuration to manage module transformation.
app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx Removed imports for Button, TextArea, and FormEvent; added imports for ChatHeader, ChatThread, and ChatInputSection; removed handleFormSubmit and handlePromptInputKeyDown; changed rendering logic to use new components.
app/client/packages/design-system/widgets/src/components/AIChat/src/ChatDescriptionModal/* Removed ChatDescriptionModal component and associated files.
app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/* Removed ThreadMessage component and associated files.
app/client/packages/design-system/widgets/src/components/AIChat/src/styles.module.css Updated .root and .header classes; removed .promptForm class.
app/client/packages/design-system/widgets/src/components/AIChat/stories/AIChat.stories.tsx Updated stories to reflect new component structure and functionality.
app/client/packages/design-system/widgets/src/components/Avatar/* Introduced new Avatar component with associated files and styles; added Storybook stories.
app/client/packages/design-system/widgets/src/components/Markdown/* Introduced new Markdown component with support for GitHub Flavored Markdown; added associated files and styles; added Storybook story.
app/client/packages/design-system/widgets/src/index.ts Added exports for Avatar and Markdown components.
app/client/packages/storybook/.storybook/preview-head.html Added script for container query polyfill; modified CSS styles for consistent theming.
app/client/test/__mocks__/reactMarkdown.tsx Introduced a mock for the remark-gfm module to enhance testing capabilities.

Possibly related PRs

Suggested labels

Task, Enhancement, ok-to-test

Suggested reviewers

  • ApekshaBhosale
  • sagar-qa007
  • ichik
  • KelvinOm

Poem

In the land of code where changes flow,
New components rise, and old ones go.
With avatars bright and Markdown's flair,
The chat interface has a brand new air.
Dependencies added, stories to tell,
In this world of widgets, all is well! 🌟


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.

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.

@github-actions github-actions bot added the skip-changelog Adding this label to a PR prevents it from being listed in the changelog label Oct 11, 2024
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: 10

🧹 Outside diff range and nitpick comments (28)
app/client/packages/design-system/widgets/src/components/Markdown/src/types.ts (1)

4-10: Excellent work on your interface properties, students!

Your MarkdownProps interface is well-structured and clearly documented. The properties cover all the bases for a versatile Markdown component. Here's a quick breakdown of your good work:

  1. children: Required string for the markdown content. Perfect!
  2. options: Optional Options type for customization. Well done!
  3. className: Optional string for additional styling. Great thinking!

The JSDoc comments are like clear instructions on a chalkboard - they help everyone understand the purpose of each property.

One small suggestion to make your work even better:

Consider adding a default empty object for the options property. This can simplify usage in some cases. Here's how you could do it:

 export interface MarkdownProps {
   /** The markdown content to render */
   children: string;
   /** Options for react-markdown */
-  options?: Options;
+  options?: Options | Record<string, never>;
   /** Additional CSS classes to apply to the component */
   className?: string;
 }

This change allows users to pass an empty object ({}) without TypeScript complaining, which can be useful in certain scenarios.

Keep up the great work, class!

app/client/packages/design-system/widgets/src/components/Avatar/src/types.ts (1)

4-12: Wonderful job defining the properties, class!

Your property definitions are clear and well-documented. The label, src, and size properties are all correctly typed. I especially appreciate the use of JSDoc comments to provide additional information.

Here's a small suggestion to make your code even better:

Consider using a type alias for the size options to improve reusability. Here's how you could do it:

type AvatarSize = "small" | "medium" | "large";

export interface AvatarProps extends Omit<HTMLProps<HTMLSpanElement>, "size"> {
  // ... other properties ...
  size?: AvatarSize;
}

This way, if you need to use these size options elsewhere, you can easily reuse the AvatarSize type. It's like creating a reusable lesson plan - very efficient!

app/client/packages/design-system/widgets/src/components/Markdown/src/components.tsx (2)

1-7: Well done on organizing your imports, class!

Your imports are neatly arranged, making it easy for everyone to understand what components we're using. It's like having a well-organized pencil case – everything has its place!

However, let's make it even better. Can you group your imports by external and internal sources? It'll be like separating your colored pencils from your regular ones.

Here's a gold star ⭐ for your effort, and a suggestion to make it shine even brighter:

 import type { Components } from "react-markdown";

+// Internal imports
 import { a } from "./mdComponents/Link";
 import { code } from "./mdComponents/Code";
 import { p } from "./mdComponents/Paragraph";
 import { ul, ol, li } from "./mdComponents/List";
 import { h1, h2, h3, h4, h5, h6 } from "./mdComponents/Heading";

9-22: Excellent work on your components map, students!

Your components constant is like a well-organized seating chart for our Markdown classroom. Each element knows exactly where it belongs!

To make it even better, let's ensure all our "students" are sitting in alphabetical order. It'll help us find them quicker when we need them!

Here's a gold star ⭐ for your effort, and a suggestion to make it shine even brighter:

 export const components: Components = {
   a,
+  code,
   h1,
   h2,
   h3,
   h4,
   h5,
   h6,
-  p,
+  li,
+  ol,
+  p,
   ul,
-  ol,
-  li,
-  code,
 };
app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Link.tsx (1)

9-17: Excellent work on the component implementation, students!

Your a component is well-structured and addresses important security considerations. The use of rel="noreferrer" and target="_blank" is a good practice for external links.

However, let's add a little homework to make it even better:

Consider adding a brief comment explaining why the component is named a. This will help other developers understand its purpose in the context of Markdown rendering. Here's a suggested addition:

+// The 'a' component name is used to match the HTML anchor tag
+// when rendering Markdown content
export const a = (props: LinkProps) => {
  // ... rest of the component
}
app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Paragraph.tsx (1)

9-10: A for effort, but let's make our component name more descriptive!

While your props destructuring is commendable, the component name 'p' is a bit too brief. Remember, clear naming helps your classmates understand your code better. How about we rename it to something more descriptive, like 'MarkdownParagraph'?

Here's a suggested improvement:

-export const p = (props: ParagraphProps) => {
+export const MarkdownParagraph = (props: ParagraphProps) => {
   const { children, ref } = props;

This change will make your code more self-explanatory. What do you think?

app/client/packages/design-system/widgets/src/components/Avatar/src/styles.module.css (1)

20-24: Very creative use of modern CSS, class!

Your use of the :has() pseudo-class is like using a new scientific method - innovative and efficient. The explanatory comment is like a good thesis statement - it clearly states the purpose. However, remember that not all browsers are as advanced as your thinking. Consider adding a fallback for older browsers, just like how we provide alternative reading materials for different learning styles.

Here's a suggestion to ensure compatibility:

/* Fallback for browsers that don't support :has() */
.avatar-fallback {
  background-color: var(--color-bg-assistive);
  color: var(--color-fg-on-assistive);
  border-radius: var(--border-radius-elevation-3);
}

/* Modern browsers will use this */
.avatar:has(div) {
  background-color: var(--color-bg-assistive);
  color: var(--color-fg-on-assistive);
  border-radius: var(--border-radius-elevation-3);
}

Don't forget to add the 'avatar-fallback' class in your JavaScript when a div is present inside the avatar!

app/client/packages/design-system/widgets/src/components/Markdown/src/Markdown.tsx (2)

11-32: Excellent component structure, students!

Your Markdown component shows good understanding of React principles. Let's break it down:

  1. You've used a functional component with arrow function syntax. Very modern!
  2. Props destructuring with rest syntax (...rest) is a clever way to handle additional props.
  3. Wrapping ReactMarkdown in a styled div gives us control over the overall appearance.

However, I have a small homework assignment for you:

Consider using TypeScript's React.FC type for your functional component. It might look like this:

export const Markdown: React.FC<MarkdownProps> = ({ children, className, options, ...rest }) => {
  // ... rest of the component
}

This explicitly declares that Markdown is a functional component and can help catch type errors related to children props.

Keep up the good work, class!


14-31: A gold star for your implementation, young coders!

Let's review what you've done well:

  1. Using clsx to combine CSS classes is a neat trick for managing multiple class names.
  2. Applying a custom typography class shows you're thinking about consistent styling. Good job!
  3. Configuring ReactMarkdown with custom components gives us flexibility in rendering. Clever!
  4. Including the remarkGfm plugin ensures we support GitHub Flavored Markdown. You're thinking ahead!

Now, for a small suggestion to make your code even more readable:

Consider extracting the className logic into a separate variable. It might look like this:

const markdownClassName = clsx(
  styles.markdown,
  getTypographyClassName("body"),
  className
);

return (
  <div className={markdownClassName} {...rest}>
    {/* ... rest of the component */}
  </div>
);

This small change can make the JSX portion of your component a bit cleaner and easier to read.

Keep up the excellent work, class!

app/client/packages/design-system/widgets/src/components/Avatar/stories/Avatar.stories.tsx (2)

13-24: Excellent work on your stories, but let's discuss the image source!

Your Default and WithImage stories are well-structured and demonstrate different use cases of the Avatar component. However, I have a small suggestion for improvement:

In the WithImage story, you're using a placeholder image URL. While this works for demonstration purposes, it's not ideal for production code. Consider using a more reliable image source or adding a comment to indicate that this URL should be replaced in a real-world scenario.

Here's a suggested improvement:

 export const WithImage: Story = {
   args: {
     label: "Jane Smith",
-    src: "https://assets.appsmith.com/integrations/25720743.png",
+    src: "https://example.com/path/to/avatar.png", // TODO: Replace with a reliable image source
   },
 };

32-43: Your Sizes story is a shining example, but let's add a little polish!

Your Sizes story does an excellent job of demonstrating the different size options for the Avatar component. The use of the Flex component for layout is very appropriate. However, I have a small suggestion to improve clarity:

Consider adding comments to explain the purpose of each Avatar size. This will help other developers understand the story more quickly.

Here's a suggested improvement:

 export const Sizes: Story = {
   args: {
     label: "Alice",
   },
   render: (args) => (
     <Flex gap="spacing-2">
-      <Avatar {...args} size="small" />
-      <Avatar {...args} size="medium" />
-      <Avatar {...args} size="large" />
+      <Avatar {...args} size="small" /> {/* Small size avatar */}
+      <Avatar {...args} size="medium" /> {/* Medium size avatar */}
+      <Avatar {...args} size="large" /> {/* Large size avatar */}
     </Flex>
   ),
 };
app/client/packages/design-system/widgets/src/components/Avatar/src/Avatar.tsx (1)

9-10: Let's add some structure to our props, shall we?

Class, you've done a splendid job setting up your Avatar component. However, I noticed that the 'size' prop isn't typed. Remember, in programming as in essay writing, being specific helps avoid confusion. Let's add a type for 'size' to make our code more robust.

Here's a little homework for you:

type AvatarSize = 'small' | 'medium' | 'large';

export interface AvatarProps {
  // ... other props
  size?: AvatarSize;
}

Now, update your component to use this new type. It's like using a ruler to make sure all your lines are straight!

app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Heading.tsx (4)

1-8: Good job on the imports and type definitions, class!

The imports and type definitions look well-organized and appropriate for the component's functionality. However, let's make a small improvement to enhance readability.

Consider grouping the imports by their source:

import React, { type Ref } from "react";
import type { ExtraProps } from "react-markdown";
import { Text, type TextProps } from "@appsmith/wds";

This arrangement makes it easier for other students to understand where each import comes from at a glance.


10-29: Excellent work on the createHeading function, students!

The function is well-structured and follows React best practices. I'm particularly impressed with the use of generics for the ref prop, ensuring type safety. The data-component attribute is a smart addition for testing and debugging purposes.

To make our heading component even more flexible, let's consider allowing customization of the color and fontWeight props:

const createHeading = (
  size: TextProps["size"],
  level: 1 | 2 | 3 | 4 | 5 | 6,
  defaultColor: TextProps["color"] = "neutral",
  defaultFontWeight: TextProps["fontWeight"] = 700
) => {
  const HeadingComponent = ({ children, ref, color, fontWeight, ...rest }: HeadingProps & Pick<TextProps, "color" | "fontWeight">) => (
    <Text
      color={color || defaultColor}
      data-component={`h${level}`}
      fontWeight={fontWeight || defaultFontWeight}
      ref={ref as Ref<HTMLDivElement>}
      size={size}
      {...rest}
    >
      {children}
    </Text>
  );

  HeadingComponent.displayName = `Heading${level}`;

  return HeadingComponent;
};

This modification allows users of our component to override the default color and font weight if needed, making it more adaptable to different design requirements.


31-36: Well done on creating the heading components, class!

Your approach of using the createHeading function to generate multiple heading components is efficient and reduces code duplication. The size assignments for each heading level seem appropriate for a typical heading hierarchy.

To improve consistency and make the code more maintainable, consider using an object to map heading levels to their corresponding sizes:

const headingSizes = {
} as const;

export const [h1, h2, h3, h4, h5, h6] = Object.entries(headingSizes).map(
  ([level, size]) => createHeading(size, parseInt(level) as 1 | 2 | 3 | 4 | 5 | 6)
);

This approach centralizes the size definitions and makes it easier to update or modify the heading sizes in the future.


1-36: Outstanding work on this Heading component, class!

Your implementation of the Markdown heading components is well-structured, clean, and follows React best practices. The use of the Appsmith design system's Text component as a base ensures consistency with the overall design.

Here's a summary of the strengths of your work:

  1. Efficient use of a factory function (createHeading) to generate multiple heading components.
  2. Type-safe implementation with appropriate use of TypeScript features.
  3. Good use of React's displayName for improved debugging experience.
  4. Consistent styling across heading levels using the design system.

The suggestions provided earlier will further enhance the flexibility and maintainability of your code. Keep up the excellent work!

As you continue to develop more Markdown components, consider creating a central index.ts file that exports all these components. This will make it easier for other parts of the application to import and use these Markdown components.

app/client/packages/storybook/.storybook/preview-head.html (2)

Line range hint 1-1: Class, let's discuss the new addition to our code!

I see you've added a container query polyfill. That's a smart move to ensure our layout behaves consistently across different browsers. However, let's consider a more secure approach.

Instead of relying on an external CDN, why don't we host this script ourselves? This way, we can ensure it's always available and reduce security risks. Here's a little homework for you:

  1. Download the polyfill script.
  2. Place it in your project's assets.
  3. Update the script tag to reference the local file.

This way, we're in control of our dependencies. What do you think about this approach?


Line range hint 3-42: Excellent work on your CSS, class!

I'm impressed by your use of CSS variables for theming. This is a great way to keep our styles consistent and easy to maintain. Your attention to detail in setting font families and sizes is commendable too.

I particularly like the comment about link styling. It's always good to leave notes for your fellow developers. However, let's make it even clearer:

-  /** Note: adding this so that all links are styled the same way excepts the one that are in the story */
+  /** 
+   * Style all links consistently, except those within story context.
+   * This ensures uniform appearance across the application while allowing
+   * flexibility for story-specific styling.
+   */

Remember, clear communication is key in coding, just like in the classroom!

app/client/packages/design-system/widgets/src/components/Text/src/Text.tsx (1)

Line range hint 52-56: Let's improve our text clamping, shall we?

Class, I see we're using the WebkitLineClamp property for our text clamping. That's good, but remember, not all browsers support this. Let's make our code more inclusive!

Here's a little exercise for you:

Consider adding a fallback for browsers that don't support WebkitLineClamp. We can do this by checking if the property is supported and applying a different style if it's not. Here's an example:

const lineClampStyle = lineClamp
  ? {
      display: '-webkit-box',
      WebkitLineClamp: lineClamp,
      WebkitBoxOrient: 'vertical',
      overflow: 'hidden',
      // Fallback for browsers that don't support -webkit-line-clamp
      maxHeight: `${lineClamp * 1.2}em`, // Assuming a line-height of 1.2
    }
  : {};

// In the return statement
<span
  className={styles.clampedText}
  style={lineClampStyle}
  title={title}
>
  {children}
</span>

This way, even if a browser doesn't understand WebkitLineClamp, it will still try to clamp the text using maxHeight. Isn't it wonderful how we can make our code work for everyone?

app/client/packages/design-system/widgets/src/components/Markdown/stories/Markdown.stories.ts (1)

14-60: Impressive Markdown content, students! But let's add one more element to make it perfect.

Your Markdown example is comprehensive and well-structured. It covers a wide range of Markdown features, which is excellent for testing the component's rendering capabilities.

To make it even better, consider adding an example of an image in Markdown. This will ensure that all common Markdown elements are represented.

Here's a suggestion to add after line 38:

[Visit Appsmith](https://www.appsmith.com)

+ ![Appsmith Logo](https://www.appsmith.com/images/appsmith-logo.png)
+

This addition will help test the component's ability to render images as well.

app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/ThreadMessage.tsx (2)

10-19: Excellent job on refactoring the props, students!

Your use of destructuring in the function signature is commendable. It makes the code more readable and concise. However, let's take it a step further. Can you think of a way to make it even cleaner?

Here's a little homework for you:

export const ThreadMessage = ({
  className,
  content,
  isAssistant,
  onApplyAssistantSuggestion,
  promptSuggestions = [],
  username,
  ...rest
}: ThreadMessageProps) => {
  // Component logic here
};

This approach eliminates the need for the separate destructuring inside the function body. Give it a try and see how it looks!


52-52: Good use of the new Avatar component!

I'm glad to see you're using our new Avatar component. It's a step towards a more consistent design system. However, I have a small suggestion to make this even better.

Consider this enhancement:

<Avatar label={username} size="small" />

Adding a size prop (if available in the new Avatar component) could ensure consistent sizing across different uses of the Avatar. It's always good to be explicit about these things in our UI components.

What do you think about this suggestion? Discuss with your classmates and see if you can implement it!

app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css (3)

1-38: Well done, class! Your table styles are looking sharp.

I'm pleased to see the use of CSS variables for colors and the thoughtful table styling. The :last-child selector for removing the right border on the last column is a nice touch. However, let's make sure our table is accessible to all students.

Consider adding a caption style to improve table accessibility:

table caption {
  caption-side: top;
  text-align: left;
  margin-bottom: var(--inner-spacing-2);
}

This will help screen reader users understand the context of the table better.

🧰 Tools
🪛 Biome

[error] 35-37: Unexpected value or character.

Expected one of:

(parse)


40-69: A+ for your heading hierarchy, students!

Your use of data attributes for styling headings is an interesting approach. The margin settings create a clear visual hierarchy, which is excellent for document structure. However, let's ensure our headings are fully accessible.

Consider adding styles for focus states to improve keyboard navigation:

[data-component^="h"]:focus {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

This will help keyboard users navigate through the headings more easily.


95-106: Your code block styling is coming along nicely, class!

I'm impressed with the visual distinction you've created for code blocks. The use of CSS variables for colors and spacing shows consistency in your work. However, let's make sure our code blocks are easy to read for everyone.

Consider adding these styles to improve readability:

[data-component="code"] {
  font-family: 'Courier New', Courier, monospace;
  font-size: 0.9em;
  line-height: 1.4;
  padding: var(--inner-spacing-2);
}

This will ensure that code is displayed in a monospace font and has appropriate spacing.

app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Code.tsx (3)

11-13: Let's refine the type definition of CodeProps for clarity.

Defining a more specific type for CodeProps can enhance type safety and make the component easier to understand. Consider specifying the exact props that your component expects rather than using broad types.


21-25: Remember to clean up the timeout to prevent memory leaks.

When using setTimeout, it's prudent to clear the timeout if the component unmounts before the callback is executed. This ensures that we're not attempting to update state on an unmounted component.

You can modify your code as follows:

Declare a variable to hold the timeout ID:

+ let timeoutId: number;

Update the handleCopy function:

  const handleCopy = useCallback(() => {
    navigator.clipboard.writeText(String(children));
    setCopied(true);
-   setTimeout(() => setCopied(false), 2000);
+   timeoutId = window.setTimeout(() => setCopied(false), 2000);
  }, [children]);

Add a useEffect hook for cleanup:

+ React.useEffect(() => {
+   return () => {
+     clearTimeout(timeoutId);
+   };
+ }, []);

34-34: Consider internationalizing the language label.

Displaying the language name directly may not support localization needs. To make your component more accessible to a global audience, think about integrating internationalization for the language text.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between e03522f and 55e2537.

⛔ Files ignored due to path filters (1)
  • app/client/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (36)
  • app/client/packages/design-system/widgets/package.json (1 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx (3 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/ChatTitle.tsx (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/index.ts (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/styles.module.css (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/types.ts (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/ThreadMessage.tsx (3 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/UserAvatar.tsx (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/index.ts (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/styles.module.css (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/types.ts (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/styles.module.css (1 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/stories/AIChat.stories.tsx (3 hunks)
  • app/client/packages/design-system/widgets/src/components/Avatar/index.ts (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Avatar/src/Avatar.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Avatar/src/index.ts (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Avatar/src/styles.module.css (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Avatar/src/types.ts (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Avatar/stories/Avatar.stories.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Link/src/index.ts (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Link/stories/Link.stories.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/index.ts (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/Markdown.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/components.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/index.ts (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Code.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Heading.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Link.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/List.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Paragraph.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/types.ts (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/stories/Markdown.stories.ts (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Text/src/Text.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/index.ts (1 hunks)
  • app/client/packages/storybook/.storybook/preview-head.html (1 hunks)
💤 Files with no reviewable changes (8)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/ChatTitle.tsx
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/index.ts
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/styles.module.css
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/types.ts
  • app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/UserAvatar.tsx
  • app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/index.ts
  • app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/styles.module.css
  • app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/types.ts
✅ Files skipped from review due to trivial changes (4)
  • app/client/packages/design-system/widgets/src/components/Avatar/index.ts
  • app/client/packages/design-system/widgets/src/components/Avatar/src/index.ts
  • app/client/packages/design-system/widgets/src/components/Markdown/index.ts
  • app/client/packages/design-system/widgets/src/components/Markdown/src/index.ts
🧰 Additional context used
🪛 Biome
app/client/packages/design-system/widgets/src/components/Avatar/src/Avatar.tsx

[error] 28-28: Avoid redundant Boolean call

It is not necessary to use Boolean call when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant Boolean call

(lint/complexity/noExtraBooleanCast)

app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css

[error] 35-37: Unexpected value or character.

Expected one of:

(parse)


[error] 113-114: Expected a qualified rule, or an at rule but instead found '}'.

Expected a qualified rule, or an at rule here.

(parse)

🔇 Additional comments (43)
app/client/packages/design-system/widgets/src/components/Link/src/index.ts (1)

2-2: Class, let's examine this new export statement.

Good job on adding this export! By exporting linkStyles, we're making our CSS module available to other parts of the application. This is like sharing your coloring book with the whole class - now everyone can use these styles!

Remember, children, when we share our styles like this, it allows other developers to easily use or even customize the appearance of our Link component. It's a wonderful example of code reusability and modularity.

app/client/packages/design-system/widgets/src/components/Markdown/src/types.ts (2)

1-1: A+ for the import statement, class!

The import of Options from "react-markdown" is spot-on. It's like bringing the right textbook to class - essential for our lesson on Markdown props!


3-3: Gold star for your interface declaration!

The MarkdownProps interface is declared and exported with perfect form. It's like writing your name clearly at the top of your homework - it sets the stage for everything that follows!

app/client/packages/design-system/widgets/src/components/Avatar/src/types.ts (2)

1-1: Well done, class! The import statement is correct.

You've properly imported the HTMLProps type from React. This is essential for our Avatar component to inherit the standard HTML properties. Keep up the good work!


3-3: Excellent work on the interface declaration, students!

Your AvatarProps interface is extending the HTMLProps for a span element, which is a smart choice. By using Omit to remove the "size" property, you're preparing to redefine it with more specific options. This is a great example of how to customize component props while still leveraging built-in types. A gold star for you!

app/client/packages/design-system/widgets/src/components/Markdown/src/components.tsx (1)

1-22: A round of applause for this well-structured file, class!

This file is like a perfectly organized lesson plan. It has a clear purpose: to map Markdown elements to our custom React components. This centralized approach makes it easy for us to customize how our Markdown "lessons" are presented.

Your code is concise, focused, and follows good practices. It's a joy to read, just like a well-written essay!

Keep up the excellent work! Here's a gold star ⭐ for your efforts!

app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Link.tsx (2)

1-7: Well done, class! Your imports and type definitions are spot on!

You've correctly imported the necessary components and types. The LinkProps type is a comprehensive combination of HTML anchor attributes, React class attributes, and additional properties from react-markdown. This will ensure type safety when using the component.


1-17: Class, your Link component gets an A+!

You've done an excellent job creating this Markdown link component. It's well-typed, secure, and uses the design system effectively. Remember, clear documentation is as important as good code. Keep up the great work!

app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Paragraph.tsx (3)

1-7: Well done, class! Your imports and type definitions are spot on!

You've demonstrated a good understanding of TypeScript by creating a comprehensive ParagraphProps type. This ensures type safety and makes your code more robust. Keep up the excellent work!


12-21: Excellent job on your component rendering, students!

Your use of the Text component shows a good understanding of component composition. I'm particularly impressed by:

  1. The proper forwarding of the ref prop.
  2. The use of the data-component attribute, which will be helpful for testing.
  3. The simple and focused nature of the component, adhering to the single responsibility principle.

These are all practices that will serve you well in your future React endeavors. Keep up the fantastic work!


1-22: Class, your Markdown paragraph component gets an A-!

Overall, this new component is a valuable addition to our Markdown rendering toolkit. You've demonstrated excellent use of TypeScript, good React practices, and proper integration with the design system.

The only area for improvement is the component naming, which we've already discussed. Once you make that small change, this will be top-notch work!

Remember, clear naming and focused components like this one make our codebase easier to understand and maintain. Well done, and keep up the great work!

app/client/packages/design-system/widgets/src/components/AIChat/src/styles.module.css (3)

3-6: Excellent work on updating the .root class, students!

I'm pleased to see the improvements you've made to the .root class. Let's review what you've done:

  1. You've used CSS variables for colors and border-radius. This is a great practice for maintaining consistency across your design system.
  2. The switch from a border to an outline is a clever choice. It allows for more flexible styling without affecting the element's dimensions.
  3. Adding overflow: hidden is a thoughtful touch. It ensures that any content within the root element doesn't spill out, maintaining a clean appearance.

These changes will make our AI chat component more visually appealing and easier to maintain. Keep up the good work!


Line range hint 9-15: Class, let's discuss the changes to our .header class.

I've noticed that you've removed the background property from the .header class. This is an interesting choice that warrants some discussion:

  1. By removing the background, we're creating a more seamless integration between the header and the rest of the component. This can lead to a cleaner, more unified look.
  2. However, we should consider how this affects the visual hierarchy of our AI chat component. Does the header still stand out sufficiently from the content below it?

I'd like you to think about these questions:

  • How does this change impact the overall design of the component?
  • Is the border at the bottom of the header (line 15) enough to differentiate it from the content?
  • Should we consider adding any other visual cues to maintain the header's prominence?

Remember, in design, every change has a purpose. Let's ensure this one serves our users well.


Line range hint 1-38: Attention, class! We need to discuss the disappearance of our .promptForm class.

I've noticed that the .promptForm class has been completely removed from our stylesheet. This is a significant change that raises some important questions:

  1. What prompted the decision to remove this class?
  2. How is the prompt input functionality being handled now?
  3. Are there any new classes or components that have taken over the role of .promptForm?

Remember, when we remove code, it's crucial to understand the implications. Let's consider:

  • How does this affect the overall user experience of our AI chat component?
  • Are there any accessibility concerns we need to address with this change?
  • Have we updated our documentation to reflect this structural change?

I'd like you to prepare a brief explanation of the reasoning behind this change and how it improves our component. This will help us all understand the evolution of our design system.

app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/List.tsx (2)

1-7: Well done on your import statements and type definitions, class!

Your imports and type definitions are spot on! You've correctly imported React and the necessary types. The use of TypeScript for defining ULProps and LIProps is commendable. It's like you've done your homework before class!

Also applies to: 14-17


1-28: Great job on your List components, class!

You've done a commendable job creating these list components for Markdown rendering. Your use of TypeScript and React is praiseworthy. With the suggested improvements, your components will be even more robust and consistent.

Remember, in coding as in school, attention to detail and consistency are crucial. Keep up the good work, and don't forget to apply these lessons to future components you create!

app/client/packages/design-system/widgets/src/components/Avatar/src/styles.module.css (4)

1-7: Excellent work on the base avatar class, students!

I'm pleased to see you've used flexbox for centering the content. It's like arranging desks in a classroom - everything is neat and orderly. The use of CSS variables for sizing is also commendable, just like using a standard ruler for all your measurements. Keep up the good work!


9-12: Well done on creating a small avatar variant!

Just as we have different sized notebooks for different subjects, you've wisely created a smaller avatar size. Your use of data attributes for variants shows good organization skills. Remember, consistency is key in design, just like in your homework!


14-17: Bravo on your large avatar variant!

Just like how we use larger posters for important announcements, you've created a larger avatar size. Your consistent approach in using data attributes and CSS variables shows excellent attention to detail. It's like following the same format for all your essay submissions - very professional!


26-31: Exemplary work on styling the avatar image!

Your approach to styling the image is like perfectly framing a photograph. The use of object-fit: cover ensures your image looks good regardless of its original dimensions - just like how a good student adapts to different learning environments. Inheriting the border-radius is a smart move, maintaining consistency like a well-structured essay. Keep up this attention to detail!

app/client/packages/design-system/widgets/src/components/Markdown/src/Markdown.tsx (1)

1-9: Well done on your import selections, class!

Let's review what we've learned from these imports:

  1. We're using React, as expected for a React component.
  2. The clsx utility will help us combine CSS classes efficiently.
  3. remarkGfm plugin extends Markdown support to GitHub Flavored Markdown.
  4. ReactMarkdown is our main library for rendering Markdown.
  5. Custom imports like getTypographyClassName, styles, components, and MarkdownProps show good code organization.

Remember, class, good imports are the foundation of a well-structured component!

app/client/packages/design-system/widgets/src/components/Avatar/stories/Avatar.stories.tsx (2)

1-11: Well done, class! Your imports and metadata are spot on!

You've correctly imported the necessary components and types, and set up the metadata for your Storybook stories. Keep up the good work!


26-30: A gold star for your SingleInitial story!

Your SingleInitial story is a perfect example of how to demonstrate the Avatar component's ability to display initials when no image is provided. It's simple, clear, and effectively showcases this feature. Keep up the excellent work!

app/client/packages/design-system/widgets/src/components/Avatar/src/Avatar.tsx (1)

1-7: Good job on your imports, class!

I'm pleased to see you've organized your imports neatly. You've brought in all the necessary tools for our Avatar component, just like a well-prepared student brings all their supplies to class. Keep up the good work!

app/client/packages/storybook/.storybook/preview-head.html (1)

Line range hint 24-28: Let's examine this interesting CSS selector, shall we?

I see you've made a clever adjustment to our code element styling. By using :not(:has(span)), you're excluding code elements that contain spans. This is quite an advanced technique!

However, let's make sure we're not leaving any of our students behind. The :has() selector is relatively new and might not work in all browsers. Let's do a quick check:

If the compatibility isn't as wide as we'd like, we might need to consider a fallback. What do you think about adding a class to code elements without spans instead? This could be a good exercise in progressive enhancement!

app/client/packages/design-system/widgets/package.json (1)

31-32: Excellent addition, class! Let's discuss the new dependency.

Now, children, pay attention to lines 31 and 32. We've added a new tool to our toolkit: "remark-gfm". Can anyone tell me what GFM stands for? That's right, it's GitHub Flavored Markdown!

This addition is like giving our Markdown component a new set of colored pencils. It will allow us to support more advanced Markdown features, just like the ones you see on GitHub. Isn't that exciting?

Remember, the "^4.0.0" is like saying "any version from 4.0.0 up to, but not including, 5.0.0". It's important to specify versions in our package.json, just like it's important to label your school supplies!

Good job on this update! It aligns perfectly with our lesson plan of improving our Markdown capabilities.

app/client/packages/design-system/widgets/src/components/Text/src/Text.tsx (1)

Line range hint 1-70: Well done, class! Let's summarize our lesson for today.

We've learned about some important changes in our Text component:

  1. We switched from a p to a div, giving us more flexibility.
  2. We discussed how to make our component even more flexible by allowing different HTML elements.
  3. We looked at improving our text clamping to work better across different browsers.

Overall, the changes look good, but remember: in coding, as in life, there's always room for improvement!

The changes are approved, but I encourage you to consider the suggestions we've discussed. They will make our Text component even better!

Now, who wants to volunteer to implement these improvements? Don't all raise your hands at once!

app/client/packages/design-system/widgets/src/components/Markdown/stories/Markdown.stories.ts (3)

1-10: Well done, class! Your imports and metadata are spot on!

You've correctly imported the necessary components and types, and set up the metadata for your Storybook story. Keep up the good work!


10-10: A+ for your type definition, students!

You've correctly defined the Story type using StoryObj with the Markdown component type. This will ensure type safety in your story arguments.


12-13: Excellent work on your story structure, class!

You've correctly defined and exported the Default story with proper typing. The use of the 'args' property is a great way to pass props to your component in Storybook.

Also applies to: 61-62

app/client/packages/design-system/widgets/src/index.ts (1)

34-35: Well done, class! These additions look splendid!

Now, let's take a moment to appreciate these new exports, shall we? They're like fresh apples in our export basket!

  1. The Avatar component: Perfect for putting a face to a name in our digital classroom.
  2. The Markdown component: Just the tool we need for formatting our digital chalkboard.

These additions are in line with our lesson plan (PR objectives) and follow the same export pattern as their classmates (other components). Keep up the good work!

app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/ThreadMessage.tsx (2)

3-4: Well done on updating the imports, class!

I'm pleased to see you've made the switch to using components from our internal "@appsmith/wds" package. This is a step in the right direction for maintaining consistency across our codebase. Keep up the good work!


29-29: Simplified Markdown rendering, very good!

I see you've streamlined the Markdown rendering process. This is a nice simplification of our code. However, let's make sure we haven't lost any functionality in the process.

For your next assignment, please verify:

  1. Does the new Markdown component handle code highlighting correctly?
  2. Are all the features from the previous implementation still available?

Remember, simplicity is good, but not at the cost of functionality!

app/client/packages/design-system/widgets/src/components/Link/stories/Link.stories.tsx (1)

24-24: Well done on updating the link text, class!

I see you've changed the text of our link from "This is a link." to "Appsmith." This is a good improvement! It makes our example more relevant to our product. Remember, children, in web development, it's important to use meaningful text in our links. This helps users understand where the link will take them.

Can anyone tell me why this change might be beneficial for our Storybook documentation? Yes, that's right! It provides a clearer example of how our Link component might be used in the actual Appsmith application.

Keep up the good work! Don't forget to raise your hand if you have any questions about this change.

app/client/packages/design-system/widgets/src/components/AIChat/stories/AIChat.stories.tsx (3)

1-3: Class, pay attention to this new import!

Good job adding the useState hook! This addition shows that you're preparing to manage local state in our component. It's like adding a new tool to our coding toolbox. Remember, hooks are very useful for making our components more dynamic and interactive.


80-94: Class, observe this excellent example of markdown rendering!

Well done on adding this markdown code example to our WithHistory story! This addition serves as a perfect illustration of how our AIChat component can handle and display complex content, including code snippets. It's like showing a math problem with its solution - it helps everyone understand the full capabilities of our component.

Remember, class, when you're testing components that render markdown, it's crucial to include examples like this to ensure all formatting is displayed correctly.


24-29: Let's examine this new render function, class!

Excellent work implementing a render function with useState! This change makes our story more interactive, allowing us to see how the AIChat component behaves with changing prompts. It's like turning our static storybook into a living, breathing example!

However, I noticed you've disabled an ESLint rule. Can you explain why this was necessary? Remember, it's always better to understand and fix the underlying issue rather than disabling the rule. Let's discuss this after class if you need help resolving it.

To ensure we're following best practices, let's check if this ESLint disable comment is necessary:

✅ Verification successful

ESLint Disable Comment is Necessary

Great job implementing the interactive render function with useState! I've verified that the ESLint disable comment in AIChat.stories.tsx is indeed necessary since hooks are used within a non-component context. This ensures our linting remains accurate without suppressing valid warnings elsewhere.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the ESLint disable comment is necessary

# Test: Search for usage of hooks in story files
rg --type typescript 'useState|useEffect|useRef|useCallback|useMemo' app/client/packages/design-system/widgets/src/components/**/stories/*.stories.tsx

# Expected result: If other story files use hooks without the disable comment, 
# it might indicate that this disable comment is unnecessary.

Length of output: 2262


Script:

#!/bin/bash
# Description: Re-run the search with the corrected file type 'ts'.

rg --type ts 'useState|useEffect|useRef|useCallback|useMemo' app/client/packages/design-system/widgets/src/components/**/stories/*.stories.tsx

Length of output: 2490

app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css (3)

71-86: Excellent work on your paragraphs and lists, class!

Your paragraph and list styles show a good understanding of spacing and readability. The use of em for list item margin is a smart choice, as it will scale with the font size. Keep up the good work!


108-113: Excellent work on your blockquote styling, students!

Your blockquote styles provide a clear visual distinction for quoted content. The use of padding and a left border is a classic and effective approach. The consistent use of CSS variables for colors and spacing shows attention to detail. Keep up the good work!


35-38: Don't worry about those red marks, class. Sometimes our tools get a bit confused!

The static analysis tool has flagged a couple of areas in our CSS, but after careful review, I can assure you that these are false positives. The CSS syntax you've used, particularly with nesting, is correct and follows modern practices.

To double-check our CSS validity, let's run it through an online CSS validator:

This will help us confirm that our CSS is indeed valid and that we can safely ignore these particular static analysis warnings.

Also applies to: 113-114

🧰 Tools
🪛 Biome

[error] 35-37: Unexpected value or character.

Expected one of:

(parse)

app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx (3)

1-4: Great work on updating the imports to include the new components.

You've correctly imported ChatInput, Text, Avatar, Flex, and Icon from @appsmith/wds, which will be essential for the redesigned AIChat component.


65-71: Excellent integration of the ChatInput component.

You've properly passed the necessary props to ChatInput, which should enhance the user experience by handling input and submission seamlessly.


79-82: Nice addition of the user guidance message.

Providing users with a reminder that the LLM assistant can make mistakes is a thoughtful touch. It promotes responsible usage and sets appropriate expectations.


export const Code = (props: CodeProps) => {
const { children, className, ...rest } = props;
const match = /language-(\w+)/.exec(className ?? "");
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

Enhance the regular expression to match all language identifiers.

The current regex /language-(\w+)/ may not match language classes that include hyphens or numbers, such as language-jsx or language-csharp. Let's adjust the regex to accommodate these cases.

Apply this diff to improve the regex:

- const match = /language-(\w+)/.exec(className ?? "");
+ const match = /language-([a-zA-Z0-9-]+)/.exec(className ?? "");
📝 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
const match = /language-(\w+)/.exec(className ?? "");
const match = /language-([a-zA-Z0-9-]+)/.exec(className ?? "");

Comment on lines 27 to 53
<Flex alignItems="center" gap="spacing-3">
<Avatar
label="Appsmith AI"
size="medium"
src="https://app.appsmith.com/static/media/appsmith_logo_square.3867b1959653dabff8dc.png"
/>
<Text fontWeight={600} size="subtitle">
{chatTitle}
</Text>
</Flex>
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 refactoring the Avatar image source for better maintainability.

Using a hardcoded URL for the src prop in the Avatar component can lead to issues if the image location changes. It's advisable to import the image locally or manage it through your project's assets.

Here's how you might adjust the code:

+ import appsmithLogo from "path/to/assets/appsmith_logo_square.png";

...

<Avatar
  label="Appsmith AI"
  size="medium"
- src="https://app.appsmith.com/static/media/appsmith_logo_square.3867b1959653dabff8dc.png"
+ src={appsmithLogo}
/>

This approach ensures the image is bundled with your application and reduces dependencies on external URLs.

Committable suggestion was skipped due to low confidence.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (5)
app/client/packages/design-system/widgets/src/components/ChatInput/src/types.ts (1)

4-7: Well done, class! These additions are quite promising.

I'm pleased to see these new properties added to our ChatInputProps interface. They will certainly enhance the functionality of our ChatInput component. The onSubmit callback will allow us to handle user submissions effectively, while the isSubmitDisabled flag gives us control over the submit button's state. Excellent work on providing clear and concise comments for each property!

However, I have a small suggestion to make your documentation even better. For the isSubmitDisabled property, let's be more specific about its purpose.

Consider updating the comment for isSubmitDisabled to:

/** flag to disable the submit button when set to true */
isSubmitDisabled?: boolean;

This clarifies that the button is disabled when the flag is true, which could prevent confusion for future developers working with this interface.

app/client/packages/design-system/widgets/src/components/ChatInput/stories/ChatInput.stories.tsx (1)

70-74: Well done, class! A new story has been added to our Storybook.

The addition of the 'SubmitDisabled' story is a valuable contribution to our component testing. It allows us to visualize and interact with the ChatInput component when the submit action is disabled. This is an important scenario to cover in our UI testing.

However, to make this story even more educational, we could consider adding a brief description. This would help other developers understand the purpose of this particular story at a glance.

Here's a suggestion to enhance our story:

 export const SubmitDisabled: Story = {
+  parameters: {
+    docs: {
+      description: {
+        story: "This story demonstrates the ChatInput component with a disabled submit action.",
+      },
+    },
+  },
   args: {
     isSubmitDisabled: true,
   },
 };

Remember, clear documentation is like a well-organized lesson plan - it helps everyone learn and understand more effectively!

app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx (1)

59-87: A gold star for improving our chat interface!

You've done an excellent job restructuring the chat input area and adding a thoughtful warning message about AI reliability. The use of Flex components shows a good grasp of layout principles.

However, let's not forget about accessibility. To make our warning message even better, consider adding an aria-label to the Icon:

- <Icon name="alert-circle" size="small" />
+ <Icon name="alert-circle" size="small" aria-label="Warning" />

This small change will help screen reader users understand the purpose of the icon. Remember, class, accessibility is an important part of web development!

app/client/packages/design-system/widgets/src/components/ChatInput/src/ChatInput.tsx (2)

95-102: Well done on updating the handleKeyDown function!

Students, pay attention to how the handleKeyDown function has been updated. The addition of the isSubmitDisabled check is a great way to prevent submission when it's not allowed. Also, notice how the dependency array in useCallback has been correctly updated.

However, there's a small opportunity for improvement:

- if (Boolean(isSubmitDisabled)) return;
+ if (isSubmitDisabled) return;

Remember, in JavaScript, we don't need to explicitly convert to boolean here. It's a good habit to keep our code clean and simple!

🧰 Tools
🪛 Biome

[error] 95-95: Avoid redundant Boolean call

It is not necessary to use Boolean call when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant Boolean call

(lint/complexity/noExtraBooleanCast)


118-129: Excellent work on updating the suffix function!

Class, let's examine how the suffix function has been modified. The inclusion of isSubmitDisabled in the disabled state calculation for both IconButton variants is spot on. This ensures that the visual state of the button accurately reflects whether submission is allowed.

For consistency with our previous suggestion, we could simplify the boolean checks:

- isDisabled={Boolean(isDisabled) || Boolean(isSubmitDisabled)}
+ isDisabled={isDisabled || isSubmitDisabled}

This change would make our code a bit more concise while maintaining the same functionality. Remember, clarity and consistency are key in programming!

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 55e2537 and 90d4504.

📒 Files selected for processing (4)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx (3 hunks)
  • app/client/packages/design-system/widgets/src/components/ChatInput/src/ChatInput.tsx (3 hunks)
  • app/client/packages/design-system/widgets/src/components/ChatInput/src/types.ts (1 hunks)
  • app/client/packages/design-system/widgets/src/components/ChatInput/stories/ChatInput.stories.tsx (1 hunks)
🧰 Additional context used
🪛 Biome
app/client/packages/design-system/widgets/src/components/ChatInput/src/ChatInput.tsx

[error] 95-95: Avoid redundant Boolean call

It is not necessary to use Boolean call when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant Boolean call

(lint/complexity/noExtraBooleanCast)

🔇 Additional comments (6)
app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx (4)

1-3: Well done, class! You've tidied up your imports.

I'm pleased to see you've organized your imports more efficiently. You've removed unnecessary imports and added new components from the "@appsmith/wds" library. This is a good practice that helps keep our code clean and maintainable.


29-38: Class, we need to revisit our homework on image management.

While I appreciate the effort in structuring the header with the new Flex component, I must remind you of our previous lesson on managing image assets. The Avatar component is still using a hardcoded URL for its image source. Remember, children, this can lead to maintenance issues down the road.

Let's apply what we've learned:

+ import appsmithLogo from "path/to/assets/appsmith_logo_square.png";

...

<Avatar
  label="Appsmith AI"
  size="medium"
- src="https://app.appsmith.com/static/media/appsmith_logo_square.3867b1959653dabff8dc.png"
+ src={appsmithLogo}
/>

This way, we ensure our image is bundled with our application, making it more reliable and easier to manage. Don't forget to practice this in your future assignments!


41-41: Excellent use of our new Avatar component!

I'm glad to see you've applied our lesson on component reusability. By using the Avatar component for the username display, you've shown a good understanding of how to leverage our design system. Keep up the good work!


Line range hint 92-92: Excellent use of forwardRef, class!

I'm impressed to see you've wrapped our AIChat component with forwardRef. This is an advanced technique that allows our component to take a ref and pass it down to its children. It's particularly useful when we need to access or manipulate DOM elements directly.

By using forwardRef, you've made our AIChat component more flexible and reusable. Well done on applying this concept!

app/client/packages/design-system/widgets/src/components/ChatInput/src/ChatInput.tsx (2)

25-25: Good job adding the isSubmitDisabled prop!

Class, let's take a moment to appreciate the addition of the isSubmitDisabled prop. This is an excellent example of enhancing component flexibility. By separating the submit disabled state from the general disabled state, we're giving more control to the parent component. This is a valuable lesson in component design!


Line range hint 1-172: Outstanding work on enhancing the ChatInput component!

Class, let's recap the excellent improvements made to our ChatInput component:

  1. We've added a new isSubmitDisabled prop, giving us more granular control over the submit functionality.
  2. The handleKeyDown function now respects this new prop, preventing submission when it's not allowed.
  3. Our IconButtons in the suffix function correctly reflect the disabled state, considering both isDisabled and isSubmitDisabled.

These changes demonstrate a thoughtful approach to component design, enhancing both flexibility and user experience. The code remains clean and consistent, with only minor opportunities for simplification.

Great job on this update! It's a perfect example of how small, well-implemented changes can significantly improve a component's functionality.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (1)
app/client/packages/design-system/widgets/jest.config.js (1)

12-14: Now, class, let's turn our attention to the transformIgnorePatterns array.

This modification is crucial for our Jest configuration. The new pattern added to transformIgnorePatterns is designed to exclude the modules specified in esModules (in this case, "remark-gfm") from being ignored during transformation.

Here's what this change accomplishes:

  1. It allows Jest to transform the "remark-gfm" module, which would typically be ignored as part of node_modules.
  2. It maintains the default behavior for other modules in node_modules.

This change is necessary to ensure proper testing of components that rely on the "remark-gfm" package.

However, to enhance code readability, I suggest adding a comment explaining the purpose of this complex pattern. Here's an example:

transformIgnorePatterns: [
  // Allow transformation of specified modules (e.g., remark-gfm) while ignoring others in node_modules
  `[/\\\\]node_modules[/\\\\](?!${esModules}).+\\.(js|jsx|mjs|cjs|ts|tsx)$`,
],

This comment will help future developers understand the intention behind this configuration.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 90d4504 and 0c191f6.

📒 Files selected for processing (3)
  • app/client/packages/design-system/widgets/jest.config.js (2 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/tests/AIChat.test.tsx (0 hunks)
  • app/client/test/mocks/reactMarkdown.tsx (1 hunks)
💤 Files with no reviewable changes (1)
  • app/client/packages/design-system/widgets/src/components/AIChat/tests/AIChat.test.tsx
🧰 Additional context used
🔇 Additional comments (2)
app/client/test/__mocks__/reactMarkdown.tsx (1)

7-8: Excellent addition of the remark-gfm mock, class!

I'm pleased to see you've added a mock for the remark-gfm module. This is a crucial step in ensuring our tests run smoothly without depending on the actual GitHub Flavored Markdown functionality. Let's break down what's happening here:

  1. We're using jest.mock() to create a mock for the "remark-gfm" module.
  2. The mock is a function that returns nothing (undefined).

This approach is perfect for our testing environment. It allows us to import and use remark-gfm in our code without actually executing its functionality during tests. Well done!

For your homework, consider the following questions:

  1. Why might we want to mock remark-gfm in our tests?
  2. How does this mock differ from the react-markdown mock above it?

Keep up the good work!

app/client/packages/design-system/widgets/jest.config.js (1)

2-2: Class, let's examine this new constant declaration.

The new constant esModules is introduced to specify modules that should be transformed by Jest. In this case, it's set to include "remark-gfm", which is a package for GitHub Flavored Markdown support in remark.

The use of join("|") prepares this constant for use in a regular expression, which we'll see applied in the transformIgnorePatterns array. This addition allows for more flexible configuration of Jest's module transformation behavior.

@@ -75,7 +49,7 @@ export const ThreadMessage = ({
</div>
) : (
<>
<UserAvatar className={styles.userAvatar} username={username} />
<Avatar label={username} />
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Created a separate avatar component instead of this creating this locally to ai chat.
Reason: Avatar is a generally a common DS component.

border: 1px solid var(--color-bd-elevation-1);
/* TODO: --bg-elevation-1 doesn't exists. Define it */
background: var(--bg-elevation-1, #fbfcfd);
background-color: var(--color-bg-elevation-3);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added these values because of our concept of elevation.

}

/* Headings */
[data-component="h1"] {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

had to use these selectorsas as our text component cant render h1, h2 or any other element except div.

@@ -28,7 +28,8 @@
"lodash": "*",
"react-aria-components": "^1.2.1",
"react-markdown": "^9.0.1",
"react-syntax-highlighter": "^15.5.0"
"react-syntax-highlighter": "^15.5.0",
"remark-gfm": "^4.0.0"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is needed to handle the table in markdown.

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 (1)
app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx (1)

74-86: Let's examine the new warning message in our chat interface.

Class, I'm pleased to see that you've added a warning message about the reliability of AI responses. This is an important addition for user awareness and responsible AI usage.

However, I have a small suggestion to improve this further. Can anyone think of how we might make this message more accessible?

Here's a hint: We could add an aria-label to the Icon component to ensure screen readers can understand its purpose. Like this:

<Icon name="alert-circle" size="small" aria-label="Warning" />

Who can tell me why this might be important for some of our users?

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 0db6233 and 4af743d.

📒 Files selected for processing (3)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx (3 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Code.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Code.tsx
🧰 Additional context used
🪛 Biome
app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css

[error] 35-37: Unexpected value or character.

Expected one of:

(parse)


[error] 111-112: Expected a qualified rule, or an at rule but instead found '}'.

Expected a qualified rule, or an at rule here.

(parse)

🔇 Additional comments (4)
app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx (3)

32-37: Excellent work on improving our component's header!

Class, I want you all to take a look at how your classmate has restructured the header section. They've used the Flex, Avatar, and Text components from our design system. This is a great example of how we can create consistent and maintainable user interfaces.

Keep up the good work! Can anyone tell me why using these pre-built components might be beneficial for our project?


Line range hint 40-44: Let's examine the changes to our username display.

Students, notice how we've updated our username display. We've replaced the custom UserAvatar component with the Avatar component from our design system. This is a good example of standardizing our components across the application.

Can anyone explain why using a standardized Avatar component might be beneficial for our project's consistency and maintainability?


58-73: Let's discuss the improvements in our chat input section.

Class, I want you to pay attention to how we've simplified our chat input. We've replaced the old form structure with a Flex container and a ChatInput component. This new approach is more concise and easier to understand.

Can anyone tell me why this new structure might be more maintainable? And how does it improve the readability of our code?

app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css (1)

1-112: Excellent work on styling the Markdown components

Well done, students! The CSS styles for the Markdown component are comprehensive and well-structured. You've thoughtfully covered various elements, ensuring consistent and visually appealing formatting throughout. Keep up the great work!

🧰 Tools
🪛 Biome

[error] 35-37: Unexpected value or character.

Expected one of:

(parse)


[error] 111-112: Expected a qualified rule, or an at rule but instead found '}'.

Expected a qualified rule, or an at rule here.

(parse)

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

🧹 Outside diff range and nitpick comments (3)
app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx (2)

Line range hint 40-44: Let's discuss our username display, class.

I see you've made some changes to how we display the user's avatar and name. This is good progress! You've replaced the UserAvatar component with the Avatar component, which brings consistency with how we display the AI's avatar.

However, I have a small suggestion to make this even better. Can anyone tell me what we might add to improve accessibility?

Here's a hint: We should always think about users who might be using screen readers. Let's add an aria-label to our Avatar component. Try updating it like this:

<Avatar label={username} aria-label={`Avatar for ${username}`} />

Can someone explain why this might be helpful for some of our users?


74-86: Class, let's discuss our new warning message.

I'm very impressed with the addition of this warning message. It's crucial that we inform our users about the potential limitations of AI responses. You've done a great job using a Flex container to structure this message, and the use of an icon really helps it stand out.

However, I have a small suggestion to make this even better. Can anyone tell me how we might improve this for users who rely on screen readers?

Here's a hint: Screen readers might not automatically read the icon. Let's add an aria-label to our Icon component. Try updating it like this:

<Icon name="alert-circle" size="small" aria-label="Warning" />

Can someone explain why this might be helpful for some of our users?

Remember, class, in web development, we always want to ensure our applications are accessible to all users. Great job on adding this important warning message!

app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css (1)

75-86: Your list styles are coming along nicely, class!

I appreciate the thought you've put into spacing and structure for your lists. The use of the :is() pseudo-class in line 76 is a modern approach, but let's consider our friends using older browsers.

Here's a little homework for you:

/* Fallback for browsers that don't support :is() */
ul, ol {
  margin-top: var(--inner-spacing-2);
  margin-bottom: var(--inner-spacing-4);
  padding-left: 0;
}

/* Modern browsers will use this */
:is(ul, ol) {
  margin-top: var(--inner-spacing-2);
  margin-bottom: var(--inner-spacing-4);
  padding-left: 0;
}

This ensures compatibility across different browser versions. What do you think about this approach?

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 4af743d and ecd66b0.

📒 Files selected for processing (4)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx (3 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Heading.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css (1 hunks)
  • app/client/test/mocks/reactMarkdown.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Heading.tsx
  • app/client/test/mocks/reactMarkdown.tsx
🧰 Additional context used
🪛 Biome
app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css

[error] 35-37: Unexpected value or character.

Expected one of:

(parse)


[error] 111-112: Expected a qualified rule, or an at rule but instead found '}'.

Expected a qualified rule, or an at rule here.

(parse)

🔇 Additional comments (6)
app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx (2)

32-37: Excellent work on our header, class!

I'm impressed with the changes you've made to our header section. Let's review what you've done:

  1. You've used the Flex component to align items. This is a great way to ensure consistent spacing and alignment.
  2. The Avatar component is now being used to display the AI's image. This is much more professional than a simple image tag.
  3. You've replaced the ChatTitle with a Text component, which is more in line with our design system.

These changes will make our chat interface look more polished and professional. Can anyone tell me why using components from our design system is beneficial?

Keep up the good work, students! Remember, consistency in design leads to a better user experience.


58-73: Let's examine our new chat input, class.

I'm pleased to see the improvements you've made to our chat input section. You've replaced the old form structure with a more flexible Flex container and introduced a new ChatInput component. This is a step in the right direction!

The new structure looks cleaner and more aligned with our design system. I particularly like how you've simplified the submit logic by using the onSubmit prop of the ChatInput component.

However, I have a question for the class: Can anyone tell me what functionality the ChatInput component might be encapsulating? What benefits might this bring to our AIChat component?

Remember, class, when we use specialized components like ChatInput, we're often able to simplify our parent components and make our code more modular and reusable. Can anyone think of other benefits this approach might bring?

app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css (4)

40-69: Excellent work on your heading hierarchy, students!

Your use of data attributes for heading styles is intriguing. It suggests you're using a custom rendering approach for your Markdown content. Could you explain to the class why you chose this method over traditional HTML tags?

The margin settings for each heading level create a clear visual hierarchy, which is crucial for readability. Well done!

Can you share with the class how this custom rendering approach benefits your project?


71-73: Good job on keeping your paragraphs simple and clean!

Your paragraph styling is straightforward and effective. The bottom margin ensures proper spacing between paragraphs, which is essential for readability.


93-104: Your code block styling is looking sharp, class!

I'm impressed with how you've styled your code blocks. The use of background color, border radius, and outline creates a clear visual distinction from regular text. The overflow property ensures long lines of code are manageable.

Your use of CSS variables for colors and spacing is excellent – it maintains consistency with the rest of your design system. Keep up the good work!


106-112: Excellent work on your blockquotes, students!

Your blockquote styling effectively sets apart quoted content from the main text. The left border and padding create a clear visual distinction.

Now, you might notice that our static analysis tool is throwing a bit of a tantrum about lines 111-112. Don't worry – this is likely a false alarm. The tool is probably confused by the nested nature of our CSS. As long as your styles are working as expected in the browser, you can safely ignore this warning.

Remember, tools are here to help us, but they don't always understand the full context of our code. It's important to use your judgment and test your styles in real-world scenarios.

🧰 Tools
🪛 Biome

[error] 111-112: Expected a qualified rule, or an at rule but instead found '}'.

Expected a qualified rule, or an at rule here.

(parse)

Comment on lines 1 to 11
import type { ForwardedRef } from "react";
import React, { forwardRef } from "react";
import { ChatInput, Text, Avatar, Flex, Icon } from "@appsmith/wds";

import styles from "./styles.module.css";
import { ThreadMessage } from "./ThreadMessage";
import type { AIChatProps, ChatMessage } from "./types";
import { UserAvatar } from "./UserAvatar";

const MIN_PROMPT_LENGTH = 3;
// This image src might come from props in the future. Temp constant for now.
const LOGO =
"https://app.appsmith.com/static/media/appsmith_logo_square.3867b1959653dabff8dc.png";
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

Class, let's discuss our imports and constants.

Children, I see you've made some changes to our imports. It's good to see you're using more modular components from our design system. This will make our code more consistent and easier to maintain.

Now, let's talk about the LOGO constant on lines 10-12. While it's good to use constants, can anyone tell me why hardcoding a URL might not be the best practice?

Here's a little homework assignment for you:

  1. Instead of using a URL, try importing the logo as a local asset.
  2. Use the imported asset in your component.

Here's an example of how you might do this:

import appsmithLogo from "path/to/assets/appsmith_logo_square.png";

// Later in your component
<Avatar label="Appsmith AI" size="large" src={appsmithLogo} />

Can anyone explain why this might be a better approach? Remember, in software development, we always want to make our code as maintainable as possible!

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

🧹 Outside diff range and nitpick comments (12)
app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Paragraph.tsx (2)

5-7: Excellent type definition, but let's make it even better!

Your 'ParagraphProps' type is well-structured, combining React's HTMLDivElement attributes with ExtraProps from react-markdown. This shows a good understanding of TypeScript's type system.

However, to improve readability, consider breaking this type definition into multiple lines:

type ParagraphProps = 
  & React.ClassAttributes<HTMLDivElement>
  & React.HTMLAttributes<HTMLDivElement>
  & ExtraProps;

This format makes it easier for your classmates to read and understand each part of the type intersection.


9-22: A gold star for your component definition!

Your 'p' component is well-structured and follows React best practices. Here's what you've done right:

  1. Used a functional component
  2. Properly destructured props
  3. Utilized the Text component from your design system
  4. Correctly forwarded the 'ref'
  5. Added a 'data-component' attribute for easier testing and debugging

To make your code even more robust, consider adding prop types:

import PropTypes from 'prop-types';

// ... your component definition ...

p.propTypes = {
  children: PropTypes.node.isRequired,
  ref: PropTypes.oneOfType([
    PropTypes.func,
    PropTypes.shape({ current: PropTypes.instanceOf(Element) })
  ])
};

This will help catch potential errors early and serve as documentation for other developers.

app/client/packages/design-system/widgets/src/components/Avatar/src/Avatar.tsx (3)

1-7: Let's tidy up our imports, class!

Good job on importing all the necessary tools for our Avatar component! However, just like we organize our school supplies, let's group our imports together. Can you move the import for AvatarProps up with the other imports? This will make our code look neater and easier to read.

Here's how it should look:

import React from "react";
import { clsx } from "clsx";
import { Text } from "@appsmith/wds";
import type { AvatarProps } from "./types";
import { getTypographyClassName } from "@appsmith/wds-theming";

import styles from "./styles.module.css";

Remember, keeping our code organized is like keeping our desk tidy - it helps us work better!


22-37: Excellent work on your Avatar display, but let's polish it a bit more!

I'm impressed with how you've structured your Avatar component, class! You've used conditional rendering effectively, just like choosing the right answer in a multiple-choice question. Your use of clsx for managing classes is spot on, and I'm glad to see you remembered to include an alt attribute for accessibility.

However, I noticed a small opportunity for improvement. Remember when we learned about truthy and falsy values? We can apply that knowledge here!

Let's simplify line 28. Instead of:

{Boolean(src) ? (

We can write:

{src ? (

This is like simplifying a math equation - it does the same thing, but in a cleaner way. Keep up the great work!

🧰 Tools
🪛 Biome

[error] 28-28: Avoid redundant Boolean call

It is not necessary to use Boolean call when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant Boolean call

(lint/complexity/noExtraBooleanCast)


9-11: A gold star for your Avatar component structure!

Class, I'm thrilled to see how well you've structured your Avatar component! You've used prop destructuring, which is like unpacking your backpack efficiently at the start of class. The way you're handling different sizes with a data attribute is clever - it's like having adjustable desk sizes for different students!

To make your component even more robust, let's add some default values and prop types. It's like having a seating chart for your props! Here's a suggestion:

import PropTypes from 'prop-types';

// ... rest of the imports

export const Avatar = ({ className = '', label = '', size, src, ...rest }: AvatarProps) => {
  // ... rest of the component
}

Avatar.propTypes = {
  className: PropTypes.string,
  label: PropTypes.string.isRequired,
  size: PropTypes.oneOf(['small', 'medium', 'large']),
  src: PropTypes.string,
};

This way, we're making sure everyone knows exactly where they should sit in our component classroom!

app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/ThreadMessage.tsx (1)

10-19: Excellent work on refactoring the props, students!

You've done a splendid job reorganizing how we handle our props. By destructuring directly in the function parameters, you've made our code cleaner and easier to read. It's like you've tidied up your room - everything is visible at a glance!

I particularly appreciate that you've set a default value for promptSuggestions. That's very thoughtful of you - it's like always having a spare pencil, just in case!

Here's a little homework for you to think about: Could we make this even better by using TypeScript's optional chaining for onApplyAssistantSuggestion? It might look something like this:

onApplyAssistantSuggestion?: (suggestion: string) => void,

What do you think? Would this make our code even more robust?

app/client/packages/design-system/widgets/src/components/AIChat/stories/AIChat.stories.tsx (2)

24-29: Let's examine your work on the board, shall we?

You've made some interesting changes to our Main story:

  1. You've introduced a render function that uses the useState hook. This is a great way to manage the prompt state dynamically. Good thinking!

  2. You're passing the prompt state and setPrompt function to the AIChat component. This creates a nice two-way binding. Excellent!

However, I noticed you've used an eslint-disable comment. While this solves the immediate issue, it's generally better to avoid disabling linting rules. Let's think about why this rule is triggering and if there's a way to restructure our code to comply with it.

Can you research the 'react-hooks/rules-of-hooks' rule and see if there's a way to use the useState hook without triggering this warning? This could be a good learning opportunity for the whole class!


80-94: A gold star for this addition!

You've added a new message to our WithHistory story that includes a markdown code example. This is an excellent way to demonstrate the AIChat component's ability to render more complex content, including code snippets. Well done!

To make this even better, consider the following suggestion:

Why don't we add a few more examples of different markdown elements? This could include:

  • A bulleted list
  • A numbered list
  • A table
  • An image (if supported)

This would give us a comprehensive showcase of the markdown rendering capabilities. What do you think? Would you like to expand on this example for extra credit?

app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css (1)

71-86: Your paragraph and list styles are on point!

The paragraph styling with a bottom margin will ensure good spacing between text blocks. For lists, you've done a great job using the :is() selector to apply styles to both unordered and ordered lists efficiently. The positioning and margins for list items will create a clean, easy-to-read layout.

One small suggestion: Consider adding a left padding to the lists to ensure bullet points or numbers don't overflow on smaller screens. What do you think about adding padding-left: 1.5em; to the ul, ol selector?

app/client/packages/design-system/widgets/src/components/ChatInput/src/ChatInput.tsx (3)

25-25: Excellent addition to your component's props, students!

Adding the isSubmitDisabled prop is a smart move. It gives us more control over when users can submit their input. However, let's not forget the importance of documentation. Can you add a comment explaining what this prop does and when to use it? It'll help your classmates understand your code better.

Would you like me to provide an example of how to document this prop?


95-96: Well done on updating the handleKeyDown function, class!

You've successfully integrated the isSubmitDisabled check into your function. That's great thinking! However, let's clean up our code a bit. The Boolean call on line 95 is redundant. Remember, in JavaScript, we can use the double negation operator !! or simply the value itself in a boolean context.

Let's refactor it like this:

if (isSubmitDisabled) return;

This makes our code cleaner and more efficient. Keep up the good work!

Also applies to: 102-102

🧰 Tools
🪛 Biome

[error] 95-95: Avoid redundant Boolean call

It is not necessary to use Boolean call when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant Boolean call

(lint/complexity/noExtraBooleanCast)


118-118: Excellent work on updating the suffix function, students!

You've done a great job incorporating the isSubmitDisabled check into your button's disabled state. This ensures that the submit button responds correctly to both general disability and specific submit disability.

To make your code even clearer, consider creating a separate variable for the disabled state. For example:

const isButtonDisabled = isDisabled || isSubmitDisabled;

// Then use it in both places:
isDisabled={isButtonDisabled}

This approach makes the logic more readable and reduces repetition. What do you think about this suggestion?

Also applies to: 125-129

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between ecd66b0 and 60d12dc.

⛔ Files ignored due to path filters (1)
  • app/client/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (42)
  • app/client/packages/design-system/widgets/jest.config.js (2 hunks)
  • app/client/packages/design-system/widgets/package.json (1 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx (4 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/ChatTitle.tsx (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/index.ts (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/styles.module.css (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/types.ts (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/ThreadMessage.tsx (3 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/UserAvatar.tsx (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/index.ts (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/styles.module.css (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/types.ts (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/styles.module.css (1 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/stories/AIChat.stories.tsx (3 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/tests/AIChat.test.tsx (0 hunks)
  • app/client/packages/design-system/widgets/src/components/Avatar/index.ts (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Avatar/src/Avatar.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Avatar/src/index.ts (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Avatar/src/styles.module.css (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Avatar/src/types.ts (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Avatar/stories/Avatar.stories.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/ChatInput/src/ChatInput.tsx (4 hunks)
  • app/client/packages/design-system/widgets/src/components/ChatInput/src/types.ts (1 hunks)
  • app/client/packages/design-system/widgets/src/components/ChatInput/stories/ChatInput.stories.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Link/src/index.ts (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Link/stories/Link.stories.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/index.ts (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/Markdown.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/components.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/index.ts (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Code.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Heading.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Link.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/List.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Paragraph.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/types.ts (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/stories/Markdown.stories.ts (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Text/src/Text.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/index.ts (1 hunks)
  • app/client/packages/storybook/.storybook/preview-head.html (1 hunks)
  • app/client/test/mocks/reactMarkdown.tsx (1 hunks)
💤 Files with no reviewable changes (9)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/ChatTitle.tsx
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/index.ts
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/styles.module.css
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/types.ts
  • app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/UserAvatar.tsx
  • app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/index.ts
  • app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/styles.module.css
  • app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/types.ts
  • app/client/packages/design-system/widgets/src/components/AIChat/tests/AIChat.test.tsx
🚧 Files skipped from review as they are similar to previous changes (25)
  • app/client/packages/design-system/widgets/jest.config.js
  • app/client/packages/design-system/widgets/package.json
  • app/client/packages/design-system/widgets/src/components/Avatar/index.ts
  • app/client/packages/design-system/widgets/src/components/Avatar/src/index.ts
  • app/client/packages/design-system/widgets/src/components/Avatar/src/styles.module.css
  • app/client/packages/design-system/widgets/src/components/Avatar/src/types.ts
  • app/client/packages/design-system/widgets/src/components/Avatar/stories/Avatar.stories.tsx
  • app/client/packages/design-system/widgets/src/components/ChatInput/src/types.ts
  • app/client/packages/design-system/widgets/src/components/ChatInput/stories/ChatInput.stories.tsx
  • app/client/packages/design-system/widgets/src/components/Link/src/index.ts
  • app/client/packages/design-system/widgets/src/components/Link/stories/Link.stories.tsx
  • app/client/packages/design-system/widgets/src/components/Markdown/index.ts
  • app/client/packages/design-system/widgets/src/components/Markdown/src/Markdown.tsx
  • app/client/packages/design-system/widgets/src/components/Markdown/src/components.tsx
  • app/client/packages/design-system/widgets/src/components/Markdown/src/index.ts
  • app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Code.tsx
  • app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Heading.tsx
  • app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Link.tsx
  • app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/List.tsx
  • app/client/packages/design-system/widgets/src/components/Markdown/src/types.ts
  • app/client/packages/design-system/widgets/src/components/Markdown/stories/Markdown.stories.ts
  • app/client/packages/design-system/widgets/src/components/Text/src/Text.tsx
  • app/client/packages/design-system/widgets/src/index.ts
  • app/client/packages/storybook/.storybook/preview-head.html
  • app/client/test/mocks/reactMarkdown.tsx
🧰 Additional context used
🪛 Biome
app/client/packages/design-system/widgets/src/components/Avatar/src/Avatar.tsx

[error] 28-28: Avoid redundant Boolean call

It is not necessary to use Boolean call when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant Boolean call

(lint/complexity/noExtraBooleanCast)

app/client/packages/design-system/widgets/src/components/ChatInput/src/ChatInput.tsx

[error] 95-95: Avoid redundant Boolean call

It is not necessary to use Boolean call when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant Boolean call

(lint/complexity/noExtraBooleanCast)

app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css

[error] 35-37: Unexpected value or character.

Expected one of:

(parse)


[error] 111-112: Expected a qualified rule, or an at rule but instead found '}'.

Expected a qualified rule, or an at rule here.

(parse)

🔇 Additional comments (16)
app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Paragraph.tsx (1)

1-3: Well done on your imports, class!

You've shown a good understanding of module imports. The named imports from 'react' are precise, and importing the Text component from '@appsmith/wds' demonstrates proper use of the design system. The ExtraProps type from 'react-markdown' will be useful for our custom type definition.

app/client/packages/design-system/widgets/src/components/AIChat/src/styles.module.css (3)

3-6: Well done, class! These changes to the .root class are a step in the right direction.

Let's review what we've learned:

  1. The new background color uses a variable, which is good for maintaining consistency.
  2. The border-radius and outline properties create a more defined appearance.
  3. The overflow property will help keep our content neat and tidy.

These changes align well with our lesson on elevation in design. Keep up the good work!


Line range hint 9-15: Class, let's discuss the changes to our .header.

I noticed that you've removed the background property from the .header class. This is an interesting choice! Can you explain your reasoning?

Is it your intention to allow the root background to show through? If so, this could create a nice, unified look for our AI chat component.

Remember, it's important to always consider how our changes affect the overall design. Let's have a quick discussion about this in our next class!


Line range hint 1-31: Class, I have a question about something that's missing from our stylesheet.

I've noticed that the .promptForm class has been completely removed from our CSS. This is quite a significant change!

Can someone explain why we've decided to remove this class? Are we no longer using a prompt form in our AI chat component? Or have we moved this styling elsewhere?

It's crucial that we understand the reasoning behind such changes. This helps us maintain a clear and organized codebase. Let's discuss this in our next code review session!

app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/ThreadMessage.tsx (2)

8-8: Nice adjustment to the import statement!

I see you've tidied up the import for AssistantSuggestionButton. It's like you've straightened up your desk - everything in its right place! Keep up the good work in keeping our code neat and organized.


52-52: Excellent application of our design system, class!

I'm thrilled to see you've implemented the Avatar component from our design system. It's like you've taken the building blocks we provided and constructed something beautiful! This change not only makes our code more consistent but also more reusable across our application.

I remember in our last class (or should I say, in the previous review), we discussed creating a separate Avatar component. You've done exactly that, and I'm proud of how you've applied that feedback. It's like you've not just listened to the lesson, but really understood and applied it!

One small note: we've changed 'username' to 'label'. Can anyone tell me why this might be a good change? Think about how this makes our Avatar component more flexible for different use cases.

app/client/packages/design-system/widgets/src/components/AIChat/stories/AIChat.stories.tsx (1)

3-3: Very good, class! You've imported a useful tool.

I see you've added the useState hook from React. This is an excellent addition that will allow us to manage state in our functional components. Well done!

app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css (4)

40-69: Well done on your heading hierarchy, students!

Your use of data attributes for headings is a clever workaround for the rendering limitations of your text component. The spacing for each heading level is well-considered, with larger margins for higher-level headings creating a clear visual hierarchy. This will help readers easily navigate through the content.

Keep up the good work!


93-104: Your code block styling is top-notch!

The distinct background color, border radius, and outline for code blocks will make them stand out nicely from the regular text. Good job on adding the overflow: auto property – this will ensure that long lines of code are properly handled without breaking your layout.

The margins for pre-formatted text will provide good spacing around code blocks. Well done!


106-111: Excellent work on your blockquote styling!

Your blockquote styles will create a clear visual distinction from the regular text. The left border and padding will make quoted content stand out, making it easier for readers to identify important excerpts or citations.

The consistent use of CSS variables for colors and spacing is commendable. It will make future updates and maintenance much easier. Keep up the good work!


1-112: Overall, an excellent job on your Markdown styles!

Class, your CSS module for Markdown styling is well-structured and thoughtfully designed. The consistent use of CSS variables throughout the file is commendable – it will make future updates and theme changes much easier.

Don't worry about the static analysis hint regarding the unexpected closing brace. This appears to be a false positive. Your closing brace on line 112 is correct and necessary to close the .markdown class.

To further improve this file, consider:

  1. Adding comments to explain the purpose of each major section (tables, headings, lists, etc.).
  2. Grouping related styles together (e.g., all text-related styles in one section).

These small changes will make your already great code even more maintainable. Keep up the excellent work!

🧰 Tools
🪛 Biome

[error] 35-37: Unexpected value or character.

Expected one of:

(parse)


[error] 111-112: Expected a qualified rule, or an at rule but instead found '}'.

Expected a qualified rule, or an at rule here.

(parse)

app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx (4)

Line range hint 14-31: Very good, class! Let's review our component props.

I'm pleased to see that you've maintained the structure of our component's props. This shows good consistency and will help keep our API stable. Remember, children, when we're working on a component that others might use, it's important to think carefully before changing how it accepts information.

Keep up the good work!


56-56: Excellent simplification, class!

I'm impressed to see how you've simplified our user avatar display. By replacing the UserAvatar component with the Avatar component from our design system, you've shown a good understanding of code reusability.

Can anyone tell me why using components from our design system is beneficial? That's right - it helps maintain consistency across our application and makes our code more maintainable.

Keep up the good work, and always look for opportunities to simplify and standardize our code!


74-102: Let's review our chat input section, class.

I'm very pleased with the changes you've made here. You've shown great progress in using our design system components and creating a more flexible layout.

First, let's talk about how you've replaced the form structure with a Flex container. Can anyone tell me why this might be beneficial? That's right - it gives us more control over the layout and makes our code more consistent with the rest of our application.

I also see you've used the ChatInput component instead of a simple TextArea. This is excellent use of our design system, children. It ensures consistency and might provide additional features specific to chat interactions.

Lastly, I want to commend you on adding the warning message about the LLM assistant. This shows good consideration for our users, reminding them to verify information. Well done!

Keep up this thoughtful approach to component design. You're all becoming excellent software engineers!


105-105: Class, let's discuss this important change in our export statement.

I'm very pleased to see that you've wrapped our AIChat component with forwardRef before exporting it. This is an advanced React technique, and I'm proud to see you applying it.

Can anyone tell the class why we might want to use forwardRef? That's right - it allows our component to take a ref and pass it to a child component. This is especially useful when we want to imperatively access or manipulate a DOM element inside our component.

This change makes our AIChat component more flexible and reusable. Excellent work! Keep exploring these advanced React concepts.

app/client/packages/design-system/widgets/src/components/ChatInput/src/ChatInput.tsx (1)

12-12: Good job on updating the imports, class!

I see you've added some new React hooks to your toolkit. That's excellent! These hooks will give you more power and flexibility in your component. Keep up the good work!

Comment on lines +12 to +20
const getLabelInitials = (label: string) => {
const names = label.split(" ");

if (names.length === 1) {
return `${names[0].charAt(0)}`;
}

return `${names[0].charAt(0)}${names[1]?.charAt(0)}`;
};
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

Let's make our initial-making machine more robust!

Great job on creating a function to get those tricky initials, class! However, just like we don't want to rewrite our notes every time we open our notebook, we don't want to recreate this function on every render. Let's move it outside our component.

Also, remember when we talked about being prepared for surprises? Let's add some safeguards for unexpected inputs.

Here's an improved version for you to study:

const getLabelInitials = (label: string): string => {
  if (!label || typeof label !== 'string') return '';
  
  const names = label.trim().split(/\s+/);
  
  if (names.length === 0) return '';
  if (names.length === 1) return names[0].charAt(0).toUpperCase();
  
  return `${names[0].charAt(0)}${names[1].charAt(0)}`.toUpperCase();
};

export const Avatar = (props: AvatarProps) => {
  // ... rest of the component
}

This way, our function is like a well-prepared lesson plan - ready to handle whatever comes its way!

Comment on lines 3 to 4
import { Flex, Text } from "@appsmith/wds";
import { Avatar, Markdown } from "@appsmith/wds";
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

SyntaxHighlighter Still Present in Code.tsx

I've noticed that SyntaxHighlighter is still being used in app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Code.tsx. To maintain consistency with our design system, please update this component to utilize the updated markdown components from @appsmith/wds.

🔗 Analysis chain

Good job updating the imports, class!

I see you've made some changes to our import statements. You've brought in some new friends from the "@appsmith/wds" package. This is a step in the right direction, as it helps us use our design system consistently.

However, I noticed we've said goodbye to our old pal SyntaxHighlighter. Can you raise your hand and tell me how we plan to handle code highlighting now? We wouldn't want our code examples to look plain and boring, would we?

Let's do a quick check to see if we're still using SyntaxHighlighter somewhere else:


Let's adjust our approach to accurately check for any remaining usage of SyntaxHighlighter. Please run the following script:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining usage of SyntaxHighlighter

rg --type typescript --type javascript 'SyntaxHighlighter'

Length of output: 93


Script:

#!/bin/bash
# Description: Check for any remaining usage of SyntaxHighlighter in .ts and .tsx files

rg 'SyntaxHighlighter' -g '*.ts' -g '*.tsx'

Length of output: 429

Comment on lines 1 to 38
.markdown {
color: var(--color-fg);

table {
border: var(--border-width-1) solid var(--color-bd);
border-collapse: separate;
border-radius: var(--border-radius-elevation-3);
border-spacing: 0px;
overflow: hidden;
}

tr {
display: table-row;
vertical-align: inherit;
border-color: inherit;
}

th,
td {
padding: var(--inner-spacing-1) var(--inner-spacing-2);
text-align: left;
vertical-align: top;
border-bottom: var(--border-width-1) solid var(--color-bd);
border-right: var(--border-width-1) solid var(--color-bd);
}

:is(td, th):last-child {
border-right: none;
}

th {
background-color: var(--color-bg-neutral-subtle);
}

thead:last-child tr:last-child th,
tbody:last-child tr:last-child td {
border-bottom: none;
}
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

⚠️ Potential issue

Excellent work on your table styles, class! But let's fix a small error.

Your table styling is quite comprehensive and makes good use of CSS variables for consistency. It's clear you've put thought into creating a cohesive design. However, we need to make a small correction. On lines 35-38, there's a syntax error in your CSS selectors. Let's fix that together:

-thead:last-child tr:last-child th,
-tbody:last-child tr:last-child td {
+thead:last-child > tr:last-child > th,
+tbody:last-child > tr:last-child > td {
   border-bottom: none;
}

This change ensures we're correctly targeting the last cells in the last row of the table header and body.

Also, a quick note on line 27: while using the :is() pseudo-class is a modern and efficient approach, we should consider adding a fallback for older browsers that might not support it. Can you think of how we might do that?

📝 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
.markdown {
color: var(--color-fg);
table {
border: var(--border-width-1) solid var(--color-bd);
border-collapse: separate;
border-radius: var(--border-radius-elevation-3);
border-spacing: 0px;
overflow: hidden;
}
tr {
display: table-row;
vertical-align: inherit;
border-color: inherit;
}
th,
td {
padding: var(--inner-spacing-1) var(--inner-spacing-2);
text-align: left;
vertical-align: top;
border-bottom: var(--border-width-1) solid var(--color-bd);
border-right: var(--border-width-1) solid var(--color-bd);
}
:is(td, th):last-child {
border-right: none;
}
th {
background-color: var(--color-bg-neutral-subtle);
}
thead:last-child tr:last-child th,
tbody:last-child tr:last-child td {
border-bottom: none;
}
.markdown {
color: var(--color-fg);
table {
border: var(--border-width-1) solid var(--color-bd);
border-collapse: separate;
border-radius: var(--border-radius-elevation-3);
border-spacing: 0px;
overflow: hidden;
}
tr {
display: table-row;
vertical-align: inherit;
border-color: inherit;
}
th,
td {
padding: var(--inner-spacing-1) var(--inner-spacing-2);
text-align: left;
vertical-align: top;
border-bottom: var(--border-width-1) solid var(--color-bd);
border-right: var(--border-width-1) solid var(--color-bd);
}
:is(td, th):last-child {
border-right: none;
}
th {
background-color: var(--color-bg-neutral-subtle);
}
thead:last-child > tr:last-child > th,
tbody:last-child > tr:last-child > td {
border-bottom: none;
}
🧰 Tools
🪛 Biome

[error] 35-37: Unexpected value or character.

Expected one of:

(parse)

Comment on lines 1 to 11
import { Avatar, Button, ChatInput, Flex, Icon, Text } from "@appsmith/wds";
import type { ForwardedRef } from "react";
import React, { forwardRef } from "react";
import { ChatDescriptionModal } from "./ChatDescriptionModal";
import { ChatTitle } from "./ChatTitle";
import styles from "./styles.module.css";
import { ThreadMessage } from "./ThreadMessage";
import type { AIChatProps, ChatMessage } from "./types";
import { UserAvatar } from "./UserAvatar";

const MIN_PROMPT_LENGTH = 3;
const LOGO =
"https://app.appsmith.com/static/media/appsmith_logo_square.3867b1959653dabff8dc.png";
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

Class, let's discuss our imports and constants.

Children, I see you've made some changes to our imports. It's good to see you're using more modular components from our design system. This will make our code more consistent and easier to maintain.

Now, let's talk about the LOGO constant on lines 10-11. While it's good to use constants, can anyone tell me why hardcoding a URL might not be the best practice?

Here's a little homework assignment for you:

  1. Instead of using a URL, try importing the logo as a local asset.
  2. Use the imported asset in your component.

Here's an example of how you might do this:

import appsmithLogo from "path/to/assets/appsmith_logo_square.png";

// Later in your component
<Avatar label="Appsmith AI" size="large" src={appsmithLogo} />

Can anyone explain why this might be a better approach? Remember, in software development, we always want to make our code as maintainable as possible!

Comment on lines 42 to 47
<Flex alignItems="center" gap="spacing-3">
<Avatar label="Appsmith AI" size="large" src={LOGO} />
<Text fontWeight={600} size="subtitle">
{chatTitle}
</Text>
</Flex>
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

Let's examine our header section, class.

I see you've made some changes to how we display our chat title. You've replaced the ChatTitle component with a more flexible structure using Flex, Avatar, and Text components. This is a good approach as it gives us more control over the layout and styling.

However, I want to draw your attention back to our earlier discussion about the LOGO constant. Can anyone spot where we're using it here? That's right, in the Avatar component!

Remember our homework assignment about importing the logo as a local asset? This is exactly where that change would be applied. Can someone tell me how we would modify this code if we had imported the logo as 'appsmithLogo'?

@jsartisan jsartisan changed the title chore: Update markdown component + create avatar component chore: Update markdown component + create avatar component + refactor Oct 11, 2024
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: 4

🧹 Outside diff range and nitpick comments (10)
app/client/packages/design-system/widgets/src/components/AIChat/src/ChatInputSection.tsx (4)

1-4: Good job on the imports and constant declaration, class!

The imports look neat and tidy, just like a well-organized pencil case. The MIN_PROMPT_LENGTH constant is a smart way to set a minimum length for the chat input. However, let's make it even better!

Consider moving the MIN_PROMPT_LENGTH constant to a separate constants file. This way, if we need to use it in other components, we can easily share it. It's like having a class set of rulers that everyone can use!


6-18: Excellent work on defining your component's props, students!

Your component interface is as clear as a well-written essay. The props you've chosen cover all the bases for a functional chat input section.

To make your code even more robust, consider using TypeScript's strict null checks. You can make the onSubmit prop non-optional and allow it to accept null:

onSubmit: (() => void) | null;

This way, you're always sure to have a value, even if it's null. It's like always having a pencil, even if it's not sharpened!


27-34: Your ChatInput implementation deserves a big checkmark, students!

You've done a fantastic job utilizing the ChatInput component. The way you've handled the disabled state for short prompts and the loading state is as smart as solving a tricky math problem correctly.

To make your component even more inclusive, consider adding an aria-label to the ChatInput for screen readers. It's like making sure everyone in the class can understand the lesson, regardless of how they perceive it:

aria-label="Chat input field"

Remember, accessibility is as important as having ramps alongside stairs in our school!


35-47: Your warning message is as clear as a well-rung school bell, class!

The way you've structured the warning message, with an icon and clear text, is excellent. It's like putting an important notice on the classroom bulletin board where everyone can see it.

To make your component ready for a global classroom, consider extracting the warning message text into a separate translations file. This way, we can easily provide the message in different languages:

import { t } from 'i18next';

// ...

<Text color="neutral" size="caption" textAlign="center">
  {t('llm.warning.message')}
</Text>

Remember, in our diverse classroom, we want to make sure everyone understands the important messages, no matter what language they speak!

app/client/packages/design-system/widgets/src/components/AIChat/src/ChatHeader.tsx (2)

27-61: Now, let's analyze the component's structure and JSX!

I'm quite pleased with how you've structured this component. You've made excellent use of the @appsmith/wds components to create a clean and organized layout.

Here are some highlights:

  1. Good use of a React fragment to wrap multiple elements.
  2. Nice job using the Flex component for layout management.
  3. The conditional rendering of the Modal based on isChatDescriptionModalOpen is spot on.

However, I have one small suggestion to improve accessibility:

Consider adding an aria-label to the Button component on lines 37-41. This will help screen readers understand the purpose of the button. For example:

<Button
  icon="info-square-rounded"
  onPress={() => setIsChatDescriptionModalOpen(true)}
  variant="ghost"
  aria-label="Open chat description"
/>

Remember, class, accessibility is an important part of web development!


1-62: Let's wrap up with an overall assessment of the ChatHeader component!

I must say, I'm quite impressed with your work on this component. You've created a well-structured, functional chat header that displays all the necessary information clearly.

Here's what stands out:

  1. Excellent use of the @appsmith/wds components to create a consistent UI.
  2. Good separation of concerns with the modal for additional chat description.
  3. Smart use of CSS modules for component-scoped styling.

For future improvements, consider the following:

  1. If this component grows more complex, you might want to break it down into smaller sub-components for better maintainability.
  2. Think about adding prop types validation using PropTypes or TypeScript's built-in type checking to catch potential errors early.
  3. If the chat description becomes more dynamic, consider implementing a custom hook for managing its state and related logic.

Remember, class, good code is not just about making it work, but also about making it easy to understand and maintain in the future. Keep up the excellent work!

app/client/packages/design-system/widgets/src/components/AIChat/src/ChatThread.tsx (3)

1-6: Well done on your imports, class! They're looking ship-shape!

You've done a splendid job importing the necessary components and types. It's clear you've been paying attention in our lessons on modular code organization.

However, let's take this opportunity for a small improvement. Consider grouping your imports by external libraries, internal modules, and local files. It'll make your code even more organized, like arranging your desk before a big test!

 import React from "react";
 import { Avatar, Flex, Markdown } from "@appsmith/wds";
+
 import styles from "./styles.module.css";
 import type { ChatMessage } from "./types";
 import { AssistantSuggestionButton } from "./AssistantSuggestionButton";

8-12: Excellent work on your component definition, students!

Your use of TypeScript for prop definitions shows you've been studying hard on type safety. It's like wearing a helmet while riding a bicycle - always a smart choice!

To make your code even more readable, consider extracting the prop types into a separate interface. It's like organizing your notebook for easier studying later!

interface ChatThreadProps {
  thread: ChatMessage[];
  onApplyAssistantSuggestion?: (suggestion: string) => void;
  username: string;
}

export const ChatThread: React.FC<ChatThreadProps> = ({ onApplyAssistantSuggestion, thread, username }) => (
  // ... component body
);

13-52: A gold star for your component structure, class!

Your use of Flex for layout and conditional rendering shows you've been paying attention to our lessons on responsive design and dynamic content. It's like building a perfect diorama - everything has its place!

However, let's think about optimization. Remember when we talked about memoization? It's like studying smart, not hard! Consider memoizing the ChatThread component to prevent unnecessary re-renders:

import React, { memo } from "react";

// ... other imports

export const ChatThread: React.FC<ChatThreadProps> = memo(({ onApplyAssistantSuggestion, thread, username }) => (
  // ... component body
));

This way, the component will only re-render when its props change, just like how you only need to review your notes when you learn new information!

app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css (1)

1-40: Excellent use of CSS variables, students!

I'm impressed with your use of CSS variables for consistency throughout the stylesheet. This is a great practice that will make our design system more maintainable.

However, I noticed we could improve our link styles. Remember, clear navigation is key to a good user experience. Let's add some styles to make our links stand out:

[data-component="a"] {
  color: var(--color-link);
  text-decoration: underline;
  
  &:hover, &:focus {
    color: var(--color-link-hover);
    text-decoration: none;
  }
}

Can anyone explain why making links more visible is important for accessibility?

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 906b65c and db2bc5c.

📒 Files selected for processing (13)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx (2 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatDescriptionModal/ChatDescriptionModal.tsx (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatDescriptionModal/index.ts (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatDescriptionModal/types.ts (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatHeader.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatInputSection.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatThread.tsx (1 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/ThreadMessage.tsx (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/index.ts (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/styles.module.css (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/types.ts (0 hunks)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/styles.module.css (1 hunks)
  • app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css (1 hunks)
💤 Files with no reviewable changes (7)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatDescriptionModal/ChatDescriptionModal.tsx
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatDescriptionModal/index.ts
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ChatDescriptionModal/types.ts
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/ThreadMessage.tsx
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/index.ts
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/styles.module.css
  • app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/types.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/client/packages/design-system/widgets/src/components/AIChat/src/styles.module.css
🧰 Additional context used
🪛 Biome
app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css

[error] 41-43: Unexpected value or character.

Expected one of:

(parse)


[error] 117-118: Expected a qualified rule, or an at rule but instead found '}'.

Expected a qualified rule, or an at rule here.

(parse)

🔇 Additional comments (12)
app/client/packages/design-system/widgets/src/components/AIChat/src/ChatInputSection.tsx (1)

19-26: A gold star for your component layout, class!

Your use of the Flex container is spot on, providing a structured layout for your chat input section. The padding values you've chosen will give your component some breathing room, just like the spaces between paragraphs in a well-formatted essay.

Keep up the good work! Your attention to layout details will make your user interface as neat as a freshly organized classroom.

app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx (4)

1-8: Class, let's discuss the importance of modular design in our code.

Children, I'm pleased to see the changes in our import statements. By introducing specialized components like ChatHeader, ChatThread, and ChatInputSection, we're embracing the principle of modular design. Can anyone tell me why this is beneficial?

Remember, when we break our code into smaller, focused components, it becomes:

  1. Easier to understand
  2. Simpler to maintain
  3. More reusable across our application

This is an excellent step towards writing cleaner, more efficient code. Well done!


28-32: Let's examine our new ChatHeader component, class.

I see we've introduced a new ChatHeader component that combines our chat title, description, and username. This is a great example of component composition. Can anyone tell me why this might be better than having separate components for each of these elements?

Here's a thought exercise for you:

  1. How does this change affect the readability of our main component?
  2. In what ways might this make our code more maintainable?

Remember, in React, we always strive for components that are focused and have a single responsibility. How does this change align with that principle?


34-46: Now, let's turn our attention to the ChatThread and ChatInputSection components.

Class, observe how we've separated our chat functionality into distinct components. The ChatThread handles the display of our conversation, while the ChatInputSection manages user input. This is an excellent application of the Single Responsibility Principle.

Can anyone explain why this separation of concerns is beneficial? Think about:

  1. How does this affect the testability of our code?
  2. If we needed to change how user input is handled, how has this structure made that easier?

As a homework assignment, I want you to think about one way we could further improve these components. Are there any props that could be combined or simplified?


Line range hint 52-52: Class, let's discuss the concept of forwarding refs in React.

I see we've wrapped our AIChat component with forwardRef. This is an advanced React technique that allows our component to take a ref and pass it down to a child DOM node. Can anyone tell me why this might be useful?

Here's a pop quiz for you:

  1. In what scenarios might we need to access the DOM node of a child component?
  2. How does forwardRef help us maintain good component encapsulation?

Remember, while refs can be powerful, they should be used sparingly. Can anyone think of a situation where using a ref might not be the best solution?

app/client/packages/design-system/widgets/src/components/AIChat/src/ChatHeader.tsx (2)

19-23: Excellent work on your component interface!

I'm impressed with how you've defined the ChatHeader component's props. You've done a great job using TypeScript to clearly specify what this component needs to work properly.

Let's break it down for the class:

  1. chatTitle?: string; - An optional string for the chat title. Good use of the optional modifier!
  2. username: string; - A required string for the username. Well done making this mandatory!
  3. chatDescription?: string; - Another optional string for the chat description.

This is a clear and concise way to define your component's interface. Keep up the good work!


24-25: Let's examine the state management, class!

Here, we see a perfect example of using React's useState hook. The developer has created a state variable isChatDescriptionModalOpen to control the visibility of the chat description modal.

What I particularly like about this:

  1. The naming is clear and descriptive - we know exactly what this boolean controls.
  2. They've used array destructuring to neatly declare both the state variable and its setter function.

This is a textbook example of how to manage local component state in React. Well done!

app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css (5)

46-75: Well done on your heading hierarchy, class!

Your heading styles from h1 to h6 are beautifully structured. I appreciate how you've used different margin settings to create a clear visual hierarchy. This will make your content much easier to read and understand.

The consistent use of data attributes for targeting elements is also commendable. Can anyone tell me why using data attributes might be preferable to targeting elements directly in some cases?


77-92: Great job on your paragraph and list styles!

Your attention to detail in spacing for paragraphs and lists is excellent. The margin settings you've chosen will help create a comfortable reading experience.

I particularly like how you've set the list items with a relative position and left margin. Can anyone explain why this might be helpful for custom list styling?


99-105: Excellent work on your code block styling!

Your code block styles are very well thought out. The distinct background color, border radius, and outline will make code snippets stand out nicely in your markdown content.

I particularly appreciate that you've set overflow: auto;. Can anyone tell the class why this is important for code blocks?


107-117: Great job on your pre and blockquote styles!

Your styling for pre-formatted text and blockquotes is spot on. The margin settings for pre elements will ensure good spacing, and the blockquote styling with the left border will make quoted content stand out nicely.

Can anyone explain to the class why we might want to style blockquotes differently from regular paragraphs?


118-118: Well done on maintaining proper structure!

Class, notice how we've properly closed our .markdown class at the end of the file. This is crucial for maintaining the scope of our styles.

Now, you might see a warning from our static analysis tool about an unexpected closing brace. In this case, that's a false alarm. Can anyone tell me why our tool might be confused, and why it's important to sometimes use our own judgment when interpreting these warnings?

🧰 Tools
🪛 Biome

[error] 117-118: Expected a qualified rule, or an at rule but instead found '}'.

Expected a qualified rule, or an at rule here.

(parse)

Comment on lines +1 to +17
import React, { useState } from "react";
import {
Avatar,
Button,
Flex,
Modal,
ModalBody,
ModalContent,
ModalHeader,
Text,
} from "@appsmith/wds";

import styles from "./styles.module.css";

// this value might come from props in future. So keeping a temporary value here.
const LOGO =
"https://app.appsmith.com/static/media/appsmith_logo_square.3867b1959653dabff8dc.png";
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

Class, let's discuss the imports and constants!

Good job on organizing your imports, but I have a small suggestion for you. The LOGO constant on lines 16-17 seems a bit out of place here. Remember, we always want to keep our code tidy and organized!

Consider moving the LOGO constant to a separate file, perhaps named constants.ts. This way, we keep our component file focused on its main job and make it easier to manage these global values. Here's how you might do it:

  1. Create a new file constants.ts:
export const LOGO = "https://app.appsmith.com/static/media/appsmith_logo_square.3867b1959653dabff8dc.png";
  1. Then in this file, you can import it like so:
import { LOGO } from './constants';

Remember, good organization is key to writing maintainable code!

Comment on lines +30 to +38
{promptSuggestions.map((suggestion) => (
<AssistantSuggestionButton
key={suggestion}
// eslint-disable-next-line react-perf/jsx-no-new-function-as-prop
onPress={() => onApplyAssistantSuggestion?.(suggestion)}
>
{suggestion}
</AssistantSuggestionButton>
))}
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

Let's optimize your suggestion buttons, students!

Your implementation of the AssistantSuggestionButton is quite good, like a well-written essay. However, there's room for improvement in how we handle the onPress event.

Remember our lesson on callback functions? Using inline functions can cause unnecessary re-renders, like rewriting your entire essay when you only need to change a single word!

Let's optimize this by using the useCallback hook:

import React, { useCallback } from 'react';

// ... in your component
const handleSuggestionPress = useCallback((suggestion: string) => {
  onApplyAssistantSuggestion?.(suggestion);
}, [onApplyAssistantSuggestion]);

// ... in your JSX
<AssistantSuggestionButton
  key={suggestion}
  onPress={() => handleSuggestionPress(suggestion)}
>
  {suggestion}
</AssistantSuggestionButton>

This way, we're creating a stable callback function, like using a template for your essays - efficient and consistent!

Comment on lines +94 to +97
[data-component="a"]:before,
[data-component="a"]:after {
content: none;
}
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

Let's make those links pop, shall we?

While removing default content before and after links is a good start, we want our links to stand out in the text. Remember, clear navigation is key to a good user experience.

Let's revisit our link styles. Try adding these rules:

[data-component="a"] {
  color: var(--color-link);
  text-decoration: underline;
  
  &:hover, &:focus {
    color: var(--color-link-hover);
    text-decoration: none;
  }
}

This will make your links more visible and provide clear feedback when users interact with them. What do you think this will do for the readability of your content?

Comment on lines +41 to +44
thead:last-child tr:last-child th,
tbody:last-child tr:last-child td {
border-bottom: none;
}
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

Class, let's fix our table selector syntax!

Good effort on your table styles, but we have a small error to correct. On lines 41-44, your CSS selectors need a little adjustment. Remember, when we want to target direct children, we use the '>' combinator. Let's update it together:

-thead:last-child tr:last-child th,
-tbody:last-child tr:last-child td {
+thead:last-child > tr:last-child > th,
+tbody:last-child > tr:last-child > td {
   border-bottom: none;
}

This change ensures we're correctly targeting the last cells in the last row of the table header and body. Can anyone tell me why this is important for our table structure?

📝 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
thead:last-child tr:last-child th,
tbody:last-child tr:last-child td {
border-bottom: none;
}
thead:last-child > tr:last-child > th,
tbody:last-child > tr:last-child > td {
border-bottom: none;
}
🧰 Tools
🪛 Biome

[error] 41-43: Unexpected value or character.

Expected one of:

(parse)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
skip-changelog Adding this label to a PR prevents it from being listed in the changelog
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants