diff --git a/dashboards/src/components/LinksDisplay/LinksDisplay.tsx b/dashboards/src/components/LinksDisplay/LinksDisplay.tsx
index dcd06a9e..16f6e93f 100644
--- a/dashboards/src/components/LinksDisplay/LinksDisplay.tsx
+++ b/dashboards/src/components/LinksDisplay/LinksDisplay.tsx
@@ -11,10 +11,24 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { IconButton, Link as LinkComponent, Menu, MenuItem, Theme, Chip, capitalize, Stack } from '@mui/material';
+import {
+ Box,
+ ClickAwayListener,
+ IconButton,
+ Link as LinkComponent,
+ Menu,
+ MenuItem,
+ MenuList,
+ Paper,
+ Popper,
+ Theme,
+ Chip,
+ capitalize,
+ Stack,
+} from '@mui/material';
import LaunchIcon from 'mdi-material-ui/Launch';
import { Link } from '@perses-dev/spec';
-import { MouseEvent, ReactElement, useState } from 'react';
+import { MouseEvent, ReactElement, useId, useState } from 'react';
import { InfoTooltip } from '@perses-dev/components';
import { useReplaceVariablesInString } from '@perses-dev/plugin-system';
@@ -73,13 +87,19 @@ export function LinksDisplay({ links, variant }: LinksProps): ReactElement | nul
}
}
- // Default: show dropdown menu for multiple links
+ if (variant === 'panel') {
+ return ;
+ }
+
+ // Dashboard variant: show dropdown menu for multiple links
+ const menuButtonId = `${variant}-links-button`;
+
return (
- <>
+
({ borderRadius: theme.shape.borderRadius, padding: '4px' })}
@@ -96,15 +116,75 @@ export function LinksDisplay({ links, variant }: LinksProps): ReactElement | nul
anchorEl={anchorEl}
open={isMenuOpened}
onClose={handleClose}
+ anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
+ transformOrigin={{ vertical: 'top', horizontal: 'right' }}
MenuListProps={{
- 'aria-labelledby': `${variant}-links-button`,
+ 'aria-labelledby': menuButtonId,
}}
>
{links.map((link: Link) => (
))}
- >
+
+ );
+}
+
+function PanelLinksDropdown({ links }: { links: Link[] }): ReactElement {
+ const [anchorEl, setAnchorEl] = useState(null);
+ const menuId = useId();
+ const open = Boolean(anchorEl);
+
+ const handleToggle = (event: MouseEvent): void => {
+ setAnchorEl(anchorEl ? null : event.currentTarget);
+ };
+
+ const handleClose = (): void => {
+ setAnchorEl(null);
+ };
+
+ return (
+ theme.palette.background.default }}>
+
+ ({ borderRadius: theme.shape.borderRadius, padding: '4px' })}
+ >
+ theme.palette.text.secondary }} />
+
+
+
+
);
}
@@ -145,12 +225,12 @@ function LinkButton({ link }: { link: Link }): ReactElement {
);
}
-function LinkMenuItem({ link }: { link: Link }): ReactElement {
+function LinkMenuItem({ link, onNavigate }: { link: Link; onNavigate?: () => void }): ReactElement {
const { url, name, tooltip, targetBlank } = useLink(link);
return (
-
diff --git a/dashboards/src/components/Panel/PanelActions.tsx b/dashboards/src/components/Panel/PanelActions.tsx
index d4a1c885..6e7f4a9c 100644
--- a/dashboards/src/components/Panel/PanelActions.tsx
+++ b/dashboards/src/components/Panel/PanelActions.tsx
@@ -109,9 +109,12 @@ export const PanelActions: React.FC = ({
return undefined;
}, [descriptionTooltipId, description]);
- const linksAction = links && links.length > 0 && ;
const extraActions = editHandlers === undefined && extra;
+ // Return a new LinksDisplay element on each call. A shared JSX variable reused across
+ // responsive header branches can bind the menu anchor to a hidden breakpoint layout.
+ const renderPanelLinks = (): ReactNode => (links?.length ? : null);
+
const queryStateIndicator = useMemo((): ReactNode | undefined => {
const hasData = queryResults.some((q) => q.data);
const isFetching = queryResults.some((q) => q.isFetching);
@@ -271,7 +274,8 @@ export const PanelActions: React.FC = ({
{divider}
- {descriptionAction} {linksAction} {queryStateIndicator} {noticesIndicator} {extraActions} {viewQueryAction}
+ {descriptionAction} {renderPanelLinks()} {queryStateIndicator} {noticesIndicator} {extraActions}{' '}
+ {viewQueryAction}
{readActions} {pluginActions} {itemActions}
{editActions}
@@ -288,7 +292,7 @@ export const PanelActions: React.FC = ({
})}
>
- {descriptionAction} {linksAction}
+ {descriptionAction} {renderPanelLinks()}
{divider} {queryStateIndicator}
{noticesIndicator}
@@ -311,7 +315,7 @@ export const PanelActions: React.FC = ({
})}
>
- {descriptionAction} {linksAction}
+ {descriptionAction} {renderPanelLinks()}
{divider} {queryStateIndicator}
{noticesIndicator}