@grafana/ui
Version:
Grafana Components Library
12,070 lines • 399 kB
JavaScript
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var css = require('@emotion/css');
require('react-data-grid/lib/styles.css');
var clsx = require('clsx');
var memoize = require('micro-memoize');
var React = require('react');
var reactDataGrid = require('react-data-grid');
var data = require('@grafana/data');
var i18n = require('@grafana/i18n');
var schema = require('@grafana/schema');
var hoistNonReactStatics = require('hoist-non-react-statics');
var lodash = require('lodash');
var tinycolor = require('tinycolor2');
var SVG = require('react-inlinesvg');
var react = require('@floating-ui/react');
var e2eSelectors = require('@grafana/e2e-selectors');
var ReactDOM = require('react-dom');
var reactUse = require('react-use');
var ReactDOMServer = require('react-dom/server');
var reactTransitionGroup = require('react-transition-group');
var dialog = require('@react-aria/dialog');
var focus = require('@react-aria/focus');
var overlays = require('@react-aria/overlays');
var reactHookForm = require('react-hook-form');
var RcDrawer = require('rc-drawer');
require('rc-drawer/assets/index.css');
var WKT = require('ol/format/WKT');
var Geometry = require('ol/geom/Geometry');
var uwrap = require('uwrap');
var geom = require('ol/geom');
var uPlot = require('uplot');
require('uplot/dist/uPlot.min.css');
var reactWindow = require('react-window');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
function _interopNamespaceCompat(e) {
if (e && typeof e === 'object' && 'default' in e) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var clsx__default = /*#__PURE__*/_interopDefaultCompat(clsx);
var memoize__default = /*#__PURE__*/_interopDefaultCompat(memoize);
var React__namespace = /*#__PURE__*/_interopNamespaceCompat(React);
var hoistNonReactStatics__default = /*#__PURE__*/_interopDefaultCompat(hoistNonReactStatics);
var tinycolor__default = /*#__PURE__*/_interopDefaultCompat(tinycolor);
var SVG__default = /*#__PURE__*/_interopDefaultCompat(SVG);
var ReactDOM__default = /*#__PURE__*/_interopDefaultCompat(ReactDOM);
var ReactDOMServer__default = /*#__PURE__*/_interopDefaultCompat(ReactDOMServer);
var RcDrawer__default = /*#__PURE__*/_interopDefaultCompat(RcDrawer);
var WKT__default = /*#__PURE__*/_interopDefaultCompat(WKT);
var Geometry__default = /*#__PURE__*/_interopDefaultCompat(Geometry);
var uPlot__default = /*#__PURE__*/_interopDefaultCompat(uPlot);
"use strict";
const fadeIn = css.keyframes({
"0%": {
opacity: 0
},
"100%": {
opacity: 1
}
});
const skeletonAnimation = {
animationName: fadeIn,
animationDelay: "100ms",
animationTimingFunction: "ease-in",
animationDuration: "100ms",
animationFillMode: "backwards"
};
const attachSkeleton = (Component, Skeleton) => {
const skeletonWrapper = (props) => {
return /* @__PURE__ */ jsxRuntime.jsx(
Skeleton,
{
...props,
rootProps: {
style: skeletonAnimation
}
}
);
};
return Object.assign(Component, { Skeleton: skeletonWrapper });
};
"use strict";
function stylesFactory(stylesCreator) {
return memoize__default.default(stylesCreator);
}
"use strict";
let ThemeContextMock = null;
const memoizedStyleCreators = /* @__PURE__ */ new WeakMap();
const withTheme = (Component) => {
const WithTheme = (props) => {
const ContextComponent = ThemeContextMock || data.ThemeContext;
return (
// @ts-ignore
/* @__PURE__ */ jsxRuntime.jsx(ContextComponent.Consumer, { children: (theme) => /* @__PURE__ */ jsxRuntime.jsx(Component, { ...props, theme: theme.v1 }) })
);
};
WithTheme.displayName = `WithTheme(${Component.displayName})`;
hoistNonReactStatics__default.default(WithTheme, Component);
return WithTheme;
};
const withTheme2 = (Component) => {
const WithTheme = (props) => {
const ContextComponent = ThemeContextMock || data.ThemeContext;
return (
// @ts-ignore
/* @__PURE__ */ jsxRuntime.jsx(ContextComponent.Consumer, { children: (theme) => /* @__PURE__ */ jsxRuntime.jsx(Component, { ...props, theme }) })
);
};
WithTheme.displayName = `WithTheme(${Component.displayName})`;
hoistNonReactStatics__default.default(WithTheme, Component);
return WithTheme;
};
function useTheme() {
return React.useContext(ThemeContextMock || data.ThemeContext).v1;
}
function useTheme2() {
return React.useContext(ThemeContextMock || data.ThemeContext);
}
function useStyles(getStyles) {
const theme = useTheme();
let memoizedStyleCreator = memoizedStyleCreators.get(getStyles);
if (!memoizedStyleCreator) {
memoizedStyleCreator = stylesFactory(getStyles);
memoizedStyleCreators.set(getStyles, memoizedStyleCreator);
}
return memoizedStyleCreator(theme);
}
function useStyles2(getStyles, ...additionalArguments) {
const theme = useTheme2();
if (!theme.colors.background.elevated) {
theme.colors.background.elevated = theme.colors.mode === "light" ? theme.colors.background.primary : theme.colors.background.secondary;
}
let memoizedStyleCreator = memoizedStyleCreators.get(getStyles);
if (!memoizedStyleCreator) {
memoizedStyleCreator = memoize__default.default(getStyles, { maxSize: 10 });
memoizedStyleCreators.set(getStyles, memoizedStyleCreator);
}
return memoizedStyleCreator(theme, ...additionalArguments);
}
const mockThemeContext = (theme) => {
ThemeContextMock = React__namespace.createContext(theme);
return () => {
ThemeContextMock = null;
};
};
"use strict";
const PALETTE_ROWS = 4;
const DEFAULT_ANNOTATION_COLOR = "rgba(0, 211, 255, 1)";
const OK_COLOR = "rgba(11, 237, 50, 1)";
const ALERTING_COLOR = "rgba(237, 46, 24, 1)";
const NO_DATA_COLOR = "rgba(150, 150, 150, 1)";
const PENDING_COLOR = "rgba(247, 149, 32, 1)";
const REGION_FILL_ALPHA = 0.09;
const colors = [
"#7EB26D",
// 0: pale green
"#EAB839",
// 1: mustard
"#6ED0E0",
// 2: light blue
"#EF843C",
// 3: orange
"#E24D42",
// 4: red
"#1F78C1",
// 5: ocean
"#BA43A9",
// 6: purple
"#705DA0",
// 7: violet
"#508642",
// 8: dark green
"#CCA300",
// 9: dark sand
"#447EBC",
"#C15C17",
"#890F02",
"#0A437C",
"#6D1F62",
"#584477",
"#B7DBAB",
"#F4D598",
"#70DBED",
"#F9BA8F",
"#F29191",
"#82B5D8",
"#E5A8E2",
"#AEA2E0",
"#629E51",
"#E5AC0E",
"#64B0C8",
"#E0752D",
"#BF1B00",
"#0A50A1",
"#962D82",
"#614D93",
"#9AC48A",
"#F2C96D",
"#65C5DB",
"#F9934E",
"#EA6460",
"#5195CE",
"#D683CE",
"#806EB7",
"#3F6833",
"#967302",
"#2F575E",
"#99440A",
"#58140C",
"#052B51",
"#511749",
"#3F2B5B",
"#E0F9D7",
"#FCEACA",
"#CFFAFF",
"#F9E2D2",
"#FCE2DE",
"#BADFF4",
"#F9D9F9",
"#DEDAF7"
];
function sortColorsByHue(hexColors) {
const hslColors = lodash.map(hexColors, hexToHsl);
const sortedHSLColors = lodash.sortBy(hslColors, ["h"]);
const chunkedHSLColors = lodash.chunk(sortedHSLColors, PALETTE_ROWS);
const sortedChunkedHSLColors = lodash.map(chunkedHSLColors, (chunk2) => {
return lodash.sortBy(chunk2, "l");
});
const flattenedZippedSortedChunkedHSLColors = lodash.flattenDeep(lodash.zip(...sortedChunkedHSLColors));
return lodash.map(flattenedZippedSortedChunkedHSLColors, hslToHex);
}
function hexToHsl(color) {
return tinycolor__default.default(color).toHsl();
}
function hslToHex(color) {
return tinycolor__default.default(color).toHexString();
}
function getTextColorForBackground(color) {
const b = tinycolor__default.default(color).getBrightness();
return b > 180 ? "rgb(32, 34, 38)" : "rgb(247, 248, 250)";
}
function getTextColorForAlphaBackground(color, themeIsDark) {
const tcolor = tinycolor__default.default(color);
const b = tcolor.getBrightness();
const a = tcolor.getAlpha();
if (a < 0.3) {
return themeIsDark ? "rgb(247, 248, 250)" : "rgb(32, 34, 38)";
}
return b > 180 ? "rgb(32, 34, 38)" : "rgb(247, 248, 250)";
}
let sortedColors = sortColorsByHue(colors);
"use strict";
function cardChrome(theme) {
return `
background: ${theme.colors.background.secondary};
&:hover {
background: ${hoverColor(theme.colors.background.secondary, theme)};
}
box-shadow: ${theme.components.panel.boxShadow};
border-radius: ${theme.shape.radius.default};
`;
}
function hoverColor(color, theme) {
return theme.isDark ? tinycolor__default.default(color).brighten(2).toString() : tinycolor__default.default(color).darken(2).toString();
}
function listItem(theme) {
return `
background: ${theme.colors.background.secondary};
&:hover {
background: ${hoverColor(theme.colors.background.secondary, theme)};
}
box-shadow: ${theme.components.panel.boxShadow};
border-radius: ${theme.shape.radius.default};
`;
}
function listItemSelected(theme) {
return `
background: ${hoverColor(theme.colors.background.secondary, theme)};
color: ${theme.colors.text.maxContrast};
`;
}
function mediaUp(breakpoint) {
return `only screen and (min-width: ${breakpoint})`;
}
const isGrafanaTheme2 = (theme) => theme.hasOwnProperty("v1");
const focusCss = (theme) => {
const isTheme2 = isGrafanaTheme2(theme);
const firstColor = isTheme2 ? theme.colors.background.canvas : theme.colors.bodyBg;
const secondColor = isTheme2 ? theme.colors.primary.main : theme.colors.formFocusOutline;
return `
outline: 2px dotted transparent;
outline-offset: 2px;
box-shadow: 0 0 0 2px ${firstColor}, 0 0 0px 4px ${secondColor};
transition-property: outline, outline-offset, box-shadow;
transition-duration: 0.2s;
transition-timing-function: cubic-bezier(0.19, 1, 0.22, 1);`;
};
function getMouseFocusStyles(theme) {
return {
outline: "none",
boxShadow: `none`
};
}
function getFocusStyles(theme) {
return {
outline: "2px dotted transparent",
outlineOffset: "2px",
boxShadow: `0 0 0 2px ${theme.colors.background.canvas}, 0 0 0px 4px ${theme.colors.primary.main}`,
transitionTimingFunction: `cubic-bezier(0.19, 1, 0.22, 1)`,
transitionDuration: "0.2s",
transitionProperty: "outline, outline-offset, box-shadow"
};
}
function getButtonFocusStyles(theme) {
return {
...getFocusStyles(theme),
transitionProperty: void 0
};
}
const getTooltipContainerStyles = (theme) => ({
overflow: "hidden",
background: theme.colors.background.elevated,
boxShadow: theme.shadows.z2,
maxWidth: "800px",
padding: theme.spacing(1),
borderRadius: theme.shape.radius.default,
zIndex: theme.zIndex.tooltip
});
const getExternalRadius = (theme, offset, additionalOptions = {}) => {
const { selfBorderWidth = 1, childBorderRadius } = additionalOptions;
const childBorderRadiusPx = childBorderRadius !== void 0 ? `${childBorderRadius}px` : theme.shape.radius.default;
return `calc(max(0px, ${childBorderRadiusPx} + ${offset}px + ${selfBorderWidth}px))`;
};
const getInternalRadius = (theme, offset, additionalOptions = {}) => {
const { parentBorderWidth = 1, parentBorderRadius } = additionalOptions;
const parentBorderRadiusPx = parentBorderRadius !== void 0 ? `${parentBorderRadius}px` : theme.shape.radius.default;
return `calc(max(0px, ${parentBorderRadiusPx} - ${offset}px - ${parentBorderWidth}px))`;
};
"use strict";
const getFocusStyle = (theme) => css.css({
"&:focus": getFocusStyles(theme)
});
const sharedInputStyle = (theme, invalid = false) => {
const borderColor = invalid ? theme.colors.error.border : theme.components.input.borderColor;
const borderColorHover = invalid ? theme.colors.error.shade : theme.components.input.borderHover;
const background = theme.components.input.background;
const textColor = theme.components.input.text;
const autoFillBorder = theme.isDark ? "#2e2f35" : "#bab4ca";
return css.cx(
inputPadding(theme),
css.css({
background,
lineHeight: theme.typography.body.lineHeight,
fontSize: theme.typography.size.md,
color: textColor,
border: `1px solid ${borderColor}`,
"&:-webkit-autofill, &:-webkit-autofill:hover": {
/* Welcome to 2005. This is a HACK to get rid od Chromes default autofill styling */
boxShadow: `inset 0 0 0 1px rgba(255, 255, 255, 0), inset 0 0 0 100px ${background}!important`,
WebkitTextFillColor: `${textColor} !important`,
borderColor: autoFillBorder
},
"&:-webkit-autofill:focus": {
/* Welcome to 2005. This is a HACK to get rid od Chromes default autofill styling */
boxShadow: `0 0 0 2px ${theme.colors.background.primary}, 0 0 0px 4px ${theme.colors.primary.main}, inset 0 0 0 1px rgba(255, 255, 255, 0), inset 0 0 0 100px ${background}!important`,
WebkitTextFillColor: `${textColor} !important`
},
"&:hover": {
borderColor: borderColorHover
},
"&:focus": {
outline: "none"
},
"&:disabled": {
backgroundColor: theme.colors.action.disabledBackground,
color: theme.colors.action.disabledText,
border: `1px solid ${theme.colors.action.disabledBackground}`,
"&:hover": {
borderColor
}
},
"&::placeholder": {
color: theme.colors.text.disabled,
opacity: 1
}
})
);
};
const inputPadding = (theme) => {
return css.css({
padding: theme.spacing(0, 1, 0, 1)
});
};
const inputSizes = () => {
return {
sm: css.css({
width: inputSizesPixels("sm")
}),
md: css.css({
width: inputSizesPixels("md")
}),
lg: css.css({
width: inputSizesPixels("lg")
}),
auto: css.css({
width: inputSizesPixels("auto")
})
};
};
const inputSizesPixels = (size) => {
switch (size) {
case "sm":
return "200px";
case "md":
return "320px";
case "lg":
return "580px";
case "auto":
default:
return "auto";
}
};
function getPropertiesForButtonSize(size, theme) {
switch (size) {
case "sm":
return {
padding: 1,
fontSize: theme.typography.size.sm,
height: theme.components.height.sm
};
case "lg":
return {
padding: 3,
fontSize: theme.typography.size.lg,
height: theme.components.height.lg
};
case "md":
default:
return {
padding: 2,
fontSize: theme.typography.size.md,
height: theme.components.height.md
};
}
}
"use strict";
const spin$1 = css.keyframes({
"0%": {
transform: "rotate(0deg)"
},
"100%": {
transform: "rotate(359deg)"
}
});
"use strict";
const alwaysMonoIcons = [
"grafana",
"favorite",
"heart-break",
"heart",
"panel-add",
"library-panel",
"circle-mono"
];
function getIconSubDir(name, type) {
if (name == null ? void 0 : name.startsWith("gf-")) {
return "custom";
} else if (alwaysMonoIcons.includes(name)) {
return "mono";
} else if (type === "default") {
return "unicons";
} else if (type === "solid") {
return "solid";
} else {
return "mono";
}
}
function getSvgSize(size) {
switch (size) {
case "xs":
return 12;
case "sm":
return 14;
case "md":
return 16;
case "lg":
return 18;
case "xl":
return 24;
case "xxl":
return 36;
case "xxxl":
return 48;
}
}
let iconRoot;
function getIconRoot() {
if (iconRoot) {
return iconRoot;
}
const grafanaPublicPath = typeof window !== "undefined" && window.__grafana_public_path__;
if (grafanaPublicPath) {
iconRoot = grafanaPublicPath + "build/img/icons/";
} else {
iconRoot = "public/build/img/icons/";
}
return iconRoot;
}
function getIconPath(name, type = "default") {
const iconRoot2 = getIconRoot();
const subDir = getIconSubDir(name, type);
return `${iconRoot2}${subDir}/${name}.svg`;
}
"use strict";
const getIconStyles = (theme) => {
return {
icon: css.css({
display: "inline-block",
fill: "currentColor",
flexShrink: 0,
label: "Icon",
// line-height: 0; is needed for correct icon alignment in Safari
lineHeight: 0,
verticalAlign: "middle"
}),
orange: css.css({
fill: theme.v1.palette.orange
}),
spin: css.css({
[theme.transitions.handleMotion("no-preference", "reduce")]: {
animation: `${spin$1} 2s infinite linear`
}
})
};
};
const Icon = React__namespace.memo(
React__namespace.forwardRef(
({ size = "md", type = "default", name, className, style, title = "", ...rest }, ref) => {
const styles = useStyles2(getIconStyles);
if (!data.isIconName(name)) {
console.warn("Icon component passed an invalid icon name", name);
}
const iconName = name === "fa fa-spinner" ? "spinner" : name;
const svgSize = getSvgSize(size);
const svgHgt = svgSize;
const svgWid = name.startsWith("gf-bar-align") ? 16 : name.startsWith("gf-interp") ? 30 : svgSize;
const svgPath = getIconPath(iconName, type);
const composedClassName = css.cx(
styles.icon,
className,
type === "mono" ? { [styles.orange]: name === "favorite" } : "",
{
[styles.spin]: iconName === "spinner"
}
);
return /* @__PURE__ */ jsxRuntime.jsx(
SVG__default.default,
{
"aria-hidden": rest.tabIndex === void 0 && !title && !rest["aria-label"] && !rest["aria-labelledby"] && !rest["aria-describedby"],
innerRef: ref,
src: svgPath,
width: svgWid,
height: svgHgt,
title,
className: composedClassName,
style,
loader: /* @__PURE__ */ jsxRuntime.jsx(
"span",
{
className: css.cx(
css.css({
width: svgWid,
height: svgHgt
}),
composedClassName
)
}
),
...rest
}
);
}
)
);
Icon.displayName = "Icon";
"use strict";
const BOUNDARY_ELEMENT_ID = "floating-boundary";
function getPositioningMiddleware(placement) {
var _a;
const middleware = [];
const flipMiddleware = react.flip({
// Ensure we flip to the perpendicular axis if it doesn't fit
// on narrow viewports.
crossAxis: "alignment",
fallbackAxisSideDirection: "end",
boundary: (_a = document.getElementById(BOUNDARY_ELEMENT_ID)) != null ? _a : void 0
});
const shiftMiddleware = react.shift();
if (placement == null ? void 0 : placement.includes("-")) {
middleware.push(flipMiddleware, shiftMiddleware);
} else {
middleware.push(shiftMiddleware, flipMiddleware);
}
return middleware;
}
"use strict";
function getPlacement(placement) {
switch (placement) {
case "auto":
return "bottom";
case "auto-start":
return "bottom-start";
case "auto-end":
return "bottom-end";
default:
return placement != null ? placement : "bottom";
}
}
function buildTooltipTheme(theme, tooltipBg, toggletipBorder, tooltipText, tooltipPadding) {
return {
arrow: css.css({
fill: tooltipBg
}),
container: css.css({
backgroundColor: tooltipBg,
borderRadius: theme.shape.radius.default,
border: `1px solid ${toggletipBorder}`,
boxShadow: theme.shadows.z2,
color: tooltipText,
fontSize: theme.typography.bodySmall.fontSize,
padding: theme.spacing(tooltipPadding.topBottom, tooltipPadding.rightLeft),
[theme.transitions.handleMotion("no-preference", "reduce")]: {
transition: "opacity 0.3s"
},
zIndex: theme.zIndex.tooltip,
maxWidth: "400px",
overflowWrap: "break-word",
"&[data-popper-interactive='false']": {
pointerEvents: "none"
}
}),
headerClose: css.css({
color: theme.colors.text.secondary,
position: "absolute",
right: theme.spacing(1),
top: theme.spacing(1.5),
backgroundColor: "transparent",
border: 0
}),
header: css.css({
paddingTop: theme.spacing(1),
paddingBottom: theme.spacing(2)
}),
body: css.css({
paddingTop: theme.spacing(1),
paddingBottom: theme.spacing(1)
}),
footer: css.css({
paddingTop: theme.spacing(2),
paddingBottom: theme.spacing(1)
})
};
}
"use strict";
function Portal(props) {
var _a;
const { children, className, root, forwardedRef } = props;
const theme = useTheme2();
const node = React.useRef(null);
const portalRoot = root != null ? root : getPortalContainer();
if (!node.current) {
node.current = document.createElement("div");
if (className) {
node.current.className = className;
}
node.current.style.position = "relative";
node.current.style.zIndex = `${(_a = props.zIndex) != null ? _a : theme.zIndex.portal}`;
}
React.useLayoutEffect(() => {
if (node.current) {
portalRoot.appendChild(node.current);
}
return () => {
if (node.current) {
portalRoot.removeChild(node.current);
}
};
}, [portalRoot]);
return ReactDOM__default.default.createPortal(/* @__PURE__ */ jsxRuntime.jsx("div", { ref: forwardedRef, children }), node.current);
}
function getPortalContainer() {
var _a;
return (_a = window.document.getElementById("grafana-portal-container")) != null ? _a : document.body;
}
function PortalContainer() {
const styles = useStyles2(getStyles$S);
return /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
id: "grafana-portal-container",
"data-testid": e2eSelectors.selectors.components.Portal.container,
className: styles.grafanaPortalContainer
}
);
}
const getStyles$S = (theme) => {
return {
grafanaPortalContainer: css.css({
position: "fixed",
top: 0,
width: "100%",
zIndex: theme.zIndex.portal
})
};
};
const RefForwardingPortal = React__namespace.forwardRef((props, ref) => {
return /* @__PURE__ */ jsxRuntime.jsx(Portal, { ...props, forwardedRef: ref });
});
RefForwardingPortal.displayName = "RefForwardingPortal";
"use strict";
const Tooltip = React.forwardRef(
({ children, theme, interactive, show, placement, content }, forwardedRef) => {
const arrowRef = React.useRef(null);
const [controlledVisible, setControlledVisible] = React.useState(show);
const isOpen = show != null ? show : controlledVisible;
const floatingUIPlacement = getPlacement(placement);
const middleware = [
react.offset(8),
...getPositioningMiddleware(floatingUIPlacement),
react.arrow({
element: arrowRef
})
];
const { context, refs, floatingStyles } = react.useFloating({
open: isOpen,
placement: floatingUIPlacement,
onOpenChange: setControlledVisible,
middleware,
whileElementsMounted: react.autoUpdate
});
const tooltipId = React.useId();
const hover = react.useHover(context, {
handleClose: interactive ? react.safePolygon() : void 0,
move: false
});
const focus = react.useFocus(context);
const dismiss = react.useDismiss(context);
const { getReferenceProps, getFloatingProps } = react.useInteractions([dismiss, hover, focus]);
const contentIsFunction = typeof content === "function";
const styles = useStyles2(getStyles$R);
const style = styles[theme != null ? theme : "info"];
const handleRef = React.useCallback(
(ref) => {
refs.setReference(ref);
if (typeof forwardedRef === "function") {
forwardedRef(ref);
} else if (forwardedRef) {
forwardedRef.current = ref;
}
},
[forwardedRef, refs]
);
const childHasMatchingAriaLabel = "aria-label" in children.props && children.props["aria-label"] === content;
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
React.cloneElement(children, {
ref: handleRef,
tabIndex: 0,
// tooltip trigger should be keyboard focusable
"aria-describedby": !childHasMatchingAriaLabel && isOpen ? tooltipId : void 0,
...getReferenceProps()
}),
isOpen && /* @__PURE__ */ jsxRuntime.jsx(Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: refs.setFloating, style: floatingStyles, ...getFloatingProps(), children: [
/* @__PURE__ */ jsxRuntime.jsx(react.FloatingArrow, { className: style.arrow, ref: arrowRef, context }),
/* @__PURE__ */ jsxRuntime.jsxs(
"div",
{
"data-testid": e2eSelectors.selectors.components.Tooltip.container,
id: tooltipId,
role: "tooltip",
className: style.container,
children: [
typeof content === "string" && content,
React.isValidElement(content) && React.cloneElement(content),
contentIsFunction && content({})
]
}
)
] }) })
] });
}
);
Tooltip.displayName = "Tooltip";
const getStyles$R = (theme) => {
const info = buildTooltipTheme(
theme,
theme.components.tooltip.background,
theme.components.tooltip.background,
theme.components.tooltip.text,
{ topBottom: 0.5, rightLeft: 1 }
);
const error = buildTooltipTheme(
theme,
theme.colors.error.main,
theme.colors.error.main,
theme.colors.error.contrastText,
{ topBottom: 0.5, rightLeft: 1 }
);
return {
info,
["info-alt"]: info,
error
};
};
"use strict";
const allButtonVariants = ["primary", "secondary", "destructive"];
const allButtonFills = ["solid", "outline", "text"];
const Button = React__namespace.forwardRef(
({
"aria-label": ariaLabel,
variant = "primary",
size = "md",
fill = "solid",
icon,
fullWidth,
children,
className,
type = "button",
tooltip,
disabled,
tooltipPlacement,
iconPlacement = "left",
onClick,
...otherProps
}, ref) => {
const theme = useTheme2();
const styles = getButtonStyles({
theme,
size,
variant,
fill,
fullWidth,
iconOnly: !children
});
const buttonStyles = css.cx(
styles.button,
{
[styles.disabled]: disabled
},
className
);
const hasTooltip = Boolean(tooltip);
const iconComponent = icon && /* @__PURE__ */ jsxRuntime.jsx(IconRenderer, { icon, size, className: styles.icon });
const button = /* @__PURE__ */ jsxRuntime.jsxs(
"button",
{
className: buttonStyles,
type,
onClick: disabled ? void 0 : onClick,
...otherProps,
"aria-disabled": hasTooltip && disabled,
disabled: !hasTooltip && disabled,
ref: tooltip ? void 0 : ref,
"aria-label": ariaLabel != null ? ariaLabel : !children && typeof tooltip === "string" ? tooltip : void 0,
children: [
iconPlacement === "left" && iconComponent,
children && /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.content, children }),
iconPlacement === "right" && iconComponent
]
}
);
if (tooltip) {
return /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { ref, content: tooltip, placement: tooltipPlacement, children: button });
}
return button;
}
);
Button.displayName = "Button";
const LinkButton = React__namespace.forwardRef(
({
"aria-label": ariaLabel,
variant = "primary",
size = "md",
fill = "solid",
icon,
fullWidth,
children,
className,
onBlur,
onFocus,
disabled,
tooltip,
tooltipPlacement,
...otherProps
}, ref) => {
const theme = useTheme2();
const styles = getButtonStyles({
theme,
fullWidth,
size,
variant,
fill,
iconOnly: !children
});
const linkButtonStyles = css.cx(
styles.button,
{
[css.css(styles.disabled, {
pointerEvents: "none"
})]: disabled
},
className
);
const button = /* @__PURE__ */ jsxRuntime.jsxs(
"a",
{
className: linkButtonStyles,
...otherProps,
tabIndex: disabled ? -1 : 0,
"aria-disabled": disabled,
ref: tooltip ? void 0 : ref,
"aria-label": ariaLabel != null ? ariaLabel : !children && typeof tooltip === "string" ? tooltip : void 0,
children: [
/* @__PURE__ */ jsxRuntime.jsx(IconRenderer, { icon, size, className: styles.icon }),
children && /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.content, children })
]
}
);
if (tooltip) {
return /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { ref, content: tooltip, placement: tooltipPlacement, children: button });
}
return button;
}
);
LinkButton.displayName = "LinkButton";
const IconRenderer = ({ icon, size, className, iconType }) => {
if (!icon) {
return null;
}
if (React__namespace.isValidElement(icon)) {
return React__namespace.cloneElement(icon, {
className,
size
});
}
return /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon, size, className, type: iconType });
};
const getButtonStyles = (props) => {
const { theme, variant, fill = "solid", size, iconOnly, fullWidth } = props;
const { height, padding, fontSize } = getPropertiesForButtonSize(size, theme);
const variantStyles = getPropertiesForVariant(theme, variant, fill);
const disabledStyles = getPropertiesForDisabled(theme, variant, fill);
const focusStyle = getButtonFocusStyles(theme);
const paddingMinusBorder = theme.spacing.gridSize * padding - 1;
return {
button: css.css({
label: "button",
display: "inline-flex",
alignItems: "center",
gap: theme.spacing(1),
fontSize,
fontWeight: theme.typography.fontWeightMedium,
fontFamily: theme.typography.fontFamily,
padding: `0 ${paddingMinusBorder}px`,
height: theme.spacing(height),
// Deduct border from line-height for perfect vertical centering on windows and linux
lineHeight: `${theme.spacing.gridSize * height - 2}px`,
verticalAlign: "middle",
cursor: "pointer",
borderRadius: theme.shape.radius.default,
"&:focus": focusStyle,
"&:focus-visible": focusStyle,
"&:focus:not(:focus-visible)": getMouseFocusStyles(theme),
...fullWidth && {
flexGrow: 1,
justifyContent: "center"
},
...variantStyles,
":disabled": disabledStyles,
"&[disabled]": disabledStyles,
[theme.transitions.handleMotion("no-preference", "reduce")]: {
transition: theme.transitions.create(["background-color", "border-color", "color"], {
duration: theme.transitions.duration.short
})
}
}),
disabled: css.css(disabledStyles, {
"&:hover": css.css(disabledStyles)
}),
img: css.css({
width: "16px",
height: "16px",
margin: theme.spacing(0, 1, 0, 0.5)
}),
icon: iconOnly ? css.css({
// Important not to set margin bottom here as it would override internal icon bottom margin
marginRight: theme.spacing(-padding / 2),
marginLeft: theme.spacing(-padding / 2)
}) : void 0,
content: css.css({
display: "flex",
flexDirection: "row",
alignItems: "center",
whiteSpace: "nowrap",
overflow: "hidden",
height: "100%"
})
};
};
function getActiveButtonStyles(color, fill) {
return {
background: fill === "solid" ? color.main : "transparent"
};
}
function getButtonVariantStyles(theme, color, fill) {
let outlineBorderColor = color.border;
let borderColor = "transparent";
let hoverBorderColor = "transparent";
if (color.name === "secondary") {
borderColor = color.border;
hoverBorderColor = theme.colors.emphasize(color.border, 0.25);
outlineBorderColor = theme.colors.border.strong;
}
if (fill === "outline") {
return {
background: "transparent",
color: color.text,
border: `1px solid ${outlineBorderColor}`,
"&:hover, &:focus": {
background: color.transparent,
borderColor: theme.colors.emphasize(outlineBorderColor, 0.25),
color: color.text
},
"&:active": {
...getActiveButtonStyles(color, fill)
}
};
}
if (fill === "text") {
return {
background: "transparent",
color: color.text,
border: "1px solid transparent",
"&:hover, &:focus": {
background: color.transparent,
textDecoration: "none",
outline: "none"
},
"&:active": {
...getActiveButtonStyles(color, fill)
}
};
}
return {
background: color.main,
color: color.contrastText,
border: `1px solid ${borderColor}`,
"&:hover": {
background: color.shade,
color: color.contrastText,
boxShadow: theme.shadows.z1,
borderColor: hoverBorderColor
},
"&:focus": {
background: color.shade,
color: color.contrastText
},
"&:active": {
...getActiveButtonStyles(color, fill)
}
};
}
function getPropertiesForDisabled(theme, variant, fill) {
const disabledStyles = {
cursor: "not-allowed",
boxShadow: "none",
color: theme.colors.text.disabled,
transition: "none",
background: theme.colors.action.disabledBackground
};
if (fill === "text") {
return {
...disabledStyles,
background: "transparent",
border: `1px solid transparent`
};
}
if (fill === "outline") {
return {
...disabledStyles,
background: "transparent",
border: `1px solid ${theme.colors.border.weak}`
};
}
return {
...disabledStyles,
background: theme.colors.action.disabledBackground,
border: `1px solid transparent`
};
}
function getPropertiesForVariant(theme, variant, fill) {
switch (variant) {
case "secondary":
return getButtonVariantStyles(theme, theme.colors.secondary, fill);
case "destructive":
return getButtonVariantStyles(theme, theme.colors.error, fill);
case "success":
return getButtonVariantStyles(theme, theme.colors.success, fill);
case "primary":
default:
return getButtonVariantStyles(theme, theme.colors.primary, fill);
}
}
const clearButtonStyles = (theme) => {
return css.css({
background: "transparent",
color: theme.colors.text.primary,
border: "none",
padding: 0
});
};
const clearLinkButtonStyles = (theme) => {
return css.css({
background: "transparent",
border: "none",
padding: 0,
fontFamily: "inherit",
color: "inherit",
height: "100%",
cursor: "context-menu",
"&:hover": {
background: "transparent",
color: "inherit"
}
});
};
"use strict";
const Pagination = ({
currentPage,
numberOfPages,
onNavigate,
hideWhenSinglePage,
showSmallVersion,
className
}) => {
const styles = useStyles2(getStyles$Q);
const pageLengthToCondense = showSmallVersion ? 1 : 8;
const pageButtons = React.useMemo(() => {
const pages = [...new Array(numberOfPages).keys()];
const condensePages = numberOfPages > pageLengthToCondense;
const getListItem = (page, variant) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: styles.item, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", variant, onClick: () => onNavigate(page), children: page }) }, page);
return pages.reduce((pagesToRender, pageIndex) => {
const page = pageIndex + 1;
const variant = page === currentPage ? "primary" : "secondary";
const lowerBoundIndex = pageLengthToCondense;
const upperBoundIndex = numberOfPages - pageLengthToCondense + 1;
const differenceOfBounds = upperBoundIndex - lowerBoundIndex;
const isFirstOrLastPage = page === 1 || page === numberOfPages;
const currentPageIsBetweenBounds = differenceOfBounds > -1 && currentPage >= lowerBoundIndex && currentPage <= upperBoundIndex;
const ellipsisOffset = showSmallVersion ? 1 : 3;
const pageOffset = showSmallVersion ? 0 : 2;
if (condensePages) {
if (isFirstOrLastPage || currentPage < lowerBoundIndex && page < lowerBoundIndex || differenceOfBounds >= 0 && currentPage > upperBoundIndex && page > upperBoundIndex || differenceOfBounds < 0 && currentPage >= lowerBoundIndex && page > upperBoundIndex || currentPageIsBetweenBounds && page >= currentPage - pageOffset && page <= currentPage + pageOffset) {
pagesToRender.push(getListItem(page, variant));
} else if (page === lowerBoundIndex && currentPage < lowerBoundIndex || page === upperBoundIndex && currentPage > upperBoundIndex || currentPageIsBetweenBounds && (page === currentPage - ellipsisOffset || page === currentPage + ellipsisOffset)) {
pagesToRender.push(
/* @__PURE__ */ jsxRuntime.jsx("li", { className: styles.item, children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: styles.ellipsis, name: "ellipsis-v", "data-testid": "pagination-ellipsis-icon" }) }, page)
);
}
} else {
pagesToRender.push(getListItem(page, variant));
}
return pagesToRender;
}, []);
}, [currentPage, numberOfPages, onNavigate, pageLengthToCondense, showSmallVersion, styles.ellipsis, styles.item]);
if (hideWhenSinglePage && numberOfPages <= 1) {
return null;
}
const previousPageLabel = i18n.t("grafana-ui.pagination.previous-page", "previous page");
const nextPageLabel = i18n.t("grafana-ui.pagination.next-page", "next page");
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: css.cx(styles.container, className), role: "navigation", children: /* @__PURE__ */ jsxRuntime.jsxs("ol", { children: [
/* @__PURE__ */ jsxRuntime.jsx("li", { className: styles.item, children: /* @__PURE__ */ jsxRuntime.jsx(
Button,
{
"aria-label": previousPageLabel,
size: "sm",
variant: "secondary",
onClick: () => onNavigate(currentPage - 1),
disabled: currentPage === 1,
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "angle-left" })
}
) }),
pageButtons,
/* @__PURE__ */ jsxRuntime.jsx("li", { className: styles.item, children: /* @__PURE__ */ jsxRuntime.jsx(
Button,
{
"aria-label": nextPageLabel,
size: "sm",
variant: "secondary",
onClick: () => onNavigate(currentPage + 1),
disabled: currentPage === numberOfPages,
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "angle-right" })
}
) })
] }) });
};
const getStyles$Q = () => {
return {
container: css.css({
float: "right"
}),
item: css.css({
display: "inline-block",
paddingLeft: "10px",
marginBottom: "5px"
}),
ellipsis: css.css({
transform: "rotate(90deg)"
})
};
};
"use strict";
const LoadingIndicator = ({ onCancel, loading }) => {
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
const styles = useStyles2(getStyles$P);
if (!loading) {
return null;
}
return /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: i18n.t("grafana-ui.panel-chrome.tooltip-cancel-loading", "Cancel query"), children: /* @__PURE__ */ jsxRuntime.jsx(
Icon,
{
className: css.cx(styles.spin, { [styles.clickable]: !!onCancel }),
name: prefersReducedMotion ? "hourglass" : "sync",
size: "sm",
onClick: onCancel,
"data-testid": e2eSelectors.selectors.components.LoadingIndicator.icon
}
) });
};
const spin = css.keyframes({
"0%": {
transform: "rotate(0deg) scaleX(-1)"
// scaleX flips the `sync` icon so arrows point the correct way
},
"100%": {
transform: "rotate(359deg) scaleX(-1)"
}
});
const getStyles$P = (theme) => {
return {
clickable: css.css({
cursor: "pointer"
}),
spin: css.css({
[theme.transitions.handleMotion("no-preference")]: {
animation: `${spin} 3s linear infinite`
}
})
};
};
"use strict";
function DelayRender({ children, delay }) {
const [shouldRender, setShouldRender] = React.useState(false);
React.useEffect(() => {
window.setTimeout(() => {
setShouldRender(true);
}, delay);
}, [children, delay]);
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: shouldRender ? children : null });
}
"use strict";
function getFeatureToggle(featureName, def = false) {
var _a, _b;
return (_b = (_a = window.grafanaBootData) == null ? void 0 : _a.settings.featureToggles[featureName]) != null ? _b : def;
}
"use strict";
function createPointerDistance(distance = 10) {
let initial = { x: 0, y: 0 };
const set = (evt) => {
initial = getPoint(evt);
};
const check = (evt, overrideDistance = distance) => checkDistance(initial, getPoint(evt), overrideDistance);
return { set, check };
}
function usePointerDistance(distance = 10) {
const initial = React__namespace.default.useRef({ x: 0, y: 0 });
const set = React.useCallback((evt) => {
initial.current = getPoint(evt);
}, []);
const check = React.useCallback(
(evt, overrideDistance = distance) => checkDistance(initial.current, getPoint(evt), overrideDistance),
[distance]
);
return React.useMemo(() => ({ set, check }), [set, check]);
}
function getPoint(evt) {
return { x: evt.clientX, y: evt.clientY };
}
function checkDistance(point1, point2, distance) {
return Math.hypot(point1.x - point2.x, point1.y - point2.y) > distance;
}
"use strict";
const ElementSelectionContext = React.createContext(void 0);
function useElementSelection(id) {
if (!id) {
return {};
}
const context = React.useContext(ElementSelectionContext);
if (!context) {
return {};
}
const isSelected = context.selected.some((item) => item.id === id);
const onSelect = React.useCallback(
(evt, options = {}) => {
var _a, _b;
if (!context.enabled) {
return;
}
evt.stopPropagation();
if (evt.shiftKey) {
evt.preventDefault();
(_a = window.getSelection()) == null ? void 0 : _a.empty();
}
context.onSelect({ id }, { ...options, multi: (_b = options.multi) != null ? _b : evt.shiftKey });
},
[context, id]
);
const onClear = React.useCallback(() => {
if (!context.enabled) {
return;
}
context.onClear();
}, [context]);
return { isSelected, onSelect, onClear, isSelectable: context.enabled };
}
"use strict";
const BAR_WIDTH = 28;
const MILLISECONDS_PER_PIXEL = 2.4;
const MIN_DURATION_MS = 500;
const MAX_DURATION_MS = 4e3;
const DEFAULT_ANIMATION_DELAY = 300;
const MAX_TRANSLATE_X = 100 / BAR_WIDTH * 100;
function LoadingBar({ width, delay = DEFAULT_ANIMATION_DELAY, ariaLabel = "Loading bar" }) {
const durationMs = Math.min(Math.max(Math.round(width * MILLISECONDS_PER_PIXEL), MIN_DURATION_MS), MAX_DURATION_MS);
const styles = useStyles2(getStyles$O, delay, durationMs);
const containerStyles = {
overflow: "hidden"
};
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: containerStyles, children: /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-label": ariaLabel, role: "status", className: styles.bar }) });
}
const getStyles$O = (theme, delay, duration) => {
const animation = css.keyframes({
"0%": {
transform: "translateX(-100%)"
},
// this gives us a delay between iterations
"85%, 100%": {
transform: `translateX(${MAX_TRANSLATE_X}%)`
}
});
return {
bar: css.css({
width: BAR_WIDTH + "%",
height: 1,
background: `linear-gradient(90deg, transparent 0%, ${theme.colors.primary.main} 80.75%, transparent 100%)`,
transform: "translateX(-100%)",
willChange: "transform",
[theme.transitions.handleMotion("no-preference")]: {
animationName: animation,
// an initial delay to prevent the loader from showing if the response is faster than the delay
animationDelay: `${delay}ms`,
animationTimingFunction: "linear",
animationIterationCount: "infinite",
animationDuration: `${duration}ms`
},
[theme.transitions.handleMotion("reduce")]: {
animationName: animation,
// an initial delay to prevent the loader from showing if the response is faster than the delay
animationDelay: `${delay}ms`,
animationTimingFunction: "linear",
animationIterationCount: "infinite",
animationDuration: `${4 * duration}ms`
}
})
};
};
"use strict";
const TruncatedText = React__namespace.forwardRef(({ childElement, children }, ref) => {
const [isOverflowing, setIsOverflowing] = React.useState(false);
const internalRef = React.useRef(null);
React.useImperativeHandle(ref, () => internalRef.current);
const resizeObserver = React.useMemo(
() => new ResizeObserver((entries) => {
for (const entry of entries) {
if (entry.target.clientWidth && entry.target.scrollWidth) {
if (entry.target.scrollWidth > entry.target.clientWidth) {
setIsOverflowing(true);
}
if (entry.target.scrollWidth <= entry.target.clientWidth) {
setIsOverflowing(false);
}
}
}
}),
[]
);
React.useEffect(() => {
const { current } = internalRef;
if (current) {
resizeObserver.observe(current);
}
return () => {
resizeObserver.disconnect();
};
}, [setIsOverflowing, resizeObserver]);
const getTooltipText = (children2) => {
if (typeof children2 === "string") {
return children2;
}
const html = ReactDOMServer__default.default.renderToStaticMarkup(/* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children2 }));
return html.replace(/(<([^>]+)>)/gi, "");
};
if (isOverflowing) {
return /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { ref: internalRef, content: getTooltipText(children), children: childElement(void 0) });
} else {
return childElement(internalRef);
}
});
TruncatedText.displayName = "TruncatedText";
"use strict";
const customWeight = (weight, theme) => {
switch (weight) {
case "bold":
return theme.typography.fontWeightBold;
case "medium":
return theme.typography.fontWeightMedium;
case "light":
return theme.typography.fontWeightLight;
case "regular":
case void 0:
return theme.typography.fontWeightRegular;
}
};
const customColor = (color, theme) => {
switch (color) {
case "error":
return theme.colors.error.text;
case "success":
return theme.colors.success.text;
case "info":
return theme.colors.info.text;
case "warning":
return theme.colors.warning.text;
default:
return color ? theme.colors.text[color] : void 0;
}
};
const customVariant = (theme, element, variant) => {
if (variant) {
return theme.typography[variant];
}
switch (element) {
//Span elements does not have a default variant to be able to take the parents style
case "span":
return;
case "h1":
return theme.typography.h1;
case "h2":
return theme.typography.h2;
case "h3":
return theme.typography.h3;
case "h4":
return theme.typography.h4;
case "h5":
return theme.typography.h5;
case "h6":
return theme.typography.h6;
default:
return theme.typography.body;
}
};
"use strict";
const Text = React__namespace.forwardRef(
({ element = "span", variant, weight, color, truncate, italic, textAlignment, children, tabular, ...restProps }, ref) => {
const styles = useStyles2(getTextStyles, element, variant, color, weight, truncate, italic, textAlignment, tabular);
const childElement = (ref2) => {
return React.createElement(
element,
{
...restProps,
style: void 0,
// Remove the style prop to avoid overriding the styles
className: styles,
// When overflowing, the internalRef is passed to the tooltip, which forwards it to the child element
ref: ref2
},
children
);
};
if (!truncate || element === "span") {
return childElement(void 0);
}
return /* @__PURE__ */ jsxRuntime.jsx(
TruncatedText,
{
childElement,
children,
ref
}
);
}
);
Text.displayName = "Text";
const getTextStyles = (theme, element, variant, color, weight, truncate, italic, textAlignment, tabular) => {
return css.css([
{
margin: 0,
padding: 0,
...customVariant(theme, element, variant)
},
variant && {
...theme.typography[variant]
},
color && {
color: customColor(color, theme)
},
weight && {
fontWeight: customWeight(weight, theme)
},
truncate && {
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap"
},
italic && {
fontStyle: "italic"
},
textAlignment && {
textAlign: textAlignment
},
tabular && {
fontFeatureSettings: '"tnum"'
}
]);
};
"use strict";
function getChildId(children) {
let inputId;
const child = React__namespace.Children.only(children);
if ("id" in (child == null ? void 0 : child.props)) {
inputId = child.props.id;
} else if ("inputId" in child.props) {
inputId = child == null ? void 0 : child.props.inputId;
}
return typeof inputId === "string" ? inputId : void 0;
}
function renderOrCallToRender(itemToRender, props) {
if (React__namespace.isValidElement(itemToRender) || typeof itemToRender === "string" || typeof itemToRender === "number") {
return itemToRender;
}
if (typeof itemToRender === "function" && props) {
return itemToRender(props);
}
throw new Error(`${itemToRender} is not a React element nor a function that returns React element`);
}
"use strict";
const Dropdown = React__namespace.memo(({ children, overlay, placement, offset, root, onVisibleChange }) => {
var _a, _b;
const [show, setShow] = React.useState(false);
const transitionRef = React.useRef(null);
const floatingUIPlacement = getPlacement(placement);
const handleOpenChange = React.useCallback(
(newState) => {
setShow(newState);
onVisibleChange == null ? void 0 : onVisibleChange(newState);
},
[onVisibleChange]
);
const middleware = [
react.offset({
mainAxis: (_a = offset == null ? void 0 : offset[0]) != null ? _a : 8,
crossAxis: (_b = offset == null ? void 0 : offset[1]) != null ? _b : 0
}),
...getPositioningMiddleware(floatingUIPlacement)
];
const { context, refs, floatingStyles } = react.useFloating({
open: show,
placement: floatingUIPlacement,
onOpenChange: handleOpenChange,
middleware,
whileElementsMounted: react.autoUpdate
});
const click = react.useClick(context);
const dismiss = react.useDismiss(context);
const { getReferenceProps, getFloatingProps } = react.useInteractions([dismiss, click]);
const animationDuration = 150;
const animationStyles = useStyles2(getStyles$N, animationDuration);
const onOverlayClicked = () => {
handleOpenChange(false);
};
const handleKeys = (event) => {
if (event.key === "Tab") {
handleOpenChange(false);
}
};
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
React__namespace.cloneElement(children, {
ref: refs.setReference,
...getReferenceProps()
}),
show && /* @__PURE__ */ jsxRuntime.jsx(Portal, { root, children: /* @__PURE__ */ jsxRuntime.jsx(react.FloatingFocusManager, { context, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: refs.setFloating, style: floatingStyles, onClick: onOverlayClicked, onKeyDown: handleKeys, children: /* @__PURE__ */ jsxRuntime.jsx(
reactTransitionGroup.CSSTransition,
{
nodeRef: transitionRef,
appear: true,
in: true,
timeout: { appear: animationDuration, exit: 0, enter: 0 },
classNames: animationStyles,
children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: transitionRef, children: renderOrCallToRender(overlay, { ...getFloatingProps() }) })
}
) }) }) })
] });
});
Dropdown.displayName = "Dropdown";
const getStyles$N = (theme, duration) => {
return {
appear: css.css({
opacity: "0",
position: "relative",
transformOrigin: "top",
[theme.transitions.handleMotion("no-preference")]: {
transform: "scaleY(0.5)"
}
}),
appearActive: css.css({
opacity: "1",
[theme.transitions.handleMotion("no-preference")]: {
transform: "scaleY(1)",
transition: `transform ${duration}ms cubic-bezier(0.2, 0, 0.2, 1), opacity ${duration}ms cubic-bezier(0.2, 0, 0.2, 1)`
}
})
};
};
"use strict";
const ToolbarButton = React.forwardRef(
({
tooltip,
icon,
iconSize,
className,
children,
imgSrc,
imgAlt,
fullWidth,
isOpen,
narrow,
variant = "default",
iconOnly,
"aria-label": ariaLabel,
isHighlighted,
...rest
}, ref) => {
const styles = useStyles2(getStyles$M);
const buttonStyles = css.cx(
{
[styles.button]: true,
[styles.buttonFullWidth]: fullWidth,
[styles.narrow]: narrow
},
styles[variant],
className
);
const contentStyles = css.cx({
[styles.content]: true,
[styles.contentWithIcon]: !!icon,
[styles.contentWithRightIcon]: isOpen !== void 0
});
const body = /* @__PURE__ */ jsxRuntime.jsxs(
"button",
{
ref,
className: buttonStyles,
"aria-label": getButtonAriaLabel(ariaLabel, tooltip),
"aria-expanded": isOpen,
type: "button",
...rest,
children: [
renderIcon(icon, iconSize),
imgSrc && /* @__PURE__ */ jsxRuntime.jsx("img", { className: styles.img, src: imgSrc, alt: imgAlt != null ? imgAlt : "" }),
children && !iconOnly && /* @__PURE__ */ jsxRuntime.jsx("div", { className: contentStyles, children }),
isOpen === false && /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "angle-down" }),
isOpen === true && /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "angle-up" }),
isHighlighted && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.highlight })
]
}
);
return tooltip ? /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { ref, content: tooltip, placement: "bottom", children: body }) : body;
}
);
ToolbarButton.displayName = "ToolbarButton";
function getButtonAriaLabel(ariaLabel, tooltip) {
return ariaLabel ? ariaLabel : tooltip ? e2eSelectors.selectors.components.PageToolbar.item(tooltip) : void 0;
}
function renderIcon(icon, iconSize) {
if (!icon) {
return null;
}
if (data.isIconName(icon)) {
return /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon, size: `${iconSize ? iconSize : "lg"}` });
}
return icon;
}
const getStyles$M = (theme) => {
const primaryVariant = getPropertiesForVariant(theme, "primary", "solid");
const destructiveVariant = getPropertiesForVariant(theme, "destructive", "solid");
const defaultOld = css.css({
color: theme.colors.text.primary,
background: theme.colors.secondary.main,
"&:hover, &:focus": {
color: theme.colors.text.primary,
background: theme.colors.secondary.shade,
border: `1px solid ${theme.colors.border.medium}`
},
"&:active": {
...getActiveButtonStyles(theme.colors.secondary, "solid")
}
});
return {
button: css.css({
label: "toolbar-button",
position: "relative",
display: "flex",
alignItems: "center",
height: theme.spacing(theme.components.height.md),
padding: theme.spacing(0, 1),
borderRadius: theme.shape.radius.default,
lineHeight: `${theme.components.height.md * theme.spacing.gridSize - 2}px`,
fontWeight: theme.typography.fontWeightMedium,
border: `1px solid ${theme.colors.secondary.border}`,
whiteSpace: "nowrap",
[theme.transitions.handleMotion("no-preference", "reduce")]: {
transition: theme.transitions.create(["background-color", "border-color", "color"], {
duration: theme.transitions.duration.short
})
},
[theme.breakpoints.down("md")]: {
width: "auto !important"
},
"&:focus, &:focus-visible": {
...getFocusStyles(theme),
zIndex: 1
},
"&:focus:not(:focus-visible)": getMouseFocusStyles(theme),
"&[disabled], &:disabled": {
cursor: "not-allowed",
opacity: theme.colors.action.disabledOpacity,
background: theme.colors.action.disabledBackground,
boxShadow: "none",
"&:hover": {
color: theme.colors.text.disabled,
background: theme.colors.action.disabledBackground,
boxShadow: "none"
}
}
}),
default: css.css({
color: theme.colors.text.secondary,
background: "transparent",
border: `1px solid transparent`,
"&:hover, &:focus": {
color: theme.colors.text.primary,
background: theme.colors.action.hover
},
"&:active": {
...getActiveButtonStyles(theme.colors.secondary, "solid")
}
}),
canvas: defaultOld,
active: css.cx(
defaultOld,
css.css({
"&::before": {
display: "block",
content: '" "',
position: "absolute",
left: 0,
right: 0,
height: "2px",
bottom: 0,
borderRadius: theme.shape.radius.default,
backgroundImage: theme.colors.gradients.brandHorizontal
}
})
),
primary: css.css(primaryVariant),
destructive: css.css(destructiveVariant),
narrow: css.css({
padding: theme.spacing(0, 0.5)
}),
img: css.css({
width: "16px",
height: "16px",
marginRight: theme.spacing(1)
}),
buttonFullWidth: css.css({
flexGrow: 1
}),
content: css.css({
display: "flex",
flexGrow: 1
}),
contentWithIcon: css.css({
display: "none",
paddingLeft: theme.spacing(1),
[`@media ${mediaUp(theme.v1.breakpoints.md)}`]: {
display: "block"
}
}),
contentWithRightIcon: css.css({
paddingRight: theme.spacing(0.5)
}),
highlight: css.css({
backgroundColor: theme.colors.success.main,
borderRadius: theme.shape.radius.circle,
width: "6px",
height: "6px",
position: "absolute",
top: "-3px",
right: "-3px",
zIndex: 1
})
};
};
"use strict";
function PanelMenu({
menu,
title,
placement = "bottom",
offset,
dragClassCancel,
menuButtonClass,
onOpenMenu
}) {
const testId = title ? e2eSelectors.selectors.components.Panels.Panel.menu(title) : `panel-menu-button`;
const handleVisibility = React.useCallback(
(show) => {
if (show && onOpenMenu) {
onOpenMenu();
}
},
[onOpenMenu]
);
return /* @__PURE__ */ jsxRuntime.jsx(Dropdown, { overlay: menu, placement, offset, onVisibleChange: handleVisibility, children: /* @__PURE__ */ jsxRuntime.jsx(
ToolbarButton,
{
"aria-label": i18n.t("grafana-ui.panel-menu.label", "Menu for panel {{ title }}", { title: title != null ? title : "Untitled" }),
title: i18n.t("grafana-ui.panel-menu.title", "Menu"),
icon: "ellipsis-v",
iconSize: "md",
narrow: true,
"data-testid": testId,
className: css.cx(menuButtonClass, dragClassCancel)
}
) });
}
"use strict";
function HoverWidget({ menu, title, dragClass, children, offset = -32, onOpenMenu }) {
const styles = useStyles2(getStyles$L);
const draggableRef = React.useRef(null);
const selectors = e2eSelectors.selectors.components.Panels.Panel.HoverWidget;
const onPointerDown = React.useCallback((e) => {
var _a;
(_a = draggableRef.current) == null ? void 0 : _a.setPointerCapture(e.pointerId);
}, []);
const onPointerUp = React.useCallback((e) => {
var _a;
(_a = draggableRef.current) == null ? void 0 : _a.releasePointerCapture(e.pointerId);
}, []);
if (children === void 0 || React__namespace.Children.count(children) === 0) {
return null;
}
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: css.cx(styles.container, "show-on-hover"), style: { top: offset }, "data-testid": selectors.container, children: [
dragClass && /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: css.cx(styles.square, styles.draggable, dragClass),
onPointerDown,
onPointerUp,
ref: draggableRef,
"data-testid": selectors.dragIcon,
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "expand-arrows", className: styles.draggableIcon })
}
),
children,
menu && /* @__PURE__ */ jsxRuntime.jsx(
PanelMenu,
{
menu,
title,
placement: "bottom",
menuButtonClass: styles.menuButton,
onOpenMenu
}
)
] });
}
function getStyles$L(theme) {
return {
container: css.css({
label: "hover-container-widget",
[theme.transitions.handleMotion("no-preference", "reduce")]: {
transition: `all .1s linear`
},
display: "flex",
position: "absolute",
zIndex: 1,
right: 0,
boxSizing: "content-box",
alignItems: "center",
background: theme.colors.background.secondary,
color: theme.colors.text.primary,
border: `1px solid ${theme.colors.border.weak}`,
borderRadius: theme.shape.radius.default,
height: theme.spacing(4),
boxShadow: theme.shadows.z1
}),
square: css.css({
display: "flex",
justifyContent: "center",
alignItems: "center",
width: theme.spacing(4),
height: "100%"
}),
draggable: css.css({
cursor: "move",
// mobile do not support draggable panels
[theme.breakpoints.down("md")]: {
display: "none"
}
}),
menuButton: css.css({
// Background and border are overriden when topnav toggle is disabled
background: "inherit",
border: "none",
"&:hover": {
background: theme.colors.secondary.main
}
}),
draggableIcon: css.css({
transform: "rotate(45deg)",
color: theme.colors.text.secondary,
"&:hover": {
color: theme.colors.text.primary
}
})
};
}
"use strict";
const TitleItem = React.forwardRef(
({ className, children, href, onClick, target, title, ...rest }, ref) => {
const styles = useStyles2(getStyles$K);
if (href) {
return /* @__PURE__ */ jsxRuntime.jsx(
"a",
{
ref,
href,
onClick,
target,
title,
className: css.cx(styles.linkItem, className),
...rest,
children
}
);
} else if (onClick) {
return /* @__PURE__ */ jsxRuntime.jsx(
Button,
{
ref,
className: css.cx(styles.buttonItem, className),
variant: "secondary",
fill: "text",
onClick,
children
}
);
} else {
return /* @__PURE__ */ jsxRuntime.jsx("span", { ref, className: css.cx(styles.item, className), ...rest, children });
}
}
);
TitleItem.displayName = "TitleItem";
const getStyles$K = (theme) => {
const item = css.css({
color: `${theme.colors.text.secondary}`,
label: "panel-header-item",
border: "none",
borderRadius: `${theme.shape.radius.default}`,
padding: `${theme.spacing(0, 1)}`,
height: `${theme.spacing(theme.components.panel.headerHeight)}`,
display: "flex",
alignItems: "center",
justifyContent: "center",
"&:focus, &:focus-visible": {
...getFocusStyles(theme),
zIndex: 1
},
"&: focus:not(:focus-visible)": getMouseFocusStyles(theme),
"&:hover ": {
boxShadow: `${theme.shadows.z1}`,
background: `${theme.colors.background.secondary}`,
color: `${theme.colors.text.primary}`
}
});
return {
item,
linkItem: css.cx(item, css.css({ cursor: "pointer" })),
buttonItem: css.cx(item, css.css({ cursor: "pointer" }))
};
};
"use strict";
function PanelDescription({ description, className }) {
const styles = useStyles2(getStyles$J);
const getDescriptionContent = () => {
const panelDescription = typeof description === "function" ? description() : description;
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "panel-info-content markdown-html", children: /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: panelDescription } }) });
};
return description !== "" ? /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { interactive: true, content: getDescriptionContent, children: /* @__PURE__ */ jsxRuntime.jsx(TitleItem, { className: css.cx(className, styles.description), children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "info-circle", size: "md" }) }) }) : null;
}
const getStyles$J = (theme) => {
return {
description: css.css({
code: {
whiteSpace: "normal",
wordWrap: "break-word"
},
"pre > code": {
display: "block"
}
})
};
};
"use strict";
function PanelStatus({ message, onClick, ariaLabel = "status" }) {
const styles = useStyles2(getStyles$I);
return /* @__PURE__ */ jsxRuntime.jsx(
ToolbarButton,
{
className: styles.buttonStyles,
onClick,
variant: "destructive",
icon: "exclamation-triangle",
iconSize: "md",
tooltip: message || "",
"aria-label": ariaLabel,
"data-testid": e2eSelectors.selectors.components.Panels.Panel.status("error")
}
);
}
const getStyles$I = (theme) => {
const { headerHeight, padding } = theme.components.panel;
return {
buttonStyles: css.css({
label: "panel-header-state-button",
display: "flex",
alignItems: "center",
justifyContent: "center",
padding: theme.spacing(padding),
width: theme.spacing(headerHeight),
height: theme.spacing(headerHeight),
borderRadius: theme.shape.radius.default
})
};
};
"use strict";
const MaybeWrap = ({ children }) => {
const styles = useStyles2(getStyles$H);
return getFeatureToggle("preventPanelChromeOverflow") ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.container, children }) : children;
};
function PanelChrome$1({
width,
height,
children,
padding = "md",
title = "",
description = "",
displayMode = "default",
titleItems,
menu,
dragClass,
dragClassCancel,
hoverHeader = false,
hoverHeaderOffset,
loadingState,
statusMessage,
statusMessageOnClick,
leftItems,
actions,
selectionId,
onCancelQuery,
onOpenMenu,
collapsible = false,
collapsed,
onToggleCollapse,
onFocus,
onMouseMove,
onMouseEnter,
onDragStart,
showMenuAlways = false
}) {
const theme = useTheme2();
const styles = useStyles2(getStyles$H);
const panelContentId = React.useId();
const panelTitleId = React.useId().replace(/:/g, "_");
const { isSelected, onSelect, isSelectable } = useElementSelection(selectionId);
const pointerDistance = usePointerDistance();
const hasHeader = !hoverHeader;
const [isOpen, toggleOpen] = reactUse.useToggle(true);
const [selectableHighlight, setSelectableHighlight] = React.useState(false);
const onHeaderEnter = React__namespace.useCallback(() => setSelectableHighlight(true), []);
const onHeaderLeave = React__namespace.useCallback(() => setSelectableHighlight(false), []);
if (collapsed === void 0) {
collapsed = !isOpen;
}
const showOnHoverClass = showMenuAlways ? "always-show" : "show-on-hover";
const isPanelTransparent = displayMode === "transparent";
const headerHeight = getHeaderHeight(theme, hasHeader);
const { contentStyle, innerWidth, innerHeight } = getContentStyle(
padding,
theme,
headerHeight,
collapsed,
height,
width
);
const headerStyles = {
height: headerHeight,
cursor: dragClass ? "move" : "auto"
};
const containerStyles = { width, height: collapsed ? void 0 : height };
const [ref, { width: loadingBarWidth }] = reactUse.useMeasure();
if (leftItems) {
actions = leftItems;
}
const testid = typeof title === "string" ? e2eSelectors.selectors.components.Panels.Panel.title(title) : "Panel";
const onPointerUp = React__namespace.useCallback(
(evt) => {
if (pointerDistance.check(evt) || dragClassCancel && evt.target instanceof Element && evt.target.closest(`.${dragClassCancel}`)) {
return;
}
setTimeout(() => onSelect == null ? void 0 : onSelect(evt));
},
[dragClassCancel, onSelect, pointerDistance]
);
const onPointerDown = React__namespace.useCallback(
(evt) => {
evt.stopPropagation();
pointerDistance.set(evt);
onDragStart == null ? void 0 : onDragStart(evt);
},
[pointerDistance, onDragStart]
);
const onContentPointerDown = React__namespace.useCallback(
(evt) => {
if (evt.target instanceof Element && evt.target.closest("button,a,canvas,svg")) {
return;
}
onSelect == null ? void 0 : onSelect(evt);
},
[onSelect]
);
const headerContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
!collapsible && title && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.title, children: /* @__PURE__ */ jsxRuntime.jsx(
Text,
{
element: "h2",
variant: "h6",
truncate: true,
title: typeof title === "string" ? title : void 0,
id: panelTitleId,
children: title
}
) }),
collapsible && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.title, children: /* @__PURE__ */ jsxRuntime.jsx(Text, { element: "h2", variant: "h6", children: /* @__PURE__ */ jsxRuntime.jsxs(
"button",
{
type: "button",
className: styles.clearButtonStyles,
onClick: () => {
toggleOpen();
if (onToggleCollapse) {
onToggleCollapse(!collapsed);
}
},
"aria-expanded": !collapsed,
"aria-controls": !collapsed ? panelContentId : void 0,
children: [
/* @__PURE__ */ jsxRuntime.jsx(
Icon,
{
name: !collapsed ? "angle-down" : "angle-right",
"aria-hidden": !!title,
"aria-label": !title ? i18n.t("grafana-ui.panel-chrome.aria-label-toggle-collapse", "toggle collapse panel") : void 0
}
),
/* @__PURE__ */ jsxRuntime.jsx(Text, { variant: "h6", truncate: true, id: panelTitleId, children: title })
]
}
) }) }),
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: css.cx(styles.titleItems, dragClassCancel), "data-testid": "title-items-container", children: [
/* @__PURE__ */ jsxRuntime.jsx(PanelDescription, { description, className: dragClassCancel }),
titleItems
] }),
loadingState === data.LoadingState.Streaming && /* @__PURE__ */ jsxRuntime.jsx(
Tooltip,
{
content: onCancelQuery ? i18n.t("grafana-ui.panel-chrome.tooltip-stop-streaming", "Stop streaming") : i18n.t("grafana-ui.panel-chrome.tooltip-streaming", "Streaming"),
children: /* @__PURE__ */ jsxRuntime.jsx(TitleItem, { className: dragClassCancel, "data-testid": "panel-streaming", onClick: onCancelQuery, children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "circle-mono", size: "md", className: styles.streaming }) })
}
),
loadingState === data.LoadingState.Loading && onCancelQuery && /* @__PURE__ */ jsxRuntime.jsx(DelayRender, { delay: 2e3, children: /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: i18n.t("grafana-ui.panel-chrome.tooltip-cancel", "Cancel query"), children: /* @__PURE__ */ jsxRuntime.jsx(
TitleItem,
{
className: css.cx(dragClassCancel, styles.pointer),
"data-testid": "panel-cancel-query",
onClick: onCancelQuery,
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "sync-slash", size: "md" })
}
) }) }),
/* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.rightAligned, children: actions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.rightActions, children: itemsRenderer(actions, (item) => item) }) })
] });
return /* @__PURE__ */ jsxRuntime.jsx(MaybeWrap, { children: /* @__PURE__ */ jsxRuntime.jsxs(
"section",
{
className: css.cx(
styles.panel,
isPanelTransparent && styles.panelTransparent,
isSelected && "dashboard-selected-element",
!isSelected && isSelectable && selectableHighlight && "dashboard-selectable-element"
),
style: containerStyles,
"aria-labelledby": !!title ? panelTitleId : void 0,
"data-testid": testid,
tabIndex: 0,
onFocus,
onMouseMove,
onMouseEnter,
ref,
children: [
/* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.loadingBarContainer, children: loadingState === data.LoadingState.Loading ? /* @__PURE__ */ jsxRuntime.jsx(
LoadingBar,
{
width: loadingBarWidth,
ariaLabel: i18n.t("grafana-ui.panel-chrome.ariaLabel-panel-loading", "Panel loading bar")
}
) : null }),
hoverHeader && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
/* @__PURE__ */ jsxRuntime.jsx(
HoverWidget,
{
menu,
title: typeof title === "string" ? title : void 0,
offset: hoverHeaderOffset,
dragClass,
onOpenMenu,
children: headerContent
}
),
statusMessage && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.errorContainerFloating, children: /* @__PURE__ */ jsxRuntime.jsx(
PanelStatus,
{
message: statusMessage,
onClick: statusMessageOnClick,
ariaLabel: i18n.t("grafana-ui.panel-chrome.ariaLabel-panel-status", "Panel status")
}
) })
] }),
hasHeader && /* @__PURE__ */ jsxRuntime.jsxs(
"div",
{
className: css.cx(styles.headerContainer, dragClass),
style: headerStyles,
"data-testid": e2eSelectors.selectors.components.Panels.Panel.headerContainer,
onPointerDown,
onMouseEnter: isSelectable ? onHeaderEnter : void 0,
onMouseLeave: isSelectable ? onHeaderLeave : void 0,
onPointerUp,
children: [
statusMessage && /* @__PURE__ */ jsxRuntime.jsx("div", { className: dragClassCancel, children: /* @__PURE__ */ jsxRuntime.jsx(
PanelStatus,
{
message: statusMessage,
onClick: statusMessageOnClick,
ariaLabel: i18n.t("grafana-ui.panel-chrome.ariaLabel-panel-status", "Panel status")
}
) }),
headerContent,
menu && /* @__PURE__ */ jsxRuntime.jsx(
PanelMenu,
{
menu,
title: typeof title === "string" ? title : void 0,
placement: "bottom-end",
menuButtonClass: css.cx(styles.menuItem, dragClassCancel, showOnHoverClass),
onOpenMenu
}
)
]
}
),
!collapsed && /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
id: panelContentId,
"data-testid": e2eSelectors.selectors.components.Panels.Panel.content,
className: css.cx(styles.content, height === void 0 && styles.containNone),
style: contentStyle,
onPointerDown: onContentPointerDown,
children: typeof children === "function" ? children(innerWidth, innerHeight) : children
}
)
]
}
) });
}
const itemsRenderer = (items, renderer) => {
const toRender = React__namespace.Children.toArray(items).filter(Boolean);
return toRender.length > 0 ? renderer(toRender) : null;
};
const getHeaderHeight = (theme, hasHeader) => {
if (hasHeader) {
return theme.spacing.gridSize * theme.components.panel.headerHeight;
}
return 0;
};
const getContentStyle = (padding, theme, headerHeight, collapsed, height, width) => {
const chromePadding = (padding === "md" ? theme.components.panel.padding : 0) * theme.spacing.gridSize;
const panelPadding = chromePadding * 2;
const panelBorder = 1 * 2;
let innerWidth = 0;
if (width) {
innerWidth = width - panelPadding - panelBorder;
}
let innerHeight = 0;
if (height) {
innerHeight = height - headerHeight - panelPadding - panelBorder;
}
if (collapsed) {
innerHeight = headerHeight;
}
const contentStyle = {
padding: chromePadding
};
return { contentStyle, innerWidth, innerHeight };
};
const getStyles$H = (theme) => {
const { background, borderColor, padding } = theme.components.panel;
return {
container: css.css({
height: "100%",
position: "relative"
}),
panel: css.css({
label: "panel-container",
backgroundColor: background,
border: `1px solid ${borderColor}`,
position: getFeatureToggle("preventPanelChromeOverflow") ? "unset" : "relative",
borderRadius: theme.shape.radius.default,
height: "100%",
display: "flex",
flexDirection: "column",
overflow: getFeatureToggle("preventPanelChromeOverflow") ? "hidden" : "initial",
".always-show": {
background: "none",
"&:focus-visible, &:hover": {
background: theme.colors.secondary.shade
}
},
".show-on-hover": {
opacity: "0",
visibility: "hidden"
},
"&:focus-visible, &:hover": {
// only show menu icon on hover or focused panel
".show-on-hover": {
opacity: "1",
visibility: "visible"
}
},
"&:focus-visible": getFocusStyles(theme),
// The not:(:focus) clause is so that this rule is only applied when decendants are focused (important otherwise the hover header is visible when panel is clicked).
"&:focus-within:not(:focus)": {
".show-on-hover": {
visibility: "visible",
opacity: "1"
}
}
}),
panelTransparent: css.css({
label: "panel-transparent-container",
backgroundColor: "transparent",
border: "1px solid transparent",
boxSizing: "border-box",
"&:hover": {
border: `1px solid ${borderColor}`
}
}),
loadingBarContainer: css.css({
label: "panel-loading-bar-container",
position: "absolute",
top: 0,
width: "100%",
// this is to force the loading bar container to create a new stacking context
// otherwise, in webkit browsers on windows/linux, the aliasing of panel text changes when the loading bar is shown
// see https://github.com/grafana/grafana/issues/88104
zIndex: 1
}),
containNone: css.css({
contain: "none"
}),
content: css.css({
label: "panel-content",
flexGrow: 1,
contain: "size layout"
}),
headerContainer: css.css({
label: "panel-header",
display: "flex",
alignItems: "center"
}),
pointer: css.css({
cursor: "pointer"
}),
streaming: css.css({
label: "panel-streaming",
marginRight: 0,
color: theme.colors.success.text,
"&:hover": {
color: theme.colors.success.text
}
}),
title: css.css({
label: "panel-title",
display: "flex",
padding: theme.spacing(0, padding),
minWidth: 0,
"& > h2": {
minWidth: 0
}
}),
items: css.css({
display: "flex"
}),
item: css.css({
display: "flex",
justifyContent: "center",
alignItems: "center"
}),
hiddenMenu: css.css({
visibility: "hidden"
}),
menuItem: css.css({
label: "panel-menu",
border: "none",
background: theme.colors.secondary.main,
"&:hover": {
background: theme.colors.secondary.shade
}
}),
errorContainerFloating: css.css({
label: "error-container",
position: "absolute",
left: 0,
top: 0,
zIndex: 1
}),
rightActions: css.css({
display: "flex",
padding: theme.spacing(0, padding),
gap: theme.spacing(1)
}),
rightAligned: css.css({
label: "right-aligned-container",
marginLeft: "auto",
display: "flex",
alignItems: "center"
}),
titleItems: css.css({
display: "flex",
height: "100%"
}),
clearButtonStyles: css.css({
alignItems: "center",
display: "flex",
gap: theme.spacing(0.5),
background: "transparent",
border: "none",
padding: 0,
maxWidth: "100%"
})
};
};
"use strict";
const PanelContextRoot = React.createContext({
eventsScope: "global",
eventBus: new data.EventBusSrv()
});
const PanelContextProvider = PanelContextRoot.Provider;
const usePanelContext = () => React.useContext(PanelContextRoot);
"use strict";
var SeriesVisibilityChangeMode = /* @__PURE__ */ ((SeriesVisibilityChangeMode2) => {
SeriesVisibilityChangeMode2["ToggleSelection"] = "select";
SeriesVisibilityChangeMode2["AppendToSelection"] = "append";
return SeriesVisibilityChangeMode2;
})(SeriesVisibilityChangeMode || {});
"use strict";
const PanelChrome = PanelChrome$1;
PanelChrome.LoadingIndicator = LoadingIndicator;
PanelChrome.TitleItem = TitleItem;
"use strict";
const IconButton = React__namespace.forwardRef((props, ref) => {
const { size = "md", variant = "secondary" } = props;
let limitedIconSize;
if (size === "xxl" || size === "xxxl") {
data.deprecationWarning("IconButton", 'size="xxl" and size="xxxl"', 'size="xl"');
limitedIconSize = "xl";
} else {
limitedIconSize = size;
}
const styles = useStyles2(getStyles$G, limitedIconSize, variant);
let ariaLabel;
let buttonRef;
if ("tooltip" in props) {
const { tooltip } = props;
ariaLabel = typeof tooltip === "string" ? tooltip : void 0;
} else if ("ariaLabel" in props || "aria-label" in props) {
const { ariaLabel: deprecatedAriaLabel, ["aria-label"]: ariaLabelProp } = props;
ariaLabel = ariaLabelProp || deprecatedAriaLabel;
buttonRef = ref;
}
if ("tooltip" in props) {
const { name, iconType, className, tooltip, tooltipPlacement, ...restProps } = props;
return /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { ref, content: tooltip, placement: tooltipPlacement, children: /* @__PURE__ */ jsxRuntime.jsx(
"button",
{
...restProps,
ref: buttonRef,
"aria-label": ariaLabel,
className: css.cx(styles.button, className),
type: "button",
children: /* @__PURE__ */ jsxRuntime.jsx(IconRenderer, { icon: name, size: limitedIconSize, className: styles.icon, iconType })
}
) });
} else {
const { name, iconType, className, ...restProps } = props;
return /* @__PURE__ */ jsxRuntime.jsx(
"button",
{
...restProps,
ref: buttonRef,
"aria-label": ariaLabel,
className: css.cx(styles.button, className),
type: "button",
children: /* @__PURE__ */ jsxRuntime.jsx(IconRenderer, { icon: name, size: limitedIconSize, className: styles.icon, iconType })
}
);
}
});
IconButton.displayName = "IconButton";
const getStyles$G = (theme, size, variant) => {
const hoverSize = getSvgSize(size) + theme.spacing.gridSize;
const activeButtonStyle = getActiveButtonStyles(theme.colors.secondary, "text");
let iconColor = theme.colors.primary.text;
let hoverColor = theme.colors.primary.transparent;
if (variant === "secondary") {
iconColor = theme.colors.secondary.text;
hoverColor = theme.colors.secondary.transparent;
} else if (variant === "destructive") {
iconColor = theme.colors.error.text;
hoverColor = theme.colors.error.transparent;
}
return {
button: css.css({
zIndex: 0,
position: "relative",
margin: `0 ${theme.spacing.x0_5} 0 0`,
boxShadow: "none",
border: "none",
display: "inline-flex",
background: "transparent",
justifyContent: "center",
alignItems: "center",
padding: 0,
color: iconColor,
borderRadius: theme.shape.radius.default,
"&:active": {
"&:before, &:hover:before": {
backgroundColor: activeButtonStyle.background
}
},
"&[disabled], &:disabled": {
cursor: "not-allowed",
color: theme.colors.action.disabledText,
opacity: 0.65,
"&:hover:before": {
backgroundColor: "transparent"
}
},
"&:before": {
zIndex: -1,
position: "absolute",
opacity: 0,
width: `${hoverSize}px`,
height: `${hoverSize}px`,
borderRadius: theme.shape.radius.default,
content: '""',
[theme.transitions.handleMotion("no-preference", "reduce")]: {
transitionDuration: "0.2s",
transitionTimingFunction: "cubic-bezier(0.4, 0, 0.2, 1)",
transitionProperty: "opacity"
}
},
"&:focus, &:focus-visible": getFocusStyles(theme),
"&:focus:not(:focus-visible)": getMouseFocusStyles(theme),
"&:hover:before": {
backgroundColor: hoverColor,
opacity: 1
}
}),
icon: css.css({
verticalAlign: "baseline"
})
};
};
"use strict";
function breakpointCSS(theme, prop, getCSS, key) {
const value = prop[key];
if (value !== void 0 && value !== null) {
return {
[theme.breakpoints.up(key)]: getCSS(value)
};
}
return;
}
function getResponsiveStyle(theme, prop, getCSS) {
if (prop === void 0 || prop === null) {
return null;
}
if (typeof prop !== "object" || !("xs" in prop)) {
return getCSS(prop);
}
return [
breakpointCSS(theme, prop, getCSS, "xs"),
breakpointCSS(theme, prop, getCSS, "sm"),
breakpointCSS(theme, prop, getCSS, "md"),
breakpointCSS(theme, prop, getCSS, "lg"),
breakpointCSS(theme, prop, getCSS, "xl"),
breakpointCSS(theme, prop, getCSS, "xxl")
];
}
"use strict";
const getSizeStyles = (theme, width, minWidth, maxWidth, height, minHeight, maxHeight) => {
return css.css([
getResponsiveStyle(theme, width, (val) => ({
width: theme.spacing(val)
})),
getResponsiveStyle(theme, minWidth, (val) => ({
minWidth: theme.spacing(val)
})),
getResponsiveStyle(theme, maxWidth, (val) => ({
maxWidth: theme.spacing(val)
})),
getResponsiveStyle(theme, height, (val) => ({
height: theme.spacing(val)
})),
getResponsiveStyle(theme, minHeight, (val) => ({
minHeight: theme.spacing(val)
})),
getResponsiveStyle(theme, maxHeight, (val) => ({
maxHeight: theme.spacing(val)
}))
]);
};
"use strict";
const Stack = React__namespace.forwardRef((props, ref) => {
const {
gap = 1,
rowGap,
columnGap,
alignItems,
justifyContent,
direction,
wrap,
children,
grow,
shrink,
basis,
flex,
width,
minWidth,
maxWidth,
height,
minHeight,
maxHeight,
...rest
} = props;
const styles = useStyles2(
getStyles$F,
gap,
rowGap,
columnGap,
alignItems,
justifyContent,
direction,
wrap,
grow,
shrink,
basis,
flex
);
const sizeStyles = useStyles2(getSizeStyles, width, minWidth, maxWidth, height, minHeight, maxHeight);
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: css.cx(styles.flex, sizeStyles), ...rest, children });
});
Stack.displayName = "Stack";
const getStyles$F = (theme, gap, rowGap, columnGap, alignItems, justifyContent, direction, wrap, grow, shrink, basis, flex) => {
return {
flex: css.css([
{
display: "flex"
},
getResponsiveStyle(theme, direction, (val) => ({
flexDirection: val
})),
getResponsiveStyle(theme, wrap, (val) => ({
flexWrap: typeof val === "boolean" ? val ? "wrap" : "nowrap" : val
})),
getResponsiveStyle(theme, alignItems, (val) => ({
alignItems: val
})),
getResponsiveStyle(theme, justifyContent, (val) => ({
justifyContent: val
})),
getResponsiveStyle(theme, gap, (val) => ({
gap: theme.spacing(val)
})),
getResponsiveStyle(theme, rowGap, (val) => ({
rowGap: theme.spacing(val)
})),
getResponsiveStyle(theme, columnGap, (val) => ({
columnGap: theme.spacing(val)
})),
getResponsiveStyle(theme, grow, (val) => ({
flexGrow: val
})),
getResponsiveStyle(theme, shrink, (val) => ({
flexShrink: val
})),
getResponsiveStyle(theme, basis, (val) => ({
flexBasis: val
})),
getResponsiveStyle(theme, flex, (val) => ({
flex: val
}))
])
};
};
"use strict";
const getModalStyles = (theme) => {
return {
modal: css.css({
position: "fixed",
zIndex: theme.zIndex.modal,
background: theme.colors.background.primary,
boxShadow: theme.shadows.z3,
borderRadius: theme.shape.radius.lg,
border: `1px solid ${theme.colors.border.weak}`,
backgroundClip: "padding-box",
outline: "none",
width: "750px",
maxWidth: "100%",
left: 0,
right: 0,
marginLeft: "auto",
marginRight: "auto",
top: "10%",
maxHeight: "80%",
display: "flex",
flexDirection: "column",
// Centre the modal vertically on smaller height screens
// this allows us to fill the full height for maximum usability
["@media (max-height: 750px)"]: {
maxHeight: "100%",
top: "50%",
transform: "translateY(-50%)"
}
}),
modalBackdrop: css.css({
position: "fixed",
zIndex: theme.zIndex.modalBackdrop,
top: 0,
right: 0,
bottom: 0,
left: 0,
backgroundColor: theme.components.overlay.background
}),
modalHeader: css.css({
label: "modalHeader",
display: "flex",
alignItems: "center",
minHeight: "42px",
margin: theme.spacing(1, 2, 0, 2),
[theme.breakpoints.down("sm")]: {
margin: theme.spacing(0, 1, 0, 1)
}
}),
modalHeaderWithTabs: css.css({
borderBottom: `1px solid ${theme.colors.border.weak}`
}),
modalHeaderTitle: css.css({
fontSize: theme.typography.size.lg,
margin: theme.spacing(0, 4, 0, 1),
display: "flex",
alignItems: "center",
position: "relative",
top: "2px"
}),
modalHeaderIcon: css.css({
marginRight: theme.spacing(2),
fontSize: "inherit",
"&:before": {
verticalAlign: "baseline"
}
}),
modalHeaderClose: css.css({
height: "100%",
display: "flex",
alignItems: "center",
color: theme.colors.text.secondary,
flexGrow: 1,
justifyContent: "flex-end"
}),
modalContent: css.css({
overflow: "auto",
padding: theme.spacing(3, 3, 0, 3),
marginBottom: theme.spacing(3),
scrollbarWidth: "thin",
width: "100%",
[theme.breakpoints.down("sm")]: {
padding: theme.spacing(1, 2, 0, 2),
marginBottom: theme.spacing(2)
}
}),
modalButtonRow: css.css({
background: theme.colors.background.primary,
position: "sticky",
bottom: 0,
paddingTop: theme.spacing(2),
paddingBottom: theme.spacing(0.5),
zIndex: 1
})
};
};
"use strict";
const ModalHeader = ({ icon, iconTooltip, title, children, id }) => {
const styles = useStyles2(getModalStyles);
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: styles.modalHeaderTitle, id, children: title }),
children
] });
};
"use strict";
function Modal(props) {
const {
title,
ariaLabel,
children,
isOpen = false,
closeOnEscape = true,
closeOnBackdropClick = true,
className,
contentClassName,
onDismiss,
onClickBackdrop,
trapFocus = true
} = props;
const styles = useStyles2(getModalStyles);
const ref = React.useRef(null);
const { overlayProps, underlayProps } = overlays.useOverlay(
{ isKeyboardDismissDisabled: !closeOnEscape, isOpen, onClose: onDismiss },
ref
);
const { dialogProps, titleProps } = dialog.useDialog(
{
"aria-label": ariaLabel
},
ref
);
if (!isOpen) {
return null;
}
const headerClass = css.cx(styles.modalHeader, typeof title !== "string" && styles.modalHeaderWithTabs);
return /* @__PURE__ */ jsxRuntime.jsxs(overlays.OverlayContainer, { children: [
/* @__PURE__ */ jsxRuntime.jsx(
"div",
{
role: "presentation",
className: styles.modalBackdrop,
onClick: onClickBackdrop || (closeOnBackdropClick ? onDismiss : void 0),
...underlayProps
}
),
/* @__PURE__ */ jsxRuntime.jsx(focus.FocusScope, { contain: trapFocus, autoFocus: true, restoreFocus: true, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: css.cx(styles.modal, className), ref, ...overlayProps, ...dialogProps, children: [
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: headerClass, children: [
typeof title === "string" && /* @__PURE__ */ jsxRuntime.jsx(DefaultModalHeader, { ...props, title, id: titleProps.id }),
// FIXME: custom title components won't get an accessible title.
// Do we really want to support them or shall we just limit this ModalTabsHeader?
typeof title !== "string" && title,
/* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.modalHeaderClose, children: /* @__PURE__ */ jsxRuntime.jsx(
IconButton,
{
name: "times",
size: "xl",
onClick: onDismiss,
"aria-label": i18n.t("grafana-ui.modal.close-tooltip", "Close")
}
) })
] }),
/* @__PURE__ */ jsxRuntime.jsx("div", { className: css.cx(styles.modalContent, contentClassName), children })
] }) })
] });
}
function ModalButtonRow({ leftItems, children }) {
const styles = useStyles2(getModalStyles);
if (leftItems) {
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.modalButtonRow, children: /* @__PURE__ */ jsxRuntime.jsxs(Stack, { justifyContent: "space-between", children: [
/* @__PURE__ */ jsxRuntime.jsx(Stack, { justifyContent: "flex-start", gap: 2, children: leftItems }),
/* @__PURE__ */ jsxRuntime.jsx(Stack, { justifyContent: "flex-end", gap: 2, children })
] }) });
}
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.modalButtonRow, children: /* @__PURE__ */ jsxRuntime.jsx(Stack, { justifyContent: "flex-end", gap: 2, wrap: "wrap", children }) });
}
Modal.ButtonRow = ModalButtonRow;
function DefaultModalHeader({ icon, iconTooltip, title, id }) {
return /* @__PURE__ */ jsxRuntime.jsx(ModalHeader, { icon, iconTooltip, title, id });
}
"use strict";
const FieldValidationMessage = ({
children,
horizontal,
className
}) => {
const styles = useStyles2(getFieldValidationMessageStyles);
const cssName = css.cx(horizontal ? styles.horizontal : styles.vertical, className);
return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "alert", className: cssName, children: [
/* @__PURE__ */ jsxRuntime.jsx(Icon, { className: styles.fieldValidationMessageIcon, name: "exclamation-triangle" }),
children
] });
};
const getFieldValidationMessageStyles = (theme) => {
const baseStyle = `
font-size: ${theme.typography.size.sm};
font-weight: ${theme.typography.fontWeightMedium};
padding: ${theme.spacing(0.5, 1)};
color: ${theme.colors.error.contrastText};
background: ${theme.colors.error.main};
border-radius: ${theme.shape.radius.default};
position: relative;
display: inline-block;
align-self: flex-start;
a {
color: ${theme.colors.error.contrastText};
text-decoration: underline;
}
a:hover {
text-decoration: none;
}
`;
return {
vertical: css.css(baseStyle, {
margin: theme.spacing(0.5, 0, 0, 0),
"&:before": {
content: '""',
position: "absolute",
left: "9px",
top: "-5px",
width: 0,
height: 0,
borderWidth: "0 4px 5px 4px",
borderColor: `transparent transparent ${theme.colors.error.main} transparent`,
borderStyle: "solid"
}
}),
horizontal: css.css(baseStyle, {
marginLeft: "10px",
"&:before": {
content: '""',
position: "absolute",
left: "-5px",
top: "9px",
width: 0,
height: 0,
borderWidth: "4px 5px 4px 0",
borderColor: "transparent #e02f44 transparent transparent",
borderStyle: "solid"
}
}),
fieldValidationMessageIcon: css.css({
marginRight: theme.spacing()
})
};
};
"use strict";
const Label = ({ children, description, className, category, ...labelProps }) => {
const styles = useStyles2(getLabelStyles);
const categories = category == null ? void 0 : category.map((c, i) => {
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: styles.categories, children: [
/* @__PURE__ */ jsxRuntime.jsx("span", { children: c }),
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "angle-right", className: styles.chevron })
] }, `${c}/${i}`);
});
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: css.cx(styles.label, className), children: /* @__PURE__ */ jsxRuntime.jsxs("label", { ...labelProps, children: [
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.labelContent, children: [
categories,
children
] }),
description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.description, children: description })
] }) });
};
const getLabelStyles = (theme) => ({
label: css.css({
label: "Label",
fontSize: theme.typography.size.sm,
fontWeight: theme.typography.fontWeightMedium,
lineHeight: 1.25,
marginBottom: theme.spacing(0.5),
color: theme.colors.text.primary,
maxWidth: "480px"
}),
labelContent: css.css({
display: "flex",
alignItems: "center"
}),
description: css.css({
label: "Label-description",
color: theme.colors.text.secondary,
fontSize: theme.typography.size.sm,
fontWeight: theme.typography.fontWeightRegular,
marginTop: theme.spacing(0.25),
display: "block"
}),
categories: css.css({
label: "Label-categories",
display: "inline-flex",
alignItems: "center"
}),
chevron: css.css({
margin: theme.spacing(0, 0.25)
})
});
"use strict";
const Field = React__namespace.forwardRef(
({
label,
description,
horizontal,
invalid,
loading,
disabled,
required,
error,
children,
className,
validationMessageHorizontalOverflow,
htmlFor,
noMargin,
...otherProps
}, ref) => {
const styles = useStyles2(getFieldStyles, noMargin);
const inputId = htmlFor != null ? htmlFor : getChildId(children);
const labelElement = typeof label === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: inputId, description, children: `${label}${required ? " *" : ""}` }) : label;
const childProps = deleteUndefinedProps({ invalid, disabled, loading });
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: css.cx(styles.field, horizontal && styles.fieldHorizontal, className), ...otherProps, children: [
labelElement,
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
/* @__PURE__ */ jsxRuntime.jsx("div", { ref, children: React__namespace.cloneElement(children, childProps) }),
invalid && error && !horizontal && /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: css.cx(styles.fieldValidationWrapper, {
[styles.validationMessageHorizontalOverflow]: !!validationMessageHorizontalOverflow
}),
children: /* @__PURE__ */ jsxRuntime.jsx(FieldValidationMessage, { children: error })
}
)
] }),
invalid && error && horizontal && /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: css.cx(styles.fieldValidationWrapper, styles.fieldValidationWrapperHorizontal, {
[styles.validationMessageHorizontalOverflow]: !!validationMessageHorizontalOverflow
}),
children: /* @__PURE__ */ jsxRuntime.jsx(FieldValidationMessage, { children: error })
}
)
] });
}
);
Field.displayName = "Field";
function deleteUndefinedProps(obj) {
for (const key in obj) {
if (obj[key] === void 0) {
delete obj[key];
}
}
return obj;
}
const getFieldStyles = (theme, noMargin) => ({
field: css.css({
display: "flex",
flexDirection: "column",
marginBottom: theme.spacing(noMargin ? 0 : 2)
}),
fieldHorizontal: css.css({
flexDirection: "row",
justifyContent: "space-between",
flexWrap: "wrap"
}),
fieldValidationWrapper: css.css({
marginTop: theme.spacing(0.5)
}),
fieldValidationWrapperHorizontal: css.css({
flex: "1 1 100%"
}),
validationMessageHorizontalOverflow: css.css({
width: 0,
overflowX: "visible",
"& > *": {
whiteSpace: "nowrap"
}
})
});
"use strict";
const isIconSize = (value) => {
return ["xs", "sm", "md", "lg", "xl", "xxl", "xxxl"].includes(value);
};
const getAvailableIcons = () => Object.keys(data.availableIconsIndex);
function getFieldTypeIcon(field) {
return getFieldTypeIconName(field == null ? void 0 : field.type);
}
function getFieldTypeIconName(type) {
if (type) {
switch (type) {
case data.FieldType.time:
return "clock-nine";
case data.FieldType.string:
return "font";
case data.FieldType.number:
return "calculator-alt";
case data.FieldType.boolean:
return "toggle-on";
case data.FieldType.trace:
return "info-circle";
case data.FieldType.enum:
return "list-ol";
case data.FieldType.geo:
return "map-marker";
case data.FieldType.other:
return "brackets-curly";
}
}
return "question-circle";
}
"use strict";
const Spinner = ({
className,
inline = false,
iconClassName,
style,
size = "md"
}) => {
const styles = useStyles2(getStyles$E);
const deprecatedStyles = useStyles2(getDeprecatedStyles, size);
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
const iconName = prefersReducedMotion ? "hourglass" : "spinner";
if (typeof size !== "string" || !isIconSize(size)) {
const iconRoot = getIconRoot();
const subDir = getIconSubDir(iconName, "default");
const svgPath = `${iconRoot}${subDir}/${iconName}.svg`;
return /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
"data-testid": "Spinner",
style,
className: css.cx(
{
[styles.inline]: inline
},
deprecatedStyles.wrapper,
className
),
children: /* @__PURE__ */ jsxRuntime.jsx(
SVG__default.default,
{
src: svgPath,
width: size,
height: size,
className: css.cx(styles.spin, deprecatedStyles.icon, className),
style
}
)
}
);
}
return /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
"data-testid": "Spinner",
style,
className: css.cx(
{
[styles.inline]: inline
},
className
),
children: /* @__PURE__ */ jsxRuntime.jsx(
Icon,
{
className: css.cx(styles.spin, iconClassName),
name: iconName,
size,
"aria-label": i18n.t("grafana-ui.spinner.aria-label", "Loading")
}
)
}
);
};
const getStyles$E = (theme) => ({
inline: css.css({
display: "inline-block",
lineHeight: 0
}),
spin: css.css({
[theme.transitions.handleMotion("no-preference")]: {
animation: `${spin$1} 2s infinite linear`
}
})
});
const getDeprecatedStyles = (theme, size) => ({
wrapper: css.css({
fontSize: typeof size === "string" ? size : `${size}px`
}),
icon: css.css({
display: "inline-block",
fill: "currentColor",
flexShrink: 0,
label: "Icon",
// line-height: 0; is needed for correct icon alignment in Safari
lineHeight: 0,
verticalAlign: "middle"
})
});
"use strict";
const AutoSizeInputContext = React__namespace.default.createContext(false);
AutoSizeInputContext.displayName = "AutoSizeInputContext";
"use strict";
const Input = React.forwardRef((props, ref) => {
const {
className,
addonAfter,
addonBefore,
prefix,
suffix: suffixProp,
invalid,
loading,
width = 0,
...restProps
} = props;
const [prefixRef, prefixRect] = reactUse.useMeasure();
const [suffixRef, suffixRect] = reactUse.useMeasure();
const isInAutoSizeInput = React.useContext(AutoSizeInputContext);
const accessoriesWidth = (prefixRect.width || 0) + (suffixRect.width || 0);
const autoSizeWidth = isInAutoSizeInput && width ? width + accessoriesWidth / 8 : void 0;
const theme = useTheme2();
const styles = getInputStyles({ theme, invalid: !!invalid, width: autoSizeWidth ? void 0 : width });
const suffix = suffixProp || loading && /* @__PURE__ */ jsxRuntime.jsx(Spinner, { inline: true });
return /* @__PURE__ */ jsxRuntime.jsxs(
"div",
{
className: css.cx(styles.wrapper, className),
style: autoSizeWidth ? { width: theme.spacing(autoSizeWidth) } : void 0,
"data-testid": "input-wrapper",
children: [
!!addonBefore && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.addon, children: addonBefore }),
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.inputWrapper, children: [
prefix && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.prefix, ref: prefixRef, children: prefix }),
/* @__PURE__ */ jsxRuntime.jsx(
"input",
{
ref,
className: styles.input,
...restProps,
style: {
paddingLeft: prefix ? prefixRect.width + 12 : void 0,
paddingRight: suffix || loading ? suffixRect.width + 12 : void 0
}
}
),
suffix && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.suffix, ref: suffixRef, children: suffix })
] }),
!!addonAfter && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.addon, children: addonAfter })
]
}
);
});
Input.displayName = "Input";
const getInputStyles = stylesFactory(({ theme, invalid = false, width }) => {
const prefixSuffixStaticWidth = "28px";
const prefixSuffix = css.css({
position: "absolute",
top: 0,
zIndex: 1,
display: "flex",
alignItems: "center",
justifyContent: "center",
flexGrow: 0,
flexShrink: 0,
fontSize: theme.typography.size.md,
height: "100%",
/* Min width specified for prefix/suffix classes used outside React component*/
minWidth: prefixSuffixStaticWidth,
color: theme.colors.text.secondary
});
return {
// Wraps inputWrapper and addons
wrapper: css.cx(
css.css({
label: "input-wrapper",
display: "flex",
width: width ? theme.spacing(width) : "100%",
height: theme.spacing(theme.components.height.md),
borderRadius: theme.shape.radius.default,
"&:hover": {
"> .prefix, .suffix, .input": {
borderColor: invalid ? theme.colors.error.border : theme.colors.primary.border
},
// only show number buttons on hover
"input[type='number']": {
appearance: "textfield"
},
"input[type='number']::-webkit-inner-spin-button, input[type='number']::-webkit-outer-spin-button": {
// Need type assertion here due to the use of !important
// see https://github.com/frenic/csstype/issues/114#issuecomment-697201978
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
WebkitAppearance: "inner-spin-button !important",
opacity: 1
}
}
})
),
// Wraps input and prefix/suffix
inputWrapper: css.css({
label: "input-inputWrapper",
position: "relative",
flexGrow: 1,
/* we want input to be above addons, especially for focused state */
zIndex: 1,
/* when input rendered with addon before only*/
"&:not(:first-child):last-child": {
"> input": {
borderLeft: "none",
borderTopLeftRadius: "unset",
borderBottomLeftRadius: "unset"
}
},
/* when input rendered with addon after only*/
"&:first-child:not(:last-child)": {
"> input": {
borderRight: "none",
borderTopRightRadius: "unset",
borderBottomRightRadius: "unset"
}
},
/* when rendered with addon before and after */
"&:not(:first-child):not(:last-child)": {
"> input": {
borderRight: "none",
borderTopRightRadius: "unset",
borderBottomRightRadius: "unset",
borderTopLeftRadius: "unset",
borderBottomLeftRadius: "unset"
}
},
input: {
/* paddings specified for classes used outside React component */
"&:not(:first-child)": {
paddingLeft: prefixSuffixStaticWidth
},
"&:not(:last-child)": {
paddingRight: prefixSuffixStaticWidth
},
"&[readonly]": {
cursor: "default"
}
}
}),
input: css.cx(
getFocusStyle(theme),
sharedInputStyle(theme, invalid),
css.css({
label: "input-input",
position: "relative",
zIndex: 0,
flexGrow: 1,
borderRadius: theme.shape.radius.default,
height: "100%",
width: "100%"
})
),
inputDisabled: css.css({
backgroundColor: theme.colors.action.disabledBackground,
color: theme.colors.action.disabledText,
border: `1px solid ${theme.colors.action.disabledBackground}`,
"&:focus": {
boxShadow: "none"
}
}),
addon: css.css({
label: "input-addon",
display: "flex",
justifyContent: "center",
alignItems: "center",
flexGrow: 0,
flexShrink: 0,
position: "relative",
"&:first-child": {
borderTopRightRadius: "unset",
borderBottomRightRadius: "unset",
"> :last-child": {
borderTopRightRadius: "unset",
borderBottomRightRadius: "unset"
}
},
"&:last-child": {
borderTopLeftRadius: "unset",
borderBottomLeftRadius: "unset",
"> :first-child": {
borderTopLeftRadius: "unset",
borderBottomLeftRadius: "unset"
}
},
"> *:focus": {
/* we want anything that has focus and is an addon to be above input */
zIndex: 2
}
}),
prefix: css.cx(
prefixSuffix,
css.css({
label: "input-prefix",
paddingLeft: theme.spacing(1),
paddingRight: theme.spacing(0.5),
borderRight: "none",
borderTopRightRadius: "unset",
borderBottomRightRadius: "unset"
})
),
suffix: css.cx(
prefixSuffix,
css.css({
label: "input-suffix",
paddingLeft: theme.spacing(1),
paddingRight: theme.spacing(1),
borderLeft: "none",
borderTopLeftRadius: "unset",
borderBottomLeftRadius: "unset",
right: 0
})
),
loadingIndicator: css.css({
"& + *": {
marginLeft: theme.spacing(0.5)
}
})
};
});
"use strict";
const ConfirmContent = ({
body,
confirmPromptText,
confirmButtonLabel,
confirmButtonVariant,
dismissButtonVariant,
dismissButtonLabel,
onConfirm,
onDismiss,
onAlternative,
alternativeButtonLabel,
description,
justifyButtons = "flex-end",
disabled
}) => {
const [isDisabled, setIsDisabled] = React.useState(disabled);
const styles = useStyles2(getStyles$D);
const buttonRef = React.useRef(null);
const onConfirmationTextChange = (event) => {
setIsDisabled((confirmPromptText == null ? void 0 : confirmPromptText.toLowerCase().localeCompare(event.currentTarget.value.toLowerCase())) !== 0);
};
React.useEffect(() => {
var _a;
(_a = buttonRef.current) == null ? void 0 : _a.focus();
}, []);
React.useEffect(() => {
setIsDisabled(disabled ? true : Boolean(confirmPromptText));
}, [confirmPromptText, disabled]);
const onConfirmClick = async () => {
if (disabled === void 0) {
setIsDisabled(true);
}
try {
await onConfirm();
} finally {
if (disabled === void 0) {
setIsDisabled(false);
}
}
};
const { handleSubmit } = reactHookForm.useForm();
const placeholder = i18n.t("grafana-ui.confirm-content.placeholder", 'Type "{{confirmPromptText}}" to confirm', {
confirmPromptText
});
return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit(onConfirmClick), children: [
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.text, children: [
body,
description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.description, children: description }) : null,
confirmPromptText ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.confirmationInput, children: /* @__PURE__ */ jsxRuntime.jsx(Stack, { alignItems: "flex-start", children: /* @__PURE__ */ jsxRuntime.jsx(Field, { disabled, children: /* @__PURE__ */ jsxRuntime.jsx(
Input,
{
placeholder,
onChange: onConfirmationTextChange,
"data-testid": e2eSelectors.selectors.pages.ConfirmModal.input
}
) }) }) }) : null
] }),
/* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.buttonsContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(Stack, { justifyContent: justifyButtons, gap: 2, wrap: "wrap", children: [
/* @__PURE__ */ jsxRuntime.jsx(Button, { variant: dismissButtonVariant, onClick: onDismiss, fill: "outline", children: dismissButtonLabel }),
/* @__PURE__ */ jsxRuntime.jsx(
Button,
{
type: "submit",
variant: confirmButtonVariant,
disabled: isDisabled,
ref: buttonRef,
"data-testid": e2eSelectors.selectors.pages.ConfirmModal.delete,
children: confirmButtonLabel
}
),
onAlternative ? /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "primary", onClick: onAlternative, children: alternativeButtonLabel }) : null
] }) })
] });
};
const getStyles$D = (theme) => ({
text: css.css({
fontSize: theme.typography.h5.fontSize,
color: theme.colors.text.primary
}),
description: css.css({
fontSize: theme.typography.body.fontSize
}),
confirmationInput: css.css({
paddingTop: theme.spacing(1)
}),
buttonsContainer: css.css({
paddingTop: theme.spacing(3)
})
});
"use strict";
const ConfirmModal = ({
isOpen,
title,
body,
description,
confirmText,
confirmVariant = "destructive",
confirmationText,
dismissText = "Cancel",
dismissVariant = "secondary",
alternativeText,
modalClass,
icon = "exclamation-triangle",
onConfirm,
onDismiss,
onAlternative,
confirmButtonVariant = "destructive",
disabled
}) => {
const styles = useStyles2(getStyles$C);
return /* @__PURE__ */ jsxRuntime.jsx(Modal, { className: css.cx(styles.modal, modalClass), title, icon, isOpen, onDismiss, children: /* @__PURE__ */ jsxRuntime.jsx(
ConfirmContent,
{
body,
description,
confirmButtonLabel: confirmText,
dismissButtonLabel: dismissText,
dismissButtonVariant: dismissVariant,
confirmPromptText: confirmationText,
alternativeButtonLabel: alternativeText,
confirmButtonVariant,
onConfirm,
onDismiss,
onAlternative,
disabled
}
) });
};
const getStyles$C = () => ({
modal: css.css({
width: "500px"
})
});
"use strict";
const getLegendStyles = (theme) => {
return {
legend: css.css({
fontSize: theme.typography.h3.fontSize,
fontWeight: theme.typography.fontWeightRegular,
margin: theme.spacing(0, 0, 2, 0)
})
};
};
const Legend = ({ children, className, ...legendProps }) => {
const styles = useStyles2(getLegendStyles);
return /* @__PURE__ */ jsxRuntime.jsx("legend", { className: css.cx(styles.legend, className), ...legendProps, children });
};
"use strict";
const FieldSet = ({ label, children, className, ...rest }) => {
const styles = useStyles2(getStyles$B);
return /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className: css.cx(styles.wrapper, className), ...rest, children: [
label && /* @__PURE__ */ jsxRuntime.jsx(Legend, { children: label }),
children
] });
};
const getStyles$B = (theme) => ({
wrapper: css.css({
marginBottom: theme.spacing(4),
"&:last-child": {
marginBottom: 0
}
})
});
"use strict";
function VariablesInputModal({ action, onDismiss, onShowConfirm, variables, setVariables }) {
const styles = useStyles2(getStyles$A);
const onModalContinue = () => {
onDismiss();
onShowConfirm();
};
return /* @__PURE__ */ jsxRuntime.jsxs(
Modal,
{
isOpen: true,
title: i18n.t("grafana-ui.action-editor.button.action-variables-title", "Action variables"),
onDismiss,
className: styles.variablesModal,
children: [
/* @__PURE__ */ jsxRuntime.jsx(FieldSet, { children: action.variables.map((variable) => {
var _a;
return /* @__PURE__ */ jsxRuntime.jsx(Field, { label: variable.name, children: /* @__PURE__ */ jsxRuntime.jsx(
Input,
{
type: "text",
value: (_a = variables[variable.key]) != null ? _a : "",
onChange: (e) => {
setVariables({ ...variables, [variable.key]: e.currentTarget.value });
},
placeholder: i18n.t("grafana-ui.action-editor.button.variable-value-placeholder", "Value"),
width: 20
}
) }, variable.name);
}) }),
/* @__PURE__ */ jsxRuntime.jsxs(Modal.ButtonRow, { children: [
/* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "secondary", onClick: onDismiss, children: i18n.t("grafana-ui.action-editor.close", "Close") }),
/* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "primary", onClick: onModalContinue, children: i18n.t("grafana-ui.action-editor.continue", "Continue") })
] })
]
}
);
}
const getStyles$A = () => {
return {
variablesModal: css.css({
zIndex: 1e4
})
};
};
"use strict";
function ActionButton({ action, ...buttonProps }) {
const theme = useTheme2();
const backgroundColor = action.style.backgroundColor || theme.colors.secondary.main;
const textColor = theme.colors.getContrastText(backgroundColor);
const [showConfirm, setShowConfirm] = React.useState(false);
const [showVarsModal, setShowVarsModal] = React.useState(false);
const [actionVars, setActionVars] = React.useState({});
const actionHasVariables = action.variables && action.variables.length > 0;
const onClick = () => {
if (actionHasVariables) {
setShowVarsModal(true);
} else {
setShowConfirm(true);
}
};
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
/* @__PURE__ */ jsxRuntime.jsx(
Button,
{
variant: "primary",
size: "sm",
onClick,
...buttonProps,
style: { width: "fit-content", backgroundColor, color: textColor },
children: action.title
}
),
actionHasVariables && showVarsModal && /* @__PURE__ */ jsxRuntime.jsx(
VariablesInputModal,
{
onDismiss: () => setShowVarsModal(false),
action,
onShowConfirm: () => setShowConfirm(true),
variables: actionVars,
setVariables: setActionVars
}
),
showConfirm && /* @__PURE__ */ jsxRuntime.jsx(
ConfirmModal,
{
isOpen: true,
title: i18n.t("grafana-ui.action-editor.button.confirm-action", "Confirm action"),
body: action.confirmation(actionVars),
confirmText: i18n.t("grafana-ui.action-editor.button.confirm", "Confirm"),
confirmButtonVariant: "primary",
onConfirm: () => {
setShowConfirm(false);
action.onClick(new MouseEvent("click"), null, actionVars);
},
onDismiss: () => {
setShowConfirm(false);
}
}
)
] });
}
"use strict";
function DataLinkButton({ link, buttonProps }) {
return /* @__PURE__ */ jsxRuntime.jsx(
"a",
{
href: link.href,
target: link.target,
rel: "noreferrer",
onClick: link.onClick ? (event) => {
if (!(event.ctrlKey || event.metaKey || event.shiftKey) && link.onClick) {
event.preventDefault();
link.onClick(event);
}
} : void 0,
children: /* @__PURE__ */ jsxRuntime.jsx(
Button,
{
icon: link.target === "_blank" ? "external-link-alt" : "link",
variant: "primary",
size: "sm",
...buttonProps,
children: link.title
}
)
}
);
}
"use strict";
const ADD_ANNOTATION_ID = "add-annotation-button";
function makeRenderLinksOrActions(renderOneClickTrans, renderItem, itemGap) {
const renderLinksOrActions = (items, styles) => {
if (items.length === 0) {
return;
}
const oneClickItem = items.find((item) => item.oneClick === true);
if (oneClickItem != null) {
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.footerSection, children: /* @__PURE__ */ jsxRuntime.jsx(Stack, { direction: "column", justifyContent: "flex-start", gap: 0.5, children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: styles.oneClickWrapper, children: [
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "info-circle", size: "lg", className: styles.infoIcon }),
renderOneClickTrans(oneClickItem.title)
] }) }) });
}
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.footerSection, children: /* @__PURE__ */ jsxRuntime.jsx(Stack, { direction: "column", justifyContent: "flex-start", gap: itemGap, children: items.map((item, i) => renderItem(item, i, styles)) }) });
};
return renderLinksOrActions;
}
const renderDataLinks = makeRenderLinksOrActions(
(title) => /* @__PURE__ */ jsxRuntime.jsxs(i18n.Trans, { i18nKey: "grafana-ui.viz-tooltip.footer-click-to-navigate", children: [
"Click to open ",
{ linkTitle: title }
] }),
(item, i, styles) => /* @__PURE__ */ jsxRuntime.jsx(DataLinkButton, { link: item, buttonProps: { className: styles.dataLinkButton, fill: "text" } }, i),
0.5
);
const renderActions = makeRenderLinksOrActions(
(title) => /* @__PURE__ */ jsxRuntime.jsxs(i18n.Trans, { i18nKey: "grafana-ui.viz-tooltip.footer-click-to-action", children: [
"Click to ",
{ actionTitle: title }
] }),
(item, i) => /* @__PURE__ */ jsxRuntime.jsx(ActionButton, { action: item, variant: "secondary" }, i)
);
const VizTooltipFooter = ({ dataLinks, actions = [], annotate, adHocFilters = [] }) => {
const styles = useStyles2(getStyles$z);
const hasOneClickLink = React.useMemo(() => dataLinks.some((link) => link.oneClick === true), [dataLinks]);
const hasOneClickAction = React.useMemo(() => actions.some((action) => action.oneClick === true), [actions]);
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.wrapper, children: [
!hasOneClickAction && renderDataLinks(dataLinks, styles),
!hasOneClickLink && renderActions(actions, styles),
!hasOneClickLink && !hasOneClickAction && adHocFilters.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.footerSection, children: adHocFilters.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(Button, { icon: "filter", variant: "secondary", size: "sm", onClick: item.onClick, children: /* @__PURE__ */ jsxRuntime.jsxs(i18n.Trans, { i18nKey: "grafana-ui.viz-tooltip.footer-filter-for-value", children: [
"Filter for '",
{ value: item.value },
"'"
] }) }, index)) }),
!hasOneClickLink && !hasOneClickAction && annotate != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.footerSection, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { icon: "comment-alt", variant: "secondary", size: "sm", id: ADD_ANNOTATION_ID, onClick: annotate, children: /* @__PURE__ */ jsxRuntime.jsx(i18n.Trans, { i18nKey: "grafana-ui.viz-tooltip.footer-add-annotation", children: "Add annotation" }) }) })
] });
};
const getStyles$z = (theme) => ({
wrapper: css.css({
display: "flex",
flexDirection: "column",
flex: 1,
padding: theme.spacing(0)
}),
footerSection: css.css({
borderTop: `1px solid ${theme.colors.border.medium}`,
padding: theme.spacing(1)
}),
dataLinkButton: css.css({
cursor: "pointer",
"&:hover": {
textDecoration: "underline",
background: "none"
},
padding: 0,
height: "auto",
"& span": {
whiteSpace: "normal",
textAlign: "left"
}
}),
oneClickWrapper: css.css({
display: "flex",
alignItems: "center"
}),
infoIcon: css.css({
color: theme.colors.primary.main,
paddingRight: theme.spacing(0.5)
})
});
"use strict";
const VizTooltipWrapper = ({ children, className }) => {
const styles = useStyles2(getStyles$y);
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx__default.default(styles, className), "data-testid": e2eSelectors.selectors.components.Panels.Visualization.Tooltip.Wrapper, children });
};
const getStyles$y = (theme) => css.css({
display: "flex",
flexDirection: "column",
fontSize: theme.typography.bodySmall.fontSize
});
"use strict";
const DataLinksActionsTooltip = ({ links, actions, value, coords, onTooltipClose }) => {
const theme = useTheme2();
const styles = useStyles2(getStyles$x);
const placement = "right-start";
const middleware = getPositioningMiddleware(placement);
const virtual = React.useMemo(() => {
const { clientX, clientY } = coords;
return {
getBoundingClientRect() {
return {
width: 0,
height: 0,
x: clientX,
y: clientY,
top: clientY,
left: clientX,
right: clientX,
bottom: clientY
};
}
};
}, [coords]);
const refCallback = (el) => {
refs.setFloating(el);
refs.setReference(virtual);
};
const { context, refs, floatingStyles } = react.useFloating({
open: true,
placement,
onOpenChange: onTooltipClose,
middleware
// whileElementsMounted: autoUpdate,
});
const dismiss = react.useDismiss(context);
const { getFloatingProps, getReferenceProps } = react.useInteractions([dismiss]);
if (links.length === 0 && !Boolean(actions == null ? void 0 : actions.length)) {
return null;
}
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
value,
/* @__PURE__ */ jsxRuntime.jsx(Portal, { zIndex: theme.zIndex.tooltip, children: /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
ref: refCallback,
...getReferenceProps(),
...getFloatingProps(),
style: floatingStyles,
className: styles.tooltipWrapper,
"data-testid": e2eSelectors.selectors.components.DataLinksActionsTooltip.tooltipWrapper,
children: /* @__PURE__ */ jsxRuntime.jsx(VizTooltipWrapper, { children: /* @__PURE__ */ jsxRuntime.jsx(VizTooltipFooter, { dataLinks: links, actions }) })
}
) })
] });
};
const renderSingleLink = (link, children, className) => {
return /* @__PURE__ */ jsxRuntime.jsx(
"a",
{
href: link.href,
onClick: link.onClick,
target: link.target,
title: link.title,
"data-testid": e2eSelectors.selectors.components.DataLinksContextMenu.singleLink,
className,
children
}
);
};
const getStyles$x = (theme) => {
return {
tooltipWrapper: css.css({
whiteSpace: "pre",
borderRadius: theme.shape.radius.default,
background: theme.colors.background.primary,
border: `1px solid ${theme.colors.border.weak}`,
boxShadow: theme.shadows.z3,
userSelect: "text",
fontSize: theme.typography.bodySmall.fontSize
})
};
};
"use strict";
function InlineToast({ referenceElement, children, suffixIcon, placement }) {
const styles = useStyles2(getStyles$w);
const theme = useTheme2();
const middleware = [react.offset(8), ...getPositioningMiddleware(placement)];
const { context, refs, floatingStyles } = react.useFloating({
open: true,
placement,
middleware,
whileElementsMounted: react.autoUpdate,
strategy: "fixed"
});
React.useLayoutEffect(() => {
refs.setReference(referenceElement);
}, [referenceElement, refs]);
const { styles: placementStyles } = react.useTransitionStyles(context, {
initial: ({ side }) => {
return {
opacity: 0,
transform: getInitialTransform(side, theme)
};
},
duration: theme.transitions.duration.shortest
});
return /* @__PURE__ */ jsxRuntime.jsx(Portal, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "inline-block", ...floatingStyles }, ref: refs.setFloating, "aria-live": "polite", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: css.cx(styles.root), style: placementStyles, children: [
children && /* @__PURE__ */ jsxRuntime.jsx("span", { children }),
suffixIcon && /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: suffixIcon })
] }) }) });
}
const getStyles$w = (theme) => {
return {
root: css.css({
...theme.typography.bodySmall,
willChange: "transform",
background: theme.components.tooltip.background,
color: theme.components.tooltip.text,
padding: theme.spacing(0.5, 1.5),
// get's an extra .5 of vertical padding to account for the rounded corners
borderRadius: theme.shape.radius.pill,
display: "inline-flex",
gap: theme.spacing(0.5),
alignItems: "center"
})
};
};
const getInitialTransform = (placement, theme) => {
const gap = 1;
switch (placement) {
case "top":
return `translateY(${theme.spacing(gap)})`;
case "bottom":
return `translateY(-${theme.spacing(gap)})`;
case "left":
return `translateX(${theme.spacing(gap)})`;
case "right":
return `translateX(-${theme.spacing(gap)})`;
}
};
"use strict";
const SHOW_SUCCESS_DURATION = 2 * 1e3;
function ClipboardButton({
onClipboardCopy,
onClipboardError,
children,
getText,
icon,
variant,
...buttonProps
}) {
const styles = useStyles2(getStyles$v);
const [showCopySuccess, setShowCopySuccess] = React.useState(false);
React.useEffect(() => {
let timeoutId;
if (showCopySuccess) {
timeoutId = setTimeout(() => {
setShowCopySuccess(false);
}, SHOW_SUCCESS_DURATION);
}
return () => {
window.clearTimeout(timeoutId);
};
}, [showCopySuccess]);
const buttonRef = React.useRef(null);
const copyTextCallback = React.useCallback(async () => {
const textToCopy = getText();
try {
await copyText(textToCopy, buttonRef);
setShowCopySuccess(true);
onClipboardCopy == null ? void 0 : onClipboardCopy(textToCopy);
} catch (e) {
onClipboardError == null ? void 0 : onClipboardError(textToCopy, e);
}
}, [getText, onClipboardCopy, onClipboardError]);
const copiedText = i18n.t("clipboard-button.inline-toast.success", "Copied");
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
showCopySuccess && /* @__PURE__ */ jsxRuntime.jsx(InlineToast, { placement: "top", referenceElement: buttonRef.current, children: copiedText }),
/* @__PURE__ */ jsxRuntime.jsxs(
Button,
{
onClick: copyTextCallback,
icon,
variant: showCopySuccess ? "success" : variant,
...buttonProps,
className: css.cx(styles.button, showCopySuccess && styles.successButton, buttonProps.className),
ref: buttonRef,
children: [
children,
showCopySuccess && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.successOverlay, children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "check" }) })
]
}
)
] });
}
const copyText = async (text, buttonRef) => {
var _a;
if (navigator.clipboard && window.isSecureContext) {
return navigator.clipboard.writeText(text);
} else {
const textarea = document.createElement("textarea");
(_a = buttonRef.current) == null ? void 0 : _a.appendChild(textarea);
textarea.value = text;
textarea.focus();
textarea.select();
document.execCommand("copy");
textarea.remove();
}
};
const getStyles$v = (theme) => {
return {
button: css.css({
position: "relative"
}),
successButton: css.css({
"> *": css.css({
visibility: "hidden"
})
}),
successOverlay: css.css({
position: "absolute",
top: 0,
bottom: 0,
right: 0,
left: 0,
visibility: "visible"
// re-visible the overlay
})
};
};
"use strict";
const getDragStyles = (theme, handlePosition) => {
const position = handlePosition || "middle";
const baseColor = theme.colors.emphasize(theme.colors.background.secondary, 0.15);
const hoverColor = theme.colors.primary.border;
const clickTargetSize = theme.spacing(2);
const handlebarThickness = 4;
const handlebarWidth = 200;
let verticalOffset = "50%";
let horizontalOffset = "50%";
switch (position) {
case "start": {
verticalOffset = "0%";
horizontalOffset = "0%";
break;
}
case "end": {
verticalOffset = "100%";
horizontalOffset = "100%";
break;
}
}
const dragHandleBase = css.css({
position: "relative",
"&:before": {
content: '""',
position: "absolute",
[theme.transitions.handleMotion("no-preference", "reduce")]: {
transition: theme.transitions.create("border-color")
},
zIndex: 1
},
"&:after": {
background: baseColor,
content: '""',
position: "absolute",
[theme.transitions.handleMotion("no-preference", "reduce")]: {
transition: theme.transitions.create("background")
},
transform: "translate(-50%, -50%)",
borderRadius: theme.shape.radius.pill,
zIndex: 1
},
"&:hover": {
"&:before": {
borderColor: hoverColor
},
"&:after": {
background: hoverColor
}
}
});
const beforeVertical = {
borderRight: "1px solid transparent",
height: "100%",
left: verticalOffset,
transform: "translateX(-50%)"
};
const beforeHorizontal = {
borderTop: "1px solid transparent",
top: horizontalOffset,
transform: "translateY(-50%)"
};
return {
dragHandleVertical: css.cx(
dragHandleBase,
css.css({
cursor: "col-resize",
width: clickTargetSize,
"&:before": beforeVertical,
"&:after": {
left: verticalOffset,
top: "50%",
height: handlebarWidth,
width: handlebarThickness
}
})
),
dragHandleHorizontal: css.cx(
dragHandleBase,
css.css({
height: clickTargetSize,
cursor: "row-resize",
"&:before": beforeHorizontal,
"&:after": {
left: "50%",
top: horizontalOffset,
height: handlebarThickness,
width: handlebarWidth
}
})
),
dragHandleBaseVertical: css.cx(
dragHandleBase,
css.css({
cursor: "col-resize",
width: clickTargetSize,
"&:before": beforeVertical
})
),
dragHandleBaseHorizontal: css.cx(
dragHandleBase,
css.css({
cursor: "row-resize",
height: clickTargetSize,
"&:before": beforeHorizontal
})
)
};
};
"use strict";
const Box = React.forwardRef((props, ref) => {
const {
children,
margin,
marginX,
marginY,
marginTop,
marginBottom,
marginLeft,
marginRight,
padding,
paddingX,
paddingY,
paddingTop,
paddingBottom,
paddingLeft,
paddingRight,
display,
backgroundColor,
grow,
shrink,
basis,
flex,
borderColor,
borderStyle,
borderRadius,
direction,
justifyContent,
alignItems,
boxShadow,
element,
gap,
width,
minWidth,
maxWidth,
height,
minHeight,
maxHeight,
position,
...rest
} = props;
const styles = useStyles2(
getStyles$u,
margin,
marginX,
marginY,
marginTop,
marginBottom,
marginLeft,
marginRight,
padding,
paddingX,
paddingY,
paddingTop,
paddingBottom,
paddingLeft,
paddingRight,
display,
backgroundColor,
grow,
shrink,
basis,
flex,
borderColor,
borderStyle,
borderRadius,
direction,
justifyContent,
alignItems,
boxShadow,
gap,
position
);
const sizeStyles = useStyles2(getSizeStyles, width, minWidth, maxWidth, height, minHeight, maxHeight);
const Element = element != null ? element : "div";
return /* @__PURE__ */ jsxRuntime.jsx(Element, { ref, className: css.cx(styles.root, sizeStyles), ...rest, children });
});
Box.displayName = "Box";
const customBorderColor = (color, theme) => {
switch (color) {
case "error":
case "success":
case "info":
case "warning":
return theme.colors[color].borderTransparent;
default:
return color ? theme.colors.border[color] : void 0;
}
};
const customBackgroundColor = (color, theme) => {
switch (color) {
case "error":
case "success":
case "info":
case "warning":
return theme.colors[color].transparent;
default:
return color ? theme.colors.background[color] : void 0;
}
};
const getStyles$u = (theme, margin, marginX, marginY, marginTop, marginBottom, marginLeft, marginRight, padding, paddingX, paddingY, paddingTop, paddingBottom, paddingLeft, paddingRight, display, backgroundColor, grow, shrink, basis, flex, borderColor, borderStyle, borderRadius, direction, justifyContent, alignItems, boxShadow, gap, position) => {
return {
root: css.css([
getResponsiveStyle(theme, margin, (val) => ({
margin: theme.spacing(val)
})),
getResponsiveStyle(theme, marginX, (val) => ({
marginLeft: theme.spacing(val),
marginRight: theme.spacing(val)
})),
getResponsiveStyle(theme, marginY, (val) => ({
marginTop: theme.spacing(val),
marginBottom: theme.spacing(val)
})),
getResponsiveStyle(theme, marginTop, (val) => ({
marginTop: theme.spacing(val)
})),
getResponsiveStyle(theme, marginBottom, (val) => ({
marginBottom: theme.spacing(val)
})),
getResponsiveStyle(theme, marginLeft, (val) => ({
marginLeft: theme.spacing(val)
})),
getResponsiveStyle(theme, marginRight, (val) => ({
marginRight: theme.spacing(val)
})),
getResponsiveStyle(theme, padding, (val) => ({
padding: theme.spacing(val)
})),
getResponsiveStyle(theme, paddingX, (val) => ({
paddingLeft: theme.spacing(val),
paddingRight: theme.spacing(val)
})),
getResponsiveStyle(theme, paddingY, (val) => ({
paddingTop: theme.spacing(val),
paddingBottom: theme.spacing(val)
})),
getResponsiveStyle(theme, paddingTop, (val) => ({
paddingTop: theme.spacing(val)
})),
getResponsiveStyle(theme, paddingBottom, (val) => ({
paddingBottom: theme.spacing(val)
})),
getResponsiveStyle(theme, paddingLeft, (val) => ({
paddingLeft: theme.spacing(val)
})),
getResponsiveStyle(theme, paddingRight, (val) => ({
paddingRight: theme.spacing(val)
})),
getResponsiveStyle(theme, display, (val) => ({
display: val
})),
getResponsiveStyle(theme, backgroundColor, (val) => ({
backgroundColor: customBackgroundColor(val, theme)
})),
getResponsiveStyle(theme, direction, (val) => ({
flexDirection: val
})),
getResponsiveStyle(theme, grow, (val) => ({
flexGrow: val
})),
getResponsiveStyle(theme, shrink, (val) => ({
flexShrink: val
})),
getResponsiveStyle(theme, basis, (val) => ({
flexBasis: val
})),
getResponsiveStyle(theme, flex, (val) => ({
flex: val
})),
getResponsiveStyle(theme, borderStyle, (val) => ({
borderStyle: val
})),
getResponsiveStyle(theme, borderColor, (val) => ({
borderColor: customBorderColor(val, theme)
})),
(borderStyle || borderColor) && {
borderWidth: "1px"
},
getResponsiveStyle(theme, justifyContent, (val) => ({
justifyContent: val
})),
getResponsiveStyle(theme, alignItems, (val) => ({
alignItems: val
})),
getResponsiveStyle(theme, borderRadius, (val) => ({
borderRadius: theme.shape.radius[val]
})),
getResponsiveStyle(theme, boxShadow, (val) => ({
boxShadow: theme.shadows[val]
})),
getResponsiveStyle(theme, gap, (val) => ({
gap: theme.spacing(val)
})),
getResponsiveStyle(theme, position, (val) => ({
position: val
}))
])
};
};
"use strict";
const ScrollIndicators = ({ children }) => {
const [showScrollTopIndicator, setShowTopScrollIndicator] = React.useState(false);
const [showScrollBottomIndicator, setShowBottomScrollIndicator] = React.useState(false);
const scrollTopMarker = React.useRef(null);
const scrollBottomMarker = React.useRef(null);
const styles = useStyles2(getStyles$t);
React.useEffect(() => {
const intersectionObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.target === scrollTopMarker.current) {
setShowTopScrollIndicator(!entry.isIntersecting);
} else if (entry.target === scrollBottomMarker.current) {
setShowBottomScrollIndicator(!entry.isIntersecting);
}
});
});
[scrollTopMarker, scrollBottomMarker].forEach((ref) => {
if (ref.current) {
intersectionObserver.observe(ref.current);
}
});
return () => intersectionObserver.disconnect();
}, []);
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
/* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: css.cx(styles.scrollIndicator, styles.scrollTopIndicator, {
[styles.scrollIndicatorVisible]: showScrollTopIndicator
}),
role: "presentation"
}
),
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.scrollContent, children: [
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: scrollTopMarker, className: css.cx(styles.scrollMarker, styles.scrollTopMarker) }),
children,
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: scrollBottomMarker, className: css.cx(styles.scrollMarker, styles.scrollBottomMarker) })
] }),
/* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: css.cx(styles.scrollIndicator, styles.scrollBottomIndicator, {
[styles.scrollIndicatorVisible]: showScrollBottomIndicator
}),
role: "presentation"
}
)
] });
};
const getStyles$t = (theme) => {
const scrollGradientColor = `rgba(0, 0, 0, ${theme.isDark ? 0.25 : 0.08})`;
return {
scrollContent: css.css({
display: "flex",
flexDirection: "column",
flexGrow: 1,
position: "relative"
}),
scrollIndicator: css.css({
height: `max(5%, ${theme.spacing(3)})`,
left: 0,
opacity: 0,
pointerEvents: "none",
position: "absolute",
right: 0,
[theme.transitions.handleMotion("no-preference", "reduce")]: {
transition: theme.transitions.create("opacity")
},
zIndex: 1
}),
scrollTopIndicator: css.css({
background: `linear-gradient(0deg, transparent, ${scrollGradientColor})`,
top: 0
}),
scrollBottomIndicator: css.css({
background: `linear-gradient(180deg, transparent, ${scrollGradientColor})`,
bottom: 0
}),
scrollIndicatorVisible: css.css({
opacity: 1
}),
scrollMarker: css.css({
height: "1px",
left: 0,
pointerEvents: "none",
position: "absolute",
right: 0
}),
scrollTopMarker: css.css({
top: 0
}),
scrollBottomMarker: css.css({
bottom: 0
})
};
};
"use strict";
const ScrollContainer = React.forwardRef(
({
children,
showScrollIndicators = false,
onScroll,
overflowX = "auto",
overflowY = "auto",
scrollbarWidth = "thin",
...rest
}, ref) => {
const styles = useStyles2(getStyles$s, scrollbarWidth, overflowY, overflowX);
const defaults = {
maxHeight: "100%",
minHeight: 0,
minWidth: 0
};
const boxProps = { ...defaults, ...rest };
return /* @__PURE__ */ jsxRuntime.jsx(Box, { ...boxProps, display: "flex", direction: "column", flex: 1, position: "relative", children: /* @__PURE__ */ jsxRuntime.jsx("div", { tabIndex: 0, onScroll, className: styles.scroller, ref, children: showScrollIndicators ? /* @__PURE__ */ jsxRuntime.jsx(ScrollIndicators, { children }) : children }) });
}
);
ScrollContainer.displayName = "ScrollContainer";
const getStyles$s = (theme, scrollbarWidth, overflowY, overflowX) => ({
scroller: css.css({
display: "flex",
flex: 1,
flexDirection: "column",
overflowX,
overflowY,
scrollbarWidth
})
});
"use strict";
const drawerSizes = {
sm: { width: "25vw", minWidth: 384 },
md: { width: "50vw", minWidth: 568 },
lg: { width: "75vw", minWidth: 744 }
};
function Drawer({
children,
onClose,
closeOnMaskClick = true,
scrollableContent = true,
title,
subtitle,
width,
size = "md",
tabs
}) {
var _a;
const [drawerWidth, onMouseDown, onTouchStart] = useResizebleDrawer();
const styles = useStyles2(getStyles$r);
const wrapperStyles = useStyles2(getWrapperStyles, size);
const dragStyles = useStyles2(getDragStyles);
const overlayRef = React__namespace.useRef(null);
const { dialogProps, titleProps } = dialog.useDialog({}, overlayRef);
const { overlayProps } = overlays.useOverlay(
{
isDismissable: false,
isOpen: true,
onClose
},
overlayRef
);
useBodyClassWhileOpen();
const content = /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.content, children });
const overrideWidth = (_a = drawerWidth != null ? drawerWidth : width) != null ? _a : drawerSizes[size].width;
const minWidth = drawerSizes[size].minWidth;
return /* @__PURE__ */ jsxRuntime.jsx(
RcDrawer__default.default,
{
open: true,
onClose,
placement: "right",
getContainer: ".main-view",
className: styles.drawerContent,
rootClassName: styles.drawer,
classNames: {
wrapper: wrapperStyles
},
styles: {
wrapper: {
width: overrideWidth,
minWidth
}
},
width: "",
motion: {
motionAppear: true,
motionName: styles.drawerMotion
},
maskClassName: styles.mask,
maskClosable: closeOnMaskClick,
maskMotion: {
motionAppear: true,
motionName: styles.maskMotion
},
children: /* @__PURE__ */ jsxRuntime.jsx(focus.FocusScope, { restoreFocus: true, contain: true, autoFocus: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
"div",
{
"aria-label": typeof title === "string" ? e2eSelectors.selectors.components.Drawer.General.title(title) : e2eSelectors.selectors.components.Drawer.General.title("no title"),
className: styles.container,
...overlayProps,
...dialogProps,
ref: overlayRef,
children: [
/* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: css.cx(dragStyles.dragHandleVertical, styles.resizer),
onMouseDown,
onTouchStart
}
),
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: css.cx(styles.header, Boolean(tabs) && styles.headerWithTabs), children: [
/* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.actions, children: /* @__PURE__ */ jsxRuntime.jsx(
IconButton,
{
name: "times",
variant: "secondary",
onClick: onClose,
"data-testid": e2eSelectors.selectors.components.Drawer.General.close,
tooltip: i18n.t(`grafana-ui.drawer.close`, "Close")
}
) }),
typeof title === "string" ? /* @__PURE__ */ jsxRuntime.jsxs(Stack, { direction: "column", children: [
/* @__PURE__ */ jsxRuntime.jsx(Text, { element: "h3", truncate: true, ...titleProps, children: title }),
subtitle && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.subtitle, "data-testid": e2eSelectors.selectors.components.Drawer.General.subtitle, children: subtitle })
] }) : title,
tabs && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.tabsWrapper, children: tabs })
] }),
!scrollableContent ? content : /* @__PURE__ */ jsxRuntime.jsx(ScrollContainer, { showScrollIndicators: true, children: content })
]
}
) })
}
);
}
function useResizebleDrawer() {
const [drawerWidth, setDrawerWidth] = React.useState(void 0);
const onMouseMove = React.useCallback((e) => {
setDrawerWidth(getCustomDrawerWidth(e.clientX));
}, []);
const onTouchMove = React.useCallback((e) => {
const touch = e.touches[0];
setDrawerWidth(getCustomDrawerWidth(touch.clientX));
}, []);
const onMouseUp = React.useCallback(
(e) => {
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseup", onMouseUp);
},
[onMouseMove]
);
const onTouchEnd = React.useCallback(
(e) => {
document.removeEventListener("touchmove", onTouchMove);
document.removeEventListener("touchend", onTouchEnd);
},
[onTouchMove]
);
function onMouseDown(e) {
e.stopPropagation();
e.preventDefault();
document.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseup", onMouseUp);
}
function onTouchStart(e) {
e.stopPropagation();
e.preventDefault();
document.addEventListener("touchmove", onTouchMove);
document.addEventListener("touchend", onTouchEnd);
}
return [drawerWidth, onMouseDown, onTouchStart];
}
function getCustomDrawerWidth(clientX) {
let offsetRight = document.body.offsetWidth - (clientX - document.body.offsetLeft);
let widthPercent = Math.min(offsetRight / document.body.clientWidth * 100, 98).toFixed(2);
return `${widthPercent}vw`;
}
function useBodyClassWhileOpen() {
React.useEffect(() => {
if (!document.body) {
return;
}
document.body.classList.add("body-drawer-open");
return () => {
document.body.classList.remove("body-drawer-open");
};
}, []);
}
const getStyles$r = (theme) => {
var _a, _b;
return {
container: css.css({
display: "flex",
flexDirection: "column",
height: "100%",
flex: "1 1 0",
minHeight: "100%",
position: "relative"
}),
drawer: css.css({
top: 0,
".rc-drawer-content-wrapper": {
boxShadow: theme.shadows.z3
}
}),
drawerContent: css.css({
backgroundColor: `${theme.colors.background.primary} !important`,
display: "flex",
overflow: "unset !important",
flexDirection: "column"
}),
drawerMotion: css.css({
"&-appear": {
[theme.transitions.handleMotion("no-preference")]: {
transform: "translateX(100%)",
transition: "none !important"
},
[theme.transitions.handleMotion("reduce")]: {
opacity: 0
},
"&-active": {
[theme.transitions.handleMotion("no-preference")]: {
transform: "translateX(0)",
transition: `${theme.transitions.create("transform")} !important`
},
[theme.transitions.handleMotion("reduce")]: {
transition: `opacity 0.2s ease-in-out`,
opacity: 1
}
}
}
}),
// we want the mask itself to span the whole page including the top bar
// this ensures trying to click something in the top bar will close the drawer correctly
// but we don't want the backdrop styling to apply over the top bar as it looks weird
// instead have a child pseudo element to apply the backdrop styling below the top bar
mask: css.css({
// The !important here is to override the default .rc-drawer-mask styles
backgroundColor: "transparent !important",
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
position: "fixed !important",
"&:before": {
backgroundColor: `${theme.components.overlay.background} !important`,
bottom: 0,
content: '""',
left: 0,
position: "fixed",
right: 0,
top: 0
}
}),
maskMotion: css.css({
"&-appear": {
opacity: 0,
"&-active": {
opacity: 1,
[theme.transitions.handleMotion("no-preference", "reduce")]: {
transition: theme.transitions.create("opacity")
}
}
}
}),
header: css.css({
label: "drawer-header",
flexGrow: 0,
padding: theme.spacing(2, 2, 3),
borderBottom: `1px solid ${theme.colors.border.weak}`
}),
headerWithTabs: css.css({
borderBottom: "none"
}),
actions: css.css({
position: "absolute",
right: theme.spacing(1),
top: theme.spacing(1)
}),
subtitle: css.css({
label: "drawer-subtitle",
color: theme.colors.text.secondary
}),
content: css.css({
padding: theme.spacing((_b = (_a = theme.components.drawer) == null ? void 0 : _a.padding) != null ? _b : 2),
height: "100%",
flexGrow: 1,
minHeight: 0
}),
tabsWrapper: css.css({
label: "drawer-tabs",
paddingLeft: theme.spacing(2),
margin: theme.spacing(1, -1, -3, -3)
}),
resizer: css.css({
top: 0,
left: theme.spacing(-1),
bottom: 0,
position: "absolute",
zIndex: theme.zIndex.modal
})
};
};
function getWrapperStyles(theme, size) {
return css.css({
label: `drawer-content-wrapper-${size}`,
overflow: "unset !important",
[theme.breakpoints.down("md")]: {
width: `calc(100% - ${theme.spacing(2)}) !important`,
minWidth: "0 !important"
}
});
}
"use strict";
const useAsyncDependency = (importStatement) => {
const state = reactUse.useAsync(async () => {
return await importStatement;
});
return {
...state,
dependency: state.value
};
};
"use strict";
const ErrorWithStack = ({ error, errorInfo, title }) => {
const style = useStyles2(getStyles$q);
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: style, children: [
/* @__PURE__ */ jsxRuntime.jsx("h2", { children: title }),
/* @__PURE__ */ jsxRuntime.jsxs("details", { style: { whiteSpace: "pre-wrap" }, children: [
error && error.toString(),
/* @__PURE__ */ jsxRuntime.jsx("br", {}),
errorInfo && errorInfo.componentStack
] })
] });
};
ErrorWithStack.displayName = "ErrorWithStack";
const getStyles$q = () => {
return css.css({
width: "500px",
margin: "64px auto"
});
};
"use strict";
const LoadingPlaceholder = ({ text, className, ...rest }) => {
const styles = useStyles2(getStyles$p);
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: css.cx(styles.container, className), ...rest, children: [
text,
" ",
/* @__PURE__ */ jsxRuntime.jsx(Spinner, { inline: true })
] });
};
const getStyles$p = (theme) => {
return {
container: css.css({
marginBottom: theme.spacing(4)
})
};
};
"use strict";
const ReactMonacoEditorLazy = (props) => {
var _a, _b;
const styles = useStyles2(getStyles$o);
const { loading, error, dependency } = useAsyncDependency(
Promise.resolve().then(function () { return require(
/* webpackChunkName: "react-monaco-editor" */
'./ReactMonacoEditor-DUGGnFc8.js'
); })
);
if (loading) {
return /* @__PURE__ */ jsxRuntime.jsx(
LoadingPlaceholder,
{
text: i18n.t("grafana-ui.monaco.loading-placeholder", "Loading editor"),
className: styles.container
}
);
}
if (error) {
return /* @__PURE__ */ jsxRuntime.jsx(
ErrorWithStack,
{
title: i18n.t("grafana-ui.monaco.error-label", "React Monaco Editor failed to load"),
error,
errorInfo: { componentStack: (_a = error == null ? void 0 : error.stack) != null ? _a : "" }
}
);
}
const ReactMonacoEditor = dependency.ReactMonacoEditor;
return /* @__PURE__ */ jsxRuntime.jsx(
ReactMonacoEditor,
{
...props,
loading: (_b = props.loading) != null ? _b : null,
wrapperProps: {
"data-testid": e2eSelectors.selectors.components.ReactMonacoEditor.editorLazy
}
}
);
};
const getStyles$o = (theme) => {
return {
container: css.css({
marginBottom: "unset",
marginLeft: theme.spacing(1)
})
};
};
"use strict";
var CodeEditorSuggestionItemKind = /* @__PURE__ */ ((CodeEditorSuggestionItemKind2) => {
CodeEditorSuggestionItemKind2["Method"] = "method";
CodeEditorSuggestionItemKind2["Field"] = "field";
CodeEditorSuggestionItemKind2["Property"] = "property";
CodeEditorSuggestionItemKind2["Constant"] = "constant";
CodeEditorSuggestionItemKind2["Text"] = "text";
return CodeEditorSuggestionItemKind2;
})(CodeEditorSuggestionItemKind || {});
"use strict";
function findInsertIndex(line) {
for (let i = line.length - 1; i > 0; i--) {
const ch = line.charAt(i);
if (ch === "$") {
return {
index: i,
prefix: line.substring(i)
};
}
if (ch === " " || ch === " " || ch === '"' || ch === "'") {
return {
index: i + 1,
prefix: line.substring(i + 1)
};
}
}
return {
index: 0,
prefix: line
};
}
function getCompletionItems(monaco, prefix, suggestions, range) {
var _a;
const items = [];
for (const suggestion of suggestions) {
if (prefix && !suggestion.label.startsWith(prefix)) {
continue;
}
items.push({
...suggestion,
kind: mapKinds(monaco, suggestion.kind),
range,
insertText: (_a = suggestion.insertText) != null ? _a : suggestion.label
});
}
return items;
}
function mapKinds(monaco, sug) {
switch (sug) {
case CodeEditorSuggestionItemKind.Method:
return monaco.languages.CompletionItemKind.Method;
case CodeEditorSuggestionItemKind.Field:
return monaco.languages.CompletionItemKind.Field;
case CodeEditorSuggestionItemKind.Property:
return monaco.languages.CompletionItemKind.Property;
case CodeEditorSuggestionItemKind.Constant:
return monaco.languages.CompletionItemKind.Constant;
case CodeEditorSuggestionItemKind.Text:
return monaco.languages.CompletionItemKind.Text;
}
return monaco.languages.CompletionItemKind.Text;
}
function registerSuggestions(monaco, language, getSuggestions, modelId) {
if (!language || !getSuggestions) {
return void 0;
}
return monaco.languages.registerCompletionItemProvider(language, {
triggerCharacters: ["$"],
provideCompletionItems: (model, position, context) => {
if (model.id !== modelId) {
return void 0;
}
const range = {
startLineNumber: position.lineNumber,
endLineNumber: position.lineNumber,
startColumn: position.column,
endColumn: position.column
};
if (context.triggerCharacter === "$") {
range.startColumn = position.column - 1;
return {
suggestions: getCompletionItems(monaco, "$", getSuggestions(), range)
};
}
const currentLine = model.getValueInRange({
startLineNumber: position.lineNumber,
startColumn: 1,
endLineNumber: position.lineNumber,
endColumn: position.column
});
const { index, prefix } = findInsertIndex(currentLine);
range.startColumn = index + 1;
const suggestions = getCompletionItems(monaco, prefix, getSuggestions(), range);
if (suggestions.length) {
return { suggestions };
}
return void 0;
}
});
}
"use strict";
class UnthemedCodeEditor extends React.PureComponent {
constructor(props) {
super(props);
this.loadCustomLanguage = () => {
const { language } = this.props;
const customLanguage = data.monacoLanguageRegistry.getIfExists(language);
if (customLanguage) {
return customLanguage.init();
}
return Promise.resolve();
};
// This is replaced with a real function when the actual editor mounts
this.getEditorValue = () => "";
this.onBlur = () => {
const { onBlur } = this.props;
if (onBlur) {
onBlur(this.getEditorValue());
}
};
this.onFocus = () => {
const { onFocus } = this.props;
if (onFocus) {
onFocus(this.getEditorValue());
}
};
this.onSave = () => {
const { onSave } = this.props;
if (onSave) {
onSave(this.getEditorValue());
}
};
this.handleBeforeMount = (monaco) => {
this.monaco = monaco;
const { onBeforeEditorMount } = this.props;
onBeforeEditorMount == null ? void 0 : onBeforeEditorMount(monaco);
};
this.handleOnMount = (editor, monaco) => {
var _a, _b;
const { getSuggestions, language, onChange, onEditorDidMount } = this.props;
this.modelId = (_a = editor.getModel()) == null ? void 0 : _a.id;
this.getEditorValue = () => editor.getValue();
if (getSuggestions && this.modelId) {
this.completionCancel = registerSuggestions(monaco, language, getSuggestions, this.modelId);
}
editor.onKeyDown((e) => {
if (e.keyCode === monaco.KeyCode.KeyS && (e.ctrlKey || e.metaKey)) {
e.preventDefault();
this.onSave();
}
});
if (onChange) {
(_b = editor.getModel()) == null ? void 0 : _b.onDidChangeContent(() => onChange(editor.getValue()));
}
if (onEditorDidMount) {
onEditorDidMount(editor, monaco);
}
};
}
componentWillUnmount() {
var _a, _b;
if (this.completionCancel) {
this.completionCancel.dispose();
}
(_b = (_a = this.props).onEditorWillUnmount) == null ? void 0 : _b.call(_a);
}
componentDidUpdate(oldProps) {
const { getSuggestions, language } = this.props;
const newLanguage = oldProps.language !== language;
const newGetSuggestions = oldProps.getSuggestions !== getSuggestions;
if (newGetSuggestions || newLanguage) {
if (this.completionCancel) {
this.completionCancel.dispose();
}
if (!this.monaco) {
console.warn("Monaco instance not loaded yet");
return;
}
if (getSuggestions && this.modelId) {
this.completionCancel = registerSuggestions(this.monaco, language, getSuggestions, this.modelId);
}
}
if (newLanguage) {
this.loadCustomLanguage();
}
}
render() {
var _a;
const { theme, language, width, height, showMiniMap, showLineNumbers, readOnly, wordWrap, monacoOptions } = this.props;
const { alwaysConsumeMouseWheel, ...restMonacoOptions } = monacoOptions != null ? monacoOptions : {};
const value = (_a = this.props.value) != null ? _a : "";
const longText = value.length > 100;
const containerStyles = css.cx(getStyles$n(theme).container, this.props.containerStyles);
const options = {
wordWrap: wordWrap ? "on" : "off",
tabSize: 2,
codeLens: false,
contextmenu: false,
minimap: {
enabled: longText && showMiniMap,
renderCharacters: false
},
readOnly,
lineNumbersMinChars: 4,
lineDecorationsWidth: 1 * theme.spacing.gridSize,
overviewRulerBorder: false,
automaticLayout: true,
padding: {
top: 0.5 * theme.spacing.gridSize,
bottom: 0.5 * theme.spacing.gridSize
},
fixedOverflowWidgets: true,
// Ensures suggestions menu is drawn on top
scrollbar: {
alwaysConsumeMouseWheel: alwaysConsumeMouseWheel != null ? alwaysConsumeMouseWheel : false
}
};
if (!showLineNumbers) {
options.glyphMargin = false;
options.folding = false;
options.lineNumbers = "off";
options.lineNumbersMinChars = 0;
}
return /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: containerStyles,
onFocus: this.onFocus,
onBlur: this.onBlur,
"data-testid": e2eSelectors.selectors.components.CodeEditor.container,
children: /* @__PURE__ */ jsxRuntime.jsx(
ReactMonacoEditorLazy,
{
width,
height,
language,
value,
options: {
...options,
...restMonacoOptions != null ? restMonacoOptions : {}
},
beforeMount: this.handleBeforeMount,
onMount: this.handleOnMount,
keepCurrentModel: true
}
)
}
);
}
}
const CodeEditor = withTheme2(UnthemedCodeEditor);
const getStyles$n = (theme) => {
return {
container: css.css({
borderRadius: theme.shape.radius.default,
border: `1px solid ${theme.components.input.borderColor}`,
overflow: "hidden"
})
};
};
"use strict";
const Counter = ({ value, variant = "secondary" }) => {
const styles = useStyles2(getStyles$m, variant);
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.counter, children: data.locale(value, 0).text });
};
const getStyles$m = (theme, variant) => ({
counter: css.css({
label: "counter",
marginLeft: theme.spacing(1),
borderRadius: theme.spacing(3),
backgroundColor: variant === "primary" ? theme.colors.primary.main : theme.colors.secondary.main,
padding: theme.spacing(0.25, 1),
color: theme.colors.text.secondary,
fontWeight: theme.typography.fontWeightMedium,
fontSize: theme.typography.size.sm
})
});
"use strict";
const Tab = React__namespace.forwardRef(
({
label,
active,
icon,
onChangeTab,
counter,
suffix: Suffix,
className,
href,
truncate,
tooltip,
disabled,
...otherProps
}, ref) => {
const tabsStyles = useStyles2(getStyles$l);
const clearStyles = useStyles2(clearButtonStyles);
const content = () => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
icon && /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon, "data-testid": `tab-icon-${icon}` }),
label,
typeof counter === "number" && /* @__PURE__ */ jsxRuntime.jsx(Counter, { value: counter }),
Suffix && /* @__PURE__ */ jsxRuntime.jsx(Suffix, { className: tabsStyles.suffix })
] });
const linkClass = css.cx(
clearStyles,
tabsStyles.link,
active ? tabsStyles.activeStyle : tabsStyles.notActive,
truncate && tabsStyles.linkTruncate,
disabled && tabsStyles.disabled
);
const commonProps = {
className: linkClass,
"data-testid": e2eSelectors.selectors.components.Tab.title(label),
...otherProps,
onClick: disabled ? void 0 : onChangeTab,
role: "tab",
"aria-selected": active,
"aria-disabled": disabled,
tabIndex: disabled ? -1 : void 0,
title: !!tooltip ? void 0 : otherProps.title
// If tooltip is provided, don't set the title on the link or button, it looks weird
};
let tab = null;
if (href) {
tab = /* @__PURE__ */ jsxRuntime.jsx("div", { className: css.cx(tabsStyles.item, truncate && tabsStyles.itemTruncate, className), children: /* @__PURE__ */ jsxRuntime.jsx(
"a",
{
...commonProps,
href: disabled ? void 0 : href,
ref,
children: content()
}
) });
} else {
tab = /* @__PURE__ */ jsxRuntime.jsx("div", { className: css.cx(tabsStyles.item, truncate && tabsStyles.itemTruncate, className), children: /* @__PURE__ */ jsxRuntime.jsx(
"button",
{
...commonProps,
type: "button",
ref,
children: content()
}
) });
}
if (tooltip) {
return /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: tooltip, children: tab });
}
return tab;
}
);
Tab.displayName = "Tab";
const getStyles$l = (theme) => {
return {
item: css.css({
listStyle: "none",
position: "relative",
display: "flex",
whiteSpace: "nowrap",
padding: theme.spacing(0, 0.5)
}),
itemTruncate: css.css({
maxWidth: theme.spacing(40)
}),
link: css.css({
color: theme.colors.text.secondary,
padding: theme.spacing(1, 1.5, 1),
borderRadius: theme.shape.radius.default,
display: "block",
height: "100%",
svg: {
marginRight: theme.spacing(1)
},
"&:focus-visible": getFocusStyles(theme),
"&::before": {
display: "block",
content: '" "',
position: "absolute",
left: 0,
right: 0,
height: "2px",
borderRadius: theme.shape.radius.default,
bottom: 0
}
}),
linkTruncate: css.css({
textOverflow: "ellipsis",
whiteSpace: "nowrap",
wordBreak: "break-word",
overflow: "hidden"
}),
notActive: css.css({
"a:hover, &:hover, &:focus": {
color: theme.colors.text.primary,
"&::before": {
backgroundColor: theme.colors.action.hover
}
}
}),
activeStyle: css.css({
label: "activeTabStyle",
color: theme.colors.text.primary,
overflow: "hidden",
"&::before": {
backgroundImage: theme.colors.gradients.brandHorizontal
}
}),
suffix: css.css({
marginLeft: theme.spacing(1)
}),
disabled: css.css({
color: theme.colors.text.disabled,
cursor: "not-allowed",
"&:hover, &:focus": {
color: theme.colors.text.disabled,
"&::before": {
backgroundColor: "transparent"
}
}
})
};
};
"use strict";
const TabsBar = React.forwardRef(({ children, className, hideBorder = false }, ref) => {
const styles = useStyles2(getStyles$k);
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: css.cx(styles.tabsWrapper, hideBorder && styles.noBorder, className), ref, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.tabs, role: "tablist", children }) });
});
const getStyles$k = (theme) => ({
tabsWrapper: css.css({
borderBottom: `1px solid ${theme.colors.border.weak}`,
overflowX: "auto"
}),
noBorder: css.css({
borderBottom: 0
}),
tabs: css.css({
position: "relative",
display: "flex",
alignItems: "center"
})
});
TabsBar.displayName = "TabsBar";
"use strict";
var TableCellInspectorMode = /* @__PURE__ */ ((TableCellInspectorMode2) => {
TableCellInspectorMode2["code"] = "code";
TableCellInspectorMode2["text"] = "text";
return TableCellInspectorMode2;
})(TableCellInspectorMode || {});
function TableCellInspector({ value, onDismiss, mode }) {
const [currentMode, setMode] = React.useState(mode);
const text = value.trim();
const styles = useStyles2(getStyles$j);
const tabs = [
{
label: "Plain text",
value: "text"
},
{
label: "Code editor",
value: "code"
}
];
const changeTabs = () => {
setMode(currentMode === "text" /* text */ ? "code" /* code */ : "text" /* text */);
};
const tabBar = /* @__PURE__ */ jsxRuntime.jsx(TabsBar, { children: tabs.map((t2, index) => /* @__PURE__ */ jsxRuntime.jsx(Tab, { label: t2.label, active: t2.value === currentMode, onChangeTab: changeTabs }, `${t2.value}-${index}`)) });
return /* @__PURE__ */ jsxRuntime.jsx(Drawer, { onClose: onDismiss, title: i18n.t("grafana-ui.table.inspect-drawer-title", "Inspect value"), tabs: tabBar, children: /* @__PURE__ */ jsxRuntime.jsxs(Stack, { direction: "column", gap: 2, children: [
/* @__PURE__ */ jsxRuntime.jsx(ClipboardButton, { icon: "copy", getText: () => text, style: { marginLeft: "auto", width: "200px" }, children: /* @__PURE__ */ jsxRuntime.jsx(i18n.Trans, { i18nKey: "grafana-ui.table.copy", children: "Copy to Clipboard" }) }),
currentMode === "code" ? /* @__PURE__ */ jsxRuntime.jsx(
CodeEditor,
{
width: "100%",
height: 500,
language: "json",
showLineNumbers: true,
showMiniMap: (text ? text.length : 0) > 100,
value: text,
readOnly: true,
wordWrap: true
}
) : /* @__PURE__ */ jsxRuntime.jsx("pre", { className: styles.textContainer, children: text })
] }) });
}
const getStyles$j = (theme) => ({
textContainer: css.css({
color: theme.colors.text.secondary,
minHeight: 42
})
});
"use strict";
const FILTER_FOR_OPERATOR$1 = "=";
const FILTER_OUT_OPERATOR$1 = "!=";
"use strict";
const COLUMN = {
DEFAULT_WIDTH: 150,
EXPANDER_WIDTH: 50,
// This will need to eventually change to 36
MIN_WIDTH: 50
};
const TABLE = {
CELL_PADDING: 6,
LINE_HEIGHT: 22,
HEADER_ROW_HEIGHT: 28,
MAX_CELL_HEIGHT: 48,
PAGINATION_LIMIT: 750,
SCROLL_BAR_WIDTH: 8,
SCROLL_BAR_MARGIN: 2,
HEADER_HEIGHT: 28,
NESTED_NO_DATA_HEIGHT: 60,
BORDER_RIGHT: 1
};
"use strict";
const getGridStyles = (theme, enablePagination, transparent) => {
const bgColor = transparent ? theme.colors.background.canvas : theme.colors.background.primary;
const borderColor = data.colorManipulator.onBackground(theme.colors.border.weak, bgColor).toHexString();
return {
grid: css.css({
"--rdg-background-color": bgColor,
"--rdg-header-background-color": bgColor,
"--rdg-border-color": borderColor,
"--rdg-color": theme.colors.text.primary,
"--rdg-summary-border-color": borderColor,
"--rdg-summary-border-width": "1px",
"--rdg-selection-color": theme.colors.info.transparent,
// note: this cannot have any transparency since default cells that
// overlay/overflow on hover inherit this background and need to occlude cells below
"--rdg-row-background-color": bgColor,
"--rdg-row-hover-background-color": transparent ? theme.colors.background.primary : theme.colors.background.secondary,
// TODO: magic 32px number is unfortunate. it would be better to have the content
// flow using flexbox rather than hard-coding this size via a calc
blockSize: enablePagination ? "calc(100% - 32px)" : "100%",
scrollbarWidth: "thin",
scrollbarColor: theme.isDark ? "#fff5 #fff1" : "#0005 #0001",
border: "none",
".rdg-cell": {
padding: TABLE.CELL_PADDING,
"&:last-child": {
borderInlineEnd: "none"
}
},
// add a box shadow on hover and selection for all body cells
"& > :not(.rdg-summary-row, .rdg-header-row) > .rdg-cell": {
[getActiveCellSelector()]: { boxShadow: theme.shadows.z2 },
// selected cells should appear below hovered cells.
...!IS_SAFARI_26 && { "&:hover": { zIndex: theme.zIndex.tooltip - 7 } },
"&[aria-selected=true]": { zIndex: theme.zIndex.tooltip - 6 }
},
".rdg-cell.rdg-cell-frozen": {
backgroundColor: "var(--rdg-row-background-color)",
zIndex: theme.zIndex.tooltip - 4,
...!IS_SAFARI_26 && { "&:hover": { zIndex: theme.zIndex.tooltip - 2 } },
"&[aria-selected=true]": { zIndex: theme.zIndex.tooltip - 3 }
},
".rdg-header-row, .rdg-summary-row": {
".rdg-cell": {
zIndex: theme.zIndex.tooltip - 5,
"&.rdg-cell-frozen": {
zIndex: theme.zIndex.tooltip - 1
}
}
},
".rdg-summary-row >": {
".rdg-cell": {
// 0.75 padding causes "jumping" on hover.
paddingBlock: theme.spacing(0.625)
},
[getActiveCellSelector()]: {
whiteSpace: "pre-line",
height: "100%",
minHeight: "fit-content",
overflowY: "visible",
boxShadow: theme.shadows.z2
}
}
}),
gridNested: css.css({
height: "100%",
width: `calc(100% - ${COLUMN.EXPANDER_WIDTH - TABLE.CELL_PADDING * 2 - 1}px)`,
overflowX: "scroll",
overflowY: "hidden",
marginLeft: COLUMN.EXPANDER_WIDTH - TABLE.CELL_PADDING - 1,
marginBlock: TABLE.CELL_PADDING
}),
cellNested: css.css({ "&[aria-selected=true]": { outline: "none" } }),
noDataNested: css.css({
height: TABLE.NESTED_NO_DATA_HEIGHT,
display: "flex",
alignItems: "center",
justifyContent: "center",
color: theme.colors.text.secondary,
fontSize: theme.typography.h4.fontSize
}),
headerRow: css.css({
paddingBlockStart: 0,
fontWeight: "normal",
"& .rdg-cell": { height: "100%", alignItems: "flex-end" }
}),
displayNone: css.css({ display: "none" }),
paginationContainer: css.css({
alignItems: "center",
display: "flex",
justifyContent: "center",
marginTop: "8px",
width: "100%"
}),
paginationSummary: css.css({
color: theme.colors.text.secondary,
fontSize: theme.typography.bodySmall.fontSize,
display: "flex",
justifyContent: "flex-end",
padding: theme.spacing(0, 1, 0, 2)
}),
menuItem: css.css({ maxWidth: "200px" }),
safariWrapper: css.css({ contain: "strict", height: "100%" })
};
};
const getHeaderCellStyles = (theme, justifyContent) => css.css({
display: "flex",
gap: theme.spacing(0.5),
zIndex: theme.zIndex.tooltip - 1,
paddingInline: TABLE.CELL_PADDING,
paddingBlockEnd: TABLE.CELL_PADDING,
justifyContent,
"&:last-child": { borderInlineEnd: "none" }
});
const getDefaultCellStyles = (theme, { textAlign, shouldOverflow, maxHeight }) => css.css({
display: "flex",
alignItems: "center",
textAlign,
justifyContent: Boolean(maxHeight) ? "flex-start" : getJustifyContent(textAlign),
...maxHeight && { overflowY: "hidden" },
...shouldOverflow && { minHeight: "100%" },
[getActiveCellSelector()]: {
...shouldOverflow && {
zIndex: theme.zIndex.tooltip - 2,
height: "fit-content",
minWidth: "fit-content"
}
},
[getHoverOnlyCellSelector()]: {
".table-cell-actions": { display: "flex" }
}
});
const getMaxHeightCellStyles = (_theme, { textAlign, maxHeight }) => css.css({
display: "flex",
alignItems: "center",
textAlign,
justifyContent: getJustifyContent(textAlign),
maxHeight,
width: "100%",
overflowY: "hidden",
[getActiveCellSelector(true)]: {
maxHeight: "none",
minHeight: "100%"
}
});
const getCellActionStyles = (theme, textAlign) => css.css({
display: "none",
position: "absolute",
top: 0,
margin: "auto",
height: "100%",
color: theme.colors.text.primary,
background: theme.isDark ? "rgba(0, 0, 0, 0.7)" : "rgba(255, 255, 255, 0.7)",
padding: theme.spacing.x0_5,
paddingInlineStart: theme.spacing.x1,
[textAlign === "right" ? "left" : "right"]: 0
});
const getLinkStyles = (theme, canBeColorized) => css.css({
a: {
cursor: "pointer",
...canBeColorized ? {
color: "inherit",
textDecoration: "underline"
} : {
color: theme.colors.text.link,
textDecoration: "none",
"&:hover": { textDecoration: "underline" }
}
}
});
const caretTriangle = (direction, bgColor) => `linear-gradient(to top ${direction}, transparent 62.5%, ${bgColor} 50%)`;
const getTooltipStyles = (theme, textAlign) => ({
tooltipContent: css.css({
height: "100%",
width: "100%",
display: "flex",
alignItems: "center"
}),
tooltipWrapper: css.css({
background: theme.colors.background.primary,
border: `1px solid ${theme.colors.border.weak}`,
borderRadius: theme.shape.radius.default,
boxShadow: theme.shadows.z3,
overflow: "hidden",
padding: theme.spacing(1),
width: "inherit"
}),
tooltipCaret: css.css({
cursor: "pointer",
position: "absolute",
top: theme.spacing(0.25),
[textAlign === "right" ? "right" : "left"]: theme.spacing(0.25),
width: theme.spacing(1.75),
height: theme.spacing(1.75),
background: caretTriangle(textAlign === "right" ? "right" : "left", theme.colors.border.strong)
})
});
const ACTIVE_CELL_SELECTORS = {
hover: {
nested: ".rdg-cell:hover &",
normal: "&:hover"
},
selected: {
nested: "[aria-selected=true] &",
normal: "&[aria-selected=true]"
}
};
const getActiveCellSelector = memoize__default.default((isNested) => {
const selectors = [];
selectors.push(ACTIVE_CELL_SELECTORS.selected[isNested ? "nested" : "normal"]);
if (!IS_SAFARI_26) {
selectors.push(ACTIVE_CELL_SELECTORS.hover[isNested ? "nested" : "normal"]);
}
return selectors.join(", ");
});
const getHoverOnlyCellSelector = memoize__default.default((isNested) => {
if (IS_SAFARI_26) {
return "";
}
return ACTIVE_CELL_SELECTORS.hover[isNested ? "nested" : "normal"];
});
"use strict";
function PillCell({ rowIdx, field, theme, getTextColorForBackground }) {
const value = field.values[rowIdx];
const pills = React.useMemo(() => {
const pillValues = inferPills(value);
return pillValues.length > 0 ? pillValues.map((pill, index) => {
const renderedValue = data.formattedValueToString(field.display(pill));
const bgColor = getPillColor(renderedValue, field, theme);
const textColor = getTextColorForBackground(bgColor);
return {
value: renderedValue,
key: `${pill}-${index}`,
bgColor,
color: textColor
};
}) : [];
}, [value, field, theme, getTextColorForBackground]);
if (pills.length === 0) {
return null;
}
return pills.map((pill) => /* @__PURE__ */ jsxRuntime.jsx(
"span",
{
style: {
backgroundColor: pill.bgColor,
color: pill.color,
border: pill.bgColor === TRANSPARENT ? `1px solid ${theme.colors.border.strong}` : void 0
},
children: pill.value
},
pill.key
));
}
const SPLIT_RE = /\s*,\s*/;
const TRANSPARENT = "rgba(0,0,0,0)";
function inferPills(rawValue) {
if (rawValue === "" || rawValue == null) {
return [];
}
if (Array.isArray(rawValue)) {
return rawValue.filter((v) => v != null).map((v) => String(v).trim());
}
const value = String(rawValue);
if (value[0] === "[") {
try {
return JSON.parse(value);
} catch (e) {
return value.trim().split(SPLIT_RE);
}
}
return value.trim().split(SPLIT_RE);
}
function getPillColor(value, field, theme) {
var _a, _b, _c, _d, _e, _f;
const cfg = field.config;
if ((_b = (_a = cfg.mappings) == null ? void 0 : _a.length) != null ? _b : 0 > 0) {
return (_c = field.display(value).color) != null ? _c : data.FALLBACK_COLOR;
}
if (((_d = cfg.color) == null ? void 0 : _d.mode) === schema.FieldColorModeId.Fixed) {
return theme.visualization.getColorByName((_f = (_e = cfg.color) == null ? void 0 : _e.fixedColor) != null ? _f : data.FALLBACK_COLOR);
}
let colors = data.classicColors;
const configuredColor = cfg.color;
if (configuredColor) {
const mode = data.fieldColorModeRegistry.get(configuredColor.mode);
if (typeof (mode == null ? void 0 : mode.getColors) === "function") {
colors = mode.getColors(theme);
}
}
return data.getColorByStringHash(colors, String(value));
}
const getStyles$i = (theme, { textWrap, shouldOverflow, maxHeight }) => css.css({
display: "inline-flex",
gap: theme.spacing(0.5),
flexWrap: textWrap ? "wrap" : "nowrap",
...shouldOverflow && {
[getActiveCellSelector(Boolean(maxHeight))]: {
flexWrap: "wrap"
}
},
"> span": {
display: "flex",
padding: theme.spacing(0.25, 0.75),
borderRadius: theme.shape.radius.default,
fontSize: theme.typography.bodySmall.fontSize,
lineHeight: theme.typography.bodySmall.lineHeight,
whiteSpace: "nowrap"
}
});
"use strict";
function getDefaultRowHeight(theme, fields, cellHeight) {
if (fields == null ? void 0 : fields.some((field) => {
var _a, _b, _c;
return (_c = (_b = (_a = field.config) == null ? void 0 : _a.custom) == null ? void 0 : _b.cellOptions) == null ? void 0 : _c.dynamicHeight;
})) {
return "auto";
}
switch (cellHeight) {
case schema.TableCellHeight.Sm:
return 36;
case schema.TableCellHeight.Md:
return 42;
case schema.TableCellHeight.Lg:
return TABLE.MAX_CELL_HEIGHT;
}
return TABLE.CELL_PADDING * 2 + theme.typography.fontSize * theme.typography.body.lineHeight;
}
function isCellInspectEnabled(field) {
var _a, _b, _c;
return (_c = (_b = (_a = field.config) == null ? void 0 : _a.custom) == null ? void 0 : _b.inspect) != null ? _c : false;
}
function shouldTextWrap(field) {
var _a;
return Boolean((_a = field.config.custom) == null ? void 0 : _a.wrapText);
}
function clampByMaxHeight(measurer, maxHeight = Infinity) {
return (value, width, field, rowIdx, lineHeight) => {
const rawHeight = measurer(value, width, field, rowIdx, lineHeight);
return Math.min(rawHeight, maxHeight);
};
}
function createTypographyContext(fontSize, fontFamily, letterSpacing = 0.15) {
const font = `${fontSize}px ${fontFamily}`;
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
ctx.letterSpacing = `${letterSpacing}px`;
ctx.font = font;
const txt = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s. 1234567890 ALL CAPS TO HELP WITH MEASUREMENT.";
const txtWidth = ctx.measureText(txt).width;
const avgCharWidth = txtWidth / txt.length + letterSpacing;
const { count } = uwrap.varPreLine(ctx);
return {
ctx,
fontFamily,
letterSpacing,
avgCharWidth,
estimateHeight: getTextHeightEstimator(avgCharWidth),
measureHeight: getTextHeightMeasurerFromUwrapCount(count)
};
}
function getTextHeightMeasurerFromUwrapCount(count) {
return (value, width, _field, _rowIdx, lineHeight) => {
if (value == null) {
return lineHeight;
}
const lines = count(String(value), width);
return lines * lineHeight;
};
}
function getTextHeightEstimator(avgCharWidth) {
return (value, width, _field, _rowIdx, lineHeight) => {
if (!value) {
return -1;
}
const strValue = String(value);
if (!spaceRegex.test(strValue)) {
return -1;
}
const charsPerLine = width / avgCharWidth;
const lines = Math.ceil(strValue.length / charsPerLine);
return lines * lineHeight;
};
}
function getDataLinksHeightMeasurer() {
const linksCountCache = {};
return (_value, _width, field, _rowIdx, lineHeight) => {
var _a, _b;
const cacheKey = getDisplayName(field);
if (linksCountCache[cacheKey] === void 0) {
let count = 0;
for (const l of (_b = (_a = field.config) == null ? void 0 : _a.links) != null ? _b : []) {
if (l.onClick || l.url) {
count += 1;
}
}
linksCountCache[cacheKey] = count;
}
return linksCountCache[cacheKey] * lineHeight;
};
}
const PILLS_FONT_SIZE = 12;
const PILLS_SPACING = 12;
const PILLS_GAP = 4;
function getPillCellHeightMeasurer(measureWidth) {
const widthCache = {};
return (value, width, _field, _rowIdx, lineHeight) => {
if (value == null) {
return 0;
}
const pillValues = inferPills(String(value));
if (pillValues.length === 0) {
return 0;
}
let lines = 0;
let currentLineUse = width;
for (const pillValue of pillValues) {
const strPill = String(pillValue);
let rawWidth = widthCache[strPill];
if (rawWidth === void 0) {
rawWidth = measureWidth(strPill);
widthCache[strPill] = rawWidth;
}
const pillWidth = rawWidth + PILLS_SPACING;
if (currentLineUse + pillWidth + PILLS_GAP > width) {
lines++;
currentLineUse = pillWidth;
} else {
currentLineUse += pillWidth + PILLS_GAP;
}
}
return lines * lineHeight + (lines - 1) * PILLS_GAP;
};
}
function buildHeaderHeightMeasurers(fields, typographyCtx) {
const wrappedColIdxs = fields.reduce((acc, field, idx) => {
var _a, _b;
if ((_b = (_a = field.config) == null ? void 0 : _a.custom) == null ? void 0 : _b.wrapHeaderText) {
acc.push(idx);
}
return acc;
}, []);
if (wrappedColIdxs.length === 0) {
return void 0;
}
return [{ measure: typographyCtx.measureHeight, fieldIdxs: wrappedColIdxs }];
}
const spaceRegex = /[\s-]/;
function buildCellHeightMeasurers(fields, typographyCtx, maxHeight) {
const result = {};
let wrappedFields = 0;
const measurerFactory = {
// for string fields, we estimate the length of a line using `avgCharWidth` to limit expensive calls `count`.
[schema.TableCellDisplayMode.Auto]: () => [typographyCtx.measureHeight, typographyCtx.estimateHeight],
[schema.TableCellDisplayMode.DataLinks]: () => [getDataLinksHeightMeasurer(), void 0],
// pills use a different font size, so they require their own typography context.
[schema.TableCellDisplayMode.Pill]: () => {
const pillTypographyCtx = createTypographyContext(
PILLS_FONT_SIZE,
typographyCtx.fontFamily,
typographyCtx.letterSpacing
);
return [
getPillCellHeightMeasurer((value) => pillTypographyCtx.ctx.measureText(value).width),
getPillCellHeightMeasurer((value) => value.length * pillTypographyCtx.avgCharWidth)
];
}
};
const setupMeasurerForIdx = (measurerFactoryKey, fieldIdx) => {
if (!result[measurerFactoryKey]) {
const [measure, estimate] = measurerFactory[measurerFactoryKey]();
result[measurerFactoryKey] = {
measure: clampByMaxHeight(measure, maxHeight),
estimate: estimate != null ? clampByMaxHeight(estimate, maxHeight) : void 0,
fieldIdxs: []
};
}
result[measurerFactoryKey].fieldIdxs.push(fieldIdx);
};
for (let fieldIdx = 0; fieldIdx < fields.length; fieldIdx++) {
const field = fields[fieldIdx];
if (shouldTextWrap(field)) {
wrappedFields++;
const cellType = getCellOptions(field).type;
if (cellType === schema.TableCellDisplayMode.DataLinks) {
setupMeasurerForIdx(schema.TableCellDisplayMode.DataLinks, fieldIdx);
} else if (cellType === schema.TableCellDisplayMode.Pill) {
setupMeasurerForIdx(schema.TableCellDisplayMode.Pill, fieldIdx);
} else if (field.type === data.FieldType.string && getCellRenderer(field, getCellOptions(field)) === AutoCellRenderer) {
setupMeasurerForIdx(schema.TableCellDisplayMode.Auto, fieldIdx);
} else {
wrappedFields--;
}
}
}
if (wrappedFields === 0) {
return void 0;
}
return Object.values(result);
}
const SINGLE_LINE_ESTIMATE_THRESHOLD = 18.5;
function getRowHeight(fields, rowIdx, columnWidths, defaultHeight, measurers, lineHeight = TABLE.LINE_HEIGHT, verticalPadding = TABLE.CELL_PADDING * 2) {
if (!(measurers == null ? void 0 : measurers.length)) {
return defaultHeight;
}
let maxHeight = -1;
let maxValue = "";
let maxWidth = 0;
let maxField;
let preciseMeasurer;
for (const { estimate, measure, fieldIdxs } of measurers) {
const measurer = estimate != null ? estimate : measure;
const isEstimating = estimate !== void 0;
for (const fieldIdx of fieldIdxs) {
const field = fields[fieldIdx];
const cellValueRaw = rowIdx === -1 ? getDisplayName(field) : field.values[rowIdx];
if (cellValueRaw != null) {
const colWidth = columnWidths[fieldIdx];
const estimatedHeight = measurer(cellValueRaw, colWidth, field, rowIdx, lineHeight);
if (estimatedHeight > maxHeight) {
maxHeight = estimatedHeight;
maxValue = cellValueRaw;
maxWidth = colWidth;
maxField = field;
preciseMeasurer = isEstimating ? measure : void 0;
}
}
}
}
if (maxField === void 0 || maxHeight < SINGLE_LINE_ESTIMATE_THRESHOLD) {
return defaultHeight;
}
if (preciseMeasurer !== void 0) {
maxHeight = preciseMeasurer(maxValue, maxWidth, maxField, rowIdx, lineHeight);
}
return Math.max(maxHeight + verticalPadding, defaultHeight);
}
function shouldTextOverflow(field) {
const cellOptions = getCellOptions(field);
const eligibleCellType = (
// Tech debt: Technically image cells are of type string, which is misleading (kinda?)
// so we need to ensurefield.type === FieldType.string we don't apply overflow hover states for type image
field.type === data.FieldType.string && cellOptions.type !== schema.TableCellDisplayMode.Image || // regardless of the underlying cell type, data links cells have text overflow.
cellOptions.type === schema.TableCellDisplayMode.DataLinks
);
return eligibleCellType && !shouldTextWrap(field) && !isCellInspectEnabled(field);
}
const TEXT_CELL_TYPES = /* @__PURE__ */ new Set([
schema.TableCellDisplayMode.Auto,
schema.TableCellDisplayMode.ColorText,
schema.TableCellDisplayMode.ColorBackground
]);
function getAlignment(field) {
var _a;
const align = (_a = field.config.custom) == null ? void 0 : _a.align;
if (!align || align === "auto") {
if (TEXT_CELL_TYPES.has(getCellOptions(field).type) && field.type === data.FieldType.number) {
return "right";
}
return "left";
}
return align;
}
function getJustifyContent(textAlign) {
return textAlign === "center" ? "center" : textAlign === "right" ? "flex-end" : "flex-start";
}
const DEFAULT_CELL_OPTIONS = { type: schema.TableCellDisplayMode.Auto };
function getCellOptions(field) {
var _a, _b, _c, _d;
if ((_a = field.config.custom) == null ? void 0 : _a.displayMode) {
return migrateTableDisplayModeToCellOptions((_b = field.config.custom) == null ? void 0 : _b.displayMode);
}
return (_d = (_c = field.config.custom) == null ? void 0 : _c.cellOptions) != null ? _d : DEFAULT_CELL_OPTIONS;
}
function getAlignmentFactor(field, displayValue, rowIndex) {
var _a, _b, _c;
let alignmentFactor = (_a = field.state) == null ? void 0 : _a.alignmentFactors;
if (alignmentFactor) {
if (data.formattedValueToString(alignmentFactor).length < data.formattedValueToString(displayValue).length) {
alignmentFactor = { ...displayValue };
field.state.alignmentFactors = alignmentFactor;
}
return alignmentFactor;
} else {
alignmentFactor = { ...displayValue };
const maxIndex = Math.min(field.values.length, rowIndex + 1e3);
for (let i = rowIndex + 1; i < maxIndex; i++) {
const nextDisplayValue = (_c = (_b = field.display) == null ? void 0 : _b.call(field, field.values[i])) != null ? _c : field.values[i];
if (data.formattedValueToString(alignmentFactor).length > data.formattedValueToString(nextDisplayValue).length) {
alignmentFactor.text = displayValue.text;
}
}
if (field.state) {
field.state.alignmentFactors = alignmentFactor;
} else {
field.state = { alignmentFactors: alignmentFactor };
}
return alignmentFactor;
}
}
const CELL_COLOR_DARKENING_MULTIPLIER = 10;
const CELL_GRADIENT_HUE_ROTATION_DEGREES = 5;
function getCellColorInlineStylesFactory(theme) {
const bgCellTextColor = memoize__default.default((color) => getTextColorForAlphaBackground(color, theme.isDark), {
maxSize: 1e3
});
const darkeningFactor = theme.isDark ? 1 : -0.7;
const gradientBg = memoize__default.default(
(color) => tinycolor__default.default(color).darken(CELL_COLOR_DARKENING_MULTIPLIER * darkeningFactor).spin(CELL_GRADIENT_HUE_ROTATION_DEGREES).toRgbString(),
{ maxSize: 1e3 }
);
const isTransparent = memoize__default.default(
(color) => {
if (color[0] === "#") {
return color.length === 9 && color.endsWith("00");
}
return tinycolor__default.default(color).getAlpha() === 0;
},
{ maxSize: 1e3 }
);
return (cellOptions, displayValue, hasApplyToRow) => {
var _a;
const result = {};
const displayValueColor = displayValue.color;
if (!displayValueColor) {
return result;
}
if (cellOptions.type === schema.TableCellDisplayMode.ColorText) {
result.color = displayValueColor;
} else if (cellOptions.type === schema.TableCellDisplayMode.ColorBackground) {
if (hasApplyToRow && isTransparent(displayValueColor)) {
return result;
}
const mode = (_a = cellOptions.mode) != null ? _a : schema.TableCellBackgroundDisplayMode.Gradient;
result.color = bgCellTextColor(displayValueColor);
result.background = mode === schema.TableCellBackgroundDisplayMode.Gradient ? `linear-gradient(120deg, ${gradientBg(displayValueColor)}, ${displayValueColor})` : displayValueColor;
}
return result;
};
}
const extractPixelValue = (spacing) => {
return typeof spacing === "number" ? spacing : parseFloat(spacing) || 0;
};
const getCellLinks = (field, rowIdx) => {
let links;
if (field.getLinks) {
links = field.getLinks({
valueRowIndex: rowIdx
});
}
if (!links) {
return;
}
for (let i = 0; i < (links == null ? void 0 : links.length); i++) {
if (links[i].onClick) {
const origOnClick = links[i].onClick;
links[i].onClick = (event) => {
if (!(event.ctrlKey || event.metaKey || event.shiftKey)) {
event.preventDefault();
origOnClick(event, {
field,
rowIndex: rowIdx
});
}
};
}
}
return links.filter((link) => link.href || link.onClick != null);
};
function applySort(rows, fields, sortColumns, columnTypes = getColumnTypes(fields), hasNestedFrames = getIsNestedTable(fields)) {
if (sortColumns.length === 0) {
return rows;
}
const sortNanos = sortColumns.map(
(c) => {
var _a;
return (_a = fields.find((f) => f.type === data.FieldType.time && getDisplayName(f) === c.columnKey)) == null ? void 0 : _a.nanos;
}
);
const compareRows = (a, b) => {
let result = 0;
for (let i = 0; i < sortColumns.length; i++) {
const { columnKey, direction } = sortColumns[i];
const compare2 = getComparator(columnTypes[columnKey]);
const sortDir = direction === "ASC" ? 1 : -1;
result = sortDir * compare2(a[columnKey], b[columnKey]);
if (result === 0) {
const nanos = sortNanos[i];
if (nanos !== void 0) {
result = sortDir * (nanos[a.__index] - nanos[b.__index]);
}
}
if (result !== 0) {
break;
}
}
return result;
};
if (hasNestedFrames) {
return processNestedTableRows(rows, (parents) => [...parents].sort(compareRows));
}
return [...rows].sort(compareRows);
}
const frameToRecords = (frame) => {
const fnBody = `
const rows = Array(frame.length);
const values = frame.fields.map(f => f.values);
let rowCount = 0;
for (let i = 0; i < frame.length; i++) {
rows[rowCount] = {
__depth: 0,
__index: i,
${frame.fields.map((field, fieldIdx) => `${JSON.stringify(getDisplayName(field))}: values[${fieldIdx}][i]`).join(",")}
};
rowCount += 1;
if (rows[rowCount-1]['__nestedFrames']){
const childFrame = rows[rowCount-1]['__nestedFrames'];
rows[rowCount] = {__depth: 1, __index: i, data: childFrame[0]}
rowCount += 1;
}
}
return rows;
`;
const convert = new Function("frame", fnBody);
return convert(frame);
};
const compare = new Intl.Collator("en", { sensitivity: "base", numeric: true }).compare;
const strCompare = (a, b) => compare(String(a != null ? a : ""), String(b != null ? b : ""));
const numCompare = (a, b) => {
if (a === b) {
return 0;
}
if (a == null) {
return -1;
}
if (b == null) {
return 1;
}
return Number(a) - Number(b);
};
const frameCompare = (a, b) => {
var _a, _b;
return ((_a = a == null ? void 0 : a.value) != null ? _a : 0) - ((_b = b == null ? void 0 : b.value) != null ? _b : 0);
};
function getComparator(sortColumnType) {
switch (sortColumnType) {
// Handle sorting for frame type fields (sparklines)
case data.FieldType.frame:
return frameCompare;
case data.FieldType.time:
case data.FieldType.number:
case data.FieldType.boolean:
return numCompare;
case data.FieldType.string:
case data.FieldType.enum:
default:
return strCompare;
}
}
const TABLE_CELL_GAUGE_DISPLAY_MODES_TO_DISPLAY_MODES = {
[schema.TableCellDisplayMode.BasicGauge]: schema.BarGaugeDisplayMode.Basic,
[schema.TableCellDisplayMode.GradientGauge]: schema.BarGaugeDisplayMode.Gradient,
[schema.TableCellDisplayMode.LcdGauge]: schema.BarGaugeDisplayMode.Lcd
};
const TABLE_CELL_COLOR_BACKGROUND_DISPLAY_MODES_TO_DISPLAY_MODES = {
[schema.TableCellDisplayMode.ColorBackground]: schema.TableCellBackgroundDisplayMode.Gradient,
[schema.TableCellDisplayMode.ColorBackgroundSolid]: schema.TableCellBackgroundDisplayMode.Basic
};
function migrateTableDisplayModeToCellOptions(displayMode) {
switch (displayMode) {
// In the case of the gauge we move to a different option
case schema.TableCellDisplayMode.BasicGauge:
case schema.TableCellDisplayMode.GradientGauge:
case schema.TableCellDisplayMode.LcdGauge:
return {
type: schema.TableCellDisplayMode.Gauge,
mode: TABLE_CELL_GAUGE_DISPLAY_MODES_TO_DISPLAY_MODES[displayMode]
};
// Also true in the case of the color background
case schema.TableCellDisplayMode.ColorBackground:
case schema.TableCellDisplayMode.ColorBackgroundSolid:
return {
type: schema.TableCellDisplayMode.ColorBackground,
mode: TABLE_CELL_COLOR_BACKGROUND_DISPLAY_MODES_TO_DISPLAY_MODES[displayMode]
};
// catching a nonsense case: `displayMode`: 'custom' should pre-date the CustomCell.
// if it doesn't, we need to just nope out and return an auto cell.
case schema.TableCellDisplayMode.Custom:
return {
type: schema.TableCellDisplayMode.Auto
};
default:
return {
type: displayMode
};
}
}
const getIsNestedTable = (fields) => fields.some(({ type }) => type === data.FieldType.nestedFrames);
const processNestedTableRows = (rows, processParents) => {
const parentRows = [];
const childRows = /* @__PURE__ */ new Map();
for (const row of rows) {
if (row.__depth === 0) {
parentRows.push(row);
} else {
childRows.set(row.__index, row);
}
}
const processedParents = processParents(parentRows);
const result = [];
processedParents.forEach((row) => {
result.push(row);
const childRow = childRows.get(row.__index);
if (childRow) {
result.push(childRow);
}
});
return result;
};
const calculateFooterHeight = (fields) => {
var _a, _b, _c, _d;
let maxReducerCount = 0;
for (const field of fields) {
maxReducerCount = Math.max(maxReducerCount, (_d = (_c = (_b = (_a = field.config.custom) == null ? void 0 : _a.footer) == null ? void 0 : _b.reducers) == null ? void 0 : _c.length) != null ? _d : 0);
}
return maxReducerCount > 0 ? maxReducerCount * TABLE.LINE_HEIGHT + TABLE.CELL_PADDING * 2 : 0;
};
const getDisplayName = (field) => {
var _a, _b;
return (_b = (_a = field.state) == null ? void 0 : _a.displayName) != null ? _b : field.name;
};
const predicateByName = (name) => (f) => f.name === name || getDisplayName(f) === name;
function getVisibleFields(fields) {
return fields.filter((field) => {
var _a, _b;
return field.type !== data.FieldType.nestedFrames && ((_b = (_a = field.config.custom) == null ? void 0 : _a.hideFrom) == null ? void 0 : _b.viz) !== true;
});
}
function getColumnTypes(fields) {
return fields.reduce((acc, field) => {
var _a, _b, _c;
switch (field.type) {
case data.FieldType.nestedFrames:
return { ...acc, ...getColumnTypes((_c = (_b = (_a = field.values[0]) == null ? void 0 : _a[0]) == null ? void 0 : _b.fields) != null ? _c : []) };
default:
return { ...acc, [getDisplayName(field)]: field.type };
}
}, {});
}
function computeColWidths(fields, availWidth) {
let autoCount = 0;
let definedWidth = 0;
return fields.map((field) => {
var _a, _b;
const width = (_b = (_a = field.config.custom) == null ? void 0 : _a.width) != null ? _b : 0;
if (width === 0) {
autoCount++;
} else {
definedWidth += width;
}
return width;
}).map(
(width, i) => {
var _a, _b;
return width || Math.max((_b = (_a = fields[i].config.custom) == null ? void 0 : _a.minWidth) != null ? _b : COLUMN.DEFAULT_WIDTH, (availWidth - definedWidth) / autoCount);
}
);
}
function getApplyToRowBgFn(fields, getCellColorInlineStyles) {
for (const field of fields) {
const cellOptions = getCellOptions(field);
const fieldDisplay = field.display;
if (fieldDisplay !== void 0 && cellOptions.type === schema.TableCellDisplayMode.ColorBackground && cellOptions.applyToRow === true) {
return (rowIndex) => getCellColorInlineStyles(cellOptions, fieldDisplay(field.values[rowIndex]), true);
}
}
}
function canFieldBeColorized(cellType, applyToRowBgFn) {
return cellType === schema.TableCellDisplayMode.ColorBackground || cellType === schema.TableCellDisplayMode.ColorText || Boolean(applyToRowBgFn);
}
const displayJsonValue = (field, decimals) => {
const origDisplay = field.display;
return (value) => {
const displayValue = origDisplay(value, decimals);
let jsonText;
if (!Array.isArray(value) && !isPlainObject(value)) {
const formattedValue = data.formattedValueToString(displayValue);
try {
const parsed = JSON.parse(formattedValue);
jsonText = JSON.stringify(parsed, null, " ");
} catch (e) {
jsonText = formattedValue;
}
} else {
jsonText = JSON.stringify(value, null, " ");
}
return { ...displayValue, text: jsonText };
};
};
function prepareSparklineValue(value, field) {
if (Array.isArray(value)) {
return {
y: {
name: `${field.name}-sparkline`,
type: data.FieldType.number,
values: value,
config: {}
}
};
}
if (data.isDataFrame(value)) {
const timeField = value.fields.find((x) => x.type === data.FieldType.time);
const numberField = value.fields.find((x) => x.type === data.FieldType.number);
if (timeField && numberField) {
return { x: timeField, y: numberField };
}
}
return;
}
function isPlainObject(value) {
return typeof value === "object" && value != null && !Array.isArray(value);
}
function buildInspectValue(value, field) {
const cellOptions = getCellOptions(field);
let inspectValue;
let mode = TableCellInspectorMode.text;
if (field.type === data.FieldType.geo && value instanceof Geometry__default.default) {
inspectValue = new WKT__default.default().writeGeometry(value, {
featureProjection: "EPSG:3857",
dataProjection: "EPSG:4326"
});
mode = TableCellInspectorMode.code;
} else if (cellOptions.type === schema.TableCellDisplayMode.Sparkline || getAutoRendererDisplayMode(field) === schema.TableCellDisplayMode.Sparkline) {
const fieldSparkline = prepareSparklineValue(value, field);
inspectValue = "[";
if (fieldSparkline != null) {
const buildValString = fieldSparkline.x != null ? (idx) => {
var _a, _b;
return `[${(_a = fieldSparkline.x.values[idx]) != null ? _a : "null"}, ${(_b = fieldSparkline.y.values[idx]) != null ? _b : "null"}]`;
} : (idx) => {
var _a;
return `${(_a = fieldSparkline.y.values[idx]) != null ? _a : "null"}`;
};
for (let i = 0; i < fieldSparkline.y.values.length; i++) {
inspectValue += `
${buildValString(i)}${i === fieldSparkline.y.values.length - 1 ? "\n" : ","}`;
}
}
inspectValue += "]";
mode = TableCellInspectorMode.code;
} else if (cellOptions.type === schema.TableCellDisplayMode.JSONView || Array.isArray(value) || isPlainObject(value)) {
let toStringify = value;
if (typeof value === "string") {
try {
toStringify = JSON.parse(value);
} catch (e) {
}
}
inspectValue = JSON.stringify(toStringify, null, " ");
mode = TableCellInspectorMode.code;
} else {
inspectValue = String(value != null ? value : "");
}
return [inspectValue, mode];
}
function getSummaryCellTextAlign(textAlign, cellType) {
if (cellType === schema.TableCellDisplayMode.Gauge) {
return {
left: "right",
right: "left",
center: "center"
}[textAlign];
}
return textAlign;
}
let warnedAboutStyleJsonSet = /* @__PURE__ */ new Set();
function parseStyleJson(rawValue) {
if (typeof rawValue === "string") {
try {
const parsedJsonValue = JSON.parse(rawValue);
if (parsedJsonValue != null && typeof parsedJsonValue === "object" && !Array.isArray(parsedJsonValue)) {
return parsedJsonValue;
}
} catch (e) {
if (!warnedAboutStyleJsonSet.has(rawValue)) {
console.error(`encountered invalid cell style JSON: ${rawValue}`, e);
warnedAboutStyleJsonSet.add(rawValue);
}
}
}
}
const IS_SAFARI_26 = (() => {
if (navigator == null) {
return false;
}
const userAgent = navigator.userAgent;
const safariVersionMatch = userAgent.match(/Version\/(\d+)\./);
return safariVersionMatch && parseInt(safariVersionMatch[1], 10) === 26;
})();
"use strict";
const ActionsCell = ({ field, rowIdx, getActions }) => {
const actions = getActions(field, rowIdx);
if (actions.length === 0) {
return null;
}
return actions.map((action, i) => /* @__PURE__ */ jsxRuntime.jsx(ActionButton, { action, variant: "secondary" }, i));
};
const getStyles$h = (theme) => css.css({ gap: theme.spacing(0.75) });
"use strict";
const MaybeWrapWithLink = React.memo(({ field, rowIdx, children }) => {
var _a, _b, _c, _d, _e;
const linksCount = (_b = (_a = field.config.links) == null ? void 0 : _a.length) != null ? _b : 0;
const actionsCount = (_d = (_c = field.config.actions) == null ? void 0 : _c.length) != null ? _d : 0;
if (linksCount === 1 && actionsCount === 0) {
let link = ((_e = getCellLinks(field, rowIdx)) != null ? _e : [])[0];
return link != null ? renderSingleLink(link, children) : children;
} else if (linksCount + actionsCount > 0) {
return (
// eslint-disable-next-line jsx-a11y/anchor-is-valid
/* @__PURE__ */ jsxRuntime.jsx("a", { title: i18n.t("table.link-wrapper.menu", "view data links and actions"), "aria-haspopup": "menu", children })
);
}
return children;
});
MaybeWrapWithLink.displayName = "MaybeWrapWithLink";
"use strict";
function AutoCell({ value, field, rowIdx }) {
const displayValue = field.display(value);
const formattedValue = data.formattedValueToString(displayValue);
return /* @__PURE__ */ jsxRuntime.jsx(MaybeWrapWithLink, { field, rowIdx, children: formattedValue });
}
const getStyles$g = (_theme, { textWrap, shouldOverflow, maxHeight }) => css.css({
...textWrap && { whiteSpace: "pre-line" },
...shouldOverflow && {
[getActiveCellSelector(Boolean(maxHeight))]: {
whiteSpace: "pre-line"
}
},
...maxHeight != null && textWrap && {
height: "auto",
overflowY: "hidden",
display: "-webkit-box",
WebkitBoxOrient: "vertical",
WebkitLineClamp: Math.floor(maxHeight / TABLE.LINE_HEIGHT),
[getActiveCellSelector(true)]: {
display: "flex",
WebkitLineClamp: "none",
WebkitBoxOrient: "unset",
overflowY: "auto",
height: "fit-content"
}
}
});
const getJsonCellStyles = (_theme, { textWrap, shouldOverflow, maxHeight }) => css.css({
fontFamily: "monospace",
...textWrap && { whiteSpace: "pre" },
...shouldOverflow && {
[getActiveCellSelector(Boolean(maxHeight))]: {
whiteSpace: "pre"
}
}
});
"use strict";
let _context;
const cache = /* @__PURE__ */ new Map();
const cacheLimit = 500;
let ctxFontStyle = "";
function getCanvasContext() {
if (!_context) {
_context = document.createElement("canvas").getContext("2d");
}
return _context;
}
function measureText(text, fontSize, fontWeight = 400) {
const fontStyle = `${fontWeight} ${fontSize}px 'Inter'`;
const cacheKey = text + fontStyle;
const fromCache = cache.get(cacheKey);
if (fromCache) {
return fromCache;
}
const context = getCanvasContext();
if (ctxFontStyle !== fontStyle) {
context.font = ctxFontStyle = fontStyle;
}
const metrics = context.measureText(text);
if (cache.size === cacheLimit) {
cache.clear();
}
cache.set(cacheKey, metrics);
return metrics;
}
function calculateFontSize(text, width, height, lineHeight, maxSize, fontWeight) {
const textSize = measureText(text, 14, fontWeight);
const fontSizeBasedOnWidth = width / (textSize.width + 2) * 14;
const fontSizeBasedOnHeight = height / lineHeight;
const optimalSize = Math.min(fontSizeBasedOnHeight, fontSizeBasedOnWidth);
return Math.min(optimalSize, maxSize != null ? maxSize : optimalSize);
}
"use strict";
function fontSizeReductionFactor(fontSize) {
if (fontSize < 20) {
return 0.9;
}
if (fontSize < 26) {
return 0.8;
}
return 0.6;
}
const FormattedValueDisplay = ({ value, className, style, ...htmlProps }) => {
var _a, _b;
const hasPrefix = ((_a = value.prefix) != null ? _a : "").length > 0;
const hasSuffix = ((_b = value.suffix) != null ? _b : "").length > 0;
let suffixStyle;
if (style && typeof style.fontSize === "number" && !Number.isNaN(style.fontSize)) {
const fontSize = style.fontSize;
const reductionFactor = fontSizeReductionFactor(fontSize);
suffixStyle = { fontSize: fontSize * reductionFactor };
}
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style, ...htmlProps, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
hasPrefix && /* @__PURE__ */ jsxRuntime.jsx("span", { children: value.prefix }),
/* @__PURE__ */ jsxRuntime.jsx("span", { children: value.text }),
hasSuffix && /* @__PURE__ */ jsxRuntime.jsx("span", { style: suffixStyle, children: value.suffix })
] }) });
};
FormattedValueDisplay.displayName = "FormattedDisplayValue";
"use strict";
const MIN_VALUE_HEIGHT = 18;
const MAX_VALUE_HEIGHT = 50;
const MAX_VALUE_WIDTH = 150;
const TITLE_LINE_HEIGHT = 1.5;
const VALUE_LINE_HEIGHT = 1;
const VALUE_LEFT_PADDING = 10;
const VALUE_RIGHT_OVERFLOW_PADDING = 15;
class BarGauge extends React.PureComponent {
render() {
const { onClick, className, theme } = this.props;
const { title } = this.props.value;
const styles = getTitleStyles(this.props);
if (onClick) {
return /* @__PURE__ */ jsxRuntime.jsxs(
"button",
{
type: "button",
style: styles.wrapper,
onClick,
className: css.cx(clearButtonStyles(theme), className),
children: [
/* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.title, children: title }),
this.renderBarAndValue()
]
}
);
}
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.wrapper, className, children: [
title && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.title, children: title }),
this.renderBarAndValue()
] });
}
renderBarAndValue() {
switch (this.props.displayMode) {
case "lcd":
return this.renderRetroBars();
case "basic":
case "gradient":
default:
return this.renderBasicAndGradientBars();
}
}
renderBasicAndGradientBars() {
const { value, showUnfilled, valueDisplayMode } = this.props;
const styles = getBasicAndGradientStyles(this.props);
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.wrapper, children: [
valueDisplayMode !== schema.BarGaugeValueMode.Hidden && /* @__PURE__ */ jsxRuntime.jsx(
FormattedValueDisplay,
{
"data-testid": e2eSelectors.selectors.components.Panels.Visualization.BarGauge.valueV2,
value,
style: styles.value
}
),
showUnfilled && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.emptyBar }),
/* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.bar })
] });
}
renderRetroBars() {
var _a, _b;
const {
display,
field,
value,
itemSpacing,
alignmentFactors,
orientation,
lcdCellWidth,
text,
valueDisplayMode,
isOverflow
} = this.props;
const { valueHeight, valueWidth, maxBarHeight, maxBarWidth, wrapperWidth, wrapperHeight } = calculateBarAndValueDimensions(this.props);
const minValue = (_a = field.min) != null ? _a : data.GAUGE_DEFAULT_MINIMUM;
const maxValue = (_b = field.max) != null ? _b : data.GAUGE_DEFAULT_MAXIMUM;
const isVert = isVertical(orientation);
const valueRange = maxValue - minValue;
const maxSize = isVert ? maxBarHeight : maxBarWidth;
const cellSpacing = itemSpacing;
const cellCount = Math.floor(maxSize / lcdCellWidth);
const cellSize = Math.floor((maxSize - cellSpacing * cellCount) / cellCount);
const valueColor = getTextValueColor(this.props);
const valueToBaseSizeOn = alignmentFactors ? alignmentFactors : value;
const valueStyles = getValueStyles(
valueToBaseSizeOn,
valueColor,
valueWidth,
valueHeight,
orientation,
isOverflow,
text
);
const containerStyles = {
width: `${wrapperWidth}px`,
height: `${wrapperHeight}px`,
display: "flex"
};
if (isVert) {
containerStyles.flexDirection = "column-reverse";
containerStyles.alignItems = "center";
} else {
containerStyles.flexDirection = "row";
containerStyles.alignItems = "center";
valueStyles.justifyContent = "flex-end";
}
const cells = [];
for (let i = 0; i < cellCount; i++) {
const currentValue = minValue + valueRange / cellCount * i;
const cellColor = getCellColor(currentValue, value, display);
const cellStyles = {
borderRadius: "2px"
};
if (cellColor.isLit) {
cellStyles.backgroundImage = `radial-gradient(${cellColor.background} 10%, ${cellColor.backgroundShade})`;
} else {
cellStyles.backgroundColor = cellColor.background;
}
if (isVert) {
cellStyles.height = `${cellSize}px`;
cellStyles.width = `${maxBarWidth}px`;
cellStyles.marginTop = `${cellSpacing}px`;
} else {
cellStyles.width = `${cellSize}px`;
cellStyles.height = `${maxBarHeight}px`;
cellStyles.marginRight = `${cellSpacing}px`;
}
cells.push(/* @__PURE__ */ jsxRuntime.jsx("div", { style: cellStyles }, i.toString()));
}
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: containerStyles, children: [
cells,
valueDisplayMode !== schema.BarGaugeValueMode.Hidden && /* @__PURE__ */ jsxRuntime.jsx(
FormattedValueDisplay,
{
"data-testid": e2eSelectors.selectors.components.Panels.Visualization.BarGauge.valueV2,
value,
style: valueStyles
}
)
] });
}
}
BarGauge.defaultProps = {
lcdCellWidth: 12,
value: {
text: "100",
numeric: 100
},
displayMode: schema.BarGaugeDisplayMode.Gradient,
orientation: data.VizOrientation.Horizontal,
field: {
min: 0,
max: 100,
thresholds: {
mode: data.ThresholdsMode.Absolute,
steps: []
}
},
itemSpacing: 8,
showUnfilled: true,
isOverflow: false
};
function isVertical(orientation) {
return orientation === data.VizOrientation.Vertical;
}
function calculateTitleDimensions(props) {
var _a, _b;
const { height, width, alignmentFactors, orientation, text, namePlacement } = props;
const title = alignmentFactors ? alignmentFactors.title : props.value.title;
if (!title) {
return { fontSize: 0, width: 0, height: 0, placement: "above" };
}
if (namePlacement === schema.BarGaugeNamePlacement.Hidden) {
return {
fontSize: 0,
width: 0,
height: 0,
placement: schema.BarGaugeNamePlacement.Hidden
};
}
if (isVertical(orientation)) {
const fontSize = (_a = text == null ? void 0 : text.titleSize) != null ? _a : 14;
return {
fontSize,
width,
height: fontSize * TITLE_LINE_HEIGHT,
placement: "below"
};
}
const shouldDisplayValueAbove = height > 40 && namePlacement === schema.BarGaugeNamePlacement.Auto || namePlacement === schema.BarGaugeNamePlacement.Top;
if (shouldDisplayValueAbove) {
if (text == null ? void 0 : text.titleSize) {
return {
fontSize: text == null ? void 0 : text.titleSize,
width: 0,
height: text.titleSize * TITLE_LINE_HEIGHT,
placement: "above"
};
}
const maxTitleHeightRatio2 = 0.45;
const titleHeight2 = Math.max(Math.min(height * maxTitleHeightRatio2, MAX_VALUE_HEIGHT), 17);
return {
fontSize: titleHeight2 / TITLE_LINE_HEIGHT,
width: 0,
height: titleHeight2,
placement: "above"
};
}
const maxTitleHeightRatio = 0.6;
const titleHeight = Math.max(height * maxTitleHeightRatio, MIN_VALUE_HEIGHT);
const titleFontSize = titleHeight / TITLE_LINE_HEIGHT;
const textSize = measureText(title, titleFontSize);
const textWidth = Math.min(textSize.width + 15, width * 0.4);
return {
fontSize: (_b = text == null ? void 0 : text.titleSize) != null ? _b : titleFontSize,
height: 0,
width: textWidth,
placement: "left"
};
}
function getTitleStyles(props) {
const wrapperStyles = {
display: "flex",
overflow: "hidden",
width: "100%"
};
const titleDim = calculateTitleDimensions(props);
const titleStyles = {
fontSize: `${titleDim.fontSize}px`,
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
width: "100%",
alignItems: "center",
alignSelf: "center"
};
if (titleDim.placement === "hidden") {
titleStyles.display = "none";
} else {
if (isVertical(props.orientation)) {
wrapperStyles.flexDirection = "column-reverse";
titleStyles.textAlign = "center";
} else {
if (titleDim.placement === "above") {
wrapperStyles.flexDirection = "column";
} else {
wrapperStyles.flexDirection = "row";
titleStyles.width = `${titleDim.width}px`;
titleStyles.textAlign = "right";
titleStyles.paddingRight = "10px";
}
}
}
return {
wrapper: wrapperStyles,
title: titleStyles
};
}
function calculateBarAndValueDimensions(props) {
var _a;
const { height, width, orientation, text, alignmentFactors, valueDisplayMode } = props;
const titleDim = calculateTitleDimensions(props);
const value = alignmentFactors != null ? alignmentFactors : props.value;
const valueString = data.formattedValueToString(value);
let maxBarHeight = 0;
let maxBarWidth = 0;
let valueHeight = 0;
let valueWidth = 0;
let wrapperWidth = 0;
let wrapperHeight = 0;
const fontSizeToMeasureWith = (_a = text == null ? void 0 : text.valueSize) != null ? _a : Math.max(titleDim.fontSize, 12);
const realTextSize = measureText(valueString, fontSizeToMeasureWith);
const realValueWidth = realTextSize.width + VALUE_LEFT_PADDING * 2;
if (isVertical(orientation)) {
if (text == null ? void 0 : text.valueSize) {
valueHeight = text.valueSize * VALUE_LINE_HEIGHT;
} else {
valueHeight = Math.min(Math.max(height * 0.1, MIN_VALUE_HEIGHT), MAX_VALUE_HEIGHT);
}
valueWidth = width;
if (valueDisplayMode === schema.BarGaugeValueMode.Hidden) {
valueHeight = 0;
valueWidth = 0;
}
maxBarHeight = height - (titleDim.height + valueHeight);
maxBarWidth = width;
wrapperWidth = width;
wrapperHeight = height - titleDim.height;
} else {
if (valueDisplayMode === schema.BarGaugeValueMode.Hidden) {
valueHeight = 0;
valueWidth = 0;
} else {
valueHeight = height - titleDim.height;
valueWidth = Math.max(Math.min(width * 0.2, MAX_VALUE_WIDTH), realValueWidth);
}
maxBarHeight = height - titleDim.height;
maxBarWidth = width - valueWidth - titleDim.width;
if (titleDim.placement === "above") {
wrapperWidth = width;
wrapperHeight = height - titleDim.height;
} else {
wrapperWidth = width - titleDim.width;
wrapperHeight = height;
}
}
return {
valueWidth,
valueHeight,
maxBarWidth,
maxBarHeight,
wrapperHeight,
wrapperWidth
};
}
function getCellColor(positionValue, value, display) {
if (positionValue === null) {
return {
background: data.FALLBACK_COLOR,
border: data.FALLBACK_COLOR
};
}
const color = display ? display(positionValue).color : null;
if (color) {
if (value === null || isNaN(value.numeric) || positionValue !== null && positionValue > value.numeric) {
return {
background: tinycolor__default.default(color).setAlpha(0.18).toRgbString(),
border: "transparent",
isLit: false
};
} else {
return {
background: tinycolor__default.default(color).setAlpha(0.95).toRgbString(),
backgroundShade: tinycolor__default.default(color).setAlpha(0.55).toRgbString(),
border: tinycolor__default.default(color).setAlpha(0.9).toRgbString(),
isLit: true
};
}
}
return {
background: data.FALLBACK_COLOR,
border: data.FALLBACK_COLOR
};
}
function getValuePercent(value, minValue, maxValue) {
const valueRatio = Math.min((value - minValue) / (maxValue - minValue), 1);
return isNaN(valueRatio) ? 0 : valueRatio;
}
function getBasicAndGradientStyles(props) {
var _a, _b, _c;
const { displayMode, field, value, alignmentFactors, orientation, theme, text, isOverflow } = props;
const { valueWidth, valueHeight, maxBarHeight, maxBarWidth } = calculateBarAndValueDimensions(props);
const minValue = (_a = field.min) != null ? _a : data.GAUGE_DEFAULT_MINIMUM;
const maxValue = (_b = field.max) != null ? _b : data.GAUGE_DEFAULT_MAXIMUM;
const valuePercent = getValuePercent(value.numeric, minValue, maxValue);
const textColor = getTextValueColor(props);
const barColor = (_c = value.color) != null ? _c : data.FALLBACK_COLOR;
const valueToBaseSizeOn = alignmentFactors ? alignmentFactors : value;
const valueStyles = getValueStyles(
valueToBaseSizeOn,
textColor,
valueWidth,
valueHeight,
orientation,
isOverflow,
text
);
const isBasic = displayMode === "basic";
const wrapperStyles = {
display: "flex",
flexGrow: 1
};
const barStyles = {
borderRadius: theme.shape.radius.sm,
position: "relative"
};
const emptyBar = {
background: theme.colors.background.secondary,
flexGrow: 1,
display: "flex",
borderRadius: theme.shape.radius.sm,
position: "relative"
};
if (isVertical(orientation)) {
const barHeight = Math.max(valuePercent * maxBarHeight, 1);
wrapperStyles.flexDirection = "column";
wrapperStyles.justifyContent = "flex-end";
barStyles.transition = "height 1s";
barStyles.height = `${barHeight}px`;
barStyles.width = `${maxBarWidth}px`;
emptyBar.bottom = "-3px";
emptyBar.width = `${valueWidth}px`;
if (isBasic) {
barStyles.background = `${tinycolor__default.default(barColor).setAlpha(0.35).toRgbString()}`;
barStyles.borderTop = `2px solid ${barColor}`;
} else {
barStyles.background = getBarGradient(props, maxBarHeight);
}
} else {
const barWidth = Math.max(valuePercent * maxBarWidth, 1);
wrapperStyles.flexDirection = "row-reverse";
wrapperStyles.justifyContent = "flex-end";
wrapperStyles.alignItems = "stretch";
barStyles.transition = "width 1s";
barStyles.height = `${maxBarHeight}px`;
barStyles.width = `${barWidth}px`;
emptyBar.left = "-3px";
emptyBar.height = `${valueHeight}px`;
if (isBasic) {
barStyles.background = `${tinycolor__default.default(barColor).setAlpha(0.35).toRgbString()}`;
barStyles.borderRight = `2px solid ${barColor}`;
} else {
barStyles.background = getBarGradient(props, maxBarWidth);
}
}
return {
wrapper: wrapperStyles,
bar: barStyles,
value: valueStyles,
emptyBar
};
}
function getBarGradient(props, maxSize) {
var _a, _b;
const { field, value, orientation, theme } = props;
const cssDirection = isVertical(orientation) ? "0deg" : "90deg";
const minValue = field.min;
const maxValue = field.max;
let gradient = "";
let lastpos = 0;
let mode = data.getFieldColorMode((_a = field.color) == null ? void 0 : _a.mode);
if (mode.id === data.FieldColorModeId.Thresholds) {
const thresholds = field.thresholds;
for (let i = 0; i < thresholds.steps.length; i++) {
const threshold = thresholds.steps[i];
const color = props.theme.visualization.getColorByName(threshold.color);
const valuePercent = thresholds.mode === data.ThresholdsMode.Percentage ? threshold.value / 100 : getValuePercent(threshold.value, minValue, maxValue);
const pos = valuePercent * maxSize;
const offset = Math.round(pos - (pos - lastpos) / 2);
const thresholdValue = thresholds.mode === data.ThresholdsMode.Percentage ? minValue + (maxValue - minValue) * valuePercent : threshold.value;
if (gradient === "") {
gradient = `linear-gradient(${cssDirection}, ${color}, ${color}`;
} else if (value.numeric < thresholdValue) {
break;
} else {
lastpos = pos;
gradient += ` ${offset}px, ${color}`;
}
}
return gradient + ")";
}
if (mode.isContinuous && mode.getColors) {
const scheme = mode.getColors(theme);
for (let i = 0; i < scheme.length; i++) {
const color = scheme[i];
if (gradient === "") {
gradient = `linear-gradient(${cssDirection}, ${color} 0px`;
} else {
const valuePercent = i / (scheme.length - 1);
const pos = valuePercent * maxSize;
gradient += `, ${color} ${pos}px`;
}
}
return gradient + ")";
}
return (_b = value.color) != null ? _b : data.FALLBACK_COLOR;
}
function getTextValueColor(props) {
if (props.valueDisplayMode === "text") {
return props.theme.colors.text.primary;
}
const { value } = props;
if (value.color) {
return value.color;
}
return data.FALLBACK_COLOR;
}
function getValueStyles(value, color, width, height, orientation, isOverflow, text) {
var _a, _b;
const styles = {
color,
height: `${height}px`,
maxWidth: `${width}px`,
display: "flex",
alignItems: "center",
textWrap: "nowrap",
lineHeight: VALUE_LINE_HEIGHT
};
let textWidth = width;
const formattedValueString = data.formattedValueToString(value);
if (isVertical(orientation)) {
styles.fontSize = (_a = text == null ? void 0 : text.valueSize) != null ? _a : calculateFontSize(formattedValueString, textWidth, height, VALUE_LINE_HEIGHT);
styles.justifyContent = `center`;
} else {
styles.fontSize = (_b = text == null ? void 0 : text.valueSize) != null ? _b : calculateFontSize(formattedValueString, textWidth - VALUE_LEFT_PADDING * 2, height, VALUE_LINE_HEIGHT);
styles.justifyContent = `flex-end`;
styles.paddingLeft = `${VALUE_LEFT_PADDING}px`;
styles.paddingRight = `${VALUE_LEFT_PADDING + (isOverflow ? VALUE_RIGHT_OVERFLOW_PADDING : 0)}px`;
textWidth -= VALUE_LEFT_PADDING;
}
return styles;
}
"use strict";
const defaultScale = {
mode: data.ThresholdsMode.Absolute,
steps: [
{
color: "blue",
value: -Infinity
},
{
color: "green",
value: 20
}
]
};
const BarGaugeCell = ({ value, field, theme, height, width, rowIdx }) => {
var _a;
const displayValue = field.display(value);
const cellOptions = getCellOptions(field);
const heightOffset = TABLE.CELL_PADDING * 2;
let config = data.getFieldConfigWithMinMax(field, false);
if (!config.thresholds) {
config = {
...config,
thresholds: defaultScale
};
}
let barGaugeMode = schema.BarGaugeDisplayMode.Gradient;
let valueDisplayMode = void 0;
if (cellOptions.type === schema.TableCellDisplayMode.Gauge) {
barGaugeMode = (_a = cellOptions.mode) != null ? _a : schema.BarGaugeDisplayMode.Gradient;
valueDisplayMode = cellOptions.valueDisplayMode !== void 0 ? cellOptions.valueDisplayMode : schema.BarGaugeValueMode.Text;
}
const alignmentFactors = getAlignmentFactor(field, displayValue, rowIdx);
const renderedHeight = Math.min(height - heightOffset, TABLE.MAX_CELL_HEIGHT);
return /* @__PURE__ */ jsxRuntime.jsx(MaybeWrapWithLink, { field, rowIdx, children: /* @__PURE__ */ jsxRuntime.jsx(
BarGauge,
{
width,
height: renderedHeight,
field: config,
display: field.display,
text: { valueSize: 14 },
value: displayValue,
orientation: data.VizOrientation.Horizontal,
theme,
alignmentFactors,
itemSpacing: 1,
lcdCellWidth: 8,
displayMode: barGaugeMode,
valueDisplayMode
}
) });
};
"use strict";
const DataLinksCell = ({ field, rowIdx }) => {
const links = getCellLinks(field, rowIdx);
if (!(links == null ? void 0 : links.length)) {
return null;
}
return links.map((link, idx) => /* @__PURE__ */ jsxRuntime.jsx("a", { onClick: link.onClick, href: link.href, target: link.target, children: link.title }, idx));
};
const getStyles$f = (theme, { textWrap, textAlign }) => css.css({
...textWrap && {
flexDirection: "column",
justifyContent: "center",
alignItems: `${getJustifyContent(textAlign)} !important`
// we can't guarantee order, and alignItems is set on a sibling class.
},
"> a": {
flexWrap: "nowrap",
...!textWrap && {
paddingInline: theme.spacing(0.5),
borderRight: `2px solid ${theme.colors.border.medium}`,
"&:first-child": {
paddingInlineStart: 0
},
"&:last-child": {
paddingInlineEnd: 0,
borderRight: "none"
}
}
}
});
"use strict";
function GeoCell({ value }) {
let disp = null;
if (value instanceof geom.Geometry) {
disp = new WKT__default.default().writeGeometry(value, {
featureProjection: "EPSG:3857",
dataProjection: "EPSG:4326"
});
} else if (value != null) {
disp = `${value}`;
}
return disp;
}
const getStyles$e = () => css.css({
fontFamily: "monospace",
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis"
});
"use strict";
const ImageCell = ({ cellOptions, field, value, rowIdx }) => {
const [error, setError] = React.useState(false);
const { text } = field.display(value);
const { alt, title } = cellOptions.type === schema.TableCellDisplayMode.Image ? cellOptions : { alt: void 0, title: void 0 };
if (!text) {
return null;
}
return /* @__PURE__ */ jsxRuntime.jsx(MaybeWrapWithLink, { field, rowIdx, children: error ? text : /* @__PURE__ */ jsxRuntime.jsx("img", { alt, src: text, title, onError: () => setError(true) }) });
};
const getStyles$d = () => css.css({
"&, a, img": {
width: "100%",
height: "100%"
},
img: {
objectFit: "contain"
}
});
"use strict";
function MarkdownCell({ field, rowIdx, disableSanitizeHtml }) {
const rawValue = field.values[rowIdx];
if (rawValue == null) {
return null;
}
const renderValue = field.display(rawValue);
return /* @__PURE__ */ jsxRuntime.jsx(MaybeWrapWithLink, { field, rowIdx, children: /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: "markdown-container",
dangerouslySetInnerHTML: {
__html: data.renderMarkdown(renderValue.text, { noSanitize: disableSanitizeHtml }).trim()
}
}
) });
}
const getStyles$c = (theme, { maxHeight }) => css.css({
[`&, ${getActiveCellSelector(Boolean(maxHeight))}`]: {
whiteSpace: "normal"
},
".markdown-container": {
width: "100%",
// for elements like `p`, `h*`, etc. which have an inherent margin,
// we want to remove the bottom margin for the last one in the container.
"> *:last-child": {
marginBottom: 0
}
},
"ol, ul": {
paddingLeft: theme.spacing(2.5)
},
p: {
whiteSpace: "pre-line"
}
});
"use strict";
function attachDebugger(key, thebugger, logger) {
var _a;
if (process.env.NODE_ENV === "production") {
return;
}
let completeDebugger = thebugger || {};
if (logger !== void 0) {
completeDebugger = { ...completeDebugger, enable: () => logger.enable(), disable: () => logger.disable() };
}
let debugGlobal = (_a = typeof window !== "undefined" && window["_debug"]) != null ? _a : {};
debugGlobal[key] = completeDebugger;
if (typeof window !== "undefined") {
window["_debug"] = debugGlobal;
}
}
"use strict";
const throttledLog = lodash.throttle((...t) => {
console.log(...t);
}, 500);
const createLogger = (name) => {
let loggingEnabled = false;
if (typeof window !== "undefined") {
loggingEnabled = window.localStorage.getItem("grafana.debug") === "true";
}
return {
logger: (id, throttle2 = false, ...t) => {
if (process.env.NODE_ENV === "production" || process.env.NODE_ENV === "test" || !loggingEnabled) {
return;
}
const fn = throttle2 ? throttledLog : console.log;
fn(`[${name}: ${id}]:`, ...t);
},
enable: () => loggingEnabled = true,
disable: () => loggingEnabled = false,
isEnabled: () => loggingEnabled
};
};
"use strict";
const FIXED_UNIT = "__fixed";
class PlotConfigBuilder {
constructor(props) {
this.props = props;
}
}
"use strict";
function buildScaleKey(config, fieldType) {
var _a, _b, _c, _d, _e, _f, _g;
const defaultPart = "na";
const scaleRange = `${config.min !== void 0 ? config.min : defaultPart}-${config.max !== void 0 ? config.max : defaultPart}`;
const scaleSoftRange = `${((_a = config.custom) == null ? void 0 : _a.axisSoftMin) !== void 0 ? config.custom.axisSoftMin : defaultPart}-${((_b = config.custom) == null ? void 0 : _b.axisSoftMax) !== void 0 ? config.custom.axisSoftMax : defaultPart}`;
const scalePlacement = `${((_c = config.custom) == null ? void 0 : _c.axisPlacement) !== void 0 ? (_d = config.custom) == null ? void 0 : _d.axisPlacement : schema.AxisPlacement.Auto}`;
const scaleUnit = (_e = config.unit) != null ? _e : FIXED_UNIT;
const scaleDistribution = ((_f = config.custom) == null ? void 0 : _f.scaleDistribution) ? getScaleDistributionPart(config.custom.scaleDistribution) : schema.ScaleDistribution.Linear;
const scaleLabel = Boolean((_g = config.custom) == null ? void 0 : _g.axisLabel) ? config.custom.axisLabel : defaultPart;
return `${scaleUnit}/${scaleRange}/${scaleSoftRange}/${scalePlacement}/${scaleDistribution}/${scaleLabel}/${fieldType}`;
}
function getScaleDistributionPart(config) {
if (config.type === schema.ScaleDistribution.Log) {
return `${config.type}${config.log}`;
}
return config.type;
}
"use strict";
const paddingSide = (u, side, sidesWithAxes) => {
let hasCrossAxis = side % 2 ? sidesWithAxes[0] || sidesWithAxes[2] : sidesWithAxes[1] || sidesWithAxes[3];
return sidesWithAxes[side] || !hasCrossAxis ? 0 : 8;
};
const DEFAULT_PLOT_CONFIG = {
ms: 1,
focus: {
alpha: 1
},
cursor: {
focus: {
prox: 30
}
},
legend: {
show: false
},
padding: [paddingSide, paddingSide, paddingSide, paddingSide],
series: [],
hooks: {}
};
var StackDirection = /* @__PURE__ */ ((StackDirection2) => {
StackDirection2[StackDirection2["Pos"] = 1] = "Pos";
StackDirection2[StackDirection2["Neg"] = -1] = "Neg";
return StackDirection2;
})(StackDirection || {});
function getStackingBands(group) {
let bands = [];
let { series, dir } = group;
let lastIdx = series.length - 1;
let rSeries = series.slice().reverse();
rSeries.forEach((si, i) => {
if (i !== lastIdx) {
let nextIdx = rSeries[i + 1];
bands.push({
series: [si, nextIdx],
// fill direction is inverted from stack direction
dir: -1 * dir
});
}
});
return bands;
}
function getStackingGroups(frame) {
let groups = /* @__PURE__ */ new Map();
frame.fields.forEach(({ config, values, type }, i) => {
var _a;
if (i === 0) {
return;
}
let { custom } = config;
if (custom == null) {
return;
}
if ((_a = custom.hideFrom) == null ? void 0 : _a.viz) {
return;
}
let { stacking } = custom;
if (stacking == null) {
return;
}
let { mode: stackingMode, group: stackingGroup } = stacking;
if (stackingMode === schema.StackingMode.None) {
return;
}
let transform = custom.transform;
let stackDir = getStackDirection(transform, values);
let drawStyle = custom.drawStyle;
let drawStyle2 = drawStyle === schema.GraphDrawStyle.Bars ? custom.barAlignment : drawStyle === schema.GraphDrawStyle.Line ? custom.lineInterpolation : null;
let stackKey = `${stackDir}|${stackingMode}|${stackingGroup}|${buildScaleKey(
config,
type
)}|${drawStyle}|${drawStyle2}`;
let group = groups.get(stackKey);
if (group == null) {
group = {
series: [],
dir: stackDir
};
groups.set(stackKey, group);
}
group.series.push(i);
});
return [...groups.values()];
}
function preparePlotData2(frame, stackingGroups, onStackMeta) {
let data = Array(frame.fields.length);
let stacksQty = stackingGroups.length;
let dataLen = frame.length;
let zeroArr = stacksQty > 0 ? Array(dataLen).fill(0) : [];
let falseArr = stacksQty > 0 ? Array(dataLen).fill(false) : [];
let accums = Array.from({ length: stacksQty }, () => zeroArr.slice());
let anyValsAtX = Array.from({ length: stacksQty }, () => falseArr.slice());
stackingGroups.forEach((group, groupIdx) => {
let groupValsAtX = anyValsAtX[groupIdx];
group.series.forEach((seriesIdx) => {
var _a, _b;
let field = frame.fields[seriesIdx];
if ((_b = (_a = field.config.custom) == null ? void 0 : _a.hideFrom) == null ? void 0 : _b.viz) {
return;
}
let vals = field.values;
for (let i = 0; i < dataLen; i++) {
if (vals[i] != null) {
groupValsAtX[i] = true;
}
}
});
});
frame.fields.forEach((field, i) => {
var _a, _b;
let vals = field.values;
if (i === 0) {
data[i] = vals;
return;
}
let { custom } = field.config;
if (!custom || ((_a = custom.hideFrom) == null ? void 0 : _a.viz)) {
data[i] = vals;
return;
}
if (custom.transform === schema.GraphTransform.Constant) {
let firstValIdx = vals.findIndex((v) => v != null);
let firstVal = vals[firstValIdx];
vals = Array(vals.length).fill(void 0);
vals[firstValIdx] = firstVal;
} else {
vals = vals.slice();
if (custom.transform === schema.GraphTransform.NegativeY) {
for (let i2 = 0; i2 < vals.length; i2++) {
if (vals[i2] != null) {
vals[i2] *= -1;
}
}
}
}
let stackingMode = (_b = custom.stacking) == null ? void 0 : _b.mode;
if (!stackingMode || stackingMode === schema.StackingMode.None) {
data[i] = vals;
} else {
let stackIdx = stackingGroups.findIndex((group) => group.series.indexOf(i) > -1);
let accum = accums[stackIdx];
let groupValsAtX = anyValsAtX[stackIdx];
let stacked = data[i] = Array(dataLen);
for (let i2 = 0; i2 < dataLen; i2++) {
let v = vals[i2];
if (v != null) {
stacked[i2] = accum[i2] += v;
} else {
stacked[i2] = groupValsAtX[i2] ? accum[i2] : v;
}
}
}
});
if (onStackMeta) {
let accumsBySeriesIdx = data.map((vals, i) => {
let stackIdx = stackingGroups.findIndex((group) => group.series.indexOf(i) > -1);
return stackIdx !== -1 ? accums[stackIdx] : vals;
});
onStackMeta({
totals: accumsBySeriesIdx
});
}
frame.fields.forEach((field, i) => {
var _a, _b, _c, _d;
if (i === 0 || ((_b = (_a = field.config.custom) == null ? void 0 : _a.hideFrom) == null ? void 0 : _b.viz)) {
return;
}
let stackingMode = (_d = (_c = field.config.custom) == null ? void 0 : _c.stacking) == null ? void 0 : _d.mode;
if (stackingMode === schema.StackingMode.Percent) {
let stackIdx = stackingGroups.findIndex((group2) => group2.series.indexOf(i) > -1);
let accum = accums[stackIdx];
let group = stackingGroups[stackIdx];
let stacked = data[i];
for (let i2 = 0; i2 < dataLen; i2++) {
let v = stacked[i2];
if (v != null) {
stacked[i2] = accum[i2] === 0 ? 0 : group.dir * (v / accum[i2]);
}
}
}
});
return data;
}
function findMidPointYPosition(u, idx) {
let y;
let sMaxIdx = 1;
let sMinIdx = 1;
let max = u.data[1][idx];
let min = u.data[1][idx];
for (let i = 1; i < u.data.length; i++) {
const sData = u.data[i];
const sVal = sData[idx];
if (sVal != null) {
if (max == null) {
max = sVal;
} else {
if (sVal > max) {
max = u.data[i][idx];
sMaxIdx = i;
}
}
if (min == null) {
min = sVal;
} else {
if (sVal < min) {
min = u.data[i][idx];
sMinIdx = i;
}
}
}
}
if (min == null && max == null) {
y = void 0;
} else if (min != null && max != null) {
y = (u.valToPos(min, u.series[sMinIdx].scale) + u.valToPos(max, u.series[sMaxIdx].scale)) / 2;
} else {
y = u.valToPos(min || max, u.series[sMaxIdx || sMinIdx].scale);
}
if (y !== void 0 && y < 0) {
y = u.bbox.height / devicePixelRatio;
}
return y;
}
function getStackDirection(transform, data) {
const hasNegSamp = hasNegSample(data);
if (transform === schema.GraphTransform.NegativeY) {
return hasNegSamp ? 1 /* Pos */ : -1 /* Neg */;
}
return hasNegSamp ? -1 /* Neg */ : 1 /* Pos */;
}
function hasNegSample(data, samples = 100) {
const len = data.length;
if (len === 0) {
return false;
}
let firstIdx = 0;
let lastIdx = len - 1;
while (firstIdx <= lastIdx && data[firstIdx] == null) {
firstIdx++;
}
while (lastIdx >= firstIdx && data[lastIdx] == null) {
lastIdx--;
}
let negCount = 0;
let posCount = 0;
if (lastIdx >= firstIdx) {
const stride = Math.max(1, Math.floor((lastIdx - firstIdx + 1) / samples));
for (let i = firstIdx; i <= lastIdx; i += stride) {
const v = data[i];
if (v != null && typeof v === "number") {
if (v < 0 || Object.is(v, -0)) {
negCount++;
} else if (v > 0) {
posCount++;
}
}
}
if (negCount > posCount) {
return true;
}
}
return false;
}
const getDisplayValuesForCalcs = (calcs, field, theme) => {
var _a;
if (!(calcs == null ? void 0 : calcs.length)) {
return [];
}
const defaultFormatter = (v) => v == null ? "-" : v.toFixed(1);
const fmt = (_a = field.display) != null ? _a : defaultFormatter;
let countFormatter = null;
const fieldCalcs = data.reduceField({
field,
reducers: calcs
});
return calcs.map((reducerId) => {
const fieldReducer = data.fieldReducers.get(reducerId);
let formatter = fmt;
if (fieldReducer.id === data.ReducerID.diffperc) {
formatter = data.getDisplayProcessor({
field: {
...field,
config: {
...field.config,
unit: "percent"
}
},
theme
});
}
if (fieldReducer.id === data.ReducerID.count || fieldReducer.id === data.ReducerID.changeCount || fieldReducer.id === data.ReducerID.distinctCount) {
if (!countFormatter) {
countFormatter = data.getDisplayProcessor({
field: {
...field,
config: {
...field.config,
unit: "none"
}
},
theme
});
}
formatter = countFormatter;
}
return {
...formatter(fieldCalcs[reducerId]),
title: fieldReducer.name,
description: fieldReducer.description
};
});
};
const pluginLogger = createLogger("uPlot");
const pluginLog = pluginLogger.logger;
attachDebugger("graphng", void 0, pluginLogger);
"use strict";
function sameDims(prevProps, nextProps) {
return nextProps.width === prevProps.width && nextProps.height === prevProps.height;
}
function sameData(prevProps, nextProps) {
return nextProps.data === prevProps.data;
}
function sameConfig(prevProps, nextProps) {
return nextProps.config === prevProps.config;
}
class UPlotChart extends React.Component {
constructor(props) {
super(props);
this.plotContainer = React.createRef();
this.plotCanvasBBox = React.createRef();
this.plotInstance = null;
}
reinitPlot() {
var _a;
let { width, height, plotRef } = this.props;
(_a = this.plotInstance) == null ? void 0 : _a.destroy();
if (width === 0 && height === 0) {
return;
}
this.props.config.addHook("setSize", (u) => {
const canvas = u.over;
if (!canvas) {
return;
}
});
const config = {
width: Math.floor(this.props.width),
height: Math.floor(this.props.height),
...this.props.config.getConfig()
};
pluginLog("UPlot", false, "Reinitializing plot", config);
const plot = new uPlot__default.default(config, this.props.data, this.plotContainer.current);
if (plotRef) {
plotRef(plot);
}
this.plotInstance = plot;
}
componentDidMount() {
this.reinitPlot();
}
componentWillUnmount() {
var _a;
(_a = this.plotInstance) == null ? void 0 : _a.destroy();
}
componentDidUpdate(prevProps) {
var _a, _b;
if (!sameDims(prevProps, this.props)) {
(_a = this.plotInstance) == null ? void 0 : _a.setSize({
width: Math.floor(this.props.width),
height: Math.floor(this.props.height)
});
} else if (!sameConfig(prevProps, this.props)) {
this.reinitPlot();
} else if (!sameData(prevProps, this.props)) {
(_b = this.plotInstance) == null ? void 0 : _b.setData(this.props.data);
}
}
render() {
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative" }, children: [
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: this.plotContainer, "data-testid": "uplot-main-div" }),
this.props.children
] });
}
}
"use strict";
class UPlotScaleBuilder extends PlotConfigBuilder {
merge(props) {
this.props.min = optMinMax("min", this.props.min, props.min);
this.props.max = optMinMax("max", this.props.max, props.max);
}
getConfig() {
var _a, _b;
let {
isTime,
auto,
scaleKey,
min: hardMin,
max: hardMax,
softMin,
softMax,
range,
direction,
orientation,
centeredZero,
decimals,
stackingMode,
padMinBy = 0.1,
padMaxBy = 0.1
} = this.props;
if (stackingMode === schema.StackingMode.Percent) {
if (hardMin == null && softMin == null) {
softMin = 0;
}
if (hardMax == null && softMax == null) {
softMax = 1;
}
}
const distr = this.props.distribution;
const distribution = !isTime ? {
distr: distr === schema.ScaleDistribution.Symlog ? 4 : distr === schema.ScaleDistribution.Log ? 3 : distr === schema.ScaleDistribution.Ordinal ? 2 : 1,
log: distr === schema.ScaleDistribution.Log || distr === schema.ScaleDistribution.Symlog ? (_a = this.props.log) != null ? _a : 2 : void 0,
asinh: distr === schema.ScaleDistribution.Symlog ? (_b = this.props.linearThreshold) != null ? _b : 1 : void 0
} : {};
if (distr === schema.ScaleDistribution.Log) {
let logBase = this.props.log;
let logFn = logBase === 2 ? Math.log2 : Math.log10;
if (hardMin != null) {
if (hardMin <= 0) {
hardMin = null;
} else {
hardMin = logBase ** Math.floor(logFn(hardMin));
}
}
if (hardMax != null) {
if (hardMax <= 0) {
hardMax = null;
} else {
hardMax = logBase ** Math.ceil(logFn(hardMax));
}
}
if (softMin != null) {
if (softMin <= 0) {
softMin = null;
} else {
softMin = logBase ** Math.floor(logFn(softMin));
}
}
if (softMax != null) {
if (softMax <= 0) {
softMax = null;
} else {
softMax = logBase ** Math.ceil(logFn(softMax));
}
}
}
let softMinMode = softMin == null ? 3 : 1;
let softMaxMode = softMax == null ? 3 : 1;
const rangeConfig = {
min: {
pad: padMinBy,
hard: hardMin != null ? hardMin : -Infinity,
soft: softMin || 0,
mode: softMinMode
},
max: {
pad: padMaxBy,
hard: hardMax != null ? hardMax : Infinity,
soft: softMax || 0,
mode: softMaxMode
}
};
let hardMinOnly = softMin == null && hardMin != null;
let hardMaxOnly = softMax == null && hardMax != null;
let hasFixedRange = hardMinOnly && hardMaxOnly;
const rangeFn = (u, dataMin, dataMax, scaleKey2) => {
var _a2;
const scale = u.scales[scaleKey2];
let minMax = [dataMin, dataMax];
if (!hasFixedRange && dataMin == null && dataMax == null) {
return minMax;
}
let logBase = (_a2 = scale.log) != null ? _a2 : 10;
if (scale.distr === 1 || scale.distr === 2 || scale.distr === 4) {
if (centeredZero) {
let absMin = Math.abs(dataMin);
let absMax = Math.abs(dataMax);
let max = Math.max(absMin, absMax);
if (max === 0) {
max = 80;
}
dataMin = -max;
dataMax = max;
}
if (scale.distr === 4) {
minMax = uPlot__default.default.rangeAsinh(dataMin, dataMax, logBase, true);
} else {
minMax = uPlot__default.default.rangeNum(hardMinOnly ? hardMin : dataMin, hardMaxOnly ? hardMax : dataMax, rangeConfig);
}
} else if (scale.distr === 3) {
minMax = uPlot__default.default.rangeLog(hardMin != null ? hardMin : dataMin, hardMax != null ? hardMax : dataMax, logBase, true);
}
if (decimals === 0) {
if (scale.distr === 1 || scale.distr === 2) {
minMax[0] = data.incrRoundDn(minMax[0], 1);
minMax[1] = data.incrRoundUp(minMax[1], 1);
} else if (scale.distr === 3) {
let logFn = scale.log === 2 ? Math.log2 : Math.log10;
if (minMax[0] <= 1) {
minMax[0] = 1;
} else {
let minExp = Math.floor(logFn(minMax[0]));
minMax[0] = logBase ** minExp;
}
let maxExp = Math.ceil(logFn(minMax[1]));
minMax[1] = logBase ** maxExp;
if (minMax[0] === minMax[1]) {
minMax[1] *= logBase;
}
} else if (scale.distr === 4) {
minMax[0] = data.incrRoundDn(minMax[0], 1);
minMax[1] = data.incrRoundUp(minMax[1], 1);
}
}
if (scale.distr === 1 || scale.distr === 4) {
if (hardMinOnly) {
minMax[0] = hardMin;
}
if (hardMaxOnly) {
minMax[1] = hardMax;
}
}
if (minMax[0] >= minMax[1]) {
minMax[0] = scale.distr === 3 ? 1 : 0;
minMax[1] = 100;
}
return minMax;
};
auto != null ? auto : auto = !isTime && !hasFixedRange;
if (data.isBooleanUnit(scaleKey)) {
auto = false;
range = [0, 1];
}
return {
[scaleKey]: {
time: isTime,
auto,
range: range != null ? range : rangeFn,
dir: direction,
ori: orientation,
...distribution
}
};
}
}
function optMinMax(minmax, a, b) {
const hasA = !(a === void 0 || a === null);
const hasB = !(b === void 0 || b === null);
if (hasA) {
if (!hasB) {
return a;
}
if (minmax === "min") {
return a < b ? a : b;
}
return a > b ? a : b;
}
return b;
}
"use strict";
const UPLOT_AXIS_FONT_SIZE = 12;
const Y_TICK_SPACING_PANEL_HEIGHT = 150;
const Y_TICK_SPACING_NORMAL = 30;
const Y_TICK_SPACING_SMALL = 15;
const X_TICK_SPACING_NORMAL = 40;
const X_TICK_VALUE_GAP = 18;
const labelPad = 8;
class UPlotAxisBuilder extends PlotConfigBuilder {
merge(props) {
this.props.size = optMinMax("max", this.props.size, props.size);
if (!this.props.label) {
this.props.label = props.label;
}
if (this.props.placement === schema.AxisPlacement.Auto) {
this.props.placement = props.placement;
}
}
getConfig() {
let {
scaleKey,
label,
show = true,
placement = schema.AxisPlacement.Auto,
grid = { show: true },
ticks,
space,
filter,
gap = 5,
formatValue,
splits,
values,
incrs,
isTime,
timeZone,
theme,
tickLabelRotation,
size,
color,
border,
decimals,
distr = schema.ScaleDistribution.Linear
} = this.props;
const font = `${UPLOT_AXIS_FONT_SIZE}px ${theme.typography.fontFamily}`;
const gridColor = theme.isDark ? "rgba(240, 250, 255, 0.09)" : "rgba(0, 10, 23, 0.09)";
if (data.isBooleanUnit(scaleKey)) {
splits = [0, 1];
}
if (decimals === 0 && distr === schema.ScaleDistribution.Linear) {
filter = (u, splits2) => splits2.map((v) => Number.isInteger(v) ? v : null);
}
let config = {
scale: scaleKey,
show,
stroke: color != null ? color : theme.colors.text.primary,
side: getUPlotSideFromAxis(placement),
font,
size: size != null ? size : (self, values2, axisIdx) => {
return calculateAxisSize(self, values2, axisIdx);
},
rotate: tickLabelRotation,
gap,
labelGap: 0,
grid: {
show: grid.show,
stroke: gridColor,
width: 1 / devicePixelRatio
},
ticks: Object.assign(
{
show: true,
stroke: (border == null ? void 0 : border.show) ? color != null ? color : theme.colors.text.primary : gridColor,
width: 1 / devicePixelRatio,
size: 4
},
ticks
),
splits,
values,
space: space != null ? space : (self, axisIdx, scaleMin, scaleMax, plotDim) => {
return calculateSpace(self, axisIdx, scaleMin, scaleMax, plotDim, formatValue);
},
filter,
incrs
};
if (border == null ? void 0 : border.show) {
config.border = {
stroke: color != null ? color : theme.colors.text.primary,
width: 1 / devicePixelRatio,
...border
};
}
if (label != null && label.length > 0) {
config.label = label;
config.labelSize = UPLOT_AXIS_FONT_SIZE + labelPad;
config.labelFont = font;
config.labelGap = labelPad;
}
if (values) {
config.values = values;
} else if (formatValue) {
config.values = (u, splits2, axisIdx, tickSpace, tickIncr) => {
let decimals2 = data.guessDecimals(data.roundDecimals(tickIncr, 6));
return splits2.map((v) => {
if (v == null) {
return null;
} else {
return formatValue(v, decimals2 > 0 ? decimals2 : void 0);
}
});
};
} else if (isTime) {
config.values = formatTime;
}
config.timeZone = timeZone;
return config;
}
}
const timeUnitSize = {
second: 1e3,
minute: 60 * 1e3,
hour: 60 * 60 * 1e3,
day: 24 * 60 * 60 * 1e3,
month: 28 * 24 * 60 * 60 * 1e3,
year: 365 * 24 * 60 * 60 * 1e3
};
function formatTime(self, splits, axisIdx, foundSpace, foundIncr) {
var _a, _b;
const axis = self.axes[axisIdx];
const timeZone = "timeZone" in axis && typeof axis.timeZone === "string" ? axis.timeZone : void 0;
const scale = self.scales.x;
const range = ((_a = scale == null ? void 0 : scale.max) != null ? _a : 0) - ((_b = scale == null ? void 0 : scale.min) != null ? _b : 0);
const yearRoundedToDay = Math.round(timeUnitSize.year / timeUnitSize.day) * timeUnitSize.day;
const incrementRoundedToDay = Math.round(foundIncr / timeUnitSize.day) * timeUnitSize.day;
let format = data.systemDateFormats.interval.year;
if (foundIncr < timeUnitSize.second) {
format = data.systemDateFormats.interval.millisecond;
} else if (foundIncr <= timeUnitSize.minute) {
format = data.systemDateFormats.interval.second;
} else if (range <= timeUnitSize.day) {
format = data.systemDateFormats.interval.minute;
} else if (foundIncr <= timeUnitSize.day) {
format = data.systemDateFormats.interval.hour;
} else if (range < timeUnitSize.year) {
format = data.systemDateFormats.interval.day;
} else if (incrementRoundedToDay === yearRoundedToDay) {
format = data.systemDateFormats.interval.year;
} else if (foundIncr <= timeUnitSize.year) {
format = data.systemDateFormats.interval.month;
}
return splits.map((v) => v == null ? "" : data.dateTimeFormat(v, { format, timeZone }));
}
function calculateSpace(self, axisIdx, scaleMin, scaleMax, plotDim, formatValue) {
const axis = self.axes[axisIdx];
const scale = self.scales[axis.scale];
if (axis.side !== 2 || !scale) {
return plotDim <= Y_TICK_SPACING_PANEL_HEIGHT ? Y_TICK_SPACING_SMALL : Y_TICK_SPACING_NORMAL;
}
const maxTicks = plotDim / X_TICK_SPACING_NORMAL;
const increment = (scaleMax - scaleMin) / maxTicks;
const bigValue = Math.max(Math.abs(scaleMin), Math.abs(scaleMax));
let sample = "";
if (scale.time) {
sample = formatTime(self, [bigValue], axisIdx, X_TICK_SPACING_NORMAL, increment)[0];
} else if (formatValue != null) {
sample = formatValue(bigValue);
} else {
return X_TICK_SPACING_NORMAL;
}
const valueWidth = measureText(sample, UPLOT_AXIS_FONT_SIZE).width;
return valueWidth + X_TICK_VALUE_GAP;
}
function calculateAxisSize(self, values, axisIdx) {
const axis = self.axes[axisIdx];
let axisSize = axis.ticks.size;
if (axis.side === 2) {
axisSize += axis.gap + UPLOT_AXIS_FONT_SIZE;
} else if (values == null ? void 0 : values.length) {
let maxTextWidth = values.reduce((acc, value) => Math.max(acc, measureText(value, UPLOT_AXIS_FONT_SIZE).width), 0);
const textWidthWithLimit = Math.min(self.width * 0.4, maxTextWidth);
axisSize += axis.gap + axis.labelGap + textWidthWithLimit;
}
return Math.ceil(axisSize);
}
function getUPlotSideFromAxis(axis) {
switch (axis) {
case schema.AxisPlacement.Top:
return 0;
case schema.AxisPlacement.Right:
return 1;
case schema.AxisPlacement.Bottom:
return 2;
case schema.AxisPlacement.Left:
}
return 3;
}
"use strict";
function makeDirectionalGradient(direction, bbox, ctx) {
let x0 = 0, y0 = 0, x1 = 0, y1 = 0;
if (direction === 3 /* Down */) {
y0 = bbox.top;
y1 = bbox.top + bbox.height;
} else if (direction === 2 /* Left */) {
x0 = bbox.left + bbox.width;
x1 = bbox.left;
} else if (direction === 1 /* Up */) {
y0 = bbox.top + bbox.height;
y1 = bbox.top;
} else if (direction === 0 /* Right */) {
x0 = bbox.left;
x1 = bbox.left + bbox.width;
}
return ctx.createLinearGradient(x0, y0, x1, y1);
}
function getOpacityGradientFn(color, opacity) {
return (plot, seriesIdx) => {
const ctx = getCanvasContext();
const gradient = makeDirectionalGradient(
plot.scales.x.ori === schema.ScaleOrientation.Horizontal ? 3 /* Down */ : 2 /* Left */,
plot.bbox,
ctx
);
gradient.addColorStop(0, data.colorManipulator.alpha(color, opacity));
gradient.addColorStop(1, data.colorManipulator.alpha(color, 0));
return gradient;
};
}
function getHueGradientFn(color, opacity, theme) {
return (plot, seriesIdx) => {
const ctx = getCanvasContext();
const gradient = makeDirectionalGradient(
plot.scales.x.ori === schema.ScaleOrientation.Horizontal ? 3 /* Down */ : 2 /* Left */,
plot.bbox,
ctx
);
const color1 = tinycolor__default.default(color).spin(-25).darken(5);
const color2 = tinycolor__default.default(color).saturate(20).spin(20).brighten(10);
if (theme.isDark) {
gradient.addColorStop(0, color2.lighten(10).setAlpha(opacity).toString());
gradient.addColorStop(1, color1.darken(10).setAlpha(opacity).toString());
} else {
gradient.addColorStop(0, color2.lighten(10).setAlpha(opacity).toString());
gradient.addColorStop(1, color1.setAlpha(opacity).toString());
}
return gradient;
};
}
var GradientDirection = /* @__PURE__ */ ((GradientDirection2) => {
GradientDirection2[GradientDirection2["Right"] = 0] = "Right";
GradientDirection2[GradientDirection2["Up"] = 1] = "Up";
GradientDirection2[GradientDirection2["Left"] = 2] = "Left";
GradientDirection2[GradientDirection2["Down"] = 3] = "Down";
return GradientDirection2;
})(GradientDirection || {});
function scaleGradient(u, scaleKey, scaleStops, discrete = false) {
let scale = u.scales[scaleKey];
let minStopIdx = null;
let maxStopIdx = null;
for (let i = 0; i < scaleStops.length; i++) {
let stopVal = scaleStops[i][0];
if (stopVal <= scale.min || minStopIdx == null) {
minStopIdx = i;
}
maxStopIdx = i;
if (stopVal >= scale.max) {
break;
}
}
if (minStopIdx === maxStopIdx) {
return scaleStops[minStopIdx][1];
}
let minStopVal = scaleStops[minStopIdx][0];
let maxStopVal = scaleStops[maxStopIdx][0];
if (minStopVal === -Infinity) {
minStopVal = scale.min;
}
if (maxStopVal === Infinity) {
maxStopVal = scale.max;
}
let minStopPos = Math.round(u.valToPos(minStopVal, scaleKey, true));
let maxStopPos = Math.round(u.valToPos(maxStopVal, scaleKey, true));
let range = minStopPos - maxStopPos;
if (range === 0) {
return scaleStops[maxStopIdx][1];
}
let x0, y0, x1, y1;
if (u.scales.x.ori === schema.ScaleOrientation.Horizontal) {
x0 = x1 = 0;
y0 = minStopPos;
y1 = maxStopPos;
} else {
y0 = y1 = 0;
x0 = minStopPos;
x1 = maxStopPos;
}
let ctx = getCanvasContext();
let grd = ctx.createLinearGradient(x0, y0, x1, y1);
let prevColor;
for (let i = minStopIdx; i <= maxStopIdx; i++) {
let s = scaleStops[i];
let stopPos = i === minStopIdx ? minStopPos : i === maxStopIdx ? maxStopPos : Math.round(u.valToPos(s[0], scaleKey, true));
let pct = (minStopPos - stopPos) / range;
if (discrete && i > minStopIdx) {
grd.addColorStop(pct, prevColor);
}
grd.addColorStop(pct, prevColor = s[1]);
}
return grd;
}
function getDataRange(plot, scaleKey) {
let sc = plot.scales[scaleKey];
let min = Infinity;
let max = -Infinity;
plot.series.forEach((ser, seriesIdx) => {
if (ser.show && ser.scale === scaleKey) {
if (ser.min == null) {
let data = plot.data[seriesIdx];
for (let i = 0; i < data.length; i++) {
if (data[i] != null) {
min = Math.min(min, data[i]);
max = Math.max(max, data[i]);
}
}
} else {
min = Math.min(min, ser.min);
max = Math.max(max, ser.max);
}
}
});
if (max === min) {
min = sc.min;
max = sc.max;
}
return [min, max];
}
function getGradientRange(u, scaleKey, hardMin, hardMax, softMin, softMax) {
var _a, _b, _c, _d;
let min = (_a = hardMin != null ? hardMin : softMin) != null ? _a : null;
let max = (_b = hardMax != null ? hardMax : softMax) != null ? _b : null;
if (min == null || max == null) {
let [dataMin, dataMax] = getDataRange(u, scaleKey);
min = (_c = min != null ? min : dataMin) != null ? _c : 0;
max = (_d = max != null ? max : dataMax) != null ? _d : 100;
}
return [min, max];
}
function isStepTransparent(color) {
return color === "transparent" || color[0] === "#" && color.slice(-2) === "00";
}
function getScaleGradientFn(opacity, theme, colorMode, thresholds, hardMin, hardMax, softMin, softMax) {
if (!colorMode) {
throw Error("Missing colorMode required for color scheme gradients");
}
if (!thresholds) {
throw Error("Missing thresholds required for color scheme gradients");
}
return (plot, seriesIdx) => {
let scaleKey = plot.series[seriesIdx].scale;
let gradient = "";
if (colorMode.id === data.FieldColorModeId.Thresholds) {
if (thresholds.mode === data.ThresholdsMode.Absolute) {
const valueStops = thresholds.steps.map((step) => [
step.value,
isStepTransparent(step.color) ? "#0000" : data.colorManipulator.alpha(theme.visualization.getColorByName(step.color), opacity)
]);
gradient = scaleGradient(plot, scaleKey, valueStops, true);
} else {
const [min, max] = getGradientRange(plot, scaleKey, hardMin, hardMax, softMin, softMax);
const range = max - min;
const valueStops = thresholds.steps.map((step) => [
min + range * (step.value / 100),
data.colorManipulator.alpha(theme.visualization.getColorByName(step.color), opacity)
]);
gradient = scaleGradient(plot, scaleKey, valueStops, true);
}
} else if (colorMode.getColors) {
const colors = colorMode.getColors(theme);
const [min, max] = getGradientRange(plot, scaleKey, hardMin, hardMax, softMin, softMax);
const range = max - min;
const valueStops = colors.map((color, i) => [
min + range * (i / (colors.length - 1)),
data.colorManipulator.alpha(theme.visualization.getColorByName(color), opacity)
]);
gradient = scaleGradient(plot, scaleKey, valueStops, false);
}
return gradient;
};
}
"use strict";
class UPlotSeriesBuilder extends PlotConfigBuilder {
getConfig() {
var _a;
const {
facets,
drawStyle,
pathBuilder,
pointsBuilder,
pointsFilter,
lineInterpolation,
lineWidth,
lineStyle,
barAlignment,
barWidthFactor,
barMaxWidth,
showPoints,
pointSize,
scaleKey,
pxAlign,
spanNulls,
show = true
} = this.props;
let lineConfig = {};
let lineColor = this.getLineColor();
lineConfig.stroke = lineColor;
lineConfig.width = lineWidth;
if (lineStyle && lineStyle.fill !== "solid") {
if (lineStyle.fill === "dot") {
lineConfig.cap = "round";
}
lineConfig.dash = (_a = lineStyle.dash) != null ? _a : [10, 10];
}
if (pathBuilder != null) {
lineConfig.paths = pathBuilder;
} else if (drawStyle === schema.GraphDrawStyle.Points) {
lineConfig.paths = () => null;
} else if (drawStyle != null) {
lineConfig.paths = (self, seriesIdx, idx0, idx1) => {
let pathsBuilder = mapDrawStyleToPathBuilder(
drawStyle,
lineInterpolation,
barAlignment,
barWidthFactor,
barMaxWidth
);
return pathsBuilder(self, seriesIdx, idx0, idx1);
};
}
const useColor = (
// @ts-ignore
typeof lineColor === "string" ? lineColor : (u, seriesIdx) => u.series[seriesIdx]._stroke
);
const pointsConfig = {
points: {
stroke: useColor,
fill: useColor,
size: !pointSize || pointSize < lineWidth ? void 0 : pointSize,
filter: pointsFilter
}
};
if (pointsBuilder != null) {
pointsConfig.points.show = pointsBuilder;
} else {
if (drawStyle === schema.GraphDrawStyle.Points) {
pointsConfig.points.show = true;
} else {
if (showPoints === schema.VisibilityMode.Auto) {
if (drawStyle === schema.GraphDrawStyle.Bars) {
pointsConfig.points.show = false;
}
} else if (showPoints === schema.VisibilityMode.Never) {
pointsConfig.points.show = false;
} else if (showPoints === schema.VisibilityMode.Always) {
pointsConfig.points.show = true;
}
}
}
return {
scale: scaleKey,
facets,
spanGaps: typeof spanNulls === "number" ? false : spanNulls,
value: () => "",
pxAlign,
show,
fill: this.getFill(),
...lineConfig,
...pointsConfig
};
}
getLineColor() {
const {
lineColor,
gradientMode,
colorMode,
thresholds,
theme,
hardMin,
hardMax,
softMin,
softMax,
dynamicSeriesColor
} = this.props;
if (gradientMode === schema.GraphGradientMode.None && dynamicSeriesColor) {
return (plot, seriesIdx) => {
var _a, _b;
return (_b = (_a = dynamicSeriesColor(seriesIdx)) != null ? _a : lineColor) != null ? _b : data.FALLBACK_COLOR;
};
}
if (gradientMode === schema.GraphGradientMode.Scheme && (colorMode == null ? void 0 : colorMode.id) !== data.FieldColorModeId.Fixed) {
return getScaleGradientFn(1, theme, colorMode, thresholds, hardMin, hardMax, softMin, softMax);
}
if (gradientMode === schema.GraphGradientMode.Hue) {
return getHueGradientFn(lineColor != null ? lineColor : data.FALLBACK_COLOR, 1, theme);
}
return lineColor != null ? lineColor : data.FALLBACK_COLOR;
}
getFill() {
const {
lineColor,
fillColor,
gradientMode,
fillOpacity,
colorMode,
thresholds,
theme,
hardMin,
hardMax,
softMin,
softMax,
dynamicSeriesColor
} = this.props;
if (fillColor) {
return fillColor;
}
const mode = gradientMode != null ? gradientMode : schema.GraphGradientMode.None;
const opacityPercent = (fillOpacity != null ? fillOpacity : 0) / 100;
if (mode === schema.GraphGradientMode.None && dynamicSeriesColor && opacityPercent > 0) {
return (u, seriesIdx) => {
let lineColor2 = u.series[seriesIdx]._stroke;
return data.colorManipulator.alpha(lineColor2 != null ? lineColor2 : "", opacityPercent);
};
}
switch (mode) {
case schema.GraphGradientMode.Opacity:
return getOpacityGradientFn(fillColor != null ? fillColor : lineColor, opacityPercent);
case schema.GraphGradientMode.Hue:
return getHueGradientFn(fillColor != null ? fillColor : lineColor, opacityPercent, theme);
case schema.GraphGradientMode.Scheme:
if ((colorMode == null ? void 0 : colorMode.id) !== data.FieldColorModeId.Fixed) {
return getScaleGradientFn(opacityPercent, theme, colorMode, thresholds, hardMin, hardMax, softMin, softMax);
}
// intentional fall-through to handle Scheme with Fixed color
default:
if (opacityPercent > 0) {
return data.colorManipulator.alpha(lineColor != null ? lineColor : "", opacityPercent);
}
}
return void 0;
}
}
let builders = void 0;
function mapDrawStyleToPathBuilder(style, lineInterpolation, barAlignment = schema.BarAlignment.Center, barWidthFactor = 0.6, barMaxWidth = 200) {
const pathBuilders = uPlot__default.default.paths;
if (!builders) {
builders = {
linear: pathBuilders.linear(),
smooth: pathBuilders.spline(),
stepBefore: pathBuilders.stepped({ align: -1 }),
stepAfter: pathBuilders.stepped({ align: 1 })
};
}
if (style === schema.GraphDrawStyle.Bars) {
let barsCfgKey = `bars|${barAlignment}|${barWidthFactor}|${barMaxWidth}`;
if (!builders[barsCfgKey]) {
builders[barsCfgKey] = pathBuilders.bars({
size: [barWidthFactor, barMaxWidth],
align: barAlignment
});
}
return builders[barsCfgKey];
} else if (style === schema.GraphDrawStyle.Line) {
if (lineInterpolation === schema.LineInterpolation.StepBefore) {
return builders.stepBefore;
}
if (lineInterpolation === schema.LineInterpolation.StepAfter) {
return builders.stepAfter;
}
if (lineInterpolation === schema.LineInterpolation.Smooth) {
return builders.smooth;
}
}
return builders.linear;
}
"use strict";
function getThresholdsDrawHook(options) {
const dashSegments = options.config.mode === schema.GraphThresholdsStyleMode.Dashed || options.config.mode === schema.GraphThresholdsStyleMode.DashedAndArea ? [10, 10] : [];
function addLines(u, yScaleKey, steps, theme2) {
let ctx = u.ctx;
let transparentIndex = 0;
for (let idx = 0; idx < steps.length; idx++) {
const step = steps[idx];
if (step.color === "transparent") {
transparentIndex = idx;
break;
}
}
ctx.lineWidth = 2;
ctx.setLineDash(dashSegments);
for (let idx = 1; idx < steps.length; idx++) {
const step = steps[idx];
let color;
if (transparentIndex >= idx && idx > 0) {
color = tinycolor__default.default(theme2.visualization.getColorByName(steps[idx - 1].color));
} else {
color = tinycolor__default.default(theme2.visualization.getColorByName(step.color));
}
if (color.getAlpha() === 1) {
color.setAlpha(0.7);
}
const isHorizontal = u.scales.x.ori === schema.ScaleOrientation.Horizontal;
const scaleVal = u.valToPos(step.value, yScaleKey, true);
let x0 = Math.round(isHorizontal ? u.bbox.left : scaleVal);
let y0 = Math.round(isHorizontal ? scaleVal : u.bbox.top);
let x1 = Math.round(isHorizontal ? u.bbox.left + u.bbox.width : scaleVal);
let y1 = Math.round(isHorizontal ? scaleVal : u.bbox.top + u.bbox.height);
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.lineTo(x1, y1);
ctx.strokeStyle = color.toString();
ctx.stroke();
}
}
function addAreas(u, yScaleKey, steps, theme2) {
let ctx = u.ctx;
let grd = scaleGradient(
u,
yScaleKey,
steps.map((step) => {
let color = tinycolor__default.default(theme2.visualization.getColorByName(step.color));
if (color.getAlpha() === 1) {
color.setAlpha(0.15);
}
return [step.value, color.toString()];
}),
true
);
ctx.fillStyle = grd;
ctx.fillRect(u.bbox.left, u.bbox.top, u.bbox.width, u.bbox.height);
}
const { scaleKey, thresholds, theme, config, hardMin, hardMax, softMin, softMax } = options;
return (u) => {
const ctx = u.ctx;
const { min: xMin, max: xMax } = u.scales.x;
const { min: yMin, max: yMax } = u.scales[scaleKey];
if (xMin == null || xMax == null || yMin == null || yMax == null) {
return;
}
let { steps, mode } = thresholds;
if (mode === data.ThresholdsMode.Percentage) {
let [min, max] = getGradientRange(u, scaleKey, hardMin, hardMax, softMin, softMax);
let range = max - min;
steps = steps.map((step) => ({
...step,
value: min + range * (step.value / 100)
}));
}
ctx.save();
switch (config.mode) {
case schema.GraphThresholdsStyleMode.Line:
case schema.GraphThresholdsStyleMode.Dashed:
addLines(u, scaleKey, steps, theme);
break;
case schema.GraphThresholdsStyleMode.Area:
addAreas(u, scaleKey, steps, theme);
break;
case schema.GraphThresholdsStyleMode.LineAndArea:
case schema.GraphThresholdsStyleMode.DashedAndArea:
addAreas(u, scaleKey, steps, theme);
addLines(u, scaleKey, steps, theme);
}
ctx.restore();
};
}
"use strict";
const cursorDefaults = {
// prevent client-side zoom from triggering at the end of a selection
drag: { setScale: false },
points: {
/*@ts-ignore*/
size: (u, seriesIdx) => u.series[seriesIdx].points.size * 2,
/*@ts-ignore*/
width: (u, seriesIdx, size) => size / 4
},
focus: {
prox: 30
}
};
class UPlotConfigBuilder {
constructor(timeZone = data.DefaultTimeZone) {
this.uid = Math.random().toString(36).slice(2);
this.series = [];
this.axes = {};
this.scales = [];
this.bands = [];
this.stackingGroups = [];
this.hasLeftAxis = false;
this.hooks = {};
this.tz = void 0;
this.mode = 1;
this.frames = void 0;
// to prevent more than one threshold per scale
this.thresholds = {};
this.padding = void 0;
this.prepData = void 0;
// Exposed to let the container know the primary scale keys
this.scaleKeys = ["", ""];
this.tzDate = (ts) => {
let date = new Date(ts);
return this.tz ? uPlot__default.default.tzDate(date, this.tz) : date;
};
var _a;
this.tz = (_a = data.getTimeZoneInfo(timeZone, Date.now())) == null ? void 0 : _a.ianaName;
}
addHook(type, hook) {
pluginLog("UPlotConfigBuilder", false, "addHook", type);
if (!this.hooks[type]) {
this.hooks[type] = [];
}
this.hooks[type].push(hook);
}
addThresholds(options) {
if (!this.thresholds[options.scaleKey]) {
this.thresholds[options.scaleKey] = options;
this.addHook("drawClear", getThresholdsDrawHook(options));
}
}
addAxis(props) {
var _a, _b, _c;
props.placement = (_a = props.placement) != null ? _a : schema.AxisPlacement.Auto;
props.grid = (_b = props.grid) != null ? _b : {};
let scaleKey = props.scaleKey;
if (scaleKey === "x") {
scaleKey += (_c = props.timeZone) != null ? _c : "";
}
if (this.axes[scaleKey]) {
this.axes[scaleKey].merge(props);
return;
}
if (props.placement === schema.AxisPlacement.Auto) {
props.placement = this.hasLeftAxis ? schema.AxisPlacement.Right : schema.AxisPlacement.Left;
}
if (props.placement === schema.AxisPlacement.Left) {
this.hasLeftAxis = true;
}
if (props.placement === schema.AxisPlacement.Hidden) {
props.grid.show = false;
props.size = 0;
}
this.axes[scaleKey] = new UPlotAxisBuilder(props);
}
getAxisPlacement(scaleKey) {
var _a;
const axis = this.axes[scaleKey];
return (_a = axis == null ? void 0 : axis.props.placement) != null ? _a : schema.AxisPlacement.Left;
}
setCursor(cursor) {
this.cursor = lodash.merge({}, this.cursor, cursor);
}
setMode(mode) {
this.mode = mode;
}
setSelect(select) {
this.select = select;
}
addSeries(props) {
this.series.push(new UPlotSeriesBuilder(props));
}
getSeries() {
return this.series;
}
/** Add or update the scale with the scale key */
addScale(props) {
const current = this.scales.find((v) => v.props.scaleKey === props.scaleKey);
if (current) {
current.merge(props);
return;
}
this.scales.push(new UPlotScaleBuilder(props));
}
addBand(band) {
this.bands.push(band);
}
setStackingGroups(groups) {
this.stackingGroups = groups;
}
getStackingGroups() {
return this.stackingGroups;
}
setPrepData(prepData) {
this.prepData = (frames) => {
this.frames = frames;
return prepData(frames, this.getStackingGroups());
};
}
setPadding(padding) {
this.padding = padding;
}
getConfig() {
if (this.cachedConfig) {
return this.cachedConfig;
}
const config = {
...DEFAULT_PLOT_CONFIG,
mode: this.mode,
series: [
this.mode === 2 ? null : {
value: () => ""
}
]
};
config.axes = this.ensureNonOverlappingAxes(Object.values(this.axes)).map((a) => a.getConfig());
config.series = [...config.series, ...this.series.map((s) => s.getConfig())];
config.scales = this.scales.reduce((acc, s) => {
return { ...acc, ...s.getConfig() };
}, {});
config.hooks = this.hooks;
config.select = this.select;
const pointColorFn = (alphaHex = "") => (u, seriesIdx) => {
let s = u.series[seriesIdx].points._stroke;
if (typeof s !== "string") {
let field = this.frames[0].fields[seriesIdx];
s = field.display(field.values[u.cursor.idxs[seriesIdx]]).color;
}
return s + alphaHex;
};
config.cursor = lodash.merge(
{},
cursorDefaults,
{
points: {
stroke: pointColorFn("80"),
fill: pointColorFn()
}
},
this.cursor
);
config.tzDate = this.tzDate;
if (Array.isArray(this.padding)) {
config.padding = this.padding;
}
this.stackingGroups.forEach((group) => {
getStackingBands(group).forEach((band) => {
this.addBand(band);
});
});
if (this.bands.length) {
config.bands = this.bands;
}
this.cachedConfig = config;
return config;
}
ensureNonOverlappingAxes(axes) {
const xAxis = axes.find((a) => a.props.scaleKey === "x");
const axesWithoutGridSet = axes.filter((a) => {
var _a;
return ((_a = a.props.grid) == null ? void 0 : _a.show) === void 0;
});
const firstValueAxisIdx = axesWithoutGridSet.findIndex(
(a) => a.props.placement === schema.AxisPlacement.Left || a.props.placement === schema.AxisPlacement.Right || a.props.placement === schema.AxisPlacement.Bottom && a !== xAxis
);
for (let i = 0; i < axesWithoutGridSet.length; i++) {
if (axesWithoutGridSet[i] === xAxis || i === firstValueAxisIdx) {
axesWithoutGridSet[i].props.grid.show = true;
} else {
axesWithoutGridSet[i].props.grid.show = false;
}
}
return axes;
}
}
"use strict";
function preparePlotFrame(sparkline, config) {
var _a, _b, _c;
const length = sparkline.y.values.length;
const yFieldConfig = {
...sparkline.y.config,
...config
};
const xField = (_a = sparkline.x) != null ? _a : {
name: "",
values: [...Array(length).keys()],
type: data.FieldType.number,
config: {}
};
let frame = {
refId: "sparkline",
fields: [
xField,
{
...sparkline.y,
config: yFieldConfig
}
],
length
};
if (!data.isLikelyAscendingVector(xField.values)) {
frame = data.sortDataFrame(frame, 0);
}
return data.applyNullInsertThreshold({
frame,
refFieldPseudoMin: (_b = sparkline.timeRange) == null ? void 0 : _b.from.valueOf(),
refFieldPseudoMax: (_c = sparkline.timeRange) == null ? void 0 : _c.to.valueOf()
});
}
function getYRange(field, alignedFrame) {
var _a, _b, _c, _d;
let { min, max } = (_a = alignedFrame.fields[1].state) == null ? void 0 : _a.range;
min = Math.max(min, (_b = field.config.min) != null ? _b : -Infinity);
max = Math.min(max, (_c = field.config.max) != null ? _c : Infinity);
const noValue = +((_d = alignedFrame.fields[1].config) == null ? void 0 : _d.noValue);
if (!Number.isNaN(noValue)) {
min = Math.min(min, noValue);
max = Math.max(max, noValue);
}
if (min === max) {
if (min === 0) {
max = 100;
} else if (min < 0) {
max = 0;
min *= 2;
} else {
min = 0;
max *= 2;
}
}
return [min, max];
}
"use strict";
const defaultConfig = {
drawStyle: schema.GraphDrawStyle.Line,
showPoints: schema.VisibilityMode.Auto,
axisPlacement: schema.AxisPlacement.Hidden,
pointSize: 2
};
class Sparkline extends React.PureComponent {
constructor(props) {
super(props);
const alignedDataFrame = preparePlotFrame(props.sparkline, props.config);
this.state = {
data: preparePlotData2(alignedDataFrame, getStackingGroups(alignedDataFrame)),
alignedDataFrame,
configBuilder: this.prepareConfig(alignedDataFrame)
};
}
static getDerivedStateFromProps(props, state) {
const _frame = preparePlotFrame(props.sparkline, props.config);
const frame = data.nullToValue(_frame);
if (!frame) {
return { ...state };
}
return {
...state,
data: preparePlotData2(frame, getStackingGroups(frame)),
alignedDataFrame: frame
};
}
componentDidUpdate(prevProps, prevState) {
var _a, _b;
const { alignedDataFrame } = this.state;
if (!alignedDataFrame) {
return;
}
let rebuildConfig = false;
if (prevProps.sparkline !== this.props.sparkline) {
const isStructureChanged = !data.compareDataFrameStructures(this.state.alignedDataFrame, prevState.alignedDataFrame);
const isRangeChanged = !lodash.isEqual(
(_a = alignedDataFrame.fields[1].state) == null ? void 0 : _a.range,
(_b = prevState.alignedDataFrame.fields[1].state) == null ? void 0 : _b.range
);
rebuildConfig = isStructureChanged || isRangeChanged;
} else {
rebuildConfig = !lodash.isEqual(prevProps.config, this.props.config);
}
if (rebuildConfig) {
this.setState({ configBuilder: this.prepareConfig(alignedDataFrame) });
}
}
getYRange(field) {
return getYRange(field, this.state.alignedDataFrame);
}
prepareConfig(data$1) {
var _a;
const { theme } = this.props;
const builder = new UPlotConfigBuilder();
builder.setCursor({
show: false,
x: false,
// no crosshairs
y: false
});
const xField = data$1.fields[0];
builder.addScale({
scaleKey: "x",
orientation: schema.ScaleOrientation.Horizontal,
direction: schema.ScaleDirection.Right,
isTime: false,
//xField.type === FieldType.time,
range: () => {
const { sparkline } = this.props;
if (sparkline.x) {
if (sparkline.timeRange && sparkline.x.type === data.FieldType.time) {
return [sparkline.timeRange.from.valueOf(), sparkline.timeRange.to.valueOf()];
}
const vals = sparkline.x.values;
return [vals[0], vals[vals.length - 1]];
}
return [0, sparkline.y.values.length - 1];
}
});
builder.addAxis({
scaleKey: "x",
theme,
placement: schema.AxisPlacement.Hidden
});
for (let i = 0; i < data$1.fields.length; i++) {
const field = data$1.fields[i];
const config = field.config;
const customConfig = {
...defaultConfig,
...config.custom
};
if (field === xField || field.type !== data.FieldType.number) {
continue;
}
const scaleKey = config.unit || "__fixed";
builder.addScale({
scaleKey,
orientation: schema.ScaleOrientation.Vertical,
direction: schema.ScaleDirection.Up,
range: () => this.getYRange(field)
});
builder.addAxis({
scaleKey,
theme,
placement: schema.AxisPlacement.Hidden
});
const colorMode = data.getFieldColorModeForField(field);
const seriesColor = colorMode.getCalculator(field, theme)(0, 0);
const pointsMode = customConfig.drawStyle === schema.GraphDrawStyle.Points ? schema.VisibilityMode.Always : customConfig.showPoints;
builder.addSeries({
pxAlign: false,
scaleKey,
theme,
colorMode,
thresholds: config.thresholds,
drawStyle: customConfig.drawStyle,
lineColor: (_a = customConfig.lineColor) != null ? _a : seriesColor,
lineWidth: customConfig.lineWidth,
lineInterpolation: customConfig.lineInterpolation,
showPoints: pointsMode,
pointSize: customConfig.pointSize,
fillOpacity: customConfig.fillOpacity,
fillColor: customConfig.fillColor,
lineStyle: customConfig.lineStyle,
gradientMode: customConfig.gradientMode,
spanNulls: customConfig.spanNulls
});
}
return builder;
}
render() {
const { data, configBuilder } = this.state;
const { width, height } = this.props;
return /* @__PURE__ */ jsxRuntime.jsx(UPlotChart, { data, config: configBuilder, width, height });
}
}
"use strict";
const defaultSparklineCellConfig = {
type: schema.TableCellDisplayMode.Sparkline,
drawStyle: schema.GraphDrawStyle.Line,
lineInterpolation: schema.LineInterpolation.Smooth,
lineWidth: 1,
fillOpacity: 17,
gradientMode: schema.GraphGradientMode.Hue,
pointSize: 2,
barAlignment: schema.BarAlignment.Center,
showPoints: schema.VisibilityMode.Never,
hideValue: false
};
const SparklineCell = (props) => {
var _a, _b;
const { field, value, theme, timeRange, rowIdx, width } = props;
const sparkline = prepareSparklineValue(value, field);
if (!sparkline) {
return /* @__PURE__ */ jsxRuntime.jsx(MaybeWrapWithLink, { field, rowIdx, children: field.config.noValue || i18n.t("grafana-ui.table.sparkline.no-data", "no data") });
}
if (sparkline.x && !sparkline.x.config.interval && sparkline.x.values.length > 1) {
sparkline.x.config.interval = sparkline.x.values[1] - sparkline.x.values[0];
}
sparkline.y.values = sparkline.y.values.map((v) => {
if (!Number.isFinite(v)) {
return null;
} else {
return v;
}
});
const range = data.getMinMaxAndDelta(sparkline.y);
sparkline.y.config.min = range.min;
sparkline.y.config.max = range.max;
sparkline.y.state = { range };
sparkline.timeRange = timeRange;
const cellOptions = getTableSparklineCellOptions(field);
const config = {
color: field.config.color,
custom: {
...defaultSparklineCellConfig,
...cellOptions
}
};
const hideValue = cellOptions.hideValue;
let valueWidth = 0;
let valueElement = null;
if (!hideValue) {
const newValue = data.isDataFrameWithValue(value) ? value.value : null;
const displayValue = field.display(newValue);
const alignmentFactor = getAlignmentFactor(field, displayValue, rowIdx);
valueWidth = measureText(`${(_a = alignmentFactor.prefix) != null ? _a : ""}${alignmentFactor.text}${(_b = alignmentFactor.suffix) != null ? _b : ""}`, 16).width + theme.spacing.gridSize;
valueElement = /* @__PURE__ */ jsxRuntime.jsx(FormattedValueDisplay, { style: { width: valueWidth }, value: displayValue });
}
return /* @__PURE__ */ jsxRuntime.jsxs(MaybeWrapWithLink, { field, rowIdx, children: [
valueElement,
/* @__PURE__ */ jsxRuntime.jsx(Sparkline, { width: width - valueWidth, height: 25, sparkline, config, theme })
] });
};
function getTableSparklineCellOptions(field) {
let options = getCellOptions(field);
if (options.type === schema.TableCellDisplayMode.Auto) {
options = { ...options, type: schema.TableCellDisplayMode.Sparkline };
}
if (options.type === schema.TableCellDisplayMode.Sparkline) {
return options;
}
throw new Error(`Expected options type ${schema.TableCellDisplayMode.Sparkline} but got ${options.type}`);
}
const getStyles$b = (theme, { textAlign }) => css.css({
"&, & > a": {
width: "100%",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
gap: theme.spacing(1),
...textAlign === "right" && { flexDirection: "row-reverse" }
}
});
"use strict";
const AutoCellRenderer = React.memo((props) => /* @__PURE__ */ jsxRuntime.jsx(AutoCell, { value: props.value, field: props.field, rowIdx: props.rowIdx }));
AutoCellRenderer.displayName = "AutoCellRenderer";
function isCustomCellOptions(options) {
return options.type === schema.TableCellDisplayMode.Custom;
}
function mixinAutoCellStyles(fn) {
return (theme, options) => {
const styles = fn(theme, options);
return clsx.clsx(styles, getStyles$g(theme, options));
};
}
const CELL_REGISTRY = {
[schema.TableCellDisplayMode.Auto]: {
renderer: AutoCellRenderer,
getStyles: getStyles$g
},
[schema.TableCellDisplayMode.ColorBackground]: {
renderer: AutoCellRenderer,
getStyles: getStyles$g
},
[schema.TableCellDisplayMode.ColorText]: {
renderer: AutoCellRenderer,
getStyles: getStyles$g
},
[schema.TableCellDisplayMode.JSONView]: {
renderer: AutoCellRenderer,
getStyles: mixinAutoCellStyles(getJsonCellStyles)
},
[schema.TableCellDisplayMode.Actions]: {
// eslint-disable-next-line react/display-name
renderer: React.memo((props) => {
var _a;
return /* @__PURE__ */ jsxRuntime.jsx(ActionsCell, { field: props.field, rowIdx: props.rowIdx, getActions: (_a = props.getActions) != null ? _a : () => [] });
}),
getStyles: getStyles$h
},
[schema.TableCellDisplayMode.DataLinks]: {
// eslint-disable-next-line react/display-name
renderer: React.memo((props) => /* @__PURE__ */ jsxRuntime.jsx(DataLinksCell, { field: props.field, rowIdx: props.rowIdx })),
getStyles: getStyles$f
},
[schema.TableCellDisplayMode.Gauge]: {
// eslint-disable-next-line react/display-name
renderer: React.memo((props) => /* @__PURE__ */ jsxRuntime.jsx(
BarGaugeCell,
{
field: props.field,
value: props.value,
theme: props.theme,
height: props.height,
width: props.width,
rowIdx: props.rowIdx
}
))
},
[schema.TableCellDisplayMode.Sparkline]: {
// eslint-disable-next-line react/display-name
renderer: React.memo((props) => /* @__PURE__ */ jsxRuntime.jsx(
SparklineCell,
{
value: props.value,
field: props.field,
timeRange: props.timeRange,
rowIdx: props.rowIdx,
theme: props.theme,
width: props.width
}
)),
getStyles: getStyles$b
},
[schema.TableCellDisplayMode.Geo]: {
// eslint-disable-next-line react/display-name
renderer: React.memo((props) => /* @__PURE__ */ jsxRuntime.jsx(GeoCell, { value: props.value, height: props.height })),
getStyles: getStyles$e
},
[schema.TableCellDisplayMode.Image]: {
// eslint-disable-next-line react/display-name
renderer: React.memo((props) => /* @__PURE__ */ jsxRuntime.jsx(ImageCell, { cellOptions: props.cellOptions, field: props.field, value: props.value, rowIdx: props.rowIdx })),
getStyles: getStyles$d
},
[schema.TableCellDisplayMode.Pill]: {
// eslint-disable-next-line react/display-name
renderer: React.memo((props) => /* @__PURE__ */ jsxRuntime.jsx(
PillCell,
{
rowIdx: props.rowIdx,
field: props.field,
theme: props.theme,
getTextColorForBackground: props.getTextColorForBackground
}
)),
getStyles: getStyles$i,
testField: (field) => field.type === data.FieldType.string || field.type === data.FieldType.other && field.values.some((val) => Array.isArray(val))
},
[schema.TableCellDisplayMode.Markdown]: {
// eslint-disable-next-line react/display-name
renderer: React.memo((props) => /* @__PURE__ */ jsxRuntime.jsx(MarkdownCell, { field: props.field, rowIdx: props.rowIdx, disableSanitizeHtml: props.disableSanitizeHtml })),
getStyles: getStyles$c,
testField: (field) => field.type === data.FieldType.string
},
[schema.TableCellDisplayMode.Custom]: {
// eslint-disable-next-line react/display-name
renderer: React.memo((props) => {
if (!isCustomCellOptions(props.cellOptions) || !props.cellOptions.cellComponent) {
return null;
}
const CustomCellComponent = props.cellOptions.cellComponent;
return /* @__PURE__ */ jsxRuntime.jsx(CustomCellComponent, { field: props.field, rowIndex: props.rowIdx, frame: props.frame, value: props.value });
})
}
};
function getCellRenderer(field, cellOptions = getCellOptions(field)) {
var _a, _b, _c, _d;
const cellType = (_a = cellOptions == null ? void 0 : cellOptions.type) != null ? _a : schema.TableCellDisplayMode.Auto;
if (cellType === schema.TableCellDisplayMode.Auto) {
return CELL_REGISTRY[getAutoRendererDisplayMode(field)].renderer;
}
if (((_b = CELL_REGISTRY[cellType]) == null ? void 0 : _b.testField) && CELL_REGISTRY[cellType].testField(field) !== true) {
return AutoCellRenderer;
}
return (_d = (_c = CELL_REGISTRY[cellType]) == null ? void 0 : _c.renderer) != null ? _d : AutoCellRenderer;
}
function getCellSpecificStyles(cellType, field, theme, options) {
var _a, _b;
if (cellType === schema.TableCellDisplayMode.Auto) {
return getAutoRendererStyles(theme, options, field);
}
return (_b = (_a = CELL_REGISTRY[cellType]) == null ? void 0 : _a.getStyles) == null ? void 0 : _b.call(_a, theme, options);
}
function getAutoRendererStyles(theme, options, field) {
var _a, _b;
const impliedDisplayMode = getAutoRendererDisplayMode(field);
if (impliedDisplayMode !== schema.TableCellDisplayMode.Auto) {
return (_b = (_a = CELL_REGISTRY[impliedDisplayMode]) == null ? void 0 : _a.getStyles) == null ? void 0 : _b.call(_a, theme, options);
}
return getStyles$g(theme, options);
}
function getAutoRendererDisplayMode(field) {
if (field.type === data.FieldType.geo) {
return schema.TableCellDisplayMode.Geo;
}
if (field.type === data.FieldType.frame) {
const firstValue = field.values[0];
if (data.isDataFrame(firstValue) && data.isTimeSeriesFrame(firstValue)) {
return schema.TableCellDisplayMode.Sparkline;
}
}
return schema.TableCellDisplayMode.Auto;
}
"use strict";
function Popover({
content,
show,
placement,
className,
wrapperClassName,
referenceElement,
renderArrow,
hidePopper,
style: styleOverrides,
...rest
}) {
const theme = useTheme2();
const arrowRef = React.useRef(null);
const floatingUIPlacement = getPlacement(placement);
const middleware = [react.offset(8), ...getPositioningMiddleware(floatingUIPlacement)];
if (renderArrow) {
middleware.push(
react.arrow({
element: arrowRef
})
);
}
const { context, refs, floatingStyles } = react.useFloating({
open: show,
placement: floatingUIPlacement,
middleware,
whileElementsMounted: react.autoUpdate,
strategy: "fixed"
});
React.useLayoutEffect(() => {
refs.setReference(referenceElement);
}, [referenceElement, refs]);
const { styles: placementStyles } = react.useTransitionStyles(context, {
initial: () => ({
opacity: 0
}),
duration: theme.transitions.duration.enteringScreen
});
return show ? /* @__PURE__ */ jsxRuntime.jsx(Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
ref: refs.setFloating,
style: {
...floatingStyles,
...placementStyles,
...styleOverrides
},
className: wrapperClassName,
...rest,
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
renderArrow && /* @__PURE__ */ jsxRuntime.jsx(react.FloatingArrow, { fill: theme.colors.border.weak, ref: arrowRef, context }),
typeof content === "string" && content,
React__namespace.isValidElement(content) && React__namespace.cloneElement(content),
typeof content === "function" && content({ hidePopper })
] })
}
) }) : void 0;
}
"use strict";
const Checkbox = React__namespace.forwardRef(
({ label, description, value, htmlValue, onChange, disabled, className, indeterminate, invalid, ...inputProps }, ref) => {
const handleOnChange = React.useCallback(
(e) => {
if (onChange) {
onChange(e);
}
},
[onChange]
);
const styles = useStyles2(getCheckboxStyles, invalid);
return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: css.cx(styles.wrapper, className), children: [
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.checkboxWrapper, children: [
/* @__PURE__ */ jsxRuntime.jsx(
"input",
{
type: "checkbox",
className: css.cx(styles.input, indeterminate && styles.inputIndeterminate),
checked: value,
disabled,
onChange: handleOnChange,
value: htmlValue,
...inputProps,
ref: (element) => {
if (element && indeterminate) {
element.indeterminate = true;
}
if (ref) {
if (typeof ref === "function") {
ref(element);
} else {
ref.current = element;
}
}
}
}
),
/* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.checkmark })
] }),
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.label, children: label }),
description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.description, children: description })
] });
}
);
const getCheckboxStyles = (theme, invalid = false) => {
const labelStyles = getLabelStyles(theme);
const checkboxSize = 2;
const labelPadding = 1;
const getBorderColor = (color) => {
return invalid ? theme.colors.error.border : color;
};
return {
wrapper: css.css({
display: "inline-grid",
alignItems: "center",
columnGap: theme.spacing(labelPadding),
// gridAutoRows is needed to prevent https://github.com/grafana/grafana/issues/68570 in safari
gridAutoRows: "max-content",
position: "relative",
verticalAlign: "middle"
}),
input: css.css({
position: "absolute",
zIndex: 1,
top: 0,
left: 0,
width: "100% !important",
// global styles unset this
height: "100%",
opacity: 0,
"&:focus + span, &:focus-visible + span": getFocusStyles(theme),
"&:focus:not(:focus-visible) + span": getMouseFocusStyles(theme),
/**
* Using adjacent sibling selector to style checked state.
* Primarily to limit the classes necessary to use when these classes will be used
* for angular components styling
* */
"&:checked + span": {
background: theme.colors.primary.main,
border: `1px solid ${getBorderColor(theme.colors.primary.main)}`,
"&:hover": {
background: theme.colors.primary.shade
},
"&:after": {
content: '""',
position: "absolute",
zIndex: 2,
left: theme.spacing(0.5),
top: 0,
width: theme.spacing(0.75),
height: theme.spacing(1.5),
border: `solid ${theme.colors.primary.contrastText}`,
borderWidth: "0 3px 3px 0",
transform: "rotate(45deg)"
}
},
"&:disabled + span": {
backgroundColor: theme.colors.action.disabledBackground,
cursor: "not-allowed",
border: `1px solid ${getBorderColor(theme.colors.action.disabledBackground)}`,
"&:hover": {
backgroundColor: theme.colors.action.disabledBackground
},
"&:after": {
borderColor: theme.colors.action.disabledText
}
}
}),
inputIndeterminate: css.css({
"&:indeterminate + span": {
border: `1px solid ${getBorderColor(theme.colors.primary.main)}`,
background: theme.colors.primary.main,
"&:hover": {
background: theme.colors.primary.shade
},
"&:after": {
content: '""',
position: "absolute",
zIndex: 2,
left: "2px",
right: "2px",
top: "calc(50% - 1.5px)",
height: "3px",
border: `1.5px solid ${theme.colors.primary.contrastText}`,
backgroundColor: theme.colors.primary.contrastText,
width: "auto",
transform: "none"
}
},
"&:disabled[aria-checked='mixed'] + span": {
backgroundColor: theme.colors.action.disabledBackground,
border: `1px solid ${getBorderColor(theme.colors.error.transparent)}`,
"&:after": {
borderColor: theme.colors.action.disabledText
}
}
}),
checkboxWrapper: css.css({
display: "flex",
alignItems: "center",
gridColumnStart: 1,
gridRowStart: 1
}),
checkmark: css.css({
position: "relative",
zIndex: 2,
display: "inline-block",
width: theme.spacing(checkboxSize),
height: theme.spacing(checkboxSize),
borderRadius: theme.shape.radius.sm,
background: theme.components.input.background,
border: `1px solid ${getBorderColor(theme.components.input.borderColor)}`,
"&:hover": {
cursor: "pointer",
borderColor: getBorderColor(theme.components.input.borderHover)
}
}),
label: css.cx(
labelStyles.label,
css.css({
gridColumnStart: 2,
gridRowStart: 1,
position: "relative",
zIndex: 2,
cursor: "pointer",
maxWidth: "fit-content",
lineHeight: theme.typography.bodySmall.lineHeight,
marginBottom: 0
})
),
description: css.cx(
labelStyles.description,
css.css({
gridColumnStart: 2,
gridRowStart: 2,
lineHeight: theme.typography.bodySmall.lineHeight,
marginTop: 0,
// Enable interacting with description when checkbox is disabled
zIndex: 1
})
)
};
};
Checkbox.displayName = "Checkbox";
"use strict";
function ClickOutsideWrapper({
includeButtonPress = true,
parent = window,
useCapture = false,
onClick,
children
}) {
const wrapperRef = React.useRef(null);
const onOutsideClick = React.useCallback(
(event) => {
const domNode = wrapperRef.current;
if (!domNode || event.target instanceof Node && !domNode.contains(event.target)) {
onClick();
}
},
[onClick]
);
React.useEffect(() => {
parent.addEventListener("click", onOutsideClick, useCapture);
if (includeButtonPress) {
parent.addEventListener("keyup", onOutsideClick, useCapture);
}
return () => {
parent.removeEventListener("click", onOutsideClick, useCapture);
if (includeButtonPress) {
parent.removeEventListener("keyup", onOutsideClick, useCapture);
}
};
}, [includeButtonPress, onOutsideClick, parent, useCapture]);
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: wrapperRef, children });
}
"use strict";
function MenuDivider() {
const styles = useStyles2(getStyles$a);
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.divider });
}
const getStyles$a = (theme) => {
return {
divider: css.css({
height: 1,
backgroundColor: theme.colors.border.weak,
margin: theme.spacing(0.5, 0)
})
};
};
"use strict";
const MenuGroup = ({ label, ariaLabel, children }) => {
const styles = useStyles2(getStyles$9);
const labelID = `group-label-${lodash.uniqueId()}`;
return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", "aria-labelledby": !ariaLabel && label ? labelID : void 0, "aria-label": ariaLabel, children: [
label && /* @__PURE__ */ jsxRuntime.jsx("label", { id: labelID, className: styles.groupLabel, "aria-hidden": true, children: label }),
children
] });
};
MenuGroup.displayName = "MenuGroup";
const getStyles$9 = (theme) => {
return {
groupLabel: css.css({
color: theme.colors.text.secondary,
fontSize: theme.typography.size.sm,
padding: theme.spacing(0.5, 1)
})
};
};
"use strict";
const modulo = (a, n) => (a % n + n) % n;
const UNFOCUSED = -1;
const useMenuFocus = ({
localRef,
isMenuOpen,
close,
onOpen,
onClose,
onKeyDown
}) => {
const [focusedItem, setFocusedItem] = React.useState(UNFOCUSED);
React.useEffect(() => {
if (isMenuOpen) {
setFocusedItem(0);
}
}, [isMenuOpen]);
React.useEffect(() => {
var _a, _b;
const menuItems = (_a = localRef == null ? void 0 : localRef.current) == null ? void 0 : _a.querySelectorAll(
'[data-role="menuitem"]:not([data-disabled])'
);
(_b = menuItems == null ? void 0 : menuItems[focusedItem]) == null ? void 0 : _b.focus();
menuItems == null ? void 0 : menuItems.forEach((menuItem, i) => {
menuItem.tabIndex = i === focusedItem ? 0 : -1;
});
}, [localRef, focusedItem]);
reactUse.useEffectOnce(() => {
onOpen == null ? void 0 : onOpen(setFocusedItem);
});
const handleKeys = (event) => {
var _a, _b, _c;
const menuItems = (_a = localRef == null ? void 0 : localRef.current) == null ? void 0 : _a.querySelectorAll(
'[data-role="menuitem"]:not([data-disabled])'
);
const menuItemsCount = (_b = menuItems == null ? void 0 : menuItems.length) != null ? _b : 0;
switch (event.key) {
case "ArrowUp":
event.preventDefault();
event.stopPropagation();
setFocusedItem(modulo(focusedItem - 1, menuItemsCount));
break;
case "ArrowDown":
event.preventDefault();
event.stopPropagation();
setFocusedItem(modulo(focusedItem + 1, menuItemsCount));
break;
case "ArrowLeft":
event.preventDefault();
event.stopPropagation();
setFocusedItem(UNFOCUSED);
close == null ? void 0 : close();
break;
case "Home":
event.preventDefault();
event.stopPropagation();
setFocusedItem(0);
break;
case "End":
event.preventDefault();
event.stopPropagation();
setFocusedItem(menuItemsCount - 1);
break;
case "Enter":
event.preventDefault();
event.stopPropagation();
(_c = menuItems == null ? void 0 : menuItems[focusedItem]) == null ? void 0 : _c.click();
break;
case "Escape":
onClose == null ? void 0 : onClose();
break;
case "Tab":
event.preventDefault();
onClose == null ? void 0 : onClose();
break;
default:
break;
}
onKeyDown == null ? void 0 : onKeyDown(event);
};
return [handleKeys];
};
"use strict";
const isElementOverflowing = (element) => {
if (!element) {
return false;
}
const wrapperPos = element.parentElement.getBoundingClientRect();
const pos = element.getBoundingClientRect();
return pos.width !== 0 && wrapperPos.right + pos.width + 10 > window.innerWidth;
};
"use strict";
const SubMenu = React.memo(({ items, isOpen, close, customStyle }) => {
const styles = useStyles2(getStyles$8);
const localRef = React.useRef(null);
const [handleKeys] = useMenuFocus({
localRef,
isMenuOpen: isOpen,
close
});
const [pushLeft, setPushLeft] = React.useState(false);
React.useEffect(() => {
if (isOpen && localRef.current) {
setPushLeft(isElementOverflowing(localRef.current));
}
}, [isOpen]);
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
/* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.iconWrapper, "aria-hidden": true, "data-testid": e2eSelectors.selectors.components.Menu.SubMenu.icon, children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "angle-right", className: styles.icon }) }),
isOpen && /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
ref: localRef,
className: css.cx(styles.subMenu, { [styles.pushLeft]: pushLeft }),
"data-testid": e2eSelectors.selectors.components.Menu.SubMenu.container,
style: customStyle,
children: /* @__PURE__ */ jsxRuntime.jsx("div", { tabIndex: -1, className: styles.itemsWrapper, role: "menu", onKeyDown: handleKeys, children: items })
}
)
] });
});
SubMenu.displayName = "SubMenu";
const getStyles$8 = (theme) => {
return {
iconWrapper: css.css({
display: "flex",
flex: 1,
justifyContent: "end"
}),
icon: css.css({
opacity: 0.7,
marginLeft: theme.spacing(1),
color: theme.colors.text.secondary
}),
itemsWrapper: css.css({
background: theme.colors.background.elevated,
padding: theme.spacing(0.5),
boxShadow: theme.shadows.z3,
display: "inline-block",
borderRadius: theme.shape.radius.default
}),
pushLeft: css.css({
right: "100%",
left: "unset"
}),
subMenu: css.css({
position: "absolute",
top: 0,
left: "100%",
zIndex: theme.zIndex.dropdown
})
};
};
"use strict";
const MenuItem = React__namespace.memo(
React__namespace.forwardRef((props, ref) => {
const {
url,
icon,
label,
description,
ariaLabel,
ariaChecked,
target,
onClick,
className,
active,
disabled,
destructive,
childItems,
role,
tabIndex = -1,
customSubMenuContainerStyles,
shortcut,
testId
} = props;
const styles = useStyles2(getStyles$7);
const [isActive, setIsActive] = React.useState(active);
const [isSubMenuOpen, setIsSubMenuOpen] = React.useState(false);
const onMouseEnter = React.useCallback(() => {
if (disabled) {
return;
}
setIsSubMenuOpen(true);
setIsActive(true);
}, [disabled]);
const onMouseLeave = React.useCallback(() => {
if (disabled) {
return;
}
setIsSubMenuOpen(false);
setIsActive(false);
}, [disabled]);
const hasSubMenu = childItems && childItems.length > 0;
const ItemElement = hasSubMenu ? "div" : url === void 0 ? "button" : "a";
const itemStyle = css.cx(
{
[styles.item]: true,
[styles.active]: isActive,
[styles.disabled]: disabled,
[styles.destructive]: destructive && !disabled
},
className
);
const disabledProps = {
[ItemElement === "button" ? "disabled" : "aria-disabled"]: disabled,
...ItemElement === "a" && disabled && { href: void 0, onClick: void 0 },
...disabled && {
tabIndex: -1,
["data-disabled"]: disabled
// used to identify disabled items in Menu.tsx
}
};
const localRef = React.useRef(null);
React.useImperativeHandle(ref, () => localRef.current);
const handleKeys = (event) => {
switch (event.key) {
case "ArrowRight":
event.preventDefault();
event.stopPropagation();
if (hasSubMenu) {
setIsSubMenuOpen(true);
setIsActive(true);
}
break;
default:
break;
}
};
const closeSubMenu = () => {
var _a;
setIsSubMenuOpen(false);
setIsActive(false);
(_a = localRef == null ? void 0 : localRef.current) == null ? void 0 : _a.focus();
};
const hasShortcut = Boolean(shortcut && shortcut.length > 0);
return /* @__PURE__ */ jsxRuntime.jsxs(
ItemElement,
{
target,
className: itemStyle,
rel: target === "_blank" ? "noopener noreferrer" : void 0,
href: url,
onClick: (event) => {
if (hasSubMenu && !isSubMenuOpen) {
event.preventDefault();
event.stopPropagation();
}
onClick == null ? void 0 : onClick(event);
},
onMouseEnter,
onMouseLeave,
onKeyDown: handleKeys,
role: !url ? role || "menuitem" : role,
"data-role": "menuitem",
ref: localRef,
"data-testid": testId,
"aria-label": ariaLabel,
"aria-checked": ariaChecked,
tabIndex,
...disabledProps,
children: [
/* @__PURE__ */ jsxRuntime.jsxs(Stack, { direction: "row", justifyContent: "flex-start", alignItems: "center", children: [
icon && /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon, className: styles.icon, "aria-hidden": true }),
/* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.ellipsis, children: label }),
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: css.cx(styles.rightWrapper, { [styles.withShortcut]: hasShortcut }), children: [
hasShortcut && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.shortcut, children: [
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "keyboard", title: i18n.t("grafana-ui.menu-item.keyboard-shortcut-label", "Keyboard shortcut") }),
shortcut
] }),
hasSubMenu && /* @__PURE__ */ jsxRuntime.jsx(
SubMenu,
{
items: childItems,
isOpen: isSubMenuOpen,
close: closeSubMenu,
customStyle: customSubMenuContainerStyles
}
)
] })
] }),
description && /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: css.cx(styles.description, styles.ellipsis, {
[styles.descriptionWithIcon]: icon !== void 0
}),
children: description
}
),
props.component ? /* @__PURE__ */ jsxRuntime.jsx(props.component, {}) : null
]
}
);
})
);
MenuItem.displayName = "MenuItem";
const getStyles$7 = (theme) => {
const menuPadding = theme.components.menu.padding * theme.spacing.gridSize;
return {
item: css.css({
background: "none",
cursor: "pointer",
whiteSpace: "nowrap",
color: theme.colors.text.primary,
display: "flex",
flexDirection: "column",
alignItems: "stretch",
justifyContent: "center",
padding: theme.spacing(0.5, 1.5),
minHeight: theme.spacing(4),
borderRadius: getInternalRadius(theme, menuPadding, { parentBorderWidth: 0 }),
margin: 0,
border: "none",
width: "100%",
position: "relative",
"&:hover, &:focus-visible": {
background: theme.colors.action.hover,
color: theme.colors.text.primary,
textDecoration: "none"
},
"&:focus-visible": getFocusStyles(theme)
}),
active: css.css({
background: theme.colors.action.hover
}),
destructive: css.css({
color: theme.colors.error.text,
svg: {
color: theme.colors.error.text
},
"&:hover, &:focus, &:focus-visible": {
background: theme.colors.error.main,
color: theme.colors.error.contrastText,
svg: {
color: theme.colors.error.contrastText
}
}
}),
disabled: css.css({
color: theme.colors.action.disabledText,
label: "menu-item-disabled",
"&:hover, &:focus, &:focus-visible": {
cursor: "not-allowed",
background: "none",
color: theme.colors.action.disabledText
}
}),
icon: css.css({
opacity: 0.7,
color: theme.colors.text.secondary
}),
rightWrapper: css.css({
display: "flex",
alignItems: "center",
marginLeft: "auto"
}),
withShortcut: css.css({
minWidth: theme.spacing(10.5)
}),
shortcut: css.css({
display: "flex",
alignItems: "center",
gap: theme.spacing(1),
marginLeft: theme.spacing(2),
color: theme.colors.text.secondary
}),
description: css.css({
...theme.typography.bodySmall,
color: theme.colors.text.secondary,
textAlign: "start"
}),
descriptionWithIcon: css.css({
marginLeft: theme.spacing(3)
}),
ellipsis: css.css({
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap"
})
};
};
"use strict";
const MenuComp = React__namespace.forwardRef(
({ header, children, ariaLabel, onOpen, onClose, onKeyDown, ...otherProps }, forwardedRef) => {
const styles = useStyles2(getStyles$6);
const componentTokens = useComponentTokens();
const localRef = React.useRef(null);
React.useImperativeHandle(forwardedRef, () => localRef.current);
const [handleKeys] = useMenuFocus({ isMenuOpen: true, localRef, onOpen, onClose, onKeyDown });
return /* @__PURE__ */ jsxRuntime.jsxs(
Box,
{
...otherProps,
"aria-label": ariaLabel,
backgroundColor: "elevated",
borderRadius: componentTokens.borderRadius,
boxShadow: "z3",
display: "inline-block",
onKeyDown: handleKeys,
padding: componentTokens.padding,
ref: localRef,
role: "menu",
tabIndex: -1,
children: [
header && /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: css.cx(
styles.header,
Boolean(children) && React__namespace.Children.toArray(children).length > 0 && styles.headerBorder
),
children: header
}
),
children
]
}
);
}
);
MenuComp.displayName = "Menu";
const Menu = Object.assign(MenuComp, {
Item: MenuItem,
Divider: MenuDivider,
Group: MenuGroup
});
const useComponentTokens = () => useStyles2((theme) => {
const {
components: { menu }
} = theme;
return {
padding: menu.padding,
borderRadius: menu.borderRadius
};
});
const getStyles$6 = (theme) => {
return {
header: css.css({
padding: theme.spacing(0.5, 0.5, 1, 0.5)
}),
headerBorder: css.css({
borderBottom: `1px solid ${theme.colors.border.weak}`,
marginBottom: theme.spacing(0.5)
})
};
};
"use strict";
const ButtonSelectComponent = (props) => {
const { className, options, value, onChange, narrow, variant, root, ...restProps } = props;
const [isOpen, setIsOpen] = React.useState(false);
const renderMenu = () => /* @__PURE__ */ jsxRuntime.jsx(Menu, { tabIndex: -1, onClose: () => setIsOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(ScrollContainer, { maxHeight: "100vh", children: options.map((item) => {
var _a;
return /* @__PURE__ */ jsxRuntime.jsx(
MenuItem,
{
label: (_a = item.label) != null ? _a : String(item.value),
onClick: () => onChange(item),
active: item.value === (value == null ? void 0 : value.value),
ariaChecked: item.value === (value == null ? void 0 : value.value),
ariaLabel: item.ariaLabel || item.label,
disabled: item.isDisabled,
component: item.component,
role: "menuitemradio"
},
`${item.value}`
);
}) }) });
return /* @__PURE__ */ jsxRuntime.jsx(Dropdown, { root, overlay: renderMenu, placement: "bottom-end", children: /* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { className, isOpen, narrow, variant, ...restProps, children: (value == null ? void 0 : value.label) || ((value == null ? void 0 : value.value) != null ? String(value == null ? void 0 : value.value) : null) }) });
};
ButtonSelectComponent.displayName = "ButtonSelect";
const ButtonSelect = React.memo(ButtonSelectComponent);
"use strict";
function useCombinedRefs(...refs) {
const targetRef = React__namespace.useRef(null);
React__namespace.useEffect(() => {
refs.forEach((ref) => {
if (!ref) {
return;
}
if (typeof ref === "function") {
ref(targetRef.current);
} else {
ref.current = targetRef.current;
}
});
}, [refs]);
return targetRef;
}
"use strict";
const FilterInput = React.forwardRef(
({ value, width, onChange, escapeRegex = true, ...restProps }, ref) => {
const innerRef = React.useRef(null);
const combinedRef = useCombinedRefs(ref, innerRef);
const suffix = value !== "" ? /* @__PURE__ */ jsxRuntime.jsx(
Button,
{
icon: "times",
fill: "text",
size: "sm",
onClick: (e) => {
var _a;
(_a = innerRef.current) == null ? void 0 : _a.focus();
onChange("");
e.stopPropagation();
},
children: /* @__PURE__ */ jsxRuntime.jsx(i18n.Trans, { i18nKey: "grafana-ui.filter-input.clear", children: "Clear" })
}
) : null;
return /* @__PURE__ */ jsxRuntime.jsx(
Input,
{
prefix: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "search" }),
suffix,
width,
type: "text",
value: escapeRegex ? data.unEscapeStringFromRegex(value != null ? value : "") : value,
onChange: (event) => onChange(escapeRegex ? data.escapeStringForRegex(event.currentTarget.value) : event.currentTarget.value),
...restProps,
ref: combinedRef
}
);
}
);
FilterInput.displayName = "FilterInput";
"use strict";
function calculateUniqueFieldValues(rows, field) {
if (!field || rows.length === 0) {
return {};
}
const set = {};
for (let index = 0; index < rows.length; index++) {
const row = rows[index];
const fieldValue = row[getDisplayName(field)];
const value = field.display ? data.formattedValueToString(field.display(fieldValue)) : String(fieldValue);
set[value || "(Blanks)"] = value;
}
return set;
}
function getFilteredOptions(options, filterValues) {
if (!filterValues) {
return [];
}
return options.filter((option) => filterValues.some((filtered) => filtered.value === option.value));
}
function valuesToOptions(unique) {
return Object.keys(unique).map((key) => ({ value: unique[key], label: key })).sort(sortOptions);
}
function sortOptions(a, b) {
if (a.label === void 0 && b.label === void 0) {
return 0;
}
if (a.label === void 0 && b.label !== void 0) {
return -1;
}
if (a.label !== void 0 && b.label === void 0) {
return 1;
}
if (a.label < b.label) {
return -1;
}
if (a.label > b.label) {
return 1;
}
return 0;
}
"use strict";
const operatorSelectableValues = {
Contains: { label: "Contains", value: "Contains", description: "Contains" },
"=": { label: "=", value: "=", description: "Equals" },
"!=": { label: "!=", value: "!=", description: "Not equals" },
">": { label: ">", value: ">", description: "Greater" },
">=": { label: ">=", value: ">=", description: "Greater or Equal" },
"<": { label: "<", value: "<", description: "Less" },
"<=": { label: "<=", value: "<=", description: "Less or Equal" },
Expression: {
label: "Expression",
value: "Expression",
description: 'Bool Expression (Char $ represents the column value in the expression, e.g. "$ >= 10 && $ <= 12")'
}
};
const OPERATORS = Object.values(operatorSelectableValues);
const FilterPopup = ({
name,
rows,
filterValue,
setFilter,
onClose,
field,
searchFilter,
setSearchFilter,
operator,
setOperator
}) => {
var _a;
const theme = useTheme2();
const uniqueValues = React.useMemo(() => calculateUniqueFieldValues(rows, field), [rows, field]);
const options = React.useMemo(() => valuesToOptions(uniqueValues), [uniqueValues]);
const filteredOptions = React.useMemo(() => getFilteredOptions(options, filterValue), [options, filterValue]);
const [values, setValues] = React.useState(filteredOptions);
const [matchCase, setMatchCase] = React.useState(false);
const containerRef = React.useRef(null);
const onCancel = React.useCallback((event) => onClose(), [onClose]);
const onFilter = React.useCallback(
(event) => {
if (values.length !== 0) {
const filteredSet = new Set(values.map((item) => item.value));
setFilter((filter) => ({
...filter,
[name]: { filtered: values, filteredSet, searchFilter, operator }
}));
} else {
setFilter((filter) => {
const newFilter = { ...filter };
delete newFilter[name];
return newFilter;
});
}
onClose();
},
[setFilter, values, onClose]
// eslint-disable-line react-hooks/exhaustive-deps
);
const onClearFilter = React.useCallback(
(event) => {
setFilter((filter) => {
const newFilter = { ...filter };
delete newFilter[name];
return newFilter;
});
onClose();
},
[setFilter, onClose]
// eslint-disable-line react-hooks/exhaustive-deps
);
const filterInputPlaceholder = i18n.t("grafana-ui.table.filter-popup-input-placeholder", "Filter values");
const clearFilterVisible = React.useMemo(() => filterValue !== void 0, [filterValue]);
const styles = useStyles2(getStyles$5);
return /* @__PURE__ */ jsxRuntime.jsx(ClickOutsideWrapper, { onClick: onCancel, useCapture: true, children: /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: styles.filterContainer,
onClick: stopPropagation,
"data-testid": e2eSelectors.selectors.components.Panels.Visualization.TableNG.Filters.Container,
ref: containerRef,
children: /* @__PURE__ */ jsxRuntime.jsxs(Stack, { direction: "column", children: [
/* @__PURE__ */ jsxRuntime.jsxs(Stack, { alignItems: "center", children: [
field && /* @__PURE__ */ jsxRuntime.jsx(Label, { className: styles.label, children: getDisplayName(field) }),
/* @__PURE__ */ jsxRuntime.jsx(
ButtonSelect,
{
variant: "canvas",
options: OPERATORS,
onChange: setOperator,
value: operator,
tooltip: operator.description,
root: (_a = containerRef.current) != null ? _a : void 0
}
)
] }),
/* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.listDivider }),
/* @__PURE__ */ jsxRuntime.jsxs(Stack, { gap: 1, children: [
/* @__PURE__ */ jsxRuntime.jsx(
FilterInput,
{
placeholder: filterInputPlaceholder,
title: filterInputPlaceholder,
onChange: setSearchFilter,
value: searchFilter
}
),
/* @__PURE__ */ jsxRuntime.jsx(
Button,
{
tooltip: i18n.t("grafana-ui.table.filter-popup-aria-label-match-case", "Match case"),
variant: "secondary",
style: { color: matchCase ? theme.colors.text.link : theme.colors.text.disabled },
onClick: () => {
setMatchCase((s) => !s);
},
icon: "text-fields"
}
)
] }),
/* @__PURE__ */ jsxRuntime.jsx(
FilterList,
{
onChange: setValues,
values,
options,
caseSensitive: matchCase,
searchFilter,
operator
}
),
/* @__PURE__ */ jsxRuntime.jsxs(Stack, { gap: 3, children: [
/* @__PURE__ */ jsxRuntime.jsxs(Stack, { children: [
/* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", onClick: onFilter, children: /* @__PURE__ */ jsxRuntime.jsx(i18n.Trans, { i18nKey: "grafana-ui.table.filter-popup-apply", children: "Ok" }) }),
/* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", variant: "secondary", onClick: onCancel, children: /* @__PURE__ */ jsxRuntime.jsx(i18n.Trans, { i18nKey: "grafana-ui.table.filter-popup-cancel", children: "Cancel" }) })
] }),
clearFilterVisible && /* @__PURE__ */ jsxRuntime.jsx(Stack, { children: /* @__PURE__ */ jsxRuntime.jsx(Button, { fill: "text", size: "sm", onClick: onClearFilter, children: /* @__PURE__ */ jsxRuntime.jsx(i18n.Trans, { i18nKey: "grafana-ui.table.filter-popup-clear", children: "Clear filter" }) }) })
] })
] })
}
) });
};
const getStyles$5 = (theme) => ({
filterContainer: css.css({
label: "filterContainer",
width: "100%",
minWidth: "250px",
height: "100%",
backgroundColor: theme.colors.background.primary,
border: `1px solid ${theme.colors.border.weak}`,
padding: theme.spacing(2),
boxShadow: theme.shadows.z3,
borderRadius: theme.shape.radius.default
}),
listDivider: css.css({
label: "listDivider",
width: "100%",
borderTop: `1px solid ${theme.colors.border.medium}`
}),
label: css.css({
marginBottom: 0
})
});
const stopPropagation = (event) => {
event.stopPropagation();
};
"use strict";
const ITEM_HEIGHT = 28;
const MIN_HEIGHT = ITEM_HEIGHT * 5;
const REGEX_OPERATOR = operatorSelectableValues["Contains"];
const XPR_OPERATOR = operatorSelectableValues["Expression"];
const comparableValue = (value) => {
value = value.trim().replace(/\\/g, "");
if (/^(\d{4}-\d{2}-\d{2}|\d{4}\/\d{2}\/\d{2})/.test(value)) {
const date = new Date(value);
if (!isNaN(date.getTime())) {
const fmt = data.getValueFormat("dateTimeAsIso");
return data.formattedValueToString(fmt(date.getTime()));
}
}
const num = parseFloat(value);
if (!isNaN(num)) {
return num;
}
const lvalue = value.toLowerCase();
if (lvalue === "true" || lvalue === "false") {
return lvalue === "true";
}
return value;
};
const FilterList = ({ options, values, caseSensitive, onChange, searchFilter, operator }) => {
const regex = React.useMemo(() => new RegExp(searchFilter, caseSensitive ? void 0 : "i"), [searchFilter, caseSensitive]);
const items = React.useMemo(
() => options.filter((option) => {
if (!searchFilter || operator.value === REGEX_OPERATOR.value) {
if (option.label === void 0) {
return false;
}
return regex.test(option.label);
} else if (operator.value === XPR_OPERATOR.value) {
if (option.value === void 0) {
return false;
}
try {
const xpr = searchFilter.replace(/\\/g, "");
const fnc = new Function("$", `'use strict'; return ${xpr};`);
const val = comparableValue(option.value);
return fnc(val);
} catch (_) {
}
return false;
} else {
if (option.value === void 0) {
return false;
}
const value1 = comparableValue(option.value);
const value2 = comparableValue(searchFilter);
switch (operator.value) {
case "=":
return value1 === value2;
case "!=":
return value1 !== value2;
case ">":
return value1 > value2;
case ">=":
return value1 >= value2;
case "<":
return value1 < value2;
case "<=":
return value1 <= value2;
}
return false;
}
}),
[options, regex, operator, searchFilter]
);
const selectedItems = React.useMemo(() => items.filter((item) => values.includes(item)), [items, values]);
const selectCheckValue = React.useMemo(() => items.length === selectedItems.length, [items, selectedItems]);
const selectCheckIndeterminate = React.useMemo(
() => selectedItems.length > 0 && items.length > selectedItems.length,
[items, selectedItems]
);
const selectCheckLabel = React.useMemo(
() => selectedItems.length ? `${selectedItems.length} selected` : `Select all`,
[selectedItems]
);
const selectCheckDescription = React.useMemo(
() => items.length !== selectedItems.length ? "Add all displayed values to the filter" : "Remove all displayed values from the filter",
[items, selectedItems]
);
const styles = useStyles2(getStyles$4);
const theme = useTheme2();
const gutter = theme.spacing.gridSize;
const height = React.useMemo(() => Math.min(items.length * ITEM_HEIGHT, MIN_HEIGHT) + gutter, [gutter, items.length]);
const onCheckedChanged = React.useCallback(
(option) => (event) => {
const newValues = event.currentTarget.checked ? values.concat(option) : values.filter((c) => c.value !== option.value);
onChange(newValues);
},
[onChange, values]
);
const onSelectChanged = React.useCallback(() => {
if (items.length === selectedItems.length) {
const newValues = values.filter((item) => !items.includes(item));
onChange(newValues);
} else {
const newValues = [.../* @__PURE__ */ new Set([...values, ...items])];
onChange(newValues);
}
}, [onChange, values, items, selectedItems]);
return /* @__PURE__ */ jsxRuntime.jsx(Stack, { direction: "column", children: items.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
/* @__PURE__ */ jsxRuntime.jsx(
reactWindow.FixedSizeList,
{
height,
itemCount: items.length,
itemSize: ITEM_HEIGHT,
itemData: { items, values: selectedItems, onCheckedChanged, className: styles.filterListRow },
width: "100%",
className: styles.filterList,
children: ItemRenderer
}
),
/* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: styles.filterListRow,
"data-testid": e2eSelectors.selectors.components.Panels.Visualization.TableNG.Filters.SelectAll,
children: /* @__PURE__ */ jsxRuntime.jsx(
Checkbox,
{
value: selectCheckValue,
indeterminate: selectCheckIndeterminate,
label: selectCheckLabel,
description: selectCheckDescription,
onChange: onSelectChanged
}
)
}
)
] }) : /* @__PURE__ */ jsxRuntime.jsx(Label, { className: styles.noValuesLabel, children: /* @__PURE__ */ jsxRuntime.jsx(i18n.Trans, { i18nKey: "grafana-ui.table.no-values-label", children: "No values" }) }) });
};
function ItemRenderer({ index, style, data: { onCheckedChanged, items, values, className } }) {
const option = items[index];
const { value, label } = option;
const isChecked = values.find((s) => s.value === value) !== void 0;
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style, title: label, children: /* @__PURE__ */ jsxRuntime.jsx(Checkbox, { value: isChecked, label, onChange: onCheckedChanged(option) }) });
}
const getStyles$4 = (theme) => ({
filterList: css.css({
label: "filterList",
backgroundColor: theme.components.input.background,
border: `1px solid ${theme.colors.border.medium}`,
borderRadius: theme.shape.radius.default
}),
filterListRow: css.css({
label: "filterListRow",
cursor: "pointer",
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
padding: theme.spacing(0.5),
":hover": {
backgroundColor: theme.colors.action.hover
}
}),
selectDivider: css.css({
label: "selectDivider",
width: "100%",
borderTop: `1px solid ${theme.colors.border.medium}`,
padding: theme.spacing(0.5, 2)
}),
noValuesLabel: css.css({
paddingTop: theme.spacing(1)
})
});
"use strict";
const Filter = ({
name,
rows,
filter,
setFilter,
field,
crossFilterOrder,
crossFilterRows,
iconClassName
}) => {
var _a, _b, _c;
const filterValue = (_a = filter[name]) == null ? void 0 : _a.filtered;
const filterIndex = crossFilterOrder.indexOf(name);
let filteredRows;
if (filterIndex > 0) {
const previousFilterName = crossFilterOrder[filterIndex - 1];
filteredRows = crossFilterRows[previousFilterName];
} else if (filterIndex === -1 && crossFilterOrder.length > 0) {
const previousFilterName = crossFilterOrder[crossFilterOrder.length - 1];
filteredRows = crossFilterRows[previousFilterName];
} else {
filteredRows = rows;
}
const ref = React.useRef(null);
const [isPopoverVisible, setPopoverVisible] = React.useState(false);
const styles = useStyles2(getStyles$3);
const filterEnabled = Boolean(filterValue);
const [searchFilter, setSearchFilter] = React.useState(((_b = filter[name]) == null ? void 0 : _b.searchFilter) || "");
const [operator, setOperator] = React.useState(((_c = filter[name]) == null ? void 0 : _c.operator) || REGEX_OPERATOR);
return /* @__PURE__ */ jsxRuntime.jsxs(
"button",
{
className: styles.headerFilter,
ref,
type: "button",
"data-testid": e2eSelectors.selectors.components.Panels.Visualization.TableNG.Filters.HeaderButton,
onClick: (ev) => {
setPopoverVisible(true);
ev.stopPropagation();
},
children: [
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "filter", className: css.cx(iconClassName, { [styles.filterIconEnabled]: filterEnabled }) }),
isPopoverVisible && ref.current && /* @__PURE__ */ jsxRuntime.jsx(
Popover,
{
content: /* @__PURE__ */ jsxRuntime.jsx(
FilterPopup,
{
name,
rows: filteredRows,
filterValue,
setFilter,
field,
onClose: () => setPopoverVisible(false),
searchFilter,
setSearchFilter,
operator,
setOperator
}
),
onKeyDown: (event) => {
if (event.key === " ") {
event.stopPropagation();
}
},
placement: "bottom-start",
referenceElement: ref.current,
show: true
}
)
]
}
);
};
const getStyles$3 = (theme) => ({
headerFilter: css.css({
background: "transparent",
border: "none",
label: "headerFilter",
padding: 0,
alignSelf: "flex-end"
}),
filterIconEnabled: css.css({
label: "filterIconEnabled",
color: theme.colors.primary.text
})
});
"use strict";
const HeaderCell = ({
column,
rows,
field,
direction,
filter,
setFilter,
crossFilterOrder,
crossFilterRows,
showTypeIcons
}) => {
var _a, _b, _c, _d;
const headerCellWrap = (_b = (_a = field.config.custom) == null ? void 0 : _a.wrapHeaderText) != null ? _b : false;
const styles = useStyles2(getStyles$2, headerCellWrap);
const displayName = getDisplayName(field);
const filterable = (_d = (_c = field.config.custom) == null ? void 0 : _c.filterable) != null ? _d : false;
React.useEffect(() => {
if (!filterable && filter[displayName]) {
setFilter((filter2) => {
const newFilter = { ...filter2 };
delete newFilter[displayName];
return newFilter;
});
}
}, [filterable, displayName, filter, setFilter]);
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
showTypeIcons && /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: styles.headerCellIcon, name: getFieldTypeIcon(field), title: field == null ? void 0 : field.type, size: "sm" }),
/* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.headerCellLabel, children: getDisplayName(field) }),
direction && /* @__PURE__ */ jsxRuntime.jsx(
Icon,
{
className: css.cx(styles.headerCellIcon, styles.headerSortIcon),
size: "lg",
name: direction === "ASC" ? "arrow-up" : "arrow-down"
}
),
filterable && /* @__PURE__ */ jsxRuntime.jsx(
Filter,
{
name: column.key,
rows,
filter,
setFilter,
field,
crossFilterOrder,
crossFilterRows,
iconClassName: styles.headerCellIcon
}
)
] });
};
const getStyles$2 = (theme, headerTextWrap) => ({
headerCellLabel: css.css({
cursor: "pointer",
fontWeight: theme.typography.fontWeightMedium,
color: theme.colors.text.secondary,
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: headerTextWrap ? "pre-line" : "nowrap",
"&:hover": {
textDecoration: "underline"
},
"&::selection": {
backgroundColor: "var(--rdg-background-color)",
color: theme.colors.text.secondary
}
}),
headerCellIcon: css.css({
marginBottom: theme.spacing(0.5),
alignSelf: "flex-end",
color: theme.colors.text.secondary
}),
headerSortIcon: css.css({
marginBottom: theme.spacing(0.25)
})
});
"use strict";
function RowExpander({ onCellExpand, isExpanded }) {
const styles = useStyles2(getStyles$1);
function handleKeyDown(e) {
if (e.key === " " || e.key === "Enter") {
e.preventDefault();
onCellExpand(e);
}
}
return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "button", tabIndex: 0, className: styles.expanderCell, onClick: onCellExpand, onKeyDown: handleKeyDown, children: /* @__PURE__ */ jsxRuntime.jsx(
Icon,
{
"aria-label": isExpanded ? i18n.t("grafana-ui.row-expander-ng.aria-label-collapse", "Collapse row") : i18n.t("grafana-ui.row-expander.aria-label-expand", "Expand row"),
name: isExpanded ? "angle-down" : "angle-right",
size: "lg"
}
) });
}
const getStyles$1 = (_theme) => ({
expanderCell: css.css({
display: "flex",
flexDirection: "column",
justifyContent: "center",
cursor: "pointer"
})
});
"use strict";
const getDisplayedValue = (row, key, fields) => {
const field = fields.find((field2) => getDisplayName(field2) === key);
if (!field || !field.display) {
return "";
}
const displayedValue = data.formattedValueToString(field.display(row[key]));
return displayedValue;
};
function useFilteredRows(rows, fields, { hasNestedFrames }) {
const [filter, setFilter] = React.useState({});
const filterValues = React.useMemo(() => Object.entries(filter), [filter]);
const crossFilterOrder = React.useMemo(
() => Array.from(new Set(filterValues.map(([key]) => key))),
[filterValues]
);
const [filteredRows, crossFilterRows] = React.useMemo(() => {
const crossFilterRows2 = {};
const filterRows = (row) => {
var _a;
for (const [key, value] of filterValues) {
const displayedValue = getDisplayedValue(row, key, fields);
if (!value.filteredSet.has(displayedValue)) {
return false;
}
crossFilterRows2[key] = (_a = crossFilterRows2[key]) != null ? _a : [];
crossFilterRows2[key].push(row);
}
return true;
};
const filteredRows2 = hasNestedFrames ? processNestedTableRows(rows, (parents) => parents.filter(filterRows)) : rows.filter(filterRows);
return [filteredRows2, crossFilterRows2];
}, [filterValues, rows, fields, hasNestedFrames]);
return {
rows: filteredRows,
filter,
setFilter,
crossFilterOrder,
crossFilterRows
};
}
function useSortedRows(rows, fields, { initialSortBy, hasNestedFrames }) {
const initialSortColumns = React.useMemo(
() => {
var _a;
return (_a = initialSortBy == null ? void 0 : initialSortBy.flatMap(({ displayName, desc }) => {
if (!fields.some((f) => getDisplayName(f) === displayName)) {
return [];
}
return [
{
columnKey: displayName,
direction: desc ? "DESC" : "ASC"
}
];
})) != null ? _a : [];
},
[]
// eslint-disable-line react-hooks/exhaustive-deps
);
const [sortColumns, setSortColumns] = React.useState(initialSortColumns);
const columnTypes = React.useMemo(() => getColumnTypes(fields), [fields]);
const sortedRows = React.useMemo(
() => applySort(rows, fields, sortColumns, columnTypes, hasNestedFrames),
[rows, fields, sortColumns, hasNestedFrames, columnTypes]
);
return {
rows: sortedRows,
sortColumns,
setSortColumns
};
}
const PAGINATION_HEIGHT = 38;
function usePaginatedRows(rows, { height, width, headerHeight, footerHeight, rowHeight, enabled }) {
const [page, setPage] = React.useState(0);
const numRows = rows.length;
const avgRowHeight = React.useMemo(() => {
if (!enabled) {
return 0;
}
if (typeof rowHeight === "number") {
return rowHeight;
}
if (typeof rowHeight === "string") {
return TABLE.MAX_CELL_HEIGHT;
}
return rows.slice(0, 100).reduce((avg, row, _, { length }) => avg + rowHeight(row) / length, 0);
}, [rows, rowHeight, enabled]);
const smallPagination = React.useMemo(() => enabled && width < TABLE.PAGINATION_LIMIT, [enabled, width]);
const { numPages, rowsPerPage, pageRangeStart, pageRangeEnd } = React.useMemo(() => {
if (!enabled) {
return { numPages: 0, rowsPerPage: 0, pageRangeStart: 1, pageRangeEnd: numRows };
}
const rowAreaHeight = height - headerHeight - footerHeight - PAGINATION_HEIGHT;
const heightPerRow = Math.floor(rowAreaHeight / (avgRowHeight || 1));
let rowsPerPage2 = heightPerRow > 1 ? heightPerRow : 1;
const pageRangeStart2 = page * rowsPerPage2 + 1;
let pageRangeEnd2 = pageRangeStart2 + rowsPerPage2 - 1;
if (pageRangeEnd2 > numRows) {
pageRangeEnd2 = numRows;
}
const numPages2 = Math.ceil(numRows / rowsPerPage2);
return {
numPages: numPages2,
rowsPerPage: rowsPerPage2,
pageRangeStart: pageRangeStart2,
pageRangeEnd: pageRangeEnd2
};
}, [height, headerHeight, footerHeight, avgRowHeight, enabled, numRows, page]);
React.useLayoutEffect(() => {
if (!enabled) {
return;
}
if (page > numPages) {
setPage(numPages - 1);
}
}, [numPages, enabled, page, setPage]);
const paginatedRows = React.useMemo(() => {
if (!enabled) {
return rows;
}
const pageOffset = page * rowsPerPage;
return rows.slice(pageOffset, pageOffset + rowsPerPage);
}, [page, rowsPerPage, rows, enabled]);
return {
rows: paginatedRows,
page: enabled ? page : -1,
setPage,
numPages,
rowsPerPage,
pageRangeStart,
pageRangeEnd,
smallPagination
};
}
const ICON_WIDTH = 16;
const ICON_GAP = 4;
function useHeaderHeight({
fields,
enabled,
columnWidths,
sortColumns,
typographyCtx,
showTypeIcons = false
}) {
const perIconSpace = ICON_WIDTH + ICON_GAP;
const measurers = React.useMemo(() => buildHeaderHeightMeasurers(fields, typographyCtx), [fields, typographyCtx]);
const columnAvailableWidths = React.useMemo(
() => columnWidths.map((c, idx) => {
var _a, _b;
if (idx >= fields.length) {
return 0;
}
let width = c - 2 * TABLE.CELL_PADDING - TABLE.BORDER_RIGHT;
const field = fields[idx];
if ((_b = (_a = field.config) == null ? void 0 : _a.custom) == null ? void 0 : _b.filterable) {
width -= perIconSpace;
}
if (sortColumns.some((col) => col.columnKey === getDisplayName(field))) {
width -= perIconSpace;
}
if (showTypeIcons) {
width -= perIconSpace;
}
return Math.floor(width) - 1;
}),
[fields, columnWidths, sortColumns, showTypeIcons, perIconSpace]
);
const headerHeight = React.useMemo(() => {
if (!enabled) {
return 0;
}
return getRowHeight(
fields,
-1,
columnAvailableWidths,
TABLE.HEADER_HEIGHT,
measurers,
TABLE.LINE_HEIGHT,
TABLE.CELL_PADDING
);
}, [fields, enabled, columnAvailableWidths, measurers]);
return headerHeight;
}
function useRowHeight({
columnWidths,
fields,
hasNestedFrames,
defaultHeight,
expandedRows,
typographyCtx,
maxHeight
}) {
const measurers = React.useMemo(
() => buildCellHeightMeasurers(fields, typographyCtx, maxHeight),
[fields, typographyCtx, maxHeight]
);
const hasWrappedCols = React.useMemo(() => {
var _a;
return (_a = measurers == null ? void 0 : measurers.length) != null ? _a : 0 > 0;
}, [measurers]);
const colWidths = React.useMemo(() => {
const columnWidthAffordance = 2 * TABLE.CELL_PADDING + TABLE.BORDER_RIGHT;
return columnWidths.map((c) => c - columnWidthAffordance);
}, [columnWidths]);
const rowHeight = React.useMemo(() => {
if (!hasNestedFrames && !hasWrappedCols || typeof defaultHeight === "string") {
return defaultHeight;
}
const cache = Array(fields[0].values.length);
return (row) => {
var _a, _b, _c, _d, _e;
if (row.__depth > 0) {
if (!expandedRows.has(row.__index)) {
return 0;
}
const rowCount = (_b = (_a = row.data) == null ? void 0 : _a.length) != null ? _b : 0;
if (rowCount === 0) {
return TABLE.NESTED_NO_DATA_HEIGHT + TABLE.CELL_PADDING * 2;
}
const nestedHeaderHeight = ((_e = (_d = (_c = row.data) == null ? void 0 : _c.meta) == null ? void 0 : _d.custom) == null ? void 0 : _e.noHeader) ? 0 : defaultHeight;
return defaultHeight * rowCount + nestedHeaderHeight + TABLE.CELL_PADDING * 2;
}
let result = cache[row.__index];
if (!result) {
result = cache[row.__index] = getRowHeight(fields, row.__index, colWidths, defaultHeight, measurers);
}
return result;
};
}, [hasNestedFrames, hasWrappedCols, defaultHeight, fields, colWidths, measurers, expandedRows]);
return rowHeight;
}
const INITIAL_COL_RESIZE_STATE = Object.freeze({ columnKey: void 0, width: 0 });
function useColumnResize(onColumnResize = () => {
}) {
const colResizeState = React.useRef({ ...INITIAL_COL_RESIZE_STATE });
const pointerIsDown = React.useRef(false);
React.useLayoutEffect(() => {
function pointerDown(_event) {
pointerIsDown.current = true;
}
function pointerUp(_event) {
pointerIsDown.current = false;
}
window.addEventListener("pointerdown", pointerDown);
window.addEventListener("pointerup", pointerUp);
return () => {
window.removeEventListener("pointerdown", pointerDown);
window.removeEventListener("pointerup", pointerUp);
};
});
const dispatchEvent = React.useCallback(() => {
if (colResizeState.current.columnKey) {
onColumnResize(colResizeState.current.columnKey, Math.floor(colResizeState.current.width));
colResizeState.current = { ...INITIAL_COL_RESIZE_STATE };
}
window.removeEventListener("click", dispatchEvent, { capture: true });
}, [onColumnResize]);
const dataGridResizeHandler = React.useCallback(
(column, width) => {
if (!colResizeState.current.columnKey) {
window.addEventListener("click", dispatchEvent, { capture: true });
}
colResizeState.current.columnKey = column.key;
colResizeState.current.width = width;
if (!pointerIsDown.current) {
dispatchEvent();
}
},
[dispatchEvent]
);
return dataGridResizeHandler;
}
function useScrollbarWidth(ref, height) {
const [scrollbarWidth, setScrollbarWidth] = React.useState(0);
React.useLayoutEffect(() => {
var _a;
const el = (_a = ref.current) == null ? void 0 : _a.element;
if (!el || IS_SAFARI_26) {
return;
}
const updateScrollbarDimensions = () => {
setScrollbarWidth(el.offsetWidth - el.clientWidth);
};
updateScrollbarDimensions();
const resizeObserver = new ResizeObserver(updateScrollbarDimensions);
resizeObserver.observe(el);
return () => {
resizeObserver.disconnect();
};
}, [ref, height]);
return scrollbarWidth;
}
const numIsEqual = (a, b) => a === b;
function useColWidths(visibleFields, availableWidth, frozenColumns) {
const [widths, setWidths] = React.useState(computeColWidths(visibleFields, availableWidth));
React.useEffect(() => {
const newWidths = computeColWidths(visibleFields, availableWidth);
if (!data.compareArrayValues(widths, newWidths, numIsEqual)) {
setWidths(newWidths);
}
}, [availableWidth, widths, visibleFields]);
const numFrozenColsFullyInView = React.useMemo(() => {
if (!frozenColumns || frozenColumns <= 0) {
return -1;
}
const fullyVisibleCols = widths.reduce(
([count, remainingWidth], nextWidth) => {
if (remainingWidth - nextWidth >= 0) {
return [count + 1, remainingWidth - nextWidth];
}
return [count, 0];
},
[0, availableWidth]
)[0];
return Math.min(fullyVisibleCols, frozenColumns);
}, [widths, availableWidth, frozenColumns]);
return [widths, numFrozenColsFullyInView];
}
const isReducer = (maybeReducer) => maybeReducer in data.ReducerID;
const nonMathReducers = /* @__PURE__ */ new Set([
data.ReducerID.allValues,
data.ReducerID.changeCount,
data.ReducerID.count,
data.ReducerID.countAll,
data.ReducerID.distinctCount,
data.ReducerID.first,
data.ReducerID.firstNotNull,
data.ReducerID.last,
data.ReducerID.lastNotNull,
data.ReducerID.uniqueValues
]);
const isNonMathReducer = (reducer) => isReducer(reducer) && nonMathReducers.has(reducer);
const noFormattingReducers = /* @__PURE__ */ new Set([data.ReducerID.count, data.ReducerID.countAll]);
const shouldReducerSkipFormatting = (reducer) => isReducer(reducer) && noFormattingReducers.has(reducer);
const useReducerEntries = (field, rows, displayName, colIdx) => {
return React.useMemo(() => {
var _a, _b, _c;
const reducers = (_c = (_b = (_a = field.config.custom) == null ? void 0 : _a.footer) == null ? void 0 : _b.reducers) != null ? _c : [];
if (reducers.length === 0 || field.type !== data.FieldType.number && reducers.every((reducerId) => !isNonMathReducer(reducerId))) {
return [];
}
const newState = {
lastProcessedRowCount: 0,
...field.state || {}
// Preserve any existing state properties
};
field.state = newState;
const currentRowCount = rows.length;
const lastRowCount = newState.lastProcessedRowCount;
if (lastRowCount !== currentRowCount) {
if (newState.calcs) {
delete newState.calcs;
}
newState.lastProcessedRowCount = currentRowCount;
}
const results = data.reduceField({
field: {
...field,
values: rows.map((row) => row[displayName])
},
reducers
});
return reducers.map((reducerId) => {
if (results[reducerId] === void 0 || // For non-number fields, only show special count reducers
field.type !== data.FieldType.number && !isNonMathReducer(reducerId) || // for countAll, only show the reducer in the first column
reducerId === data.ReducerID.countAll && colIdx !== 0) {
return [reducerId, null];
}
const value = results[reducerId];
let result = null;
if (!shouldReducerSkipFormatting(reducerId) && field.display) {
result = data.formattedValueToString(field.display(value));
} else if (value != null) {
result = String(value);
}
return [reducerId, result];
});
}, [field, rows, displayName, colIdx]);
};
"use strict";
const getReducerName = (reducerId) => {
var _a;
if (reducerId === data.ReducerID.countAll) {
return i18n.t("grafana-ui.table.footer.reducer.count", "Count");
}
return ((_a = data.fieldReducers.get(reducerId)) == null ? void 0 : _a.name) || reducerId;
};
const SummaryCell = ({
rows,
footers,
field,
colIdx,
hideLabel = false,
rowLabel = false,
textAlign
}) => {
const styles = useStyles2(getStyles, textAlign, hideLabel);
const theme = useTheme2();
const defaultFooterCellStyles = getDefaultCellStyles(theme, {
textAlign: "left",
// alignment is set in footerItem
shouldOverflow: true,
textWrap: false
});
const displayName = getDisplayName(field);
const reducerResultsEntries = useReducerEntries(field, rows, displayName, colIdx);
const cellClass = clsx__default.default(styles.footerCell, defaultFooterCellStyles);
const firstFooterReducers = React.useMemo(() => {
var _a, _b;
for (const footer of footers) {
if ((_b = (_a = footer == null ? void 0 : footer.reducers) == null ? void 0 : _a.length) != null ? _b : 0 > 0) {
return footer.reducers;
}
}
return;
}, [footers]);
const renderRowLabel = rowLabel && reducerResultsEntries.length === 0 && Boolean(firstFooterReducers);
const SummaryCellItem = ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.footerItem, children });
const SummaryCellLabel = ({ children }) => /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
"data-testid": e2eSelectors.selectors.components.Panels.Visualization.TableNG.Footer.ReducerLabel,
className: styles.footerItemLabel,
children
}
);
const SummaryCellValue = ({ children }) => /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
"data-testid": e2eSelectors.selectors.components.Panels.Visualization.TableNG.Footer.Value,
className: styles.footerItemValue,
children
}
);
return /* @__PURE__ */ jsxRuntime.jsxs(
"div",
{
className: cellClass,
"data-testid": reducerResultsEntries.length === 0 && !renderRowLabel ? "summary-cell-empty" : void 0,
children: [
reducerResultsEntries.map(([reducerId, reducerResult]) => {
if (reducerResult === null) {
return /* @__PURE__ */ jsxRuntime.jsx(SummaryCellItem, { children: rowLabel ? /* @__PURE__ */ jsxRuntime.jsx(SummaryCellLabel, { children: getReducerName(reducerId) }) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: "\xA0" }) }, reducerId);
}
return /* @__PURE__ */ jsxRuntime.jsxs(SummaryCellItem, { children: [
!hideLabel && /* @__PURE__ */ jsxRuntime.jsx(SummaryCellLabel, { children: getReducerName(reducerId) }),
/* @__PURE__ */ jsxRuntime.jsx(SummaryCellValue, { children: reducerResult })
] }, reducerId);
}),
renderRowLabel && firstFooterReducers.map((reducerId) => /* @__PURE__ */ jsxRuntime.jsx(SummaryCellItem, { children: /* @__PURE__ */ jsxRuntime.jsx(SummaryCellLabel, { children: getReducerName(reducerId) }) }, reducerId))
]
}
);
};
const getStyles = (theme, textAlign, hideLabel) => ({
footerCell: css.css({
flexDirection: "column",
minHeight: "100%",
width: "100%"
}),
footerItem: css.css({
display: "flex",
flexDirection: "row",
justifyContent: hideLabel ? getJustifyContent(textAlign) : "space-between",
alignItems: "flex-start",
width: "100%",
gap: theme.spacing(0.5)
}),
footerItemLabel: css.css({
flexShrink: 0,
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
color: theme.colors.text.secondary,
fontSize: theme.typography.bodySmall.fontSize,
fontWeight: theme.typography.fontWeightLight,
textTransform: "uppercase",
lineHeight: "22px"
}),
footerItemValue: css.css({
overflow: "hidden",
textOverflow: "ellipsis",
fontWeight: theme.typography.fontWeightMedium
})
});
"use strict";
const FILTER_FOR_OPERATOR = "=";
const FILTER_OUT_OPERATOR = "!=";
"use strict";
const TableCellActions = React.memo(
({ field, value, setInspectCell, onCellFilterAdded, className, cellInspect, showFilters }) => (
// stopping propagation to prevent clicks within the actions menu from triggering the cell click events
// for things like the data links tooltip.
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
/* @__PURE__ */ jsxRuntime.jsxs("div", { className, onClick: (ev) => ev.stopPropagation(), children: [
cellInspect && /* @__PURE__ */ jsxRuntime.jsx(
IconButton,
{
name: "eye",
"aria-label": i18n.t("grafana-ui.table.cell-inspect-tooltip", "Inspect value"),
onClick: () => {
const [inspectValue, mode] = buildInspectValue(value, field);
setInspectCell({ value: inspectValue, mode });
}
}
),
showFilters && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
/* @__PURE__ */ jsxRuntime.jsx(
IconButton,
{
name: "filter-plus",
"aria-label": i18n.t("grafana-ui.table.cell-filter-on", "Filter for value"),
onClick: () => {
onCellFilterAdded == null ? void 0 : onCellFilterAdded({
key: field.name,
operator: FILTER_FOR_OPERATOR,
value: String(value != null ? value : "")
});
}
}
),
/* @__PURE__ */ jsxRuntime.jsx(
IconButton,
{
name: "filter-minus",
"aria-label": i18n.t("grafana-ui.table.cell-filter-out", "Filter out value"),
onClick: () => {
onCellFilterAdded == null ? void 0 : onCellFilterAdded({
key: field.name,
operator: FILTER_OUT_OPERATOR,
value: String(value != null ? value : "")
});
}
}
)
] })
] })
)
);
TableCellActions.displayName = "TableCellActions";
"use strict";
const TableCellTooltip = React.memo(
({
cellOptions,
children,
classes,
className,
data,
disableSanitizeHtml,
field,
getActions,
getTextColorForBackground,
gridRef,
height,
placement,
renderer: CellRenderer,
rowIdx,
style,
theme,
tooltipField,
width = 300
}) => {
var _a, _b, _c;
const rawValue = field.values[rowIdx];
const tooltipCaretRef = React.useRef(null);
const [hovered, setHovered] = React.useState(false);
const [pinned, setPinned] = React.useState(false);
const show = hovered || pinned;
const dynamicHeight = (_b = (_a = tooltipField.config.custom) == null ? void 0 : _a.cellOptions) == null ? void 0 : _b.dynamicHeight;
React.useEffect(() => {
var _a2;
if (pinned) {
const gridRoot = (_a2 = gridRef.current) == null ? void 0 : _a2.element;
const windowListener = (ev) => {
if (ev.target === tooltipCaretRef.current) {
return;
}
setPinned(false);
window.removeEventListener("click", windowListener);
};
window.addEventListener("click", windowListener);
const scrollListener = () => {
setPinned(false);
};
gridRoot == null ? void 0 : gridRoot.addEventListener("scroll", scrollListener, { once: true });
return () => {
window.removeEventListener("click", windowListener);
gridRoot == null ? void 0 : gridRoot.removeEventListener("scroll", scrollListener);
};
}
return;
}, [pinned, gridRef]);
const rendererProps = React.useMemo(
() => ({
cellInspect: false,
cellOptions,
disableSanitizeHtml,
field,
frame: data,
getActions,
getTextColorForBackground,
height,
rowIdx,
showFilters: false,
theme,
value: rawValue,
width
}),
[
cellOptions,
data,
disableSanitizeHtml,
field,
getActions,
getTextColorForBackground,
height,
rawValue,
rowIdx,
theme,
width
]
);
const cellElement = (_c = tooltipCaretRef.current) == null ? void 0 : _c.closest(".rdg-cell");
if (rawValue === null || rawValue === void 0) {
return children;
}
const onMouseLeave = () => setHovered(false);
const onMouseEnter = () => setHovered(true);
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
cellElement && /* @__PURE__ */ jsxRuntime.jsx(
Popover,
{
content: /* @__PURE__ */ jsxRuntime.jsx(CellRenderer, { ...rendererProps }),
show,
placement,
wrapperClassName: classes.tooltipWrapper,
className,
style: { ...style, width, ...!dynamicHeight && { height } },
referenceElement: cellElement,
onMouseLeave,
onMouseEnter,
onClick: (ev) => ev.stopPropagation(),
"data-testid": e2eSelectors.selectors.components.Panels.Visualization.TableNG.Tooltip.Wrapper
}
),
/* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: classes.tooltipCaret,
ref: tooltipCaretRef,
"data-testid": e2eSelectors.selectors.components.Panels.Visualization.TableNG.Tooltip.Caret,
"aria-pressed": pinned,
onClick: () => setPinned((prev) => !prev),
onMouseLeave,
onMouseEnter,
onBlur: onMouseLeave,
onFocus: onMouseEnter
}
),
children
] });
}
);
TableCellTooltip.displayName = "TableCellTooltip";
"use strict";
const EXPANDED_COLUMN_KEY = "expanded";
function TableNG(props) {
var _a, _b, _c;
const {
cellHeight,
data: data$1,
disableSanitizeHtml,
enablePagination = false,
enableSharedCrosshair = false,
enableVirtualization,
frozenColumns = 0,
getActions = () => [],
height,
initialSortBy,
maxRowHeight: _maxRowHeight,
noHeader,
onCellFilterAdded,
onColumnResize,
onSortByChange,
showTypeIcons,
structureRev,
timeRange,
transparent,
width
} = props;
const theme = useTheme2();
const styles = useStyles2(getGridStyles, enablePagination, transparent);
const panelContext = usePanelContext();
const userCanExecuteActions = React.useMemo(() => {
var _a2, _b2;
return (_b2 = (_a2 = panelContext.canExecuteActions) == null ? void 0 : _a2.call(panelContext)) != null ? _b2 : false;
}, [panelContext]);
const getCellActions = React.useCallback(
(field, rowIdx) => {
if (!userCanExecuteActions) {
return [];
}
return getActions(data$1, field, rowIdx);
},
[getActions, data$1, userCanExecuteActions]
);
const visibleFields = React.useMemo(() => getVisibleFields(data$1.fields), [data$1.fields]);
const hasHeader = !noHeader;
const hasFooter = React.useMemo(
() => visibleFields.some((field) => {
var _a2, _b2, _c2;
return Boolean((_c2 = (_b2 = (_a2 = field.config.custom) == null ? void 0 : _a2.footer) == null ? void 0 : _b2.reducers) == null ? void 0 : _c2.length);
}),
[visibleFields]
);
const footerHeight = React.useMemo(
() => hasFooter ? calculateFooterHeight(visibleFields) : 0,
[hasFooter, visibleFields]
);
const resizeHandler = useColumnResize(onColumnResize);
const rows = React.useMemo(() => frameToRecords(data$1), [data$1]);
const hasNestedFrames = React.useMemo(() => getIsNestedTable(data$1.fields), [data$1]);
const getTextColorForBackground$1 = React.useMemo(() => memoize__default.default(getTextColorForBackground, { maxSize: 1e3 }), []);
const {
rows: filteredRows,
filter,
setFilter,
crossFilterOrder,
crossFilterRows
} = useFilteredRows(rows, data$1.fields, { hasNestedFrames });
const {
rows: sortedRows,
sortColumns,
setSortColumns
} = useSortedRows(filteredRows, data$1.fields, { hasNestedFrames, initialSortBy });
const [inspectCell, setInspectCell] = React.useState(null);
const [tooltipState, setTooltipState] = React.useState();
const [expandedRows, setExpandedRows] = React.useState(() => /* @__PURE__ */ new Set());
const defaultRowHeight = React.useMemo(
() => getDefaultRowHeight(theme, visibleFields, cellHeight),
[theme, visibleFields, cellHeight]
);
const gridRef = React.useRef(null);
const scrollbarWidth = useScrollbarWidth(gridRef, height);
const availableWidth = React.useMemo(
() => (hasNestedFrames ? width - COLUMN.EXPANDER_WIDTH : width) - scrollbarWidth,
[width, hasNestedFrames, scrollbarWidth]
);
const getCellColorInlineStyles = React.useMemo(() => getCellColorInlineStylesFactory(theme), [theme]);
const applyToRowBgFn = React.useMemo(
() => {
var _a2;
return (_a2 = getApplyToRowBgFn(data$1.fields, getCellColorInlineStyles)) != null ? _a2 : void 0;
},
[data$1.fields, getCellColorInlineStyles]
);
const typographyCtx = React.useMemo(
() => createTypographyContext(
theme.typography.fontSize,
theme.typography.fontFamily,
extractPixelValue(theme.typography.body.letterSpacing) * theme.typography.fontSize
),
[theme]
);
const [widths, numFrozenColsFullyInView] = useColWidths(visibleFields, availableWidth, frozenColumns);
const headerHeight = useHeaderHeight({
columnWidths: widths,
fields: visibleFields,
enabled: hasHeader,
sortColumns,
showTypeIcons: showTypeIcons != null ? showTypeIcons : false,
typographyCtx
});
const maxRowHeight = _maxRowHeight != null ? Math.max(TABLE.LINE_HEIGHT, _maxRowHeight) : void 0;
const rowHeight = useRowHeight({
columnWidths: widths,
fields: visibleFields,
hasNestedFrames,
defaultHeight: defaultRowHeight,
expandedRows,
typographyCtx,
maxHeight: maxRowHeight
});
const {
rows: paginatedRows,
page,
setPage,
numPages,
pageRangeStart,
pageRangeEnd,
smallPagination
} = usePaginatedRows(sortedRows, {
enabled: enablePagination,
width: availableWidth,
height,
footerHeight,
headerHeight: hasHeader ? TABLE.HEADER_ROW_HEIGHT : 0,
rowHeight
});
const [footers, isUniformFooter] = React.useMemo(() => {
var _a2, _b2, _c2, _d, _e;
const footers2 = [];
let isUniformFooter2 = true;
let firstReducers;
for (const field of visibleFields) {
const footer = (_b2 = (_a2 = field.config) == null ? void 0 : _a2.custom) == null ? void 0 : _b2.footer;
footers2.push(footer);
if (firstReducers === void 0 && ((_d = (_c2 = footer == null ? void 0 : footer.reducers) == null ? void 0 : _c2.length) != null ? _d : 0) > 0) {
firstReducers = footer == null ? void 0 : footer.reducers;
} else if (firstReducers !== void 0) {
const reducers = footer == null ? void 0 : footer.reducers;
if ((_e = reducers == null ? void 0 : reducers.length) != null ? _e : 0 > 0) {
if (reducers.length !== firstReducers.length || reducers.some((r, idx) => (firstReducers == null ? void 0 : firstReducers[idx]) !== r)) {
isUniformFooter2 = false;
break;
}
}
}
}
return [footers2, isUniformFooter2];
}, [visibleFields]);
const rowHeightFn = React.useMemo(() => {
if (typeof rowHeight === "function") {
return rowHeight;
}
if (typeof rowHeight === "string") {
return () => TABLE.MAX_CELL_HEIGHT;
}
return () => rowHeight;
}, [rowHeight]);
const renderRow = React.useMemo(
() => renderRowFactory(data$1.fields, panelContext, expandedRows, enableSharedCrosshair),
[data$1, enableSharedCrosshair, expandedRows, panelContext]
);
const commonDataGridProps = React.useMemo(
() => ({
enableVirtualization: !IS_SAFARI_26 && enableVirtualization !== false && rowHeight !== "auto",
defaultColumnOptions: {
minWidth: 50,
resizable: true,
sortable: true
// draggable: true,
},
onColumnResize: resizeHandler,
onSortColumnsChange: (newSortColumns) => {
setSortColumns(newSortColumns);
onSortByChange == null ? void 0 : onSortByChange(
newSortColumns.map(({ columnKey, direction }) => ({
displayName: columnKey,
desc: direction === "DESC"
}))
);
},
sortColumns,
rowHeight,
bottomSummaryRows: hasFooter ? [{}] : void 0,
summaryRowHeight: footerHeight,
headerRowClass: styles.headerRow,
headerRowHeight: noHeader ? 0 : TABLE.HEADER_ROW_HEIGHT
}),
[
enableVirtualization,
hasFooter,
resizeHandler,
sortColumns,
rowHeight,
styles.headerRow,
noHeader,
setSortColumns,
onSortByChange,
footerHeight
]
);
const buildNestedTableExpanderColumn = React.useCallback(
(nestedColumns, hasNestedHeaders, renderers) => ({
key: EXPANDED_COLUMN_KEY,
name: "",
field: {
name: "",
type: data.FieldType.other,
config: {},
values: []
},
cellClass(row) {
if (row.__depth !== 0) {
return styles.cellNested;
}
return;
},
colSpan(args) {
return args.type === "ROW" && args.row.__depth === 1 ? data$1.fields.length : 1;
},
renderCell: ({ row }) => {
if (row.__depth === 0) {
const rowIdx = row.__index;
return /* @__PURE__ */ jsxRuntime.jsx(
RowExpander,
{
isExpanded: expandedRows.has(rowIdx),
onCellExpand: () => {
if (expandedRows.has(rowIdx)) {
expandedRows.delete(rowIdx);
} else {
expandedRows.add(rowIdx);
}
setExpandedRows(new Set(expandedRows));
}
}
);
}
const nestedData = row.data;
if (!nestedData) {
return null;
}
const expandedRecords = applySort(frameToRecords(nestedData), nestedData.fields, sortColumns);
if (!expandedRecords.length) {
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.noDataNested, children: /* @__PURE__ */ jsxRuntime.jsx(i18n.Trans, { i18nKey: "grafana-ui.table.nested-table.no-data", children: "No data" }) });
}
return /* @__PURE__ */ jsxRuntime.jsx(
reactDataGrid.DataGrid,
{
...commonDataGridProps,
className: clsx.clsx(styles.grid, styles.gridNested),
headerRowClass: clsx.clsx(styles.headerRow, { [styles.displayNone]: !hasNestedHeaders }),
headerRowHeight: hasNestedHeaders ? TABLE.HEADER_HEIGHT : 0,
columns: nestedColumns,
rows: expandedRecords,
renderers
}
);
},
width: COLUMN.EXPANDER_WIDTH,
minWidth: COLUMN.EXPANDER_WIDTH
}),
[commonDataGridProps, data$1.fields.length, expandedRows, sortColumns, styles]
);
const fromFields = React.useCallback(
(f, widths2) => {
const result = {
columns: [],
cellRootRenderers: {}
};
let lastRowIdx = -1;
let rowCellStyle = {
color: void 0,
background: void 0
};
f.forEach((field, i) => {
var _a2, _b2, _c2, _d, _e, _f, _g, _h, _i, _j, _k;
const cellOptions = getCellOptions(field);
const cellType = cellOptions.type;
if (cellType === schema.TableCellDisplayMode.Pill && ((_b2 = (_a2 = field.config.mappings) == null ? void 0 : _a2.length) != null ? _b2 : 0 > 0)) {
field = {
...field,
config: {
...field.config,
color: {
...field.config.color,
mode: schema.FieldColorModeId.Fixed,
fixedColor: (_d = (_c2 = field.config.color) == null ? void 0 : _c2.fixedColor) != null ? _d : data.FALLBACK_COLOR
}
}
};
field.display = data.getDisplayProcessor({ field, theme });
}
if (cellType === schema.TableCellDisplayMode.JSONView || field.type === data.FieldType.other) {
field.display = displayJsonValue(field);
}
const textAlign = getAlignment(field);
const justifyContent = getJustifyContent(textAlign);
const displayName = getDisplayName(field);
const headerCellClass = getHeaderCellStyles(theme, justifyContent);
const CellType = getCellRenderer(field, cellOptions);
const cellInspect = isCellInspectEnabled(field);
const showFilters = Boolean(field.config.filterable && onCellFilterAdded != null);
const showActions = cellInspect || showFilters;
const width2 = widths2[i];
const cellActionClassName = showActions ? clsx.clsx("table-cell-actions", getCellActionStyles(theme, textAlign)) : void 0;
const shouldOverflow = !IS_SAFARI_26 && rowHeight !== "auto" && (shouldTextOverflow(field) || Boolean(maxRowHeight));
const textWrap = rowHeight === "auto" || shouldTextWrap(field);
const canBeColorized = canFieldBeColorized(cellType, applyToRowBgFn);
const cellStyleOptions = {
textAlign,
textWrap,
shouldOverflow,
maxHeight: maxRowHeight
};
const defaultCellStyles = getDefaultCellStyles(theme, cellStyleOptions);
const cellSpecificStyles = getCellSpecificStyles(cellType, field, theme, cellStyleOptions);
const linkStyles = getLinkStyles(theme, canBeColorized);
const cellParentStyles = clsx.clsx(defaultCellStyles, linkStyles);
const maxHeightClassName = maxRowHeight ? getMaxHeightCellStyles(theme, cellStyleOptions) : void 0;
const styleFieldValue = (_e = field.config.custom) == null ? void 0 : _e.styleField;
const styleField = styleFieldValue ? data$1.fields.find(predicateByName(styleFieldValue)) : void 0;
const styleFieldName = styleField ? getDisplayName(styleField) : void 0;
const hasValidStyleField = Boolean(styleFieldName);
const renderCellRoot2 = (key, props2) => {
const rowIdx = props2.row.__index;
if (rowIdx !== lastRowIdx) {
lastRowIdx = rowIdx;
rowCellStyle.color = void 0;
rowCellStyle.background = void 0;
if (applyToRowBgFn != null) {
rowCellStyle = { ...rowCellStyle, ...applyToRowBgFn(rowIdx) };
}
}
let style = { ...rowCellStyle };
if (canBeColorized) {
const value = props2.row[props2.column.key];
const displayValue = field.display(value);
const cellColorStyles = getCellColorInlineStyles(cellOptions, displayValue, applyToRowBgFn != null);
Object.assign(style, cellColorStyles);
}
if (hasValidStyleField) {
style = { ...style, ...parseStyleJson(props2.row[styleFieldName]) };
}
return /* @__PURE__ */ jsxRuntime.jsx(
reactDataGrid.Cell,
{
...props2,
className: clsx.clsx(
props2.className,
cellParentStyles,
cellSpecificStyles != null && { [cellSpecificStyles]: maxRowHeight == null }
),
style
},
key
);
};
result.cellRootRenderers[displayName] = renderCellRoot2;
const renderBasicCellContent = (props2) => {
const rowIdx = props2.row.__index;
const value = props2.row[props2.column.key];
const height2 = rowHeightFn(props2.row);
const frame = data$1;
let result2 = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
/* @__PURE__ */ jsxRuntime.jsx(
CellType,
{
cellOptions,
frame,
field,
height: height2,
rowIdx,
theme,
value,
width: width2,
timeRange,
cellInspect,
showFilters,
getActions: getCellActions,
disableSanitizeHtml,
getTextColorForBackground: getTextColorForBackground$1
}
),
showActions && /* @__PURE__ */ jsxRuntime.jsx(
TableCellActions,
{
field,
value,
displayName,
cellInspect,
showFilters,
className: cellActionClassName,
setInspectCell,
onCellFilterAdded
}
)
] });
if (maxRowHeight != null) {
result2 = /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx.clsx(maxHeightClassName, cellSpecificStyles), children: result2 });
}
return result2;
};
let renderCellContent = renderBasicCellContent;
const tooltipFieldName = (_g = (_f = field.config.custom) == null ? void 0 : _f.tooltip) == null ? void 0 : _g.field;
if (tooltipFieldName) {
const tooltipField = data$1.fields.find(predicateByName(tooltipFieldName));
if (tooltipField) {
const tooltipDisplayName = getDisplayName(tooltipField);
const tooltipCellOptions = getCellOptions(tooltipField);
const tooltipFieldRenderer = getCellRenderer(tooltipField, tooltipCellOptions);
const tooltipCellStyleOptions = {
textAlign: getAlignment(tooltipField),
textWrap: shouldTextWrap(tooltipField),
shouldOverflow: false,
maxHeight: maxRowHeight
};
const tooltipCanBeColorized = canFieldBeColorized(tooltipCellOptions.type, applyToRowBgFn);
const tooltipDefaultStyles = getDefaultCellStyles(theme, tooltipCellStyleOptions);
const tooltipSpecificStyles = getCellSpecificStyles(
tooltipCellOptions.type,
tooltipField,
theme,
tooltipCellStyleOptions
);
const tooltipLinkStyles = getLinkStyles(theme, tooltipCanBeColorized);
const tooltipClasses = getTooltipStyles(theme, textAlign);
const placement = (_j = (_i = (_h = field.config.custom) == null ? void 0 : _h.tooltip) == null ? void 0 : _i.placement) != null ? _j : schema.TableCellTooltipPlacement.Auto;
const tooltipWidth = placement === schema.TableCellTooltipPlacement.Left || placement === schema.TableCellTooltipPlacement.Right ? (_k = tooltipField.config.custom) == null ? void 0 : _k.width : width2;
const tooltipProps = {
cellOptions: tooltipCellOptions,
classes: tooltipClasses,
className: clsx.clsx(
tooltipClasses.tooltipContent,
tooltipDefaultStyles,
tooltipSpecificStyles,
tooltipLinkStyles
),
data: data$1,
disableSanitizeHtml,
field: tooltipField,
getActions: getCellActions,
getTextColorForBackground: getTextColorForBackground$1,
gridRef,
placement,
renderer: tooltipFieldRenderer,
tooltipField,
theme,
width: tooltipWidth
};
renderCellContent = (props2) => {
const tooltipHeight = rowHeightFn(props2.row);
let tooltipStyle = { ...rowCellStyle };
if (tooltipCanBeColorized) {
const tooltipDisplayValue = tooltipField.display(props2.row[tooltipDisplayName]);
const tooltipCellColorStyles = getCellColorInlineStyles(
tooltipCellOptions,
tooltipDisplayValue,
applyToRowBgFn != null
);
Object.assign(tooltipStyle, tooltipCellColorStyles);
}
return /* @__PURE__ */ jsxRuntime.jsx(
TableCellTooltip,
{
...tooltipProps,
height: tooltipHeight,
rowIdx: props2.row.__index,
style: tooltipStyle,
children: renderBasicCellContent(props2)
}
);
};
}
}
result.columns.push({
field,
key: displayName,
name: displayName,
width: width2,
headerCellClass,
frozen: Math.min(frozenColumns, numFrozenColsFullyInView) > i,
renderCell: renderCellContent,
renderHeaderCell: ({ column, sortDirection }) => /* @__PURE__ */ jsxRuntime.jsx(
HeaderCell,
{
column,
rows,
field,
filter,
setFilter,
crossFilterOrder,
crossFilterRows,
direction: sortDirection,
showTypeIcons
}
),
renderSummaryCell: () => /* @__PURE__ */ jsxRuntime.jsx(
SummaryCell,
{
rows: sortedRows,
footers,
field,
colIdx: i,
textAlign: getSummaryCellTextAlign(textAlign, cellType),
rowLabel: isUniformFooter && i === 0,
hideLabel: isUniformFooter && i !== 0
}
)
});
});
return result;
},
[
applyToRowBgFn,
crossFilterOrder,
crossFilterRows,
data$1,
disableSanitizeHtml,
filter,
footers,
frozenColumns,
getCellActions,
getCellColorInlineStyles,
getTextColorForBackground$1,
isUniformFooter,
maxRowHeight,
numFrozenColsFullyInView,
onCellFilterAdded,
rows,
rowHeight,
rowHeightFn,
setFilter,
sortedRows,
showTypeIcons,
theme,
timeRange
]
);
const firstRowNestedData = React.useMemo(
() => {
var _a2;
return hasNestedFrames ? (_a2 = rows.find((r) => r.data)) == null ? void 0 : _a2.data : void 0;
},
[hasNestedFrames, rows]
);
const [nestedFieldWidths] = useColWidths((_a = firstRowNestedData == null ? void 0 : firstRowNestedData.fields) != null ? _a : [], availableWidth);
const { columns, cellRootRenderers } = React.useMemo(() => {
var _a2, _b2;
const result = fromFields(visibleFields, widths);
if (!firstRowNestedData) {
return result;
}
const hasNestedHeaders = ((_b2 = (_a2 = firstRowNestedData.meta) == null ? void 0 : _a2.custom) == null ? void 0 : _b2.noHeader) !== true;
const renderRow2 = renderRowFactory(firstRowNestedData.fields, panelContext, expandedRows, enableSharedCrosshair);
const { columns: nestedColumns, cellRootRenderers: nestedCellRootRenderers } = fromFields(
firstRowNestedData.fields,
nestedFieldWidths
);
const expanderCellRenderer = (key, props2) => /* @__PURE__ */ jsxRuntime.jsx(reactDataGrid.Cell, { ...props2 }, key);
result.cellRootRenderers[EXPANDED_COLUMN_KEY] = expanderCellRenderer;
result.columns.unshift(
buildNestedTableExpanderColumn(nestedColumns, hasNestedHeaders, {
renderRow: renderRow2,
renderCell: (key, props2) => nestedCellRootRenderers[props2.column.key](key, props2)
})
);
return result;
}, [
buildNestedTableExpanderColumn,
enableSharedCrosshair,
expandedRows,
firstRowNestedData,
fromFields,
nestedFieldWidths,
panelContext,
visibleFields,
widths
]);
const structureRevColumns = React.useMemo(() => columns, [columns, structureRev]);
const renderCellRoot = React.useCallback(
(key, props2) => cellRootRenderers[props2.column.key](key, props2),
[cellRootRenderers]
);
const itemsRangeStart = pageRangeStart;
const displayedEnd = pageRangeEnd;
const numRows = sortedRows.length;
let rendered = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
/* @__PURE__ */ jsxRuntime.jsx(
reactDataGrid.DataGrid,
{
...commonDataGridProps,
ref: gridRef,
className: styles.grid,
columns: structureRevColumns,
rows: paginatedRows,
headerRowClass: clsx.clsx(styles.headerRow, { [styles.displayNone]: noHeader }),
headerRowHeight: headerHeight,
onCellClick: ({ column, row }, { clientX, clientY, preventGridDefault, target }) => {
var _a2;
const field = columns[column.idx].field;
if (target instanceof HTMLElement && // this walks up the tree to find either a faux link wrapper or the cell root
// it then only proceeds if we matched the faux link wrapper
((_a2 = target.closest("a[aria-haspopup], .rdg-cell")) == null ? void 0 : _a2.matches("a"))) {
const rowIdx = row.__index;
setTooltipState({
coords: {
clientX,
clientY
},
links: getCellLinks(field, rowIdx),
actions: getCellActions(field, rowIdx)
});
preventGridDefault();
}
},
onCellKeyDown: hasNestedFrames ? (_, event) => {
if (event.isDefaultPrevented()) {
event.preventGridDefault();
}
} : null,
renderers: { renderRow, renderCell: renderCellRoot }
}
),
enablePagination && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.paginationContainer, children: [
/* @__PURE__ */ jsxRuntime.jsx(
Pagination,
{
className: "table-ng-pagination",
currentPage: page + 1,
numberOfPages: numPages,
showSmallVersion: smallPagination,
onNavigate: (toPage) => {
setPage(toPage - 1);
}
}
),
!smallPagination && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.paginationSummary, children: /* @__PURE__ */ jsxRuntime.jsxs(i18n.Trans, { i18nKey: "grafana-ui.table.pagination-summary", children: [
{ itemsRangeStart },
" - ",
{ displayedEnd },
" of ",
{ numRows },
" rows"
] }) })
] }),
tooltipState && /* @__PURE__ */ jsxRuntime.jsx(
DataLinksActionsTooltip,
{
links: (_b = tooltipState.links) != null ? _b : [],
actions: tooltipState.actions,
coords: tooltipState.coords,
onTooltipClose: () => setTooltipState(void 0)
}
),
inspectCell && /* @__PURE__ */ jsxRuntime.jsx(
TableCellInspector,
{
mode: (_c = inspectCell.mode) != null ? _c : TableCellInspectorMode.text,
value: inspectCell.value,
onDismiss: () => setInspectCell(null)
}
)
] });
if (IS_SAFARI_26) {
rendered = /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.safariWrapper, children: rendered });
}
return rendered;
}
const renderRowFactory = (fields, panelContext, expandedRows, enableSharedCrosshair) => (
// eslint-disable-next-line react/display-name
(key, props) => {
const { row } = props;
const rowIdx = row.__index;
const isExpanded = expandedRows.has(rowIdx);
if (row.__depth === 1 && !isExpanded) {
return null;
}
if (row.data) {
return /* @__PURE__ */ jsxRuntime.jsx(reactDataGrid.Row, { ...props, "aria-expanded": isExpanded }, key);
}
const handlers = {};
if (enableSharedCrosshair) {
const timeField = fields.find((f) => f.type === data.FieldType.time);
if (timeField) {
handlers.onMouseEnter = () => {
panelContext.eventBus.publish(
new data.DataHoverEvent({
point: {
time: timeField == null ? void 0 : timeField.values[rowIdx]
}
})
);
};
handlers.onMouseLeave = () => {
panelContext.eventBus.publish(new data.DataHoverClearEvent());
};
}
}
return /* @__PURE__ */ jsxRuntime.jsx(reactDataGrid.Row, { ...props, ...handlers }, key);
}
);
"use strict";
exports.TableNG = TableNG;
exports.attachSkeleton = attachSkeleton;
exports.skeletonAnimation = skeletonAnimation;
exports.useTheme2 = useTheme2;
//# sourceMappingURL=unstable-DPFHteXp.js.map