Skip to content

Hotfix/vanilla react#29

Merged
fernando-plank merged 3 commits intomainfrom
hotfix/vanilla-react
Feb 24, 2025
Merged

Hotfix/vanilla react#29
fernando-plank merged 3 commits intomainfrom
hotfix/vanilla-react

Conversation

@fernando-plank
Copy link
Collaborator

@fernando-plank fernando-plank commented Feb 24, 2025

Summary by Entelligence.AI

  • New Feature: Introduced a Python script for a simple file browser with CORS headers for web access.
  • Refactor: Updated the handling of MarkdownText in the application, including memoization and new components for Markdown rendering and code copying.
  • New Feature: Added Tooltip and Button components using Radix UI and class-variance-authority respectively, enhancing user interaction.
  • Style: Implemented new CSS custom properties and styles for a dark theme, improving visual aesthetics.
  • Refactor: Added a utility function to merge class values, enhancing code readability.
  • Refactor: Modified the initialization process of a React component to ensure it only initializes when the DOM is ready, improving performance and stability.

EntelligenceAI PR Summary

The update introduces a components.json file for managing UI settings, including Tailwind CSS and path aliases, while removing package-lock.json to possibly streamline dependency management.

@fernando-plank fernando-plank merged commit e1fbd81 into main Feb 24, 2025
1 of 2 checks passed
@vercel
Copy link

vercel bot commented Feb 24, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
chat-popup 🔄 Building (Inspect) Visit Preview 💬 Add feedback Feb 24, 2025 7:56pm

@github-actions
Copy link

github-actions bot commented Feb 24, 2025

Image description Entelligence.AI

Walkthrough

This update introduces a local file browser script, refactors and enhances the UI components with new features like tooltips and button variants, adds dark theme support in CSS, optimizes class merging utility, and improves the initialization process of a React component.

Changes

Files Summary
server.py Introduced a Python script for a simple local file browser using http.server.
src/app/index.tsx, src/components/assistant-ui/markdown-text.tsx Refactored MarkdownText handling, added new components and functions related to Markdown rendering and code copying.
src/components/assistant-ui/tooltip-icon-button.tsx, src/components/ui/button.tsx, src/components/ui/tooltip.tsx Added new Tooltip and Button components with enhanced functionality and styles.
src/index.css, tailwind.config.js Added new CSS custom properties and styles for a dark theme and base styles for various elements.
src/lib/utils.ts Introduced a new function cn that merges class values using clsx and twMerge.
src/main-vanilla.tsx Improved the initialization process of a React component, ensuring it is only initialized when the DOM is ready.

🎉 Code changes here, code changes there,
New features everywhere! 🚀
Tooltips pop, buttons shine,
In the dark theme, they look so fine. 🌙
Class merging got a boost,
And React's init is now more robust! 💪
Celebrate these changes, big and small,
For they make our code stand tall! 🏗️🎊


Uplevel your code reviews with Entelligence.AI Pro

Entelligence.AI Pro

If you like this project, please support us by purchasing the Pro version. The Pro version has advanced context, superior noise reduction and several proprietary improvements compared to the open source version. Moreover, Entelligence.AI Pro is free for open source projects.

@entelligence-ai-pr-reviews
Copy link

Walkthrough

This PR introduces a new components.json file to manage UI component settings, including Tailwind CSS configurations and path aliases. Additionally, the removal of package-lock.json suggests a shift in dependency management or a cleanup of unused dependencies.

Changes

File(s) Summary
components.json Introduced a new configuration file for UI components, specifying Tailwind CSS settings, path aliases, and other component-related configurations.
package-lock.json Removed the file, possibly indicating a change in dependency management strategy or a cleanup of unused dependencies.
Entelligence.ai can learn from your feedback. Simply add 👍 / 👎 emojis to teach it your preferences. More shortcuts below

Emoji Descriptions:

  • ⚠️ Potential Issue - May require further investigation.
  • 🔒 Security Vulnerability - Fix to ensure system safety.
  • 💻 Code Improvement - Suggestions to enhance code quality.
  • 🔨 Refactor Suggestion - Recommendations for restructuring code.
  • ℹ️ Others - General comments and information.

Interact with the Bot:

  • Send a message or request using the format:
    @bot + *your message*
Example: @bot Can you suggest improvements for this code?
  • Help the Bot learn by providing feedback on its responses.
    @bot + *feedback*
Example: @bot Do not comment on `save_auth` function !

Comment on lines +44 to +52
def do_GET(self):
path = unquote(self.path[1:]) # Remove leading slash
if not path:
path = '.'

if os.path.isdir(path):
self.list_directory(path)
else:
return SimpleHTTPRequestHandler.do_GET(self)

Choose a reason for hiding this comment

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

Directory traversal vulnerability: The code does not sanitize the path parameter, allowing attackers to access files outside the intended directory using ../ sequences.

📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
def do_GET(self):
path = unquote(self.path[1:]) # Remove leading slash
if not path:
path = '.'
if os.path.isdir(path):
self.list_directory(path)
else:
return SimpleHTTPRequestHandler.do_GET(self)
def do_GET(self):
path = unquote(self.path[1:]) # Remove leading slash
if not path:
path = '.'
# Normalize path and ensure it's within the allowed directory
path = os.path.normpath(path)
if path.startswith('..'):
self.send_error(403, "Access denied")
return
if os.path.isdir(path):
self.list_directory(path)
else:
return SimpleHTTPRequestHandler.do_GET(self)

Comment on lines +8 to +12
def end_headers(self):
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
self.send_header('Access-Control-Allow-Headers', 'Content-Type')
super().end_headers()

Choose a reason for hiding this comment

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

CORS is configured to allow all origins (*) and methods, which is a security risk. Should restrict to specific trusted origins if this is meant for production use.

📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
def end_headers(self):
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
self.send_header('Access-Control-Allow-Headers', 'Content-Type')
super().end_headers()
def end_headers(self):
allowed_origins = ['https://trusted-domain1.com', 'https://trusted-domain2.com']
origin = self.headers.get('Origin')
if origin in allowed_origins:
self.send_header('Access-Control-Allow-Origin', origin)
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
self.send_header('Access-Control-Allow-Headers', 'Content-Type')
super().end_headers()

Comment on lines +18 to +26
const MarkdownTextImpl = () => {
return (
<MarkdownTextPrimitive
remarkPlugins={[remarkGfm]}
className="aui-md"
components={defaultComponents}
/>
);
};

Choose a reason for hiding this comment

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

The MarkdownTextImpl component doesn't accept any props but MarkdownTextPrimitive likely requires content/markdown props to render, making it non-functional.

📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
const MarkdownTextImpl = () => {
return (
<MarkdownTextPrimitive
remarkPlugins={[remarkGfm]}
className="aui-md"
components={defaultComponents}
/>
);
};
const MarkdownTextImpl = ({ content }) => {
return (
<MarkdownTextPrimitive
remarkPlugins={[remarkGfm]}
className="aui-md"
components={defaultComponents}
children={content}
/>
);
};

Comment on lines +58 to +61
navigator.clipboard.writeText(value).then(() => {
setIsCopied(true);
setTimeout(() => setIsCopied(false), copiedDuration);
});

Choose a reason for hiding this comment

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

navigator.clipboard.writeText() promise error is not handled, which could cause silent failures when copy operation fails

📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
navigator.clipboard.writeText(value).then(() => {
setIsCopied(true);
setTimeout(() => setIsCopied(false), copiedDuration);
});
navigator.clipboard.writeText(value).then(() => {
setIsCopied(true);
setTimeout(() => setIsCopied(false), copiedDuration);
}).catch(err => {
console.error('Failed to copy text:', err);
});

Comment on lines +26 to +30
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initReact);
} else {
initReact();
}

Choose a reason for hiding this comment

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

Missing cleanup of DOMContentLoaded event listener when component unmounts, which could lead to memory leaks if init() is called multiple times while DOM is still loading

📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initReact);
} else {
initReact();
}
const initHandler = () => {
document.removeEventListener('DOMContentLoaded', initHandler);
initReact();
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initHandler);
} else {
initReact();
}

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Image description Entelligence.AI

Commits Files that changed from the base of the PR and between 781e7c5 and 0a9efd4 commits.
Files selected (10)
  • server.py (1)
  • src/app/index.tsx (2)
  • src/components/assistant-ui/markdown-text.tsx (1)
  • src/components/assistant-ui/tooltip-icon-button.tsx (1)
  • src/components/ui/button.tsx (1)
  • src/components/ui/tooltip.tsx (1)
  • src/index.css (1)
  • src/lib/utils.ts (1)
  • src/main-vanilla.tsx (1)
  • tailwind.config.js (1)
Files ignored due to filter (4)
  • components.json
  • package-lock.json
  • package.json
  • pnpm-lock.yaml
Files skipped from review due to trivial changes (5)
  • server.py
  • src/app/index.tsx
  • src/components/ui/tooltip.tsx
  • src/index.css
  • tailwind.config.js
Review comments generated (8)
  • Review: 4
  • LGTM: 4

Tips

Chat with Image description Entelligence.AI Bot (@Entelligence.AI)

  • Reply on review comments left by this bot to ask follow-up questions. A review comment is a comment on a diff or a file.
  • Invite the bot into a review comment chain by tagging @Entelligence.AI in a reply.

Code suggestions

  • The bot may make code suggestions, but please review them carefully before committing since the line number ranges may be misaligned.
  • You can edit the comment made by the bot and manually tweak the suggestion if it is slightly off.

Pausing incremental reviews

  • Add @Entelligence.AI: ignore anywhere in the PR description to pause further reviews from the bot.

Comment on lines +1 to +132
"use client";

import "@assistant-ui/react-markdown/styles/dot.css";

import {
CodeHeaderProps,
MarkdownTextPrimitive,
unstable_memoizeMarkdownComponents as memoizeMarkdownComponents,
useIsMarkdownCodeBlock,
} from "@assistant-ui/react-markdown";
import remarkGfm from "remark-gfm";
import { FC, memo, useState } from "react";
import { CheckIcon, CopyIcon } from "lucide-react";

import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
import { cn } from "@/lib/utils";

const MarkdownTextImpl = () => {
return (
<MarkdownTextPrimitive
remarkPlugins={[remarkGfm]}
className="aui-md"
components={defaultComponents}
/>
);
};

export const MarkdownText = memo(MarkdownTextImpl);

const CodeHeader: FC<CodeHeaderProps> = ({ language, code }) => {
const { isCopied, copyToClipboard } = useCopyToClipboard();
const onCopy = () => {
if (!code || isCopied) return;
copyToClipboard(code);
};

return (
<div className="flex items-center justify-between gap-4 rounded-t-lg bg-zinc-900 px-4 py-2 text-sm font-semibold text-white">
<span className="lowercase [&>span]:text-xs">{language}</span>
<TooltipIconButton tooltip="Copy" onClick={onCopy}>
{!isCopied && <CopyIcon />}
{isCopied && <CheckIcon />}
</TooltipIconButton>
</div>
);
};

const useCopyToClipboard = ({
copiedDuration = 3000,
}: {
copiedDuration?: number;
} = {}) => {
const [isCopied, setIsCopied] = useState<boolean>(false);

const copyToClipboard = (value: string) => {
if (!value) return;

navigator.clipboard.writeText(value).then(() => {
setIsCopied(true);
setTimeout(() => setIsCopied(false), copiedDuration);
});
};

return { isCopied, copyToClipboard };
};

const defaultComponents = memoizeMarkdownComponents({
h1: ({ className, ...props }) => (
<h1 className={cn("mb-8 scroll-m-20 text-4xl font-extrabold tracking-tight last:mb-0", className)} {...props} />
),
h2: ({ className, ...props }) => (
<h2 className={cn("mb-4 mt-8 scroll-m-20 text-3xl font-semibold tracking-tight first:mt-0 last:mb-0", className)} {...props} />
),
h3: ({ className, ...props }) => (
<h3 className={cn("mb-4 mt-6 scroll-m-20 text-2xl font-semibold tracking-tight first:mt-0 last:mb-0", className)} {...props} />
),
h4: ({ className, ...props }) => (
<h4 className={cn("mb-4 mt-6 scroll-m-20 text-xl font-semibold tracking-tight first:mt-0 last:mb-0", className)} {...props} />
),
h5: ({ className, ...props }) => (
<h5 className={cn("my-4 text-lg font-semibold first:mt-0 last:mb-0", className)} {...props} />
),
h6: ({ className, ...props }) => (
<h6 className={cn("my-4 font-semibold first:mt-0 last:mb-0", className)} {...props} />
),
p: ({ className, ...props }) => (
<p className={cn("mb-5 mt-5 leading-7 first:mt-0 last:mb-0", className)} {...props} />
),
a: ({ className, ...props }) => (
<a className={cn("text-primary font-medium underline underline-offset-4", className)} {...props} />
),
blockquote: ({ className, ...props }) => (
<blockquote className={cn("border-l-2 pl-6 italic", className)} {...props} />
),
ul: ({ className, ...props }) => (
<ul className={cn("my-5 ml-6 list-disc [&>li]:mt-2", className)} {...props} />
),
ol: ({ className, ...props }) => (
<ol className={cn("my-5 ml-6 list-decimal [&>li]:mt-2", className)} {...props} />
),
hr: ({ className, ...props }) => (
<hr className={cn("my-5 border-b", className)} {...props} />
),
table: ({ className, ...props }) => (
<table className={cn("my-5 w-full border-separate border-spacing-0 overflow-y-auto", className)} {...props} />
),
th: ({ className, ...props }) => (
<th className={cn("bg-muted px-4 py-2 text-left font-bold first:rounded-tl-lg last:rounded-tr-lg [&[align=center]]:text-center [&[align=right]]:text-right", className)} {...props} />
),
td: ({ className, ...props }) => (
<td className={cn("border-b border-l px-4 py-2 text-left last:border-r [&[align=center]]:text-center [&[align=right]]:text-right", className)} {...props} />
),
tr: ({ className, ...props }) => (
<tr className={cn("m-0 border-b p-0 first:border-t [&:last-child>td:first-child]:rounded-bl-lg [&:last-child>td:last-child]:rounded-br-lg", className)} {...props} />
),
sup: ({ className, ...props }) => (
<sup className={cn("[&>a]:text-xs [&>a]:no-underline", className)} {...props} />
),
pre: ({ className, ...props }) => (
<pre className={cn("overflow-x-auto rounded-b-lg bg-black p-4 text-white", className)} {...props} />
),
code: function Code({ className, ...props }) {
const isCodeBlock = useIsMarkdownCodeBlock();
return (
<code
className={cn(!isCodeBlock && "bg-muted rounded border font-semibold", className)}
{...props}
/>
);
},
CodeHeader,
});

Choose a reason for hiding this comment

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

Image description Entelligence.AI

The changes in this file look good overall. However, there's a potential issue with the useCopyToClipboard hook at line 48. The setTimeout function is used to reset the isCopied state after a certain duration. This could lead to a memory leak if the component using this hook is unmounted before the timeout finishes. To prevent this, you should clear the timeout when the component is unmounted.

Here's how you can do it:

const useCopyToClipboard = ({
  copiedDuration = 3000,
}: {
  copiedDuration?: number;
} = {}) => {
  const [isCopied, setIsCopied] = useState<boolean>(false);

  const copyToClipboard = (value: string) => {
    if (!value) return;

    navigator.clipboard.writeText(value).then(() => {
      setIsCopied(true);
+      const timerId = setTimeout(() => setIsCopied(false), copiedDuration);
+      return () => clearTimeout(timerId);
    });
  };

  return { isCopied, copyToClipboard };
};

This way, the timeout will be cleared whenever the component using this hook is unmounted, preventing any potential memory leaks.

Comment on lines +9 to +13
// Create container and add to body
const container = document.createElement('div');
container.id = 'entelligence-chat-root';
container.className = 'entelligence-chat-container';
document.body.appendChild(container);

Choose a reason for hiding this comment

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

Image description Entelligence.AI

The creation of the container element and appending it to the body is done without any checks. It's possible that an element with the same id already exists in the DOM, which could lead to unexpected behavior. Consider checking if an element with the same id already exists before creating a new one.

+    // Check if container already exists
+    let container = document.getElementById('entelligence-chat-root');
+
+    // Create container if it doesn't exist and add to body
+    if (!container) {
+        container = document.createElement('div');
+        container.id = 'entelligence-chat-root';
+        container.className = 'entelligence-chat-container';
+        document.body.appendChild(container);
+    }

Comment on lines +20 to +22
} catch (err) {
console.error('Failed to initialize chat:', err);
}

Choose a reason for hiding this comment

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

Image description Entelligence.AI

Error handling here only logs the error to the console. Depending on the severity of the failure, you might want to consider re-throwing the error after logging, or handling it in a way that's appropriate for your application.

 try {
     const root = createRoot(container);
     root.render(<EntelligenceChat analyticsData={analyticsData} />);
 } catch (err) {
     console.error('Failed to initialize chat:', err);
+    throw err;
 }

Comment on lines +38 to 40
// Export for UMD/global usage
if (typeof window !== 'undefined') {
(window as any).EntelligenceChat = { init };

Choose a reason for hiding this comment

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

Image description Entelligence.AI

Exposing init function globally can be risky as it can be overwritten by other scripts. Consider using a more unique name or encapsulating it within a namespace to avoid potential conflicts.

 if (typeof window !== 'undefined') {
-    (window as any).EntelligenceChat = { init };
+    (window as any).EntelligenceChatInit = { init };
 }

@entelligence-ai-pr-reviews
Copy link

📚 Documentation Updates

I've created a pull request with documentation updates based on your changes:
https://github.com/Entelligence-AI/entelligence-docs/pull/25

The documentation updates are in branch: doc-updates-1740427118

Please review the documentation changes to ensure they accurately reflect your code changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant