grafana/public/app/features/explore/ShortLinkButtonMenu.tsx
Kristina bc8ad7b6e5
Explore: Create menu for short link button (#77336)
* WIP first pass

* Change to toolbarbutton/buttonselect pattern

* Move to two toolbarbuttons with dropdown

* Justify text to the right of icons

* Fix betterer

* Fix styling and tests

* Add to docs

* Perist last clicked, add translations

* move styling to core component

* use label for tooltip, let parser combine panes in multiple params

* Explore: Panes encoding suggestions (#78210)

panes encoding suggestions

* WIP-add menu groups

* Get group actions working

* add icons and non-local last selected state

* Fix translations after merge

* Add categories to translation, tweak the verbiage

* Fix translation extraction

* Fix tests

* fix translation conflict

* Log if time is absolute

---------

Co-authored-by: Giordano Ricci <me@giordanoricci.com>
2023-12-12 09:55:03 -06:00

158 lines
4.8 KiB
TypeScript

import React, { useState } from 'react';
import { IconName } from '@grafana/data';
import { reportInteraction, config } from '@grafana/runtime';
import { ToolbarButton, Dropdown, Menu, Stack, ToolbarButtonRow, MenuGroup } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { copyStringToClipboard } from 'app/core/utils/explore';
import { createAndCopyShortLink } from 'app/core/utils/shortLinks';
import { useSelector } from 'app/types';
import { selectPanes } from './state/selectors';
import { constructAbsoluteUrl } from './utils/links';
interface ShortLinkGroupData {
key: string;
label: string;
items: ShortLinkMenuItemData[];
}
interface ShortLinkMenuItemData {
key: string;
label: string;
icon: IconName;
getUrl: Function;
shorten: boolean;
absTime: boolean;
}
const defaultMode: ShortLinkMenuItemData = {
key: 'copy-link',
label: t('explore.toolbar.copy-shortened-link', 'Copy shortened URL'),
icon: 'share-alt',
getUrl: () => undefined,
shorten: true,
absTime: false,
};
export function ShortLinkButtonMenu() {
const panes = useSelector(selectPanes);
const [isOpen, setIsOpen] = useState(false);
const [lastSelected, setLastSelected] = useState(defaultMode);
const onCopyLink = (shorten: boolean, absTime: boolean, url?: string) => {
if (shorten) {
createAndCopyShortLink(url || global.location.href);
reportInteraction('grafana_explore_shortened_link_clicked', { isAbsoluteTime: absTime });
} else {
copyStringToClipboard(
url !== undefined
? `${window.location.protocol}//${window.location.host}${config.appSubUrl}${url}`
: global.location.href
);
reportInteraction('grafana_explore_copy_link_clicked', { isAbsoluteTime: absTime });
}
};
const menuOptions: ShortLinkGroupData[] = [
{
key: 'normal',
label: t('explore.toolbar.copy-links-normal-category', 'Normal URL links'),
items: [
{
key: 'copy-shortened-link',
icon: 'link',
label: t('explore.toolbar.copy-shortened-link', 'Copy shortened URL'),
getUrl: () => undefined,
shorten: true,
absTime: false,
},
{
key: 'copy-link',
icon: 'link',
label: t('explore.toolbar.copy-link', 'Copy URL'),
getUrl: () => undefined,
shorten: false,
absTime: false,
},
],
},
{
key: 'timesync',
label: t('explore.toolbar.copy-links-absolute-category', 'Time-sync URL links (share with time range intact)'),
items: [
{
key: 'copy-short-link-abs-time',
icon: 'clock-nine',
label: t('explore.toolbar.copy-shortened-link-abs-time', 'Copy Absolute Shortened URL'),
shorten: true,
getUrl: () => {
return constructAbsoluteUrl(panes);
},
absTime: true,
},
{
key: 'copy-link-abs-time',
icon: 'clock-nine',
label: t('explore.toolbar.copy-link-abs-time', 'Copy Absolute Shortened URL'),
shorten: false,
getUrl: () => {
return constructAbsoluteUrl(panes);
},
absTime: true,
},
],
},
];
const MenuActions = (
<Menu>
{menuOptions.map((groupOption) => {
return (
<MenuGroup key={groupOption.key} label={groupOption.label}>
{groupOption.items.map((option) => {
return (
<Menu.Item
key={option.key}
label={option.label}
icon={option.icon}
onClick={() => {
const url = option.getUrl();
onCopyLink(option.shorten, option.absTime, url);
setLastSelected(option);
}}
/>
);
})}
</MenuGroup>
);
})}
</Menu>
);
// we need the Toolbar button click to be an action separate from opening/closing the menu
return (
<ToolbarButtonRow>
<Stack gap={0} direction="row" alignItems="center" wrap="nowrap">
<ToolbarButton
tooltip={lastSelected.label}
icon={lastSelected.icon}
iconOnly={true}
narrow={true}
onClick={() => {
const url = lastSelected.getUrl();
onCopyLink(lastSelected.shorten, lastSelected.absTime, url);
}}
aria-label={t('explore.toolbar.copy-shortened-link', 'Copy shortened URL')}
/>
<Dropdown overlay={MenuActions} placement="bottom-end" onVisibleChange={setIsOpen}>
<ToolbarButton
narrow={true}
isOpen={isOpen}
aria-label={t('explore.toolbar.copy-shortened-link-menu', 'Open copy link options')}
/>
</Dropdown>
</Stack>
</ToolbarButtonRow>
);
}