init: initial updates
This commit is contained in:
@@ -1,11 +1,9 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useBeforeUnload, useUnmount } from 'react-use';
|
import { useBeforeUnload, useUnmount } from 'react-use';
|
||||||
|
|
||||||
import { GrafanaTheme2, colorManipulator } from '@grafana/data';
|
|
||||||
import { Trans, t } from '@grafana/i18n';
|
import { Trans, t } from '@grafana/i18n';
|
||||||
import { reportInteraction } from '@grafana/runtime';
|
import { reportInteraction } from '@grafana/runtime';
|
||||||
import { Button, Icon, Stack, Tooltip, useStyles2 } from '@grafana/ui';
|
import { Alert, Badge, Button, Stack, Text } from '@grafana/ui';
|
||||||
import { Prompt } from 'app/core/components/FormPrompt/Prompt';
|
import { Prompt } from 'app/core/components/FormPrompt/Prompt';
|
||||||
import { CORRELATION_EDITOR_POST_CONFIRM_ACTION, ExploreItemState } from 'app/types/explore';
|
import { CORRELATION_EDITOR_POST_CONFIRM_ACTION, ExploreItemState } from 'app/types/explore';
|
||||||
import { useDispatch, useSelector } from 'app/types/store';
|
import { useDispatch, useSelector } from 'app/types/store';
|
||||||
@@ -21,7 +19,6 @@ import { selectCorrelationDetails, selectIsHelperShowing } from './state/selecto
|
|||||||
|
|
||||||
export const CorrelationEditorModeBar = ({ panes }: { panes: Array<[string, ExploreItemState]> }) => {
|
export const CorrelationEditorModeBar = ({ panes }: { panes: Array<[string, ExploreItemState]> }) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const styles = useStyles2(getStyles);
|
|
||||||
const correlationDetails = useSelector(selectCorrelationDetails);
|
const correlationDetails = useSelector(selectCorrelationDetails);
|
||||||
const isHelperShowing = useSelector(selectIsHelperShowing);
|
const isHelperShowing = useSelector(selectIsHelperShowing);
|
||||||
const [saveMessage, setSaveMessage] = useState<string | undefined>(undefined); // undefined means do not show
|
const [saveMessage, setSaveMessage] = useState<string | undefined>(undefined); // undefined means do not show
|
||||||
@@ -230,74 +227,68 @@ export const CorrelationEditorModeBar = ({ panes }: { panes: Array<[string, Expl
|
|||||||
message={saveMessage}
|
message={saveMessage}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className={styles.correlationEditorTop}>
|
<Alert title="" severity="info" bottomSpacing={0} topSpacing={0}>
|
||||||
<Stack gap={2} justifyContent="flex-end" alignItems="center">
|
<Stack width="100%" alignItems="start" justifyContent="space-between">
|
||||||
<Tooltip
|
<Stack gap={1} direction="column">
|
||||||
content={t(
|
<Stack gap={2} alignItems="center" direction="row">
|
||||||
'explore.correlation-editor-mode-bar.content-correlations-editor-explore-experimental-feature',
|
<Text variant="h4">
|
||||||
'Correlations editor in Explore is an experimental feature.'
|
<Trans i18nKey="explore.correlation-editor-mode-bar.edit-mode-title">Correlation Editor Mode</Trans>
|
||||||
)}
|
</Text>
|
||||||
>
|
<Badge
|
||||||
<Icon className={styles.iconColor} name="info-circle" size="xl" />
|
color="orange"
|
||||||
</Tooltip>
|
text={t('explore.correlation-editor-mode-bar.experimental', 'Experimental')}
|
||||||
<Button
|
tooltip={t(
|
||||||
variant="secondary"
|
'explore.correlation-editor-mode-bar.content-correlations-editor-explore-experimental-feature',
|
||||||
disabled={!correlationDetails?.canSave}
|
'Correlations editor in Explore is an experimental feature.'
|
||||||
fill="outline"
|
)}
|
||||||
className={correlationDetails?.canSave ? styles.buttonColor : styles.disabledButtonColor}
|
/>
|
||||||
onClick={() => {
|
</Stack>
|
||||||
saveCorrelationPostAction(true);
|
<Stack gap={0} direction="column">
|
||||||
}}
|
<Text variant="bodySmall">
|
||||||
>
|
<Trans i18nKey="explore.correlation-editor-mode-bar.instructions">
|
||||||
<Trans i18nKey="explore.correlation-editor-mode-bar.save">Save</Trans>
|
Step 1: In the left pane, run a query and click a table cell link or a "🔗 Correlate with"
|
||||||
</Button>
|
button.
|
||||||
<Button
|
</Trans>
|
||||||
variant="secondary"
|
</Text>
|
||||||
fill="outline"
|
<Text variant="bodySmall">
|
||||||
className={styles.buttonColor}
|
<Trans i18nKey="explore.correlation-editor-mode-bar.instructions-2">
|
||||||
icon="times"
|
Step 2: In the right pane (Target Query Builder), build and test your correlation query.
|
||||||
onClick={() => {
|
</Trans>
|
||||||
dispatch(changeCorrelationEditorDetails({ isExiting: true }));
|
</Text>
|
||||||
reportInteraction('grafana_explore_correlation_editor_exit_pressed');
|
<Text variant="bodySmall">
|
||||||
}}
|
<Trans i18nKey="explore.correlation-editor-mode-bar.instructions-3">
|
||||||
>
|
Step 3: Click Save to create the correlation.
|
||||||
<Trans i18nKey="explore.correlation-editor-mode-bar.exit-correlation-editor">Exit correlation editor</Trans>
|
</Trans>
|
||||||
</Button>
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
<Stack gap={1} alignItems="center">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
disabled={!correlationDetails?.canSave}
|
||||||
|
variant="secondary"
|
||||||
|
onClick={() => {
|
||||||
|
saveCorrelationPostAction(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Trans i18nKey="explore.correlation-editor-mode-bar.save">Save</Trans>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
icon="times"
|
||||||
|
variant="secondary"
|
||||||
|
onClick={() => {
|
||||||
|
dispatch(changeCorrelationEditorDetails({ isExiting: true }));
|
||||||
|
reportInteraction('grafana_explore_correlation_editor_exit_pressed');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Trans i18nKey="explore.correlation-editor-mode-bar.exit-correlation-editor">
|
||||||
|
Exit correlation editor
|
||||||
|
</Trans>
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
</div>
|
</Alert>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getStyles = (theme: GrafanaTheme2) => {
|
|
||||||
const contrastColor = theme.colors.getContrastText(theme.colors.primary.main);
|
|
||||||
const lighterBackgroundColor = colorManipulator.lighten(theme.colors.primary.main, 0.1);
|
|
||||||
const darkerBackgroundColor = colorManipulator.darken(theme.colors.primary.main, 0.2);
|
|
||||||
|
|
||||||
const disabledColor = colorManipulator.darken(contrastColor, 0.2);
|
|
||||||
|
|
||||||
return {
|
|
||||||
correlationEditorTop: css({
|
|
||||||
backgroundColor: theme.colors.primary.main,
|
|
||||||
marginTop: '3px',
|
|
||||||
padding: theme.spacing(1),
|
|
||||||
}),
|
|
||||||
iconColor: css({
|
|
||||||
color: contrastColor,
|
|
||||||
}),
|
|
||||||
buttonColor: css({
|
|
||||||
color: contrastColor,
|
|
||||||
borderColor: contrastColor,
|
|
||||||
'&:hover': {
|
|
||||||
color: contrastColor,
|
|
||||||
borderColor: contrastColor,
|
|
||||||
backgroundColor: lighterBackgroundColor,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
// important needed to override disabled state styling
|
|
||||||
disabledButtonColor: css({
|
|
||||||
color: `${disabledColor} !important`,
|
|
||||||
backgroundColor: `${darkerBackgroundColor} !important`,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -157,19 +157,37 @@ export const CorrelationHelper = ({ exploreId, correlations }: Props) => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Alert title={t('explore.correlation-helper.title-correlation-details', 'Correlation details')} severity="info">
|
<Alert
|
||||||
<Trans
|
className={styles.alertWrapper}
|
||||||
i18nKey="explore.correlation-helper.body-correlation-details"
|
title={t('explore.correlation-helper.title-correlation-details', 'Correlation details')}
|
||||||
values={{ resultField: correlations.resultField }}
|
severity="info"
|
||||||
>
|
>
|
||||||
The correlation link will appear by the <code>{'{{resultField}}'}</code> field. You can use the following
|
<div className={styles.alertContent}>
|
||||||
variables to set up your correlations:
|
<div>
|
||||||
</Trans>
|
<Trans
|
||||||
<pre>
|
i18nKey="explore.correlation-helper.body-correlation-details"
|
||||||
{Object.entries(correlations.vars).map((entry) => {
|
values={{ resultField: correlations.resultField }}
|
||||||
return `\$\{${entry[0]}\} = ${entry[1]}\n`;
|
>
|
||||||
})}
|
When saved, the <code>{'{{resultField}}'}</code> field will have a clickable link that runs your target
|
||||||
</pre>
|
query below. Use the below variables in your query. When clicked, they're replaced with values from that
|
||||||
|
row.
|
||||||
|
</Trans>
|
||||||
|
</div>
|
||||||
|
<div className={styles.variableList}>
|
||||||
|
{Object.entries(correlations.vars).map(([name, value]) => (
|
||||||
|
<div key={name} className={styles.variableRow}>
|
||||||
|
<div className={styles.variableNameCell}>
|
||||||
|
<code className={styles.variableName}>${`{${name}}`}</code>
|
||||||
|
</div>
|
||||||
|
<div className={styles.variableValueCell}>
|
||||||
|
<Tooltip content={value} placement="auto-start">
|
||||||
|
<span className={styles.variableValue}>{value}</span>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<Collapse
|
<Collapse
|
||||||
isOpen={isLabelDescOpen}
|
isOpen={isLabelDescOpen}
|
||||||
onToggle={() => {
|
onToggle={() => {
|
||||||
@@ -177,7 +195,9 @@ export const CorrelationHelper = ({ exploreId, correlations }: Props) => {
|
|||||||
}}
|
}}
|
||||||
label={
|
label={
|
||||||
<Stack gap={1} direction="row" wrap="wrap" alignItems="center">
|
<Stack gap={1} direction="row" wrap="wrap" alignItems="center">
|
||||||
<Trans i18nKey="explore.correlation-helper.label-description-header">Label / Description</Trans>
|
<Trans i18nKey="explore.correlation-helper.label-description-header">
|
||||||
|
Correlation Label / Description
|
||||||
|
</Trans>
|
||||||
{!isLabelDescOpen && !loadingLabel && (
|
{!isLabelDescOpen && !loadingLabel && (
|
||||||
<span className={styles.labelCollapseDetails}>{`Label: ${getValues('label') || defaultLabel}`}</span>
|
<span className={styles.labelCollapseDetails}>{`Label: ${getValues('label') || defaultLabel}`}</span>
|
||||||
)}
|
)}
|
||||||
@@ -287,5 +307,69 @@ const getStyles = (theme: GrafanaTheme2) => {
|
|||||||
transformationMeta: css({
|
transformationMeta: css({
|
||||||
alignItems: 'baseline',
|
alignItems: 'baseline',
|
||||||
}),
|
}),
|
||||||
|
alertWrapper: css({
|
||||||
|
'& > div': {
|
||||||
|
minWidth: 0,
|
||||||
|
maxWidth: '100%',
|
||||||
|
overflow: 'hidden',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
alertContent: css({
|
||||||
|
minWidth: 0,
|
||||||
|
maxWidth: '100%',
|
||||||
|
overflow: 'hidden',
|
||||||
|
width: '100%',
|
||||||
|
}),
|
||||||
|
variableList: css({
|
||||||
|
marginTop: theme.spacing(1.5),
|
||||||
|
marginBottom: theme.spacing(2),
|
||||||
|
display: 'table',
|
||||||
|
width: '100%',
|
||||||
|
tableLayout: 'auto',
|
||||||
|
borderCollapse: 'collapse',
|
||||||
|
}),
|
||||||
|
variableRow: css({
|
||||||
|
display: 'table-row',
|
||||||
|
}),
|
||||||
|
variableNameCell: css({
|
||||||
|
display: 'table-cell',
|
||||||
|
width: '1%',
|
||||||
|
paddingBottom: theme.spacing(0.5),
|
||||||
|
paddingRight: theme.spacing(1),
|
||||||
|
verticalAlign: 'top',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
}),
|
||||||
|
variableName: css({
|
||||||
|
display: 'inline-block',
|
||||||
|
backgroundColor: theme.colors.background.secondary,
|
||||||
|
padding: theme.spacing(0.5, 1),
|
||||||
|
borderRadius: theme.shape.radius.default,
|
||||||
|
fontFamily: theme.typography.fontFamilyMonospace,
|
||||||
|
fontSize: theme.typography.bodySmall.fontSize,
|
||||||
|
color: theme.colors.primary.text,
|
||||||
|
fontWeight: theme.typography.fontWeightMedium,
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
}),
|
||||||
|
variableValueCell: css({
|
||||||
|
display: 'table-cell',
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: 0,
|
||||||
|
paddingBottom: theme.spacing(0.5),
|
||||||
|
verticalAlign: 'top',
|
||||||
|
}),
|
||||||
|
variableValue: css({
|
||||||
|
display: 'inline-block',
|
||||||
|
backgroundColor: theme.colors.background.secondary,
|
||||||
|
padding: theme.spacing(0.5, 1),
|
||||||
|
borderRadius: theme.shape.radius.default,
|
||||||
|
fontFamily: theme.typography.fontFamilyMonospace,
|
||||||
|
fontSize: theme.typography.bodySmall.fontSize,
|
||||||
|
color: theme.colors.text.primary,
|
||||||
|
maxWidth: '100%',
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
verticalAlign: 'top',
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -120,9 +120,6 @@ const getStyles = (theme: GrafanaTheme2) => {
|
|||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
}),
|
}),
|
||||||
correlationsEditorIndicator: css({
|
correlationsEditorIndicator: css({
|
||||||
borderLeft: `4px solid ${theme.colors.primary.main}`,
|
|
||||||
borderRight: `4px solid ${theme.colors.primary.main}`,
|
|
||||||
borderBottom: `4px solid ${theme.colors.primary.main}`,
|
|
||||||
overflow: 'scroll',
|
overflow: 'scroll',
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import {
|
|||||||
ButtonGroup,
|
ButtonGroup,
|
||||||
useStyles2,
|
useStyles2,
|
||||||
Button,
|
Button,
|
||||||
|
Badge,
|
||||||
|
Tooltip,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
|
import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
|
||||||
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
|
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
|
||||||
@@ -57,6 +59,10 @@ const getStyles = (theme: GrafanaTheme2, splitted: Boolean) => ({
|
|||||||
marginRight: theme.spacing(0.5),
|
marginRight: theme.spacing(0.5),
|
||||||
width: splitted && theme.spacing(6),
|
width: splitted && theme.spacing(6),
|
||||||
}),
|
}),
|
||||||
|
badgeWrapper: css({
|
||||||
|
marginTop: theme.spacing(2),
|
||||||
|
marginLeft: theme.spacing(2),
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -219,10 +225,34 @@ export function ExploreToolbar({ exploreId, onChangeTime, onContentOutlineToogle
|
|||||||
<ShortLinkButtonMenu key="share" />,
|
<ShortLinkButtonMenu key="share" />,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const showBuilderIndicator = isCorrelationsEditorMode && !isLeftPane;
|
||||||
|
const showSourceIndicator = isCorrelationsEditorMode && isLeftPane && splitted;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{refreshInterval && <SetInterval func={onRunQuery} interval={refreshInterval} loading={loading} />}
|
{refreshInterval && <SetInterval func={onRunQuery} interval={refreshInterval} loading={loading} />}
|
||||||
<AppChromeUpdate actions={navBarActions} />
|
<AppChromeUpdate actions={navBarActions} />
|
||||||
|
{showSourceIndicator && (
|
||||||
|
<div className={styles.badgeWrapper}>
|
||||||
|
<Tooltip
|
||||||
|
content={t(
|
||||||
|
'explore.toolbar.source-correlation-query',
|
||||||
|
'Run a query and click a correlation link to start building your correlation'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Badge color="blue" icon="arrow-from-right" text={t('explore.toolbar.source-query', 'Source query')} />
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{showBuilderIndicator && (
|
||||||
|
<div className={styles.badgeWrapper}>
|
||||||
|
<Tooltip
|
||||||
|
content={t('explore.toolbar.build-correlation-query', 'Build and test your correlation target query here')}
|
||||||
|
>
|
||||||
|
<Badge color="orange" icon="crosshair" text={t('explore.toolbar.target-query-builder', 'Target query')} />
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<PageToolbar
|
<PageToolbar
|
||||||
aria-label={t('explore.toolbar.aria-label', 'Explore toolbar')}
|
aria-label={t('explore.toolbar.aria-label', 'Explore toolbar')}
|
||||||
leftItems={[
|
leftItems={[
|
||||||
|
|||||||
@@ -7017,10 +7017,10 @@
|
|||||||
"add-transformation": "Add transformation",
|
"add-transformation": "Add transformation",
|
||||||
"aria-label-delete-transformation": "Delete transformation",
|
"aria-label-delete-transformation": "Delete transformation",
|
||||||
"aria-label-edit-transformation": "Edit transformation",
|
"aria-label-edit-transformation": "Edit transformation",
|
||||||
"body-correlation-details": "The correlation link will appear by the <1>{{resultField}}</1> field. You can use the following variables to set up your correlations:",
|
"body-correlation-details": "When saved, the <1>{{resultField}}</1> field will have a clickable link that runs your target query below. Use the below variables in your query. When clicked, they're replaced with values from that row.",
|
||||||
"expression": "Expression: <1>{{expression}}</1>",
|
"expression": "Expression: <1>{{expression}}</1>",
|
||||||
"label-description": "Description",
|
"label-description": "Description",
|
||||||
"label-description-header": "Label / Description",
|
"label-description-header": "Correlation Label / Description",
|
||||||
"label-label": "Label",
|
"label-label": "Label",
|
||||||
"title-correlation-details": "Correlation details",
|
"title-correlation-details": "Correlation details",
|
||||||
"tooltip-transformations": "A transformation extracts one or more variables out of a single field.",
|
"tooltip-transformations": "A transformation extracts one or more variables out of a single field.",
|
||||||
|
|||||||
Reference in New Issue
Block a user