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

new-log-viewer: Add NotificationContextProvider for managing pop-up messages; add pop-ups for errors and remove status bar dummy message. #84

Merged
merged 46 commits into from
Oct 19, 2024

Conversation

junhaoliao
Copy link
Collaborator

@junhaoliao junhaoliao commented Sep 30, 2024

References

new-log-viewer series: #45 #46 #48 #51 #52 #53 #54 #55 #56 #59 #60 #61 #62 #63 #66 #67 #68 #69 #70 #71 #72 #73 #74 #76 #77 #78 #79 #80 #81 #82 #83

Description

  1. Add NotificationContextProvider for publishing and subscribing notifications.
  2. Fix "FIXME" items that originally log to console / show browser pop-up to now use the NotificationProvider to publish messages.
  3. Remove the dummy "Status Message" in the StatusBar.

Validation performed

  1. Loaded debug server as specified in Add support for loading files, decoding them as JSONL, and formatting them using a Logback-like format string. #46.
  2. Dragged and dropped a file with no extension (e.g. testFile) into the viewport and observed a message shown in the status bar showing "No decoder supports testFile".
  3. Opened the settings modal and tried setting an invalid page size of value 100000000000. A pop-up notification shown in the bottom-right of the viewport with title "Unable to apply config." and content "Page size must be greater than 0 and less than 1000001.". The pop-up did not disappear until the "close" button in it was clicked.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features
    • Introduced a NotificationContext for enhanced user notifications, allowing dynamic status messages and popup alerts.
    • Added PopupMessageBox and PopUps components for improved message display, including visual countdowns for message dismissal.
    • Implemented ThemeSwitchToggle for users to switch between themes easily.
  • Improvements
    • Refactored layout components to ensure proper theme context handling.
    • Enhanced notification handling in the StateContextProvider for better user feedback during form submissions.
  • Bug Fixes
    • Improved spacing in the StatusBar by removing unnecessary padding.

Copy link

coderabbitai bot commented Sep 30, 2024

Walkthrough

The changes introduce a new NotificationContextProvider in the App component, enhancing context management without altering existing functionalities. The Layout component now uses CssVarsProvider from @mui/joy, and a new PopupMessageBox component is added for displaying alert messages. The PopUps component has been created to render popup messages conditionally. The SettingsDialog is updated to use the notification context for error handling, and a new ThemeSwitchToggle component is introduced for theme switching. CSS styles for pop-up messages are also added.

Changes

Files Change Summary
new-log-viewer/src/App.tsx Added NotificationContextProvider to wrap existing context providers.
new-log-viewer/src/components/Layout.tsx Updated to import CssVarsProvider from @mui/joy and render PopUps within it.
`new-log-viewer/src/components/Popups/PopupMessageBox.tsx Introduced PopupMessageBox component for displaying alert messages using Material UI.
`new-log-viewer/src/components/Popups/index.css Added new CSS styles for positioning and styling pop-up messages.
`new-log-viewer/src/components/Popups/index.tsx Added PopUps component to display messages using Material UI's Snackbar and Stack components.
`new-log-viewer/src/components/modals/SettingsModal/SettingsDialog.tsx Updated to use NotificationContext for displaying notifications instead of alerts.
`new-log_viewer/src/components/modals/SettingsModal/ThemeSwitchToggle.tsx Introduced ThemeSwitchToggle component for theme switching.
`new-log-viewer/src/contexts/NotificationContextProvider.tsx Established NotificationContext for managing notifications, including methods for posting and closing messages.
`new-log-viewer/src/contexts/StateContextProvider.tsx Updated to integrate NotificationContext, replacing console logging with postPopup for notifications.
`new-log-viewer/src/typings/common.ts Introduced a new type alias WithId<T> for combining types with an id property.
`new-log-viewer/src/typings/notifications.ts Added a new interface PopupMessage to define the structure for popup messages.

Possibly related PRs


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 6980c7a and df5be3b.

📒 Files selected for processing (1)
  • new-log-viewer/src/contexts/NotificationContextProvider.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • new-log-viewer/src/contexts/NotificationContextProvider.tsx

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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@junhaoliao junhaoliao marked this pull request as draft September 30, 2024 04:27
Copy link

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

🧹 Outside diff range and nitpick comments (9)
new-log-viewer/src/components/Layout.tsx (1)

Line range hint 1-5: Remove unused imports

The CssVarsProvider import seems to be unused after the recent changes. Consider removing it to keep the imports clean and avoid potential confusion.

Apply this diff to remove the unused import:

-import { CssVarsProvider } from "@mui/joy/styles";
new-log-viewer/src/App.tsx (2)

1-1: Excellent addition of CssVarsProvider for theming!

The implementation of CssVarsProvider from MUI Joy is a great choice for managing the application's theme. It allows for easy configuration and persistence of the theme mode.

A small suggestion to improve code readability:

Consider extracting the CssVarsProvider props into a separate constant. This would make the component more readable and easier to maintain. For example:

const cssVarsProviderProps = {
  defaultMode: CONFIG_DEFAULT[CONFIG_KEY.THEME],
  modeStorageKey: CONFIG_KEY.THEME,
  theme: APP_THEME,
};

// Then in your JSX:
<CssVarsProvider {...cssVarsProviderProps}>
  {/* ... */}
</CssVarsProvider>

This approach would make it easier to modify or extend the provider's configuration in the future.

Also applies to: 19-23, 31-31


19-31: Well-structured component hierarchy

The restructuring of the component hierarchy is well-done. The new structure provides a clear separation of concerns:

  1. Theming (CssVarsProvider)
  2. Notifications (NotificationContextProvider)
  3. URL handling (UrlContextProvider)
  4. State management (StateContextProvider)
  5. Layout

This hierarchy allows each context to potentially access the functionalities provided by its parent contexts, which is a good design choice.

To improve the maintainability of the code, consider adding a comment explaining the purpose and dependencies of each context provider in this hierarchy. This would help future developers understand the rationale behind this structure more quickly.

new-log-viewer/src/components/StatusBar/index.tsx (1)

30-30: LGTM: NotificationContext implemented correctly.

The NotificationContext is properly utilized to display a dynamic status message. This implementation aligns well with the PR objective of introducing a NotificationContextProvider for managing notifications.

Consider adding a fallback value for when statusMessage is undefined:

-                {statusMessage}
+                {statusMessage || "No status message"}

This ensures that a meaningful message is always displayed, even if the context fails to provide a status message.

Also applies to: 40-40

new-log-viewer/src/contexts/StateContextProvider.tsx (1)

177-178: LGTM: Notification handling improved

The modification correctly replaces console logging with the new notification system, improving user experience by displaying notifications in the UI.

Consider adding a default log level in case args.logLevel is undefined:

postStatus(args.logLevel || 'info', args.message);

This ensures that a notification is always posted, even if the log level is not specified.

new-log-viewer/src/contexts/NotificationContextProvider.tsx (3)

49-53: Add JSDoc description and @return declaration

The JSDoc comment for NotificationContextProvider is missing a block description and a @return declaration. Providing a clear description and return information enhances code readability and maintainability.

🧰 Tools
🪛 GitHub Check: lint-check

[warning] 49-49:
Missing JSDoc block description


[warning] 49-49:
Missing JSDoc @return declaration


68-70: Use conventional comparison order in condition

In line 68, it's more conventional to write title === "" instead of "" === title for better readability.

Apply this diff:

             title: title === "" ?
                 LOG_LEVEL[level] :
                 title,

66-67: Simplify object property assignments

When the property name and variable name are the same, you can simplify the assignment. Instead of level: level and message: message, you can simply write level and message.

Apply this diff:

             setPopupNotification({
-                level: level,
-                message: message,
+                level,
+                message,
                 title: title === "" ?
                     LOG_LEVEL[level] :
                     title,
             });
new-log-viewer/src/components/modals/SettingsModal/SettingsDialog.tsx (1)

82-84: Clarify the JSDoc comment for the custom hook

The JSDoc comment currently describes useHandleConfigFormSubmit as generating a handler. Since it's a custom hook that returns a submit handler, consider updating the comment to reflect its purpose more accurately.

You might revise the comment as follows:

/**
- * Generates a handler for the submit event for the configuration form.
+ * Custom hook that returns a handler for the submit event of the configuration form.
 *
 * @return the generated handler.
 */
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between d185624 and 61f4b6e.

📒 Files selected for processing (6)
  • new-log-viewer/src/App.tsx (2 hunks)
  • new-log-viewer/src/components/Layout.tsx (1 hunks)
  • new-log-viewer/src/components/StatusBar/index.tsx (3 hunks)
  • new-log-viewer/src/components/modals/SettingsModal/SettingsDialog.tsx (4 hunks)
  • new-log-viewer/src/contexts/NotificationContextProvider.tsx (1 hunks)
  • new-log-viewer/src/contexts/StateContextProvider.tsx (3 hunks)
🧰 Additional context used
🪛 GitHub Check: lint-check
new-log-viewer/src/contexts/NotificationContextProvider.tsx

[warning] 34-34:
No empty blocks


[warning] 49-49:
Missing JSDoc block description


[warning] 49-49:
Missing JSDoc @return declaration


[failure] 76-76:
No magic number: 5000


[failure] 89-89:
No magic number: 5000


[failure] 109-109:
The closing bracket must be aligned with the opening tag (expected column 44)


[failure] 128-128:
Expected closing tag to match indentation of opening

🔇 Additional comments (6)
new-log-viewer/src/components/Layout.tsx (1)

14-20: Verify the impact of removing CssVarsProvider

The removal of CssVarsProvider simplifies the component structure, but it may have unintended consequences on the application's theming. Please ensure that:

  1. The application's visual consistency is maintained across all components.
  2. Any child components that relied on the theme context provided by CssVarsProvider are updated accordingly.
  3. The default theme mode and configuration (CONFIG_DEFAULT and APP_THEME) are properly applied elsewhere if still needed.

Consider documenting the reason for this change and any necessary adjustments made to compensate for the removal of CssVarsProvider.

To help verify the impact, you can run the following script to check for any remaining references to the removed provider or its related constants:

✅ Verification successful

Verified: Removal of CssVarsProvider Maintains Theming Consistency

The CssVarsProvider has been successfully removed from Layout.tsx without disrupting the application's theming. Since CssVarsProvider is still utilized in App.tsx, the global theming context remains intact. Additionally, CONFIG_DEFAULT and APP_THEME are consistently referenced across relevant components, ensuring continued visual consistency.

  • Global theming is managed through App.tsx.
  • No child components within Layout.tsx rely on a local CssVarsProvider.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for references to CssVarsProvider and related constants

# Search for CssVarsProvider usage
echo "Searching for CssVarsProvider usage:"
rg --type typescript --type typescriptreact 'CssVarsProvider'

# Search for CONFIG_DEFAULT usage
echo "\nSearching for CONFIG_DEFAULT usage:"
rg --type typescript --type typescriptreact 'CONFIG_DEFAULT'

# Search for APP_THEME usage
echo "\nSearching for APP_THEME usage:"
rg --type typescript --type typescriptreact 'APP_THEME'

Length of output: 526


Script:

#!/bin/bash
# Description: Check for references to CssVarsProvider and related constants in .ts and .tsx files

# Search for CssVarsProvider usage
echo "Searching for CssVarsProvider usage in TypeScript files:"
rg 'CssVarsProvider' --glob '*.ts' --glob '*.tsx'

# Search for CONFIG_DEFAULT usage
echo -e "\nSearching for CONFIG_DEFAULT usage in TypeScript files:"
rg 'CONFIG_DEFAULT' --glob '*.ts' --glob '*.tsx'

# Search for APP_THEME usage
echo -e "\nSearching for APP_THEME usage in TypeScript files:"
rg 'APP_THEME' --glob '*.ts' --glob '*.tsx'

Length of output: 1524

new-log-viewer/src/App.tsx (2)

4-4: Well-structured imports for theme and configuration

The imports for APP_THEME, CONFIG_KEY, and CONFIG_DEFAULT are well-organized and follow a good separation of concerns. This structure makes the code more maintainable and easier to understand.

Also applies to: 8-9


5-5: Great addition of NotificationContextProvider

The implementation of NotificationContextProvider aligns well with the PR objective of adding a system for publishing and subscribing to notifications. Its placement in the component hierarchy, wrapping other context providers, seems appropriate.

To ensure the NotificationContextProvider is implemented correctly, could you provide more details on its implementation? Specifically:

  1. How are notifications published and subscribed to?
  2. Are there any performance considerations for the notification system?
  3. How does this integrate with the existing state management?

You can run the following script to examine the NotificationContextProvider implementation:

Also applies to: 24-24, 30-30

✅ Verification successful

To ensure that postPopup and postStatus are utilized correctly throughout the application, please run the following script to identify their usage locations:


---

To address the issue with the previous script, please run the following corrected script to locate all usages of `postPopup` and `postStatus` while excluding the `node_modules` directory:




NotificationContextProvider Usage Verified

All instances of postPopup and postStatus are correctly utilized within the application, aligning with the intended notification system implementation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Examine the NotificationContextProvider implementation

# Test: Display the content of NotificationContextProvider
cat $(fd --type f --glob '*NotificationContextProvider*' --exec echo {})

Length of output: 4111


Script:

#!/bin/bash
# Description: Locate all usages of postPopup and postStatus in the codebase

rg 'postPopup|postStatus' --ignore-dir=node_modules

Length of output: 496


Script:

#!/bin/bash
# Description: Locate all usages of postPopup and postStatus in the codebase, excluding node_modules

rg 'postPopup|postStatus' -g '!node_modules/*'

Length of output: 1461

new-log-viewer/src/components/StatusBar/index.tsx (1)

7-7: LGTM: NotificationContext import added correctly.

The import statement for NotificationContext is properly formatted and the relative path appears to be correct.

new-log-viewer/src/contexts/StateContextProvider.tsx (2)

33-33: LGTM: NotificationContext import added

The import of NotificationContext is correctly placed and necessary for the new notification functionality being integrated into the StateContextProvider.


143-143: LGTM: postStatus function obtained from NotificationContext

The postStatus function is correctly destructured from the NotificationContext. This allows for proper integration of the new notification system within the StateContextProvider.

Comment on lines 30 to 33
const {statusMessage} = useContext(NotificationContext);
const {numEvents} = useContext(StateContext);
const {logEventNum} = useContext(UrlContext);

Copy link

@coderabbitai coderabbitai bot Sep 30, 2024

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider improving maintainability and documentation.

The StatusBar component now relies on three different contexts: NotificationContext, StateContext, and UrlContext. While this implementation works, it might lead to maintainability issues in the future. Consider the following suggestions:

  1. Add comments explaining the purpose and source of each context to improve code readability.
  2. Consider creating a custom hook that encapsulates all the context usage, which could simplify testing and make the component more maintainable.
  3. Evaluate if a more centralized state management approach might be beneficial for the application as it grows.

Example of a custom hook:

function useStatusBarData() {
  const {statusMessage} = useContext(NotificationContext);
  const {numEvents} = useContext(StateContext);
  const {logEventNum} = useContext(UrlContext);
  
  return {statusMessage, numEvents, logEventNum};
}

Then use it in the component:

const StatusBar = () => {
  const {statusMessage, numEvents, logEventNum} = useStatusBarData();
  // ... rest of the component
}

This approach would centralize the context usage and make it easier to mock for testing.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The suggested approach seems pretty smart but I guess this is something we want to try in some future PR when we have better mock testing facilities set up.

Copy link

Choose a reason for hiding this comment

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

@junhaoliao, understood. Let me know if you'd like me to open a GitHub issue to track this for future implementation.

Comment on lines 34 to 36
*
*/
const NOTIFICATION_DEFAULT: Readonly<NotificationContextType> = Object.freeze({
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove empty JSDoc block

There is an empty JSDoc comment block at lines 34-36. Empty blocks are unnecessary and should be removed to clean up the code.

🧰 Tools
🪛 GitHub Check: lint-check

[warning] 34-34:
No empty blocks

if (LOG_LEVEL.INFO >= level) {
popupNotificationTimeoutRef.current = setTimeout(() => {
setPopupNotification(null);
}, 5000);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Replace magic numbers with constants

The timeout value 5000 is used directly in the code at lines 76 and 89. Consider defining a constant to improve readability and ease of maintenance.

Apply this diff to define a constant and replace the magic numbers:

+const AUTO_DISMISS_TIMEOUT_MS = 5000;
...
74              if (LOG_LEVEL.INFO >= level) {
75                  popupNotificationTimeoutRef.current = setTimeout(() => {
76-                     setPopupNotification(null);
76+                     setPopupNotification(null);
77                  }, AUTO_DISMISS_TIMEOUT_MS);
...
87              if (LOG_LEVEL.INFO >= level) {
88                  statusMsgTimeoutRef.current = setTimeout(() => {
89-                     setStatusMessage(NOTIFICATION_DEFAULT.statusMessage);
89+                     setStatusMessage(NOTIFICATION_DEFAULT.statusMessage);
90                  }, AUTO_DISMISS_TIMEOUT_MS);

Also applies to: 89-89

🧰 Tools
🪛 GitHub Check: lint-check

[failure] 76-76:
No magic number: 5000

color={popupNotification.level >= LOG_LEVEL.ERROR ?
"danger" :
"primary"}
>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix indentation of JSX elements

The closing bracket at line 109 and the closing tag at line 128 are misaligned. Proper indentation improves code readability.

Also applies to: 128-128

🧰 Tools
🪛 GitHub Check: lint-check

[failure] 109-109:
The closing bracket must be aligned with the opening tag (expected column 44)

Comment on lines 29 to 31
interface NotificationContextProvider {
children: React.ReactNode;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Rename interface to avoid name collision

The interface NotificationContextProvider and the component NotificationContextProvider share the same name, which may cause confusion. Consider renaming the interface to NotificationContextProviderProps for clarity.

Apply this diff to rename the interface:

-interface NotificationContextProvider {
+interface NotificationContextProviderProps {
     children: React.ReactNode;
 }
...
-const NotificationContextProvider = ({children}: NotificationContextProvider) => {
+const NotificationContextProvider = ({children}: NotificationContextProviderProps) => {

Also applies to: 54-54

Comment on lines 86 to 114
const useHandleConfigFormSubmit = () => {
const {postPopup} = useContext(NotificationContext);

return (ev: React.FormEvent) => {
ev.preventDefault();
const formData = new FormData(ev.target as HTMLFormElement);
const getFormDataValue = (key: string) => formData.get(key) as string;

const formatString = getFormDataValue(LOCAL_STORAGE_KEY.DECODER_OPTIONS_FORMAT_STRING);
const logLevelKey = getFormDataValue(LOCAL_STORAGE_KEY.DECODER_OPTIONS_LOG_LEVEL_KEY);
const timestampKey = getFormDataValue(LOCAL_STORAGE_KEY.DECODER_OPTIONS_TIMESTAMP_KEY);
const pageSize = getFormDataValue(LOCAL_STORAGE_KEY.PAGE_SIZE);
const formatString = getFormDataValue(LOCAL_STORAGE_KEY.DECODER_OPTIONS_FORMAT_STRING);
const logLevelKey = getFormDataValue(LOCAL_STORAGE_KEY.DECODER_OPTIONS_LOG_LEVEL_KEY);
const timestampKey = getFormDataValue(LOCAL_STORAGE_KEY.DECODER_OPTIONS_TIMESTAMP_KEY);
const pageSize = getFormDataValue(LOCAL_STORAGE_KEY.PAGE_SIZE);

let error: Nullable<string> = null;
error ||= setConfig({
key: CONFIG_KEY.DECODER_OPTIONS,
value: {formatString, logLevelKey, timestampKey},
});
error ||= setConfig({
key: CONFIG_KEY.PAGE_SIZE,
value: Number(pageSize),
});
let error: Nullable<string> = null;
error ||= setConfig({
key: CONFIG_KEY.DECODER_OPTIONS,
value: {formatString, logLevelKey, timestampKey},
});
error ||= setConfig({
key: CONFIG_KEY.PAGE_SIZE,
value: Number(pageSize),
});

if (null !== error) {
// eslint-disable-next-line no-warning-comments
// TODO: Show an error pop-up once NotificationProvider is implemented.
// eslint-disable-next-line no-alert
window.alert(error);
} else {
window.location.reload();
}
if (null !== error) {
postPopup(LOG_LEVEL.ERROR, error, "Unable to apply config.");
} else {
window.location.reload();
}
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Improper use of custom hook within JSX

In React, custom hooks like useHandleConfigFormSubmit should be called at the top level of your component, not within the JSX markup. Calling hooks inside JSX can lead to unexpected behaviour and violates the rules of hooks.

To fix this, call useHandleConfigFormSubmit at the top level and assign the returned handler to a variable, then pass that variable to the onSubmit prop.

Apply this diff to correct the issue:

 const SettingsDialog = forwardRef<HTMLFormElement>((_, ref) => {
     const {setMode, mode} = useColorScheme();
+    const handleConfigFormSubmit = useHandleConfigFormSubmit();

     return (
         <form
             ref={ref}
             tabIndex={-1}
             onReset={handleConfigFormReset}
-            onSubmit={useHandleConfigFormSubmit()}
+            onSubmit={handleConfigFormSubmit}
         >

Also applies to: 130-130

Comment on lines 99 to 114
let error: Nullable<string> = null;
error ||= setConfig({
key: CONFIG_KEY.DECODER_OPTIONS,
value: {formatString, logLevelKey, timestampKey},
});
error ||= setConfig({
key: CONFIG_KEY.PAGE_SIZE,
value: Number(pageSize),
});

if (null !== error) {
// eslint-disable-next-line no-warning-comments
// TODO: Show an error pop-up once NotificationProvider is implemented.
// eslint-disable-next-line no-alert
window.alert(error);
} else {
window.location.reload();
}
if (null !== error) {
postPopup(LOG_LEVEL.ERROR, error, "Unable to apply config.");
} else {
window.location.reload();
}
};
Copy link

@coderabbitai coderabbitai bot Sep 30, 2024

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add validation for form inputs before saving configuration

Currently, there's no validation on the form inputs before setting the configuration. This might lead to issues if the user provides invalid data. For example, Number(pageSize) could result in NaN if the input isn't a valid number.

Consider adding validation to ensure that pageSize is a valid number and that other fields meet the expected formats before saving the configuration.

You can modify the code to include basic validation:

+           const parsedPageSize = Number(pageSize);
+
+           if (isNaN(parsedPageSize) || parsedPageSize <= 0) {
+               postPopup(LOG_LEVEL.ERROR, 'Page size must be a positive number.', 'Invalid Input');
+               return;
+           }

            let error: Nullable<string> = null;
            error ||= setConfig({
                key: CONFIG_KEY.DECODER_OPTIONS,
                value: {formatString, logLevelKey, timestampKey},
            });
            error ||= setConfig({
                key: CONFIG_KEY.PAGE_SIZE,
-               value: Number(pageSize),
+               value: parsedPageSize,
            });

Ensure setConfig properly handles invalid inputs and consider adding validation for the other fields if necessary.

📝 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
let error: Nullable<string> = null;
error ||= setConfig({
key: CONFIG_KEY.DECODER_OPTIONS,
value: {formatString, logLevelKey, timestampKey},
});
error ||= setConfig({
key: CONFIG_KEY.PAGE_SIZE,
value: Number(pageSize),
});
if (null !== error) {
// eslint-disable-next-line no-warning-comments
// TODO: Show an error pop-up once NotificationProvider is implemented.
// eslint-disable-next-line no-alert
window.alert(error);
} else {
window.location.reload();
}
if (null !== error) {
postPopup(LOG_LEVEL.ERROR, error, "Unable to apply config.");
} else {
window.location.reload();
}
};
const parsedPageSize = Number(pageSize);
if (isNaN(parsedPageSize) || parsedPageSize <= 0) {
postPopup(LOG_LEVEL.ERROR, 'Page size must be a positive number.', 'Invalid Input');
return;
}
let error: Nullable<string> = null;
error ||= setConfig({
key: CONFIG_KEY.DECODER_OPTIONS,
value: {formatString, logLevelKey, timestampKey},
});
error ||= setConfig({
key: CONFIG_KEY.PAGE_SIZE,
value: parsedPageSize,
});
if (null !== error) {
postPopup(LOG_LEVEL.ERROR, error, "Unable to apply config.");
} else {
window.location.reload();
}
};

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not related to this PR.

Copy link

Choose a reason for hiding this comment

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

@junhaoliao, understood. Thank you for clarifying.

(_/)
( •_•)
/>💧


✏️ Learnings added
Learnt from: junhaoliao
PR: y-scope/yscope-log-viewer#84
File: new-log-viewer/src/components/modals/SettingsModal/SettingsDialog.tsx:99-114
Timestamp: 2024-09-30T20:49:32.323Z
Learning: When suggesting to add validation for form inputs in `SettingsDialog.tsx`, the user considered it not related to the PR. In future reviews, ensure suggestions align with the PR's scope.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@junhaoliao junhaoliao marked this pull request as draft October 8, 2024 08:00
@junhaoliao junhaoliao changed the title new-log-viewer: Add NotificationContextProvider for publishing and subscribing notifications. WIP - new-log-viewer: Add NotificationContextProvider for publishing and subscribing notifications. Oct 8, 2024
Copy link

@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 (1)
new-log-viewer/src/contexts/StateContextProvider.tsx (1)

177-178: LGTM with a minor suggestion: Improved error handling using NotificationContext

The changes effectively replace console.error with proper UI notifications using postStatus and postPopup. This improvement enhances user feedback and aligns with the PR objectives.

Suggestion: Consider adding postPopup to the useCallback dependency array as well, to ensure consistency with postStatus.

Apply this change to the dependency array:

-    }, [postStatus]);
+    }, [postStatus, postPopup]);

Also applies to: 191-191

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 0df2470 and d0ab264.

📒 Files selected for processing (3)
  • new-log-viewer/src/components/modals/SettingsModal/SettingsDialog.tsx (4 hunks)
  • new-log-viewer/src/contexts/NotificationContextProvider.tsx (1 hunks)
  • new-log-viewer/src/contexts/StateContextProvider.tsx (4 hunks)
🧰 Additional context used
🔇 Additional comments (6)
new-log-viewer/src/contexts/StateContextProvider.tsx (3)

33-33: LGTM: NotificationContext import added

The import statement for NotificationContext has been correctly added. This import is necessary for integrating the new notification system into the StateContextProvider.


143-143: LGTM: NotificationContext integrated

The NotificationContext has been properly integrated into the component using the useContext hook. The destructuring of postStatus and postPopup functions allows for clean and efficient usage of the notification system within the component.


Line range hint 1-364: Overall assessment: Well-implemented NotificationContext integration

The changes in this file successfully integrate the new NotificationContext, improving error handling and user feedback. The modifications align well with the PR objectives and enhance the functionality of the StateContextProvider component. The code is clean, consistent, and follows good practices.

A minor suggestion has been made to include postPopup in the useCallback dependency array for completeness. Otherwise, the implementation looks solid and ready for merging.

new-log-viewer/src/components/modals/SettingsModal/SettingsDialog.tsx (3)

3-3: Imports are correctly updated

The added imports for useContext and NotificationContext are appropriate and correctly utilized in the code.

Also applies to: 27-27


89-117: Well-implemented custom hook for form submission

The useHandleConfigFormSubmit hook effectively encapsulates the form submission logic and properly utilizes the NotificationContext to handle error notifications. The use of useContext within the custom hook is appropriate.


127-127: Proper use of custom hook in component

The handleConfigFormSubmit handler is correctly obtained from the useHandleConfigFormSubmit hook and appropriately used in the onSubmit prop of the form.

window.location.reload();
}
if (null !== error) {
postPopup(LOG_LEVEL.ERROR, error, "Unable to apply config.", DO_NOT_TIMEOUT_VALUE);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure error messages are user-friendly and secure

When displaying errors using postPopup, ensure that the error message is suitable for end-users and does not expose internal details or sensitive information. Consider mapping internal error messages to more user-friendly descriptions.

Comment on lines 85 to 87
const [popupMessages, setPopupMessages] = useState<PopupMessage[]>([]);
const [statusMessage, setStatusMessage] = useState<string>(NOTIFICATION_DEFAULT.statusMessage);
const statusMsgTimeoutRef = useRef<Nullable<ReturnType<typeof setTimeout>>>(null);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Extract repeated colour logic into a helper function

The colour determination logic m.level >= LOG_LEVEL.ERROR ? "danger" : "primary" is repeated at lines 152-154, 161-163, and 169-171. To enhance code maintainability and adhere to the DRY (Don't Repeat Yourself) principle, consider extracting this logic into a helper function.

Apply this diff to refactor the code:

+        const getColourForLevel = (level: LOG_LEVEL): "danger" | "primary" => {
+            return level >= LOG_LEVEL.ERROR ? "danger" : "primary";
+        };
...
-                                color={m.level >= LOG_LEVEL.ERROR ?
-                                    "danger" :
-                                    "primary"}
+                                color={getColourForLevel(m.level)}
...
-                                            color={m.level >= LOG_LEVEL.ERROR ?
-                                                "danger" :
-                                                "primary"}
+                                            color={getColourForLevel(m.level)}
...
-                                            color={m.level >= LOG_LEVEL.ERROR ?
-                                                "danger" :
-                                                "primary"}
+                                            color={getColourForLevel(m.level)}

Also applies to: 152-154, 161-163, 169-171

Comment on lines 172 to 174
onClick={() => {
setPopupMessages((v) => v.filter((vm) => vm !== m));
}}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Clear timeouts when dismissing popup messages manually

When a popup message is dismissed manually via the close button at lines 172-174, the associated timeout is not cleared. This could lead to unnecessary execution of the timeout function and potential memory leaks. To ensure proper cleanup, consider clearing the timeout when the message is dismissed manually.

Apply this diff to fix the issue:

                                             onClick={() => {
+                                                if (m.timeout !== null) {
+                                                    clearTimeout(m.timeout);
+                                                }
                                                 setPopupMessages((v) => v.filter((vm) => vm !== m));
                                             }}
📝 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
onClick={() => {
setPopupMessages((v) => v.filter((vm) => vm !== m));
}}
onClick={() => {
if (m.timeout !== null) {
clearTimeout(m.timeout);
}
setPopupMessages((v) => v.filter((vm) => vm !== m));
}}

@davemarco
Copy link
Contributor

davemarco commented Oct 11, 2024

I took a brieft look a behaviour. I think the pop up is cool. What do you think about not setting the message bar on errors, and just leaving blank for now? We could potentially find another use for it later, but I dont know if we need both the popup and the status message bar showing the same message?

const [statusMessage, setStatusMessage] = useState<string>(NOTIFICATION_DEFAULT.statusMessage);
const statusMsgTimeoutRef = useRef<Nullable<ReturnType<typeof setTimeout>>>(null);

const postPopup = useCallback((
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we have a type for this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We might not need to explicitly specify it at the declaration of postPopup here. When this postPopup value is passed into <NotificationContext.Provider/>'s value prop, if the type doesn't match we should be warned.

title,
timeout: DO_NOT_TIMEOUT_VALUE === timeoutMillis ?
null :
setTimeout(() => {
Copy link
Contributor

Choose a reason for hiding this comment

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

This scares me a bit putting timeout on the state. I have two ideas for this. (1) SIMPLE: Just take the timeout outside the state, but still set it. (2) COMPLICATED: Create a popup component, and pass it a onClose() method - allowing it to delete itself similiar to the filter function underneath. You could also pass it the timeoutMillis. Then you could register the timeout with a ref in the popup component, and have it call onClose() after the timeout.

Later I suggest moving to its own component for UI reasons. But you can do that without the fancy timeout.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Create a popup component, and pass it a onClose() method - allowing it to delete itself similiar to the filter function underneath. You could also pass it the timeoutMillis. Then you could register the timeout with a ref in the popup component, and have it call onClose() after the timeout.

Note that we support creating multiple notification boxes (i.e. multiple pop-up messages can exist) at the same time. Does it mean that we will have to keep the components always mounted once created?

Copy link
Collaborator Author

@junhaoliao junhaoliao Oct 11, 2024

Choose a reason for hiding this comment

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

Right, I think now there's no reason to store the return value of setTimeout. Before we support multiple pop-up messages, the return value was intended to cancel the timeout to avoid the new message getting erased due to the timeout callback.

Copy link
Contributor

Choose a reason for hiding this comment

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

What might work is that the onClose() method will delete the entry from PopupMessages, so the component will unmount after it is deleted?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

sg. implemented at e346322

Note this implementation starts the timer only after PopUpMessageBox is mounted, which is even better imo.

timeout: DO_NOT_TIMEOUT_VALUE === timeoutMillis ?
null :
setTimeout(() => {
setPopupMessages((v) => v.filter((m) => m !== newMessage));
Copy link
Contributor

Choose a reason for hiding this comment

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

This may be fine but also maybe worries me. Is the comparison safe? Consider maybe assigning each one an id or timestamp, so the comparison is safer.

Copy link
Contributor

Choose a reason for hiding this comment

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

By safe i mean there is no deep compare, also maybe an issue for duplicates

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I believe this comparison compares the identities (or I should say "reference") of the objects, which should be safe given no two objects can have the same identity in JS. let me know if I misunderstood.

Copy link
Contributor

Choose a reason for hiding this comment

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

okay sg. I trust.

"primary"}
>
<Stack>
<Box sx={{display: "flex", alignItems: "center"}}>
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible to create a component in another file for this. I think it would clean this up.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done. sorry for not cleaning it up before asking for the review

new-log-viewer/src/contexts/StateContextProvider.tsx Outdated Show resolved Hide resolved
const formData = new FormData(ev.target as HTMLFormElement);
const getFormDataValue = (key: string) => formData.get(key) as string;
const useHandleConfigFormSubmit = () => {
const {postPopup} = useContext(NotificationContext);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason why we aren't defining this directly in the SettingsDialog component? I think it would be simpler and you can still get the context at the root of the component.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Do you mean that we can retrieve the context in SettingsDialog and pass the postPopup as an argument to this useHandleConfigFormSubmit() function?

Copy link
Contributor

Choose a reason for hiding this comment

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

That could work too. Basically I just wanted handleConfigFormSubmit to be a regular callback. I thought of maybe defining inside SettingsDialog so you would have access to popPopup in the parent scope, but passing an arg can also work.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

defining inside SettingsDialog

I see what you mean now. yeah i had to pull this callback out earlier cuz SettingsDialog was getting too long. let me see if I can move the other stuff to squeeze this in.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done. it fits after pulling out the theme toggle lol

new-log-viewer/src/contexts/StateContextProvider.tsx Outdated Show resolved Hide resolved
}
}, []);

return (
Copy link
Contributor

Choose a reason for hiding this comment

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

How do you feel about moving UI stuff into layout? I like the idea of having a higher level notification context, but perhaps a component in the layout imports the context and actually does the rendering?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Sure. That solves the dependency violations.

Copy link
Collaborator Author

@junhaoliao junhaoliao Oct 11, 2024

Choose a reason for hiding this comment

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

Interestingly theming doesn't break on the popup messages after I move the CssVarsProvider back into Layout, possibly due to how the Snackbar is mounted. With that said, I'll still move the PopUpMessagesContainer into Layout to ensure the interdependencies are clean. If it looks too bad we can revert the commit.

<Layout/>
</StateContextProvider>
</UrlContextProvider>
<CssVarsProvider
Copy link
Contributor

Choose a reason for hiding this comment

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

If we move UI into layout, perhaps this change is not neccesary.

Copy link
Collaborator Author

@junhaoliao junhaoliao Oct 11, 2024

Choose a reason for hiding this comment

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

It's a bit tricky that we need to have NotificationContextProvider to be a direct / indirect child of CssVarsProvider so that JoyUI theming stuff can be correctly applied to the UI component like PopUpMessagesContainer.

On the other hand, we need to have the NotificationContextProvider to wrap any children who need to publish / subscribe to the notifications, so we have to change the structure that way.

Are you suggesting that we can extract the UI stuff of the NotificationContextProvider as a separate component which subscribes from the provider and is to be placed inside Layout? Sounds like some enclave territory to me lol. but I guess that works and makes the code cleaner. Let me know if i misunderstood

Copy link
Collaborator Author

@junhaoliao junhaoliao Oct 11, 2024

Choose a reason for hiding this comment

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

Sorry i didn't see #84 (comment) when I read this. Let's continue our discussion there

new-log-viewer/src/contexts/StateContextProvider.tsx Outdated Show resolved Hide resolved
@y-scope y-scope deleted a comment from coderabbitai bot Oct 11, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (6)
new-log-viewer/src/typings/notifications.ts (2)

4-12: LGTM: PopupMessage interface is well-defined. Consider enhancing the JSDoc comment.

The PopupMessage interface is well-structured and includes all necessary properties. However, the JSDoc comment could be more descriptive.

Consider expanding the JSDoc comment to describe each property of the interface. For example:

/**
 * Represents the contents and behaviour of popup messages.
 * @property {LOG_LEVEL} level - The severity level of the message.
 * @property {string} message - The content of the popup message.
 * @property {number} timeoutMillis - The duration in milliseconds before the message is automatically dismissed. Use DO_NOT_TIMEOUT_VALUE for messages that should not auto-dismiss.
 * @property {string} title - The title of the popup message.
 */
interface PopupMessage {
    // ... (rest of the interface remains the same)
}

14-17: LGTM: DO_NOT_TIMEOUT_VALUE is well-defined. Consider using a more distinct sentinel value.

The DO_NOT_TIMEOUT_VALUE constant is appropriately named and its purpose is clear from the JSDoc comment. However, using 0 as a sentinel value might be confused with a very short timeout.

Consider using a more distinct sentinel value, such as -1 or Number.NEGATIVE_INFINITY, to clearly differentiate it from valid timeout values. For example:

/**
 * A value that indicates that a pop-up message should not be automatically dismissed.
 */
const DO_NOT_TIMEOUT_VALUE = Number.NEGATIVE_INFINITY;

This change would make it impossible to confuse the sentinel value with a valid timeout.

new-log-viewer/src/components/Popups/PopupMessageBox.tsx (1)

40-63: LGTM with a minor optimization suggestion.

The state management and effect hook implementation look good. The cleanup function properly clears the interval, which is a good practice to prevent memory leaks.

Consider memoizing the handleCloseButtonClick function to optimize performance:

const handleCloseButtonClick = useCallback(() => {
    handlePopupMessageClose(id);
}, [handlePopupMessageClose, id]);

This change would prevent unnecessary re-creation of the function on each render, potentially improving performance in scenarios with frequent re-renders.

new-log-viewer/src/components/modals/SettingsModal/SettingsDialog.tsx (3)

81-82: LGTM: Good use of forwardRef and context.

The component now correctly uses forwardRef, which is a good practice for reusable components. The extraction of postPopup from NotificationContext is also well-implemented.

Consider adding a prop types definition for better type safety and documentation:

type SettingsDialogProps = {
  // Add any props here if needed
};

const SettingsDialog = forwardRef<HTMLFormElement, SettingsDialogProps>((props, ref) => {
  // ...
});

84-114: LGTM: Improved form submission handling with better error management.

The refactored handleConfigFormSubmit function is well-implemented:

  • Good use of useCallback for performance optimization.
  • Improved error handling using postPopup.
  • Comprehensive handling of form data extraction and config setting.

Consider adding input validation before setting the config:

const pageSize = Number(getFormDataValue(LOCAL_STORAGE_KEY.PAGE_SIZE));
if (isNaN(pageSize) || pageSize <= 0) {
  postPopup({
    level: LOG_LEVEL.ERROR,
    message: "Page size must be a positive number.",
    timeoutMillis: DO_NOT_TIMEOUT_VALUE,
    title: "Invalid Input",
  });
  return;
}

// Then proceed with setting the config

This will prevent invalid values from being set and provide more specific error messages to the user.


Line range hint 1-174: LGTM: Overall improvements to error handling and component structure.

The changes to the SettingsDialog component are well-implemented:

  • Improved error handling with the new notification system.
  • Simplified theme switching with the ThemeSwitchToggle component.
  • Maintained overall functionality while incorporating these improvements.

Consider adding aria-label attributes to the form inputs for better accessibility:

<Input
  defaultValue={field.initialValue}
  name={field.name}
  type={field.type}
  aria-label={field.label}
/>

This will improve the experience for users relying on screen readers.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 779d93b and 38cafbd.

📒 Files selected for processing (5)
  • new-log-viewer/src/components/Popups/PopupMessageBox.tsx (1 hunks)
  • new-log-viewer/src/components/modals/SettingsModal/SettingsDialog.tsx (3 hunks)
  • new-log-viewer/src/contexts/NotificationContextProvider.tsx (1 hunks)
  • new-log-viewer/src/contexts/StateContextProvider.tsx (5 hunks)
  • new-log-viewer/src/typings/notifications.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • new-log-viewer/src/contexts/NotificationContextProvider.tsx
  • new-log-viewer/src/contexts/StateContextProvider.tsx
🧰 Additional context used
🔇 Additional comments (8)
new-log-viewer/src/typings/notifications.ts (3)

1-1: LGTM: Import statement is correct.

The import of LOG_LEVEL from "./logs" is appropriate and necessary for the PopupMessage interface.


19-22: LGTM: DEFAULT_AUTO_DISMISS_TIMEOUT_MILLIS is well-defined and appropriately valued.

The DEFAULT_AUTO_DISMISS_TIMEOUT_MILLIS constant is clearly named, well-documented, and uses numeric literal separation for improved readability. The default value of 10 seconds seems reasonable for auto-dismissing notifications.


25-29: LGTM: Exports are correct and follow good TypeScript practices.

The export statements correctly expose all defined entities (PopupMessage type and both constants). The separation of type and value exports is a good TypeScript practice, enhancing type checking and allowing for potential tree-shaking optimizations.

new-log-viewer/src/components/Popups/PopupMessageBox.tsx (3)

28-39: LGTM: Well-defined interface and component signature.

The PopupMessageProps interface and the PopupMessageBox component signature are well-defined. The JSDoc provides a clear description of the component's purpose, which enhances code readability and maintainability.


80-118: LGTM: Well-structured rendering with good use of Material-UI components.

The component rendering is well-implemented, making good use of Material-UI components. The circular progress indicator provides an excellent visual representation of the message timeout. The overall structure ensures a consistent and user-friendly display of popup messages.


65-78: 🛠️ Refactor suggestion

Enhance color determination for different log levels.

The current color determination is simple but could be more informative. Consider implementing a more detailed color scheme for different log levels, as suggested in a previous review:

const getColorForLogLevel = (level: LOG_LEVEL): string => {
    switch (level) {
        case LOG_LEVEL.ERROR:
            return 'danger';
        case LOG_LEVEL.WARNING:
            return 'warning';
        case LOG_LEVEL.INFO:
            return 'info';
        default:
            return 'primary';
    }
};

const color = getColorForLogLevel(level);

This approach would provide more visual distinction between different types of messages, improving the user experience.

new-log-viewer/src/components/modals/SettingsModal/SettingsDialog.tsx (2)

1-5: LGTM: Import statements are appropriate and necessary.

The new imports (useCallback, useContext, NotificationContext, LOG_LEVEL, and DO_NOT_TIMEOUT_VALUE) are correctly added and align with the changes made in the component. These imports support the refactored handleConfigFormSubmit function and the new notification system.

Also applies to: 19-19, 25-26


131-131: LGTM: Simplified theme switching with ThemeSwitchToggle.

The introduction of the ThemeSwitchToggle component simplifies the UI and likely encapsulates the theme switching logic. This is a good improvement for maintainability and code organization.

Could you provide more information about the ThemeSwitchToggle component? It would be helpful to understand its implementation and ensure it correctly handles theme switching functionality.

Comment on lines 1 to 26
import {
useContext,
useEffect,
useState,
} from "react";

import {
Alert,
Box,
CircularProgress,
IconButton,
Typography,
} from "@mui/joy";

import CloseIcon from "@mui/icons-material/Close";

import {
NotificationContext,
PopupMessage,
} from "../../contexts/NotificationContextProvider";
import {WithId} from "../../typings/common";
import {LOG_LEVEL} from "../../typings/logs";
import {DO_NOT_TIMEOUT_VALUE} from "../../typings/notifications";


const AUTO_DISMISS_PERCENT_UPDATE_INTERVAL_MILLIS = 50;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider increasing the update interval for better performance.

The AUTO_DISMISS_PERCENT_UPDATE_INTERVAL_MILLIS constant is set to 50ms, which might lead to frequent re-renders. Consider increasing this value to reduce the update frequency while still maintaining a smooth visual effect.

For example, you could increase it to 100ms or 200ms:

-const AUTO_DISMISS_PERCENT_UPDATE_INTERVAL_MILLIS = 50;
+const AUTO_DISMISS_PERCENT_UPDATE_INTERVAL_MILLIS = 200;

This change would reduce the number of updates by a factor of 4, potentially improving performance without significantly affecting the user experience.

📝 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
import {
useContext,
useEffect,
useState,
} from "react";
import {
Alert,
Box,
CircularProgress,
IconButton,
Typography,
} from "@mui/joy";
import CloseIcon from "@mui/icons-material/Close";
import {
NotificationContext,
PopupMessage,
} from "../../contexts/NotificationContextProvider";
import {WithId} from "../../typings/common";
import {LOG_LEVEL} from "../../typings/logs";
import {DO_NOT_TIMEOUT_VALUE} from "../../typings/notifications";
const AUTO_DISMISS_PERCENT_UPDATE_INTERVAL_MILLIS = 50;
import {
useContext,
useEffect,
useState,
} from "react";
import {
Alert,
Box,
CircularProgress,
IconButton,
Typography,
} from "@mui/joy";
import CloseIcon from "@mui/icons-material/Close";
import {
NotificationContext,
PopupMessage,
} from "../../contexts/NotificationContextProvider";
import {WithId} from "../../typings/common";
import {LOG_LEVEL} from "../../typings/logs";
import {DO_NOT_TIMEOUT_VALUE} from "../../typings/notifications";
const AUTO_DISMISS_PERCENT_UPDATE_INTERVAL_MILLIS = 200;


let percentRemaining = 100;
if (DO_NOT_TIMEOUT_VALUE !== timeoutMillis) {
const totalIntervals = timeoutMillis / AUTO_DISMISS_PERCENT_UPDATE_INTERVAL_MILLIS;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thinking JoyUI can deal with decimal points I remove the Math.ceil rounding. Let me know if you think the rounding is necessary.

Copy link
Contributor

Choose a reason for hiding this comment

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

I would leave it in. In the percent remaining calc percentRemaining = 100 - (100 * (intervalCount / totalIntervals)); total invervals can be less than one say 0.00001 if timeouttMilis is small. I mean it will never happen but safer to keep in and bound minimum at 1.

Copy link

@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 (4)
new-log-viewer/src/typings/notifications.ts (2)

4-12: LGTM: Well-structured interface. Consider enhancing the JSDoc comment.

The PopUpMessage interface is well-defined with appropriate properties. However, the JSDoc comment could be more descriptive.

Consider expanding the JSDoc comment to describe each property:

/**
 * Represents the contents and behaviour of a pop-up message.
 * @property {LOG_LEVEL} level - The severity level of the message.
 * @property {string} message - The content of the pop-up message.
 * @property {number} timeoutMillis - The duration in milliseconds before the message is automatically dismissed. Use DO_NOT_TIMEOUT_VALUE for messages that should not auto-dismiss.
 * @property {string} title - The title of the pop-up message.
 */

14-17: LGTM: Clear constant definition. Consider using a more distinct sentinel value.

The DO_NOT_TIMEOUT_VALUE constant is well-defined and its purpose is clear from the JSDoc comment. However, using 0 as a sentinel value might be confused with a very short timeout.

Consider using a more distinct sentinel value, such as -1 or Number.NEGATIVE_INFINITY, to clearly differentiate it from valid timeout values:

const DO_NOT_TIMEOUT_VALUE = -1; // or Number.NEGATIVE_INFINITY

This change would make it unambiguous that the value is not a regular timeout duration.

new-log-viewer/src/components/modals/SettingsModal/SettingsDialog.tsx (2)

81-82: LGTM: Improved component structure with context usage

The use of forwardRef and the NotificationContext aligns well with the PR objectives. Great job on implementing the notification system!

Consider using object destructuring for a cleaner syntax:

-const {postPopUp} = useContext(NotificationContext);
+const {postPopUp: postPopup} = useContext(NotificationContext);

This change would maintain consistency with the camelCase naming convention used elsewhere in the codebase.


84-114: LGTM: Improved form submission with new notification system

The refactored handleConfigFormSubmit function effectively implements the new notification system, aligning with the PR objectives. The use of useCallback is a good optimization.

Consider adding a check for the pageSize value before setting the config:

 const pageSize = getFormDataValue(LOCAL_STORAGE_KEY.PAGE_SIZE);
+const parsedPageSize = Number(pageSize);
+
+if (isNaN(parsedPageSize) || parsedPageSize <= 0) {
+    postPopUp({
+        level: LOG_LEVEL.ERROR,
+        message: "Page size must be a positive number.",
+        timeoutMillis: DO_NOT_TIMEOUT_VALUE,
+        title: "Invalid Input",
+    });
+    return;
+}

 let error: Nullable<string> = null;
 error ||= setConfig({
     key: CONFIG_KEY.DECODER_OPTIONS,
     value: {formatString, logLevelKey, timestampKey},
 });
 error ||= setConfig({
     key: CONFIG_KEY.PAGE_SIZE,
-    value: Number(pageSize),
+    value: parsedPageSize,
 });

This addition would prevent invalid page sizes from being set and provide a more specific error message to the user.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 38cafbd and 189be81.

📒 Files selected for processing (7)
  • new-log-viewer/src/components/Layout.tsx (2 hunks)
  • new-log-viewer/src/components/Popups/PopUpMessageBox.tsx (1 hunks)
  • new-log-viewer/src/components/Popups/index.tsx (1 hunks)
  • new-log-viewer/src/components/modals/SettingsModal/SettingsDialog.tsx (3 hunks)
  • new-log-viewer/src/contexts/NotificationContextProvider.tsx (1 hunks)
  • new-log-viewer/src/contexts/StateContextProvider.tsx (5 hunks)
  • new-log-viewer/src/typings/notifications.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • new-log-viewer/src/components/Popups/index.tsx
  • new-log-viewer/src/contexts/NotificationContextProvider.tsx
  • new-log-viewer/src/contexts/StateContextProvider.tsx
🧰 Additional context used
🪛 GitHub Check: lint-check
new-log-viewer/src/components/Layout.tsx

[failure] 7-7:
Unable to resolve path to module './PopUps'

🔇 Additional comments (9)
new-log-viewer/src/typings/notifications.ts (3)

1-1: LGTM: Import statement is correct.

The import of LOG_LEVEL from "./logs" is appropriate and necessary for the PopUpMessage interface.


19-22: LGTM: Well-defined constant with clear purpose.

The DEFAULT_AUTO_DISMISS_TIMEOUT_MILLIS constant is well-defined with a clear purpose. The use of an underscore for numeric literal separation (10_000) improves readability. The JSDoc comment effectively explains its purpose.


25-29: LGTM: Exports are correct and follow good TypeScript practices.

The export statements are well-structured, exporting all necessary items. The separation of type exports and named exports follows good TypeScript practices, improving clarity and type inference in importing files.

new-log-viewer/src/components/Layout.tsx (3)

1-1: LGTM: Import statement simplified

The modification of the import statement for CssVarsProvider from '@mui/joy/styles' to '@mui/joy' is a valid change. This simplification doesn't affect the functionality and aligns with the MUI Joy UI's export structure.


Line range hint 1-33: Overall structure maintains consistency while adding new functionality

The changes to the Layout component successfully introduce the new PopUps component for notifications while maintaining the existing structure and theming. Key points:

  1. The CssVarsProvider continues to wrap all components, ensuring consistent theming.
  2. The addition of PopUps aligns with the PR objectives for implementing a notification system.
  3. The overall layout structure (MenuBar, CentralContainer, StatusBar) remains unchanged.

These modifications effectively address the previous concerns about theming and introduce the new notification functionality without disrupting the existing layout.

🧰 Tools
🪛 GitHub Check: lint-check

[failure] 7-7:
Unable to resolve path to module './PopUps'


7-7: Verify the PopUps component path

The addition of the PopUps component to the layout is in line with the PR objectives for implementing a notification system. Its placement within the CssVarsProvider ensures it receives the correct theme context.

However, the static analysis tool indicates an issue with resolving the path to './PopUps'. Please verify that:

  1. The PopUps component file exists in the same directory as Layout.tsx.
  2. The file name matches the import statement exactly (case-sensitive).

If the file exists and the name is correct, this might be a false positive from the static analysis tool. In that case, you can safely ignore this warning.

To confirm the existence of the PopUps component, you can run:

Also applies to: 27-27

🧰 Tools
🪛 GitHub Check: lint-check

[failure] 7-7:
Unable to resolve path to module './PopUps'

new-log-viewer/src/components/modals/SettingsModal/SettingsDialog.tsx (3)

1-5: LGTM: New imports align with PR objectives

The addition of useCallback, useContext, and the NotificationContext import aligns well with the PR objective of implementing a NotificationContextProvider. The new imports from the logs and notifications typings also support this implementation.

Also applies to: 19-19, 25-26


131-131: LGTM: Simplified theme switching UI

The introduction of the ThemeSwitchToggle component appears to simplify the user interface for theme switching. This is a nice improvement to the settings dialog.

Could you provide more information about the ThemeSwitchToggle component? It would be helpful to understand its functionality and how it integrates with the existing theme system. Consider adding a comment above the component usage to explain its purpose:

+    {/* ThemeSwitchToggle: Allows users to switch between light and dark themes */}
     <ThemeSwitchToggle/>

Line range hint 1-170: Great job implementing the new notification system!

This PR successfully introduces the NotificationContextProvider and integrates it into the SettingsDialog component. The changes align well with the PR objectives:

  1. The NotificationContextProvider is now used for managing notifications.
  2. Existing "FIXME" items have been resolved by utilizing the NotificationProvider for message publishing.
  3. The code structure and error handling have been improved, enhancing the overall user experience.

The introduction of the ThemeSwitchToggle component, while not directly related to the main objectives, is a nice addition that simplifies the UI.

Overall, this is a solid implementation that improves both the functionality and maintainability of the code.

Comment on lines 74 to 76
setTimeout(() => {
handlePopUpMessageClose(id);
}, 0);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Simplify pop-up closure by removing unnecessary setTimeout

In lines 74-76, using setTimeout with a zero delay to call handlePopUpMessageClose(id); is unnecessary. You can directly invoke handlePopUpMessageClose(id); without wrapping it in setTimeout, which simplifies the code and avoids the extra function call.

Apply this diff:

             if (percentRemaining <= 0) {
-                setTimeout(() => {
-                    handlePopUpMessageClose(id);
-                }, 0);
+                handlePopUpMessageClose(id);
             }
📝 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
setTimeout(() => {
handlePopUpMessageClose(id);
}, 0);
if (percentRemaining <= 0) {
handlePopUpMessageClose(id);
}

Comment on lines 69 to 78
let percentRemaining = 100;
if (DO_NOT_TIMEOUT_VALUE !== timeoutMillis) {
const totalIntervals = timeoutMillis / AUTO_DISMISS_PERCENT_UPDATE_INTERVAL_MILLIS;
percentRemaining = 100 - (100 * (intervalCount / totalIntervals));
if (0 >= percentRemaining) {
setTimeout(() => {
handlePopUpMessageClose(id);
}, 0);
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Prevent potential division by zero in percentRemaining calculation

In lines 71-72, if timeoutMillis is less than or equal to zero, totalIntervals may become zero, leading to a division by zero when calculating percentRemaining. This could result in percentRemaining being NaN, causing unexpected behaviour in the progress indicator.

Consider adding a check to prevent division by zero:

     let percentRemaining = 100;
     if (DO_NOT_TIMEOUT_VALUE !== timeoutMillis) {
+        if (timeoutMillis <= 0) {
+            percentRemaining = 0;
+        } else {
             const totalIntervals = timeoutMillis / AUTO_DISMISS_PERCENT_UPDATE_INTERVAL_MILLIS;
             percentRemaining = 100 - (100 * (intervalCount / totalIntervals));
+        }
         if (percentRemaining <= 0) {
             handlePopUpMessageClose(id);
         }
     }
📝 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
let percentRemaining = 100;
if (DO_NOT_TIMEOUT_VALUE !== timeoutMillis) {
const totalIntervals = timeoutMillis / AUTO_DISMISS_PERCENT_UPDATE_INTERVAL_MILLIS;
percentRemaining = 100 - (100 * (intervalCount / totalIntervals));
if (0 >= percentRemaining) {
setTimeout(() => {
handlePopUpMessageClose(id);
}, 0);
}
}
let percentRemaining = 100;
if (DO_NOT_TIMEOUT_VALUE !== timeoutMillis) {
if (timeoutMillis <= 0) {
percentRemaining = 0;
} else {
const totalIntervals = timeoutMillis / AUTO_DISMISS_PERCENT_UPDATE_INTERVAL_MILLIS;
percentRemaining = 100 - (100 * (intervalCount / totalIntervals));
}
if (percentRemaining <= 0) {
handlePopUpMessageClose(id);
}
}

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (6)
new-log-viewer/src/components/PopUps/index.tsx (1)

22-38: Effective rendering logic with room for accessibility improvement.

The component's rendering logic is well-implemented, utilizing MUI Joy components effectively. The use of Stack with column-reverse direction ensures proper message ordering. The map function correctly renders PopUpMessageBox components with unique keys.

Consider adding an aria-live attribute to the Snackbar component to improve accessibility for screen readers:

 <Snackbar
     className={"pop-up-messages-container-snackbar"}
     open={0 < popUpMessages.length}
+    aria-live="polite"
 >

This change will ensure that new messages are announced to users relying on assistive technologies.

new-log-viewer/src/components/PopUps/index.css (2)

1-14: LGTM with a minor suggestion

The .pop-up-messages-container-snackbar class is well-structured and the comments provide clear explanations. The use of CSS variables for positioning is a good practice for maintainability.

Consider reviewing the necessity of !important declarations. While they may be required to override MUI styles, it's generally best to avoid them when possible. If they are indeed necessary, you might want to add a comment explaining why.


42-47: LGTM with suggestions for improvement

The .pop-up-message-box-close-button class effectively customizes the close button size and applies a border radius. The use of a CSS custom property for the button size is good for maintainability.

Consider the following suggestions:

  1. The !important flag on line 44 might be necessary to override MUI styles, but it's generally discouraged. If possible, try to increase the specificity of the selector instead.

  2. The stylelint disable comment on line 43 suggests a linting rule violation. Consider addressing the underlying issue that triggered this rule, if possible, rather than disabling the lint rule.

  3. For consistency, consider using the same units for the border-radius as used for the button size (px instead of rem, or vice versa).

Example refactor:

.MuiIconButton-root.pop-up-message-box-close-button {
    --IconButton-size: 18px;
    border-radius: 9px;
}

This increases specificity, potentially eliminating the need for !important, and uses consistent units.

new-log-viewer/src/components/PopUps/PopUpMessageBox.tsx (3)

28-38: Enhance JSDoc for better documentation

The JSDoc for the PopUpMessageBox component provides a basic description, but it could be more informative. Consider expanding the documentation to include details about the message prop and its structure.

Here's a suggested improvement:

/**
 * Display a pop-up message in an alert box.
 *
 * @param props - The component props
 * @param props.message - An object containing the message details
 * @param props.message.id - Unique identifier for the message
 * @param props.message.level - The severity level of the message
 * @param props.message.message - The content of the message
 * @param props.message.title - The title of the message
 * @param props.message.timeoutMillis - The duration in milliseconds before the message auto-dismisses
 * @returns A React component displaying the pop-up message
 */

39-78: LGTM: Well-implemented state management and auto-dismiss logic

The component's state management and auto-dismiss functionality are well-implemented. The use of useContext for handling message closure and the useEffect hook for managing the auto-dismiss timer are appropriate.

One minor optimization suggestion:

Consider memoizing the handleCloseButtonClick function using useCallback to prevent unnecessary re-creations:

const handleCloseButtonClick = useCallback(() => {
    handlePopUpMessageClose(id);
}, [handlePopUpMessageClose, id]);

This optimization can help prevent potential re-renders of child components that might receive this function as a prop.


80-117: LGTM: Well-structured rendering with good UX considerations

The component's rendering logic is well-implemented, using appropriate MUI components and providing good visual feedback through color coding and the circular progress indicator.

Suggestion for improvement:

Consider enhancing accessibility by adding an aria-label to the close button:

<IconButton
    className={"pop-up-message-box-close-button"}
    color={color}
    size={"sm"}
    onClick={handleCloseButtonClick}
    aria-label="Close message"
>
    <CloseIcon/>
</IconButton>

This addition will improve the experience for users relying on screen readers.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 189be81 and c81d38c.

📒 Files selected for processing (3)
  • new-log-viewer/src/components/PopUps/PopUpMessageBox.tsx (1 hunks)
  • new-log-viewer/src/components/PopUps/index.css (1 hunks)
  • new-log-viewer/src/components/PopUps/index.tsx (1 hunks)
🧰 Additional context used
🔇 Additional comments (9)
new-log-viewer/src/components/PopUps/index.tsx (3)

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

The imports are properly structured, including necessary React hooks, MUI Joy components, and local modules. This demonstrates good modularity and adherence to the project's UI framework.


14-20: Well-structured component with proper context usage.

The PopUps component is well-defined as a functional component with clear JSDoc comments. The use of the useContext hook to access popUpMessages from NotificationContext demonstrates proper implementation of React's context API for state management.


42-42: LGTM: Proper component export.

The PopUps component is correctly exported as the default export, following standard React component export practices.

new-log-viewer/src/components/PopUps/index.css (4)

22-27: LGTM!

The .pop-up-message-box-alert class correctly restores pointer events and adds appropriate padding. The comment explaining the reason for restoring pointer events is helpful for maintainability.


33-36: LGTM!

The .pop-up-message-box-title-container class appropriately uses flexbox for aligning items in the title container. This is a good practice for creating flexible and responsive layouts.


38-40: LGTM!

The .pop-up-message-box-title-text class correctly uses flex-grow: 1 to allow the title text to expand and fill available space within its flex container. This is a good use of flexbox properties.


16-20: Consider scrollbar visibility

The .pop-up-messages-container-stack class effectively manages vertical scrolling and sets a dynamic height using CSS variables, which is good for maintainability.

However, hiding the scrollbar with scrollbar-width: none might affect usability, especially if there's a lot of content. Consider making the scrollbar visible but styled to match your UI. Also, verify if horizontal scrolling should be addressed.

To check if horizontal scrolling is needed, run this script:

new-log-viewer/src/components/PopUps/PopUpMessageBox.tsx (2)

1-26: LGTM: Imports and constants are well-organized

The imports are appropriately structured, including necessary React hooks, MUI components, and custom types. The constant AUTO_DISMISS_PERCENT_UPDATE_INTERVAL_MILLIS is well-defined, enhancing code readability and maintainability.


120-120: LGTM: Correct component export

The component is correctly exported as the default export, following common React practices.

Comment on lines +29 to +31
.pop-up-message-box-alert-layout {
width: 300px;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider using relative units for width

The .pop-up-message-box-alert-layout class sets a fixed width for the alert box. While this ensures consistency, it might not be ideal for all screen sizes.

Consider using relative units (like percentages or rem) or a combination of min-width and max-width to make the layout more responsive. For example:

.pop-up-message-box-alert-layout {
    width: 90%;
    max-width: 300px;
    min-width: 200px;
}

This approach would maintain the desired size on larger screens while adapting to smaller screens.

Comment on lines 73 to 76
if (0 >= percentRemaining) {
setTimeout(() => {
handlePopUpMessageClose(id);
}, 0);
Copy link
Contributor

Choose a reason for hiding this comment

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

I dont fully understand this. Can't we just close if 0 === percentRemaining. Why do we need timeout?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We want to avoid updating some component while rendering another component. (See the console error if that is removed. )

A more proper way is to move this handlePopUpMessageClose() call inside the useEffect. Let me make the change we can discuss further.

new-log-viewer/src/components/PopUps/index.css Outdated Show resolved Hide resolved
@davemarco
Copy link
Contributor

Also i responded to question about Math.Ceil

@davemarco
Copy link
Contributor

I still think the Math.Ceil is safer. After that I approve

davemarco
davemarco previously approved these changes Oct 18, 2024
Copy link
Collaborator

@Henry8192 Henry8192 left a comment

Choose a reason for hiding this comment

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

Some minor suggestions.

@Henry8192 Henry8192 self-requested a review October 18, 2024 20:23
Copy link
Collaborator

@Henry8192 Henry8192 left a comment

Choose a reason for hiding this comment

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

LGTM

@junhaoliao
Copy link
Collaborator Author

junhaoliao commented Oct 19, 2024

For the PR title, how about:

new-log-viewer: Add `NotificationContextProvider` for managing pop-up messages; add pop-ups for errors and remove status bar dummy message.

@junhaoliao junhaoliao changed the title new-log-viewer: Add NotificationContextProvider for publishing and subscribing notifications. new-log-viewer: Add NotificationContextProvider for managing pop-up messages; add pop-ups for errors and remove status bar dummy message. Oct 19, 2024
@junhaoliao junhaoliao merged commit f402065 into y-scope:main Oct 19, 2024
2 checks passed
@junhaoliao junhaoliao deleted the notification branch October 19, 2024 00:39
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.

3 participants