Thanks to visit codestin.com
Credit goes to github.com

Skip to content

refactor: unified panel title for discover vis saved objects#11896

Open
ruanyl wants to merge 3 commits into
opensearch-project:mainfrom
ruanyl:better-vis-title
Open

refactor: unified panel title for discover vis saved objects#11896
ruanyl wants to merge 3 commits into
opensearch-project:mainfrom
ruanyl:better-vis-title

Conversation

@ruanyl
Copy link
Copy Markdown
Member

@ruanyl ruanyl commented May 7, 2026

Description

Removed the custom visualization title setting to keep the behavior consistent with the existing visualizations

Issues Resolved

Screenshot

Testing the changes

Check List

  • All tests pass
    • yarn test:jest
    • yarn test:jest_integration
  • New functionality includes testing.
  • New functionality has been documented.
  • Commits are signed per the DCO using --signoff

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 7, 2026

PR Reviewer Guide 🔍

(Review updated until commit fbae838)

Here are some key observations to aid the review process:

🧪 No relevant tests
🔒 No security concerns identified
✅ No TODO sections
🔀 No multiple PR themes
⚡ Recommended focus areas for review

Missing Config

In createFacetedTimeBarChart, the call to createBaseConfig now passes an empty object instead of a title configuration. However, unlike other similar changes in this file, this line was added as a new line rather than replacing an existing call. This suggests the original createBaseConfig call may have been accidentally removed entirely in the old hunk, potentially breaking the chart configuration pipeline if createBaseConfig is required.

createBaseConfig({}),
Possible Issue

The toolbarVisibility prop logic changed from always passing an object with conditional boolean values inside to conditionally passing false or an object. If the EUI DataGrid component expects toolbarVisibility to always be an object (even with false values), passing the boolean false directly when disableActions is true could cause a runtime error or unexpected behavior.

toolbarVisibility={
  disableActions
    ? false
    : {
        showFullScreenSelector: false,
        showStyleSelector: showStyleSelector ?? true,
        showColumnSelector: true,
      }
}

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 7, 2026

PR Code Suggestions ✨

Latest suggestions up to fbae838

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
General
Verify toolbarVisibility accepts false value

The toolbarVisibility prop now accepts false when disableActions is true, but the
type definition may expect an object or boolean true. Verify that the component's
type definition allows false as a valid value to prevent potential runtime errors.

src/plugins/explore/public/components/visualizations/table/table_vis.tsx [348-356]

 toolbarVisibility={
   disableActions
-    ? false
+    ? undefined
     : {
         showFullScreenSelector: false,
         showStyleSelector: showStyleSelector ?? true,
         showColumnSelector: true,
       }
 }
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a potential type safety issue where toolbarVisibility is set to false when disableActions is true. Using undefined instead of false is a safer approach if the component's type definition doesn't explicitly allow false, preventing potential runtime errors.

Medium

Previous suggestions

Suggestions up to commit 7307d61
CategorySuggestion                                                                                                                                    Impact
Possible issue
Reset loading state after operation

The isLoading state is set to true but never reset to false after the operation
completes or fails. This will prevent subsequent save attempts. Add proper state
cleanup in both success and error cases.

src/plugins/explore/public/components/visualizations/add_to_dashboard_modal.tsx [72-85]

 const handleSave = async () => {
   if (isLoading) return;
   setIsLoading(true);
-  if (savedExplore) {
-    await onConfirm({
-      savedExplore,
-      isTitleDuplicateConfirmed: true,
-      mode: selectedOption,
-      selectDashboard: selectedDashboard,
-      newDashboardName,
-      newTitle: title,
-    });
+  try {
+    if (savedExplore) {
+      await onConfirm({
+        savedExplore,
+        isTitleDuplicateConfirmed: true,
+        mode: selectedOption,
+        selectDashboard: selectedDashboard,
+        newDashboardName,
+        newTitle: title,
+      });
+    }
+  } finally {
+    setIsLoading(false);
   }
 };
Suggestion importance[1-10]: 8

__

Why: The isLoading state is set to true but never reset to false, which will prevent subsequent save attempts. This is a critical bug that needs proper error handling and state cleanup.

Medium
General
Ensure consistent toolbarVisibility type

The toolbarVisibility prop accepts either false or an object, but the type safety is
unclear. Verify that the component's type definition allows false as a valid value,
or use a consistent object structure with all properties set to false.

src/plugins/explore/public/components/visualizations/table/table_vis.tsx [348-357]

 toolbarVisibility={
   disableActions
-    ? false
+    ? {
+        showFullScreenSelector: false,
+        showStyleSelector: false,
+        showColumnSelector: false,
+      }
     : {
         showFullScreenSelector: false,
         showStyleSelector: showStyleSelector ?? true,
         showColumnSelector: true,
       }
 }
Suggestion importance[1-10]: 5

__

Why: Using false vs an object with all properties set to false may cause type inconsistencies. Using a consistent object structure improves type safety and code clarity.

Low
Rename misleading toggle function

The toggleIsPopoverOpen function only opens the popover but never closes it, despite
its name suggesting toggle behavior. This could lead to confusion and unexpected
behavior. Either rename the function or implement proper toggle logic.

src/plugins/explore/public/components/visualizations/style_panel/title/title.tsx [29-33]

-const toggleIsPopoverOpen = useCallback(() => {
+const openPopoverIfNeeded = useCallback(() => {
   if (!isPopoverOpen && !titleOptions.titleName && suggestions.length > 0) {
     setIsPopoverOpen(true);
   }
 }, [isPopoverOpen, titleOptions.titleName, suggestions.length]);
Suggestion importance[1-10]: 4

__

Why: The function name toggleIsPopoverOpen is misleading as it only opens the popover. Renaming to openPopoverIfNeeded would improve code clarity and maintainability.

Low
Suggestions up to commit b16d8e6
CategorySuggestion                                                                                                                                    Impact
General
Fix useMemo dependency array

The useMemo dependency array only includes chartConfig?.styles, but the logic also
accesses chartConfig.styles.titleOptions.titleName. If titleName changes without
styles object reference changing, the memo won't recompute, leading to stale values.

src/plugins/explore/public/components/visualizations/add_to_dashboard_button.tsx [90-95]

 const defaultTitle = useMemo(() => {
   if (chartConfig?.styles && 'titleOptions' in chartConfig.styles) {
     return chartConfig.styles.titleOptions?.titleName || 'Untitled';
   }
   return 'Untitled';
-}, [chartConfig?.styles]);
+}, [chartConfig?.styles?.titleOptions?.titleName]);
Suggestion importance[1-10]: 7

__

Why: The dependency array should include chartConfig?.styles?.titleOptions?.titleName instead of just chartConfig?.styles to ensure the memo recomputes when titleName changes. This is a valid optimization concern that could prevent stale values.

Medium
Suggestions up to commit e4685fe
CategorySuggestion                                                                                                                                    Impact
General
Fix useMemo dependency array

The useMemo dependency array only includes chartConfig?.styles, but the logic also
accesses chartConfig.styles.titleOptions.titleName. If titleName changes without the
styles object reference changing, the memoized value won't update. Consider adding
chartConfig?.styles?.titleOptions?.titleName to dependencies.

src/plugins/explore/public/components/visualizations/add_to_dashboard_button.tsx [90-95]

 const defaultTitle = useMemo(() => {
   if (chartConfig?.styles && 'titleOptions' in chartConfig.styles) {
     return chartConfig.styles.titleOptions?.titleName || 'Untitled';
   }
   return 'Untitled';
-}, [chartConfig?.styles]);
+}, [chartConfig?.styles?.titleOptions?.titleName]);
Suggestion importance[1-10]: 6

__

Why: Valid concern about useMemo dependencies. The current dependency chartConfig?.styles may not trigger re-computation if only titleName changes. However, the impact is moderate since styles object reference typically changes when its properties change.

Low
Log errors in catch block

The empty catch block silently swallows all errors, including potential security
issues or unexpected failures. Consider logging the error for debugging purposes
while still falling through to the default behavior.

src/plugins/explore/public/embeddable/explore_embeddable.tsx [261-272]

 try {
   const { params } = JSON.parse(this.savedExplore.visualization || '{}');
   if (params?.titleOptions?.titleName) {
     return params.titleOptions.titleName;
   }
   if (params?.title) {
     return params.title;
   }
-} catch {
-  // fall through if visualization JSON is malformed
+} catch (error) {
+  // Log error for debugging but fall through to default title
+  console.warn('Failed to parse visualization JSON:', error);
 }
Suggestion importance[1-10]: 5

__

Why: Reasonable suggestion to add logging in the catch block for debugging purposes. However, the current silent failure is intentional fallback behavior, and adding console.warn has minimal impact on functionality.

Low
Handle focus state in effect

The effect doesn't include inputRef.current in the dependency array, but it's used
in the condition. This could lead to stale closure issues. Consider using a ref
callback or adding proper dependencies to ensure the effect runs when focus state
changes.

src/plugins/explore/public/components/visualizations/style_panel/title/title.tsx [35-43]

 useEffect(() => {
   if (titleOptions.titleName) {
     setIsPopoverOpen(false);
   } else {
-    if (inputRef.current === document.activeElement && suggestions.length > 0) {
+    const isInputFocused = inputRef.current === document.activeElement;
+    if (isInputFocused && suggestions.length > 0) {
       setIsPopoverOpen(true);
     }
   }
 }, [titleOptions.titleName, suggestions.length]);
Suggestion importance[1-10]: 4

__

Why: The suggestion identifies a potential stale closure issue with inputRef.current not being in dependencies. However, the improved code doesn't actually fix the issue—it just extracts the value. The real fix would require a different approach or accepting this pattern.

Low
Possible issue
Validate removeById function signature

Verify that removeById is a valid function that accepts an array parameter. If
removeById expects a single ID or different signature, this could cause runtime
errors. Ensure the function is properly imported and handles empty arrays correctly.

src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx [359-361]

 const sortedActions = [...regularActions, ...extraActions]
   .sort(sortByOrderField)
   .filter(removeById(disabledActions ?? []));
+// Add validation: ensure removeById handles empty arrays
Suggestion importance[1-10]: 3

__

Why: The suggestion asks to verify removeById function signature, but without evidence of an actual issue in the PR diff, this is a low-priority validation suggestion. The code appears syntactically correct.

Low
Suggestions up to commit f9f5433
CategorySuggestion                                                                                                                                    Impact
General
Log errors in catch block

The empty catch block silently swallows all errors, including unexpected ones.
Consider logging the error for debugging purposes while still allowing fallback
behavior.

src/plugins/explore/public/embeddable/explore_embeddable.tsx [261-272]

 try {
   const { params } = JSON.parse(this.savedExplore.visualization || '{}');
   if (params?.titleOptions?.titleName) {
     return params.titleOptions.titleName;
   }
   if (params?.title) {
     return params.title;
   }
-} catch {
-  // fall through if visualization JSON is malformed
+} catch (error) {
+  // Log error for debugging but continue with fallback
+  console.warn('Failed to parse visualization JSON:', error);
 }
Suggestion importance[1-10]: 5

__

Why: Adding error logging in the catch block is a reasonable improvement for debugging, though the current silent failure is intentional as indicated by the comment. The suggestion provides marginal value for troubleshooting malformed JSON.

Low
Optimize useMemo dependency array

The dependency array [chartConfig?.styles] may cause unnecessary re-renders.
Consider using chartConfig as the dependency instead, or add
chartConfig?.styles?.titleOptions?.titleName for more precise tracking.

src/plugins/explore/public/components/visualizations/add_to_dashboard_button.tsx [90-95]

 const defaultTitle = useMemo(() => {
   if (chartConfig?.styles && 'titleOptions' in chartConfig.styles) {
     return chartConfig.styles.titleOptions?.titleName || 'Untitled';
   }
   return 'Untitled';
-}, [chartConfig?.styles]);
+}, [chartConfig]);
Suggestion importance[1-10]: 4

__

Why: The suggestion to use chartConfig instead of chartConfig?.styles as a dependency is reasonable but minor. Using the parent object as a dependency is more conservative and may cause slightly more re-renders, but it's safer and the performance impact is negligible in this context.

Low
Add missing dependency to useEffect

The effect lacks inputRef in the dependency array, which could lead to stale closure
issues. Add inputRef.current to dependencies or use a ref callback pattern to avoid
potential bugs.

src/plugins/explore/public/components/visualizations/style_panel/title/title.tsx [35-43]

 useEffect(() => {
   if (titleOptions.titleName) {
     setIsPopoverOpen(false);
   } else {
     if (inputRef.current === document.activeElement && suggestions.length > 0) {
       setIsPopoverOpen(true);
     }
   }
-}, [titleOptions.titleName, suggestions.length]);
+}, [titleOptions.titleName, suggestions.length, inputRef]);
Suggestion importance[1-10]: 3

__

Why: Adding inputRef to the dependency array is technically correct per React's exhaustive-deps rule, but inputRef is a ref object that doesn't change between renders. The current implementation is functionally correct, though adding it would satisfy the linter.

Low
Suggestions up to commit d0ca920
CategorySuggestion                                                                                                                                    Impact
General
Ensure title fallback in handleSave

The title state is initialized with defaultTitle but is never used in the handleSave
function. The newTitle parameter in onConfirm is now optional and may be undefined,
which could cause issues if the consuming code expects a string value.

src/plugins/explore/public/components/visualizations/add_to_dashboard_modal.tsx [72-83]

-const [title, setTitle] = useState<string>(defaultTitle);
+const handleSave = async () => {
+  if (isLoading) return;
+  setIsLoading(true);
+  if (savedExplore) {
+    await onConfirm({
+      savedExplore,
+      isTitleDuplicateConfirmed: true,
+      mode: selectedOption,
+      selectDashboard: selectedDashboard,
+      newDashboardName,
+      newTitle: title || defaultTitle,
+    });
+  }
+};
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that title state is initialized with defaultTitle but the handleSave function passes title which could be empty if the user clears it. Using title || defaultTitle ensures a fallback value is always provided, improving robustness.

Medium
Provide fallback title for panels

The getTitle method returns an empty string when no title is found, but this may
cause panels to appear without any identifier. Consider returning a fallback title
like 'Untitled' or the saved object's ID to ensure panels are always identifiable.

src/plugins/explore/public/embeddable/explore_embeddable.tsx [252-274]

 public getTitle(): string {
   if (this.input.title) {
     return this.input.title;
   }
 
   try {
     const { params } = JSON.parse(this.savedExplore.visualization || '{}');
     if (params?.titleOptions?.titleName) {
       return params.titleOptions.titleName;
     }
     if (params?.title) {
       return params.title;
     }
   } catch {
     // fall through if visualization JSON is malformed
   }
 
-  return '';
+  return this.savedExplore.title || 'Untitled';
 }
Suggestion importance[1-10]: 6

__

Why: Returning an empty string when no title is found could make panels difficult to identify. The suggestion to return this.savedExplore.title || 'Untitled' provides a reasonable fallback, improving user experience by ensuring panels always have some identifier.

Low
Fix toggle behavior for popover

The toggleIsPopoverOpen callback only opens the popover but never closes it, despite
its name suggesting toggle behavior. This could lead to confusion and potential bugs
where the popover remains open unexpectedly.

src/plugins/explore/public/components/visualizations/style_panel/title/title.tsx [29-33]

 const toggleIsPopoverOpen = useCallback(() => {
-  if (!isPopoverOpen && !titleOptions.titleName && suggestions.length > 0) {
-    setIsPopoverOpen(true);
+  if (!titleOptions.titleName && suggestions.length > 0) {
+    setIsPopoverOpen((prev) => !prev);
   }
-}, [isPopoverOpen, titleOptions.titleName, suggestions.length]);
+}, [titleOptions.titleName, suggestions.length]);
Suggestion importance[1-10]: 5

__

Why: The function name toggleIsPopoverOpen suggests toggle behavior, but it only opens the popover. However, the current implementation may be intentional (only open on focus when empty). The suggestion improves naming consistency but may change intended behavior.

Low

@ruanyl ruanyl force-pushed the better-vis-title branch from 907fcdd to 5135979 Compare May 7, 2026 09:44
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 7, 2026

Persistent review updated to latest commit 5135979

Qxisylolo
Qxisylolo previously approved these changes May 7, 2026
});

const { disabledActions } = this.props.embeddable.getInput();
if (disabledActions) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: it seems the earlier filter on just regularActions is redundant as we will filter on regularActions and extraActions, perhaps we can remove it?

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 7, 2026

✅ All unit and integration tests passing

🔗 Workflow run · commit fbae8383b3af362242e24eb84e0ffc0a74fc8d0c

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

Persistent review updated to latest commit 7189aa3

1 similar comment
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

Persistent review updated to latest commit 7189aa3

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

Persistent review updated to latest commit aa4a731

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

Persistent review updated to latest commit 93c7aa6

@ruanyl ruanyl force-pushed the better-vis-title branch from 93c7aa6 to d0ca920 Compare May 8, 2026 08:47
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

Persistent review updated to latest commit d0ca920

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 9, 2026

Persistent review updated to latest commit f9f5433

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 9, 2026

Persistent review updated to latest commit e4685fe

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 9, 2026

Persistent review updated to latest commit b16d8e6

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 9, 2026

Persistent review updated to latest commit 7307d61

@ruanyl ruanyl force-pushed the better-vis-title branch from 7307d61 to fbae838 Compare May 11, 2026 05:01
@github-actions
Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit fbae838

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants