View File Name : explore.476912733278e2a99729.js.map
\n }\n isOpen={enabled}\n collapsible={true}\n onToggle={onToggleLogsSampleCollapse}\n >\n {LogsSamplePanelContent}\n \n ) : null;\n}\n\nconst getStyles = (theme: GrafanaTheme2) => {\n return {\n logSamplesButton: css`\n position: absolute;\n top: ${theme.spacing(1)};\n right: ${theme.spacing(1)};\n `,\n logContainer: css`\n overflow: scroll;\n `,\n infoTooltip: css`\n margin-left: ${theme.spacing(1)};\n `,\n };\n};\n","import { css } from '@emotion/css';\nimport React from 'react';\n\nimport { GrafanaTheme2 } from '@grafana/data/src';\nimport { useStyles2, PanelContainer } from '@grafana/ui';\n\nexport const NoData = () => {\n const css = useStyles2(getStyles);\n return (\n <>\n
\n {'No data'}\n \n >\n );\n};\n\nconst getStyles = (theme: GrafanaTheme2) => ({\n wrapper: css({\n label: 'no-data-card',\n padding: theme.spacing(3),\n background: theme.colors.background.primary,\n borderRadius: theme.shape.radius.default,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n flexGrow: 1,\n }),\n message: css({\n fontSize: theme.typography.h2.fontSize,\n padding: theme.spacing(4),\n color: theme.colors.text.disabled,\n }),\n});\n","import { css } from '@emotion/css';\nimport React from 'react';\n\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { LinkButton, CallToActionCard, Icon, useStyles2 } from '@grafana/ui';\nimport { contextSrv } from 'app/core/core';\nimport { AccessControlAction } from 'app/types';\n\nfunction getCardStyles(theme: GrafanaTheme2) {\n return css({\n maxWidth: `${theme.breakpoints.values.lg}px`,\n marginTop: theme.spacing(2),\n alignSelf: 'center',\n });\n}\n\nexport const NoDataSourceCallToAction = () => {\n const cardStyles = useStyles2(getCardStyles);\n\n const canCreateDataSource =\n contextSrv.hasPermission(AccessControlAction.DataSourcesCreate) &&\n contextSrv.hasPermission(AccessControlAction.DataSourcesWrite);\n\n const message =\n 'Explore requires at least one data source. Once you have added a data source, you can query it here.';\n const footer = (\n <>\n
\n <> ProTip: You can also define data sources through configuration files. >\n
\n Learn more\n \n >\n );\n\n const ctaElement = (\n
\n Add data source\n \n );\n\n return
;\n};\n","import { css } from '@emotion/css';\nimport React, { useEffect, useRef, useState } from 'react';\nimport { connect, ConnectedProps } from 'react-redux';\nimport { useToggle, useWindowSize } from 'react-use';\n\nimport { applyFieldOverrides, DataFrame, GrafanaTheme2, SplitOpen } from '@grafana/data';\nimport { config, reportInteraction } from '@grafana/runtime';\nimport { useStyles2, useTheme2, PanelChrome } from '@grafana/ui';\n\nimport { NodeGraph } from '../../../plugins/panel/nodeGraph';\nimport { useCategorizeFrames } from '../../../plugins/panel/nodeGraph/useCategorizeFrames';\nimport { StoreState } from '../../../types';\nimport { useLinks } from '../utils/links';\n\nconst getStyles = (theme: GrafanaTheme2) => ({\n warningText: css`\n label: warningText;\n display: flex;\n align-items: center;\n font-size: ${theme.typography.bodySmall.fontSize};\n color: ${theme.colors.text.secondary};\n `,\n});\n\ninterface OwnProps {\n // Edges and Nodes are separate frames\n dataFrames: DataFrame[];\n exploreId: string;\n // When showing the node graph together with trace view we do some changes so it works better.\n withTraceView?: boolean;\n datasourceType: string;\n splitOpenFn: SplitOpen;\n}\n\ntype Props = OwnProps & ConnectedProps
;\n\nexport function UnconnectedNodeGraphContainer(props: Props) {\n const { dataFrames, range, splitOpenFn, withTraceView, datasourceType } = props;\n const getLinks = useLinks(range, splitOpenFn);\n const theme = useTheme2();\n const styles = useStyles2(getStyles);\n\n // This is implicit dependency that is needed for links to work. At some point when replacing variables in the link\n // it requires field to have a display property which is added by the overrides even though we don't add any field\n // overrides in explore.\n const frames = applyFieldOverrides({\n fieldConfig: {\n defaults: {},\n overrides: [],\n },\n data: dataFrames,\n // We don't need proper replace here as it is only used in getLinks and we use getFieldLinks\n replaceVariables: (value) => value,\n theme,\n });\n\n const { nodes } = useCategorizeFrames(frames);\n const [collapsed, toggleCollapsed] = useToggle(true);\n\n const toggled = () => {\n toggleCollapsed();\n reportInteraction('grafana_traces_node_graph_panel_clicked', {\n datasourceType: datasourceType,\n grafana_version: config.buildInfo.version,\n isExpanded: !open,\n });\n };\n\n // Calculate node graph height based on window and top position, with some padding\n const { height: windowHeight } = useWindowSize();\n const containerRef = useRef(null);\n const [top, setTop] = useState(250);\n useEffect(() => {\n if (containerRef.current) {\n const { top } = containerRef.current.getBoundingClientRect();\n setTop(top);\n }\n }, [containerRef]);\n const height = windowHeight - top - 32;\n\n const countWarning =\n withTraceView && nodes[0]?.length > 1000 ? (\n ({nodes[0].length} nodes, can be slow to load)\n ) : null;\n\n return (\n \n \n \n
\n \n );\n}\n\nfunction mapStateToProps(state: StoreState, { exploreId }: OwnProps) {\n return {\n range: state.explore.panes[exploreId]!.range,\n };\n}\n\nconst connector = connect(mapStateToProps, {});\nexport const NodeGraphContainer = connector(UnconnectedNodeGraphContainer);\n","import { createSelector } from '@reduxjs/toolkit';\nimport React, { useCallback, useMemo } from 'react';\n\nimport { CoreApp } from '@grafana/data';\nimport { reportInteraction } from '@grafana/runtime';\nimport { DataQuery } from '@grafana/schema';\nimport { getNextRefIdChar } from 'app/core/utils/query';\nimport { useDispatch, useSelector } from 'app/types';\n\nimport { getDatasourceSrv } from '../plugins/datasource_srv';\nimport { QueryEditorRows } from '../query/components/QueryEditorRows';\n\nimport { changeQueries, runQueries } from './state/query';\nimport { getExploreItemSelector } from './state/selectors';\n\ninterface Props {\n exploreId: string;\n}\n\nconst makeSelectors = (exploreId: string) => {\n const exploreItemSelector = getExploreItemSelector(exploreId);\n return {\n getQueries: createSelector(exploreItemSelector, (s) => s!.queries),\n getQueryResponse: createSelector(exploreItemSelector, (s) => s!.queryResponse),\n getHistory: createSelector(exploreItemSelector, (s) => s!.history),\n getEventBridge: createSelector(exploreItemSelector, (s) => s!.eventBridge),\n getDatasourceInstanceSettings: createSelector(\n exploreItemSelector,\n (s) => getDatasourceSrv().getInstanceSettings(s!.datasourceInstance?.uid)!\n ),\n };\n};\n\nexport const QueryRows = ({ exploreId }: Props) => {\n const dispatch = useDispatch();\n const { getQueries, getDatasourceInstanceSettings, getQueryResponse, getHistory, getEventBridge } = useMemo(\n () => makeSelectors(exploreId),\n [exploreId]\n );\n\n const queries = useSelector(getQueries);\n const dsSettings = useSelector(getDatasourceInstanceSettings);\n const queryResponse = useSelector(getQueryResponse);\n const history = useSelector(getHistory);\n const eventBridge = useSelector(getEventBridge);\n\n const onRunQueries = useCallback(() => {\n dispatch(runQueries({ exploreId }));\n }, [dispatch, exploreId]);\n\n const onChange = useCallback(\n (newQueries: DataQuery[]) => {\n dispatch(changeQueries({ exploreId, queries: newQueries }));\n },\n [dispatch, exploreId]\n );\n\n const onAddQuery = useCallback(\n (query: DataQuery) => {\n onChange([...queries, { ...query, refId: getNextRefIdChar(queries) }]);\n },\n [onChange, queries]\n );\n\n const onQueryCopied = () => {\n reportInteraction('grafana_explore_query_row_copy');\n };\n\n const onQueryRemoved = () => {\n reportInteraction('grafana_explore_query_row_remove');\n };\n\n const onQueryToggled = (queryStatus?: boolean) => {\n reportInteraction('grafana_query_row_toggle', queryStatus === undefined ? {} : { queryEnabled: queryStatus });\n };\n\n return (\n \n );\n};\n","import { css } from '@emotion/css';\nimport { cloneDeep } from 'lodash';\nimport React, { useEffect, useId, useRef, useState } from 'react';\nimport { useWindowSize } from 'react-use';\nimport { VariableSizeList as List } from 'react-window';\n\nimport { DataFrame, Field as DataFrameField } from '@grafana/data/';\nimport { reportInteraction } from '@grafana/runtime/src';\nimport { Field, Switch } from '@grafana/ui/';\n\nimport { ItemLabels } from './ItemLabels';\nimport RawListItem from './RawListItem';\nimport {\n getRawPrometheusListItemsFromDataFrame,\n RawPrometheusListItemEmptyValue,\n} from './utils/getRawPrometheusListItemsFromDataFrame';\n\nexport type instantQueryRawVirtualizedListData = { Value: string; __name__: string; [index: string]: string };\n\nexport interface RawListContainerProps {\n tableResult: DataFrame;\n}\n\nconst styles = {\n wrapper: css`\n height: 100%;\n overflow: scroll;\n `,\n switchWrapper: css`\n display: flex;\n flex-direction: row;\n margin-bottom: 0;\n `,\n switchLabel: css`\n margin-left: 15px;\n margin-bottom: 0;\n `,\n switch: css`\n margin-left: 10px;\n `,\n resultCount: css`\n margin-bottom: 4px;\n `,\n header: css`\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 10px 0;\n font-size: 12px;\n line-height: 1.25;\n `,\n};\n\nconst mobileWidthThreshold = 480;\nconst numberOfColumnsBeforeExpandedViewIsDefault = 2;\n\n/**\n * The container that provides the virtualized list to the child components\n * @param props\n * @constructor\n */\nconst RawListContainer = (props: RawListContainerProps) => {\n const { tableResult } = props;\n const dataFrame = cloneDeep(tableResult);\n const listRef = useRef(null);\n\n const valueLabels = dataFrame.fields.filter((field) => field.name.includes('Value'));\n const items = getRawPrometheusListItemsFromDataFrame(dataFrame);\n const { width } = useWindowSize();\n const [isExpandedView, setIsExpandedView] = useState(\n width <= mobileWidthThreshold || valueLabels.length > numberOfColumnsBeforeExpandedViewIsDefault\n );\n\n const onContentClick = () => {\n setIsExpandedView(!isExpandedView);\n const props = {\n isExpanded: !isExpandedView,\n };\n reportInteraction('grafana_explore_prometheus_instant_query_ui_raw_toggle_expand', props);\n };\n\n useEffect(() => {\n // After the expanded view has updated, tell the list to re-render\n listRef.current?.resetAfterIndex(0, true);\n }, [isExpandedView]);\n\n const calculateInitialHeight = (length: number): number => {\n const maxListHeight = 600;\n const shortListLength = 10;\n\n if (length < shortListLength) {\n let sum = 0;\n for (let i = 0; i < length; i++) {\n sum += getListItemHeight(i, true);\n }\n\n return Math.min(maxListHeight, sum);\n }\n\n return maxListHeight;\n };\n\n const getListItemHeight = (itemIndex: number, isExpandedView: boolean) => {\n const singleLineHeight = 32;\n const additionalLineHeight = 22;\n if (!isExpandedView) {\n return singleLineHeight;\n }\n const item = items[itemIndex];\n\n // Height of 1.5 lines, plus the number of non-value attributes times the height of additional lines\n return 1.5 * singleLineHeight + (Object.keys(item).length - valueLabels.length) * additionalLineHeight;\n };\n\n const switchId = `isExpandedView ${useId()}`;\n\n return (\n \n \n\n \n {\n <>\n {/* Show the value headings above all the values, but only if we're in the contracted view */}\n {valueLabels.length > 1 && !isExpandedView && (\n
\n )}\n
getListItemHeight(index, isExpandedView)}\n height={calculateInitialHeight(items.length)}\n width=\"100%\"\n >\n {({ index, style }) => {\n let filteredValueLabels: DataFrameField[] | undefined;\n if (isExpandedView) {\n filteredValueLabels = valueLabels.filter((valueLabel) => {\n const itemWithValue = items[index][valueLabel.name];\n return itemWithValue && itemWithValue !== RawPrometheusListItemEmptyValue;\n });\n }\n\n return (\n \n \n
\n );\n }}\n
\n >\n }\n
\n \n );\n};\n\nexport default RawListContainer;\n","import { css } from '@emotion/css';\nimport React, { PureComponent } from 'react';\nimport { connect, ConnectedProps } from 'react-redux';\n\nimport { applyFieldOverrides, DataFrame, SelectableValue, SplitOpen } from '@grafana/data';\nimport { getTemplateSrv, reportInteraction } from '@grafana/runtime';\nimport { TimeZone } from '@grafana/schema';\nimport { RadioButtonGroup, Table, AdHocFilterItem, PanelChrome } from '@grafana/ui';\nimport { config } from 'app/core/config';\nimport { PANEL_BORDER } from 'app/core/constants';\nimport { StoreState, TABLE_RESULTS_STYLE } from 'app/types';\nimport { ExploreItemState, TABLE_RESULTS_STYLES, TableResultsStyle } from 'app/types/explore';\n\nimport { MetaInfoText } from '../MetaInfoText';\nimport RawListContainer from '../PrometheusListView/RawListContainer';\nimport { exploreDataLinkPostProcessorFactory } from '../utils/links';\n\ninterface RawPrometheusContainerProps {\n ariaLabel?: string;\n exploreId: string;\n width: number;\n timeZone: TimeZone;\n onCellFilterAdded?: (filter: AdHocFilterItem) => void;\n showRawPrometheus?: boolean;\n splitOpenFn: SplitOpen;\n}\n\ninterface PrometheusContainerState {\n resultsStyle: TableResultsStyle;\n}\n\nfunction mapStateToProps(state: StoreState, { exploreId }: RawPrometheusContainerProps) {\n const explore = state.explore;\n const item: ExploreItemState = explore.panes[exploreId]!;\n const { tableResult, rawPrometheusResult, range, queryResponse } = item;\n const rawPrometheusFrame: DataFrame[] = rawPrometheusResult ? [rawPrometheusResult] : [];\n const result = (tableResult?.length ?? 0) > 0 && rawPrometheusResult ? tableResult : rawPrometheusFrame;\n const loading = queryResponse.state;\n\n return { loading, tableResult: result, range };\n}\n\nconst connector = connect(mapStateToProps, {});\n\ntype Props = RawPrometheusContainerProps & ConnectedProps;\n\nexport class RawPrometheusContainer extends PureComponent {\n constructor(props: Props) {\n super(props);\n\n // If resultsStyle is undefined we won't render the toggle, and the default table will be rendered\n if (props.showRawPrometheus) {\n this.state = {\n resultsStyle: TABLE_RESULTS_STYLE.raw,\n };\n }\n }\n\n onChangeResultsStyle = (resultsStyle: TableResultsStyle) => {\n this.setState({ resultsStyle });\n };\n\n getTableHeight() {\n const { tableResult } = this.props;\n\n if (!tableResult || tableResult.length === 0) {\n return 200;\n }\n\n // tries to estimate table height\n return Math.max(Math.min(600, tableResult[0].length * 35) + 35);\n }\n\n renderLabel = () => {\n const spacing = css({\n display: 'flex',\n justifyContent: 'space-between',\n flex: '1',\n });\n const ALL_GRAPH_STYLE_OPTIONS: Array> = TABLE_RESULTS_STYLES.map((style) => ({\n value: style,\n // capital-case it and switch `_` to ` `\n label: style[0].toUpperCase() + style.slice(1).replace(/_/, ' '),\n }));\n\n return (\n \n {\n const props = {\n state:\n this.state.resultsStyle === TABLE_RESULTS_STYLE.table\n ? TABLE_RESULTS_STYLE.raw\n : TABLE_RESULTS_STYLE.table,\n };\n reportInteraction('grafana_explore_prometheus_instant_query_ui_toggle_clicked', props);\n }}\n size=\"sm\"\n options={ALL_GRAPH_STYLE_OPTIONS}\n value={this.state?.resultsStyle}\n onChange={this.onChangeResultsStyle}\n />\n
\n );\n };\n\n render() {\n const { loading, onCellFilterAdded, tableResult, width, splitOpenFn, range, ariaLabel, timeZone } = this.props;\n const height = this.getTableHeight();\n const tableWidth = width - config.theme.panelPadding * 2 - PANEL_BORDER;\n\n let dataFrames = tableResult;\n\n const dataLinkPostProcessor = exploreDataLinkPostProcessorFactory(splitOpenFn, range);\n\n if (dataFrames?.length) {\n dataFrames = applyFieldOverrides({\n data: dataFrames,\n timeZone,\n theme: config.theme2,\n replaceVariables: getTemplateSrv().replace.bind(getTemplateSrv()),\n fieldConfig: {\n defaults: {},\n overrides: [],\n },\n dataLinkPostProcessor,\n });\n }\n\n const frames = dataFrames?.filter(\n (frame: DataFrame | undefined): frame is DataFrame => !!frame && frame.length !== 0\n );\n\n const title = this.state.resultsStyle === TABLE_RESULTS_STYLE.raw ? 'Raw' : 'Table';\n const label = this.state?.resultsStyle !== undefined ? this.renderLabel() : 'Table';\n\n // Render table as default if resultsStyle is not set.\n const renderTable = !this.state?.resultsStyle || this.state?.resultsStyle === TABLE_RESULTS_STYLE.table;\n\n return (\n \n {frames?.length && (\n <>\n {renderTable && (\n \n )}\n {this.state?.resultsStyle === TABLE_RESULTS_STYLE.raw && }\n >\n )}\n {!frames?.length && }\n \n );\n }\n}\n\nexport default connector(RawPrometheusContainer);\n","import React, { CSSProperties } from 'react';\nimport Transition, { ExitHandler } from 'react-transition-group/Transition';\n\ninterface Props {\n duration: number;\n children: JSX.Element;\n in: boolean;\n unmountOnExit?: boolean;\n onExited?: ExitHandler;\n}\n\nexport const FadeIn = (props: Props) => {\n const defaultStyle: CSSProperties = {\n transition: `opacity ${props.duration}ms linear`,\n opacity: 0,\n };\n\n const transitionStyles: { [str: string]: CSSProperties } = {\n exited: { opacity: 0, display: 'none' },\n entering: { opacity: 0 },\n entered: { opacity: 1 },\n exiting: { opacity: 0 },\n };\n\n return (\n \n {(state) => (\n \n {props.children}\n
\n )}\n \n );\n};\n","import React from 'react';\n\nimport { DataQueryError } from '@grafana/data';\nimport { Alert } from '@grafana/ui';\nimport { FadeIn } from 'app/core/components/Animations/FadeIn';\n\nexport interface ErrorContainerProps {\n queryError?: DataQueryError;\n}\n\nexport const ErrorContainer = (props: ErrorContainerProps) => {\n const { queryError } = props;\n const showError = queryError ? true : false;\n const duration = showError ? 100 : 10;\n const title = queryError ? 'Query error' : 'Unknown error';\n const message = queryError?.message || queryError?.data?.message || null;\n\n return (\n \n \n {message}\n \n \n );\n};\n","import React from 'react';\n\nimport { LoadingState } from '@grafana/data';\nimport { useSelector } from 'app/types';\n\nimport { ErrorContainer } from './ErrorContainer';\n\ninterface Props {\n exploreId: string;\n}\nexport function ResponseErrorContainer(props: Props) {\n const queryResponse = useSelector((state) => state.explore.panes[props.exploreId]!.queryResponse);\n const queryError = queryResponse?.state === LoadingState.Error ? queryResponse?.error : undefined;\n\n // Errors with ref ids are shown below the corresponding query\n if (queryError?.refId) {\n return null;\n }\n\n return ;\n}\n","import { css, cx } from '@emotion/css';\nimport React, { useCallback, useState } from 'react';\nimport { connect, ConnectedProps } from 'react-redux';\nimport { useAsync } from 'react-use';\n\nimport { GrafanaTheme2, DataSourceApi } from '@grafana/data';\nimport { config, getDataSourceSrv, reportInteraction, getAppEvents } from '@grafana/runtime';\nimport { DataQuery } from '@grafana/schema';\nimport { TextArea, Button, IconButton, useStyles2, LoadingPlaceholder } from '@grafana/ui';\nimport { notifyApp } from 'app/core/actions';\nimport { createSuccessNotification } from 'app/core/copy/appNotification';\nimport { Trans, t } from 'app/core/internationalization';\nimport { copyStringToClipboard } from 'app/core/utils/explore';\nimport { createUrlFromRichHistory, createQueryText } from 'app/core/utils/richHistory';\nimport { createAndCopyShortLink } from 'app/core/utils/shortLinks';\nimport { changeDatasource } from 'app/features/explore/state/datasource';\nimport { starHistoryItem, commentHistoryItem, deleteHistoryItem } from 'app/features/explore/state/history';\nimport { setQueries } from 'app/features/explore/state/query';\nimport { dispatch } from 'app/store/store';\nimport { StoreState } from 'app/types';\nimport { ShowConfirmModalEvent } from 'app/types/events';\nimport { RichHistoryQuery } from 'app/types/explore';\n\nfunction mapStateToProps(state: StoreState, { exploreId }: { exploreId: string }) {\n const explore = state.explore;\n const { datasourceInstance } = explore.panes[exploreId]!;\n return {\n exploreId,\n datasourceInstance,\n };\n}\n\nconst mapDispatchToProps = {\n changeDatasource,\n deleteHistoryItem,\n commentHistoryItem,\n starHistoryItem,\n setQueries,\n};\n\nconst connector = connect(mapStateToProps, mapDispatchToProps);\n\ninterface OwnProps {\n queryHistoryItem: RichHistoryQuery;\n}\n\nexport type Props = ConnectedProps & OwnProps;\n\nconst getStyles = (theme: GrafanaTheme2) => {\n /* Hard-coded value so all buttons and icons on right side of card are aligned */\n const rightColumnWidth = '240px';\n const rightColumnContentWidth = '170px';\n\n /* If datasource was removed, card will have inactive color */\n const cardColor = theme.colors.background.secondary;\n\n return {\n queryCard: css`\n position: relative;\n display: flex;\n flex-direction: column;\n border: 1px solid ${theme.colors.border.weak};\n margin: ${theme.spacing(1)} 0;\n background-color: ${cardColor};\n border-radius: ${theme.shape.radius.default};\n .starred {\n color: ${theme.v1.palette.orange};\n }\n `,\n cardRow: css`\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: ${theme.spacing(1)};\n border-bottom: none;\n :first-of-type {\n border-bottom: 1px solid ${theme.colors.border.weak};\n padding: ${theme.spacing(0.5, 1)};\n }\n img {\n height: ${theme.typography.fontSize}px;\n max-width: ${theme.typography.fontSize}px;\n margin-right: ${theme.spacing(1)};\n }\n `,\n queryActionButtons: css`\n max-width: ${rightColumnContentWidth};\n display: flex;\n justify-content: flex-end;\n font-size: ${theme.typography.size.base};\n button {\n margin-left: ${theme.spacing(1)};\n }\n `,\n queryContainer: css`\n font-weight: ${theme.typography.fontWeightMedium};\n width: calc(100% - ${rightColumnWidth});\n `,\n updateCommentContainer: css`\n width: calc(100% + ${rightColumnWidth});\n margin-top: ${theme.spacing(1)};\n `,\n comment: css`\n overflow-wrap: break-word;\n font-size: ${theme.typography.bodySmall.fontSize};\n font-weight: ${theme.typography.fontWeightRegular};\n margin-top: ${theme.spacing(0.5)};\n `,\n commentButtonRow: css`\n > * {\n margin-top: ${theme.spacing(1)};\n margin-right: ${theme.spacing(1)};\n }\n `,\n textArea: css`\n width: 100%;\n `,\n runButton: css`\n max-width: ${rightColumnContentWidth};\n display: flex;\n justify-content: flex-end;\n button {\n height: auto;\n padding: ${theme.spacing(0.5, 2)};\n line-height: 1.4;\n span {\n white-space: normal !important;\n }\n }\n `,\n loader: css`\n position: absolute;\n width: 100%;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: ${theme.colors.background.secondary};\n `,\n };\n};\n\nexport function RichHistoryCard(props: Props) {\n const {\n queryHistoryItem,\n commentHistoryItem,\n starHistoryItem,\n deleteHistoryItem,\n changeDatasource,\n exploreId,\n datasourceInstance,\n setQueries,\n } = props;\n\n const [activeUpdateComment, setActiveUpdateComment] = useState(false);\n const [comment, setComment] = useState(queryHistoryItem.comment);\n const { value: historyCardData, loading } = useAsync(async () => {\n let datasourceInstance: DataSourceApi | undefined;\n try {\n datasourceInstance = await getDataSourceSrv().get(queryHistoryItem.datasourceUid);\n } catch (e) {}\n\n return {\n datasourceInstance,\n queries: await Promise.all(\n queryHistoryItem.queries.map(async (query) => {\n let datasource;\n if (datasourceInstance?.meta.mixed) {\n try {\n datasource = await getDataSourceSrv().get(query.datasource);\n } catch (e) {}\n } else {\n datasource = datasourceInstance;\n }\n\n return {\n query,\n datasource,\n };\n })\n ),\n };\n }, [queryHistoryItem.datasourceUid, queryHistoryItem.queries]);\n\n const styles = useStyles2(getStyles);\n\n const onRunQuery = async () => {\n const queriesToRun = queryHistoryItem.queries;\n const differentDataSource = queryHistoryItem.datasourceUid !== datasourceInstance?.uid;\n if (differentDataSource) {\n await changeDatasource({ exploreId, datasource: queryHistoryItem.datasourceUid });\n }\n setQueries(exploreId, queriesToRun);\n\n reportInteraction('grafana_explore_query_history_run', {\n queryHistoryEnabled: config.queryHistoryEnabled,\n differentDataSource,\n });\n };\n\n const onCopyQuery = async () => {\n const datasources = [...queryHistoryItem.queries.map((query) => query.datasource?.type || 'unknown')];\n reportInteraction('grafana_explore_query_history_copy_query', {\n datasources,\n mixed: Boolean(historyCardData?.datasourceInstance?.meta.mixed),\n });\n\n if (loading || !historyCardData) {\n return;\n }\n\n const queriesText = historyCardData.queries\n .map((query) => {\n return createQueryText(query.query, query.datasource);\n })\n .join('\\n');\n\n copyStringToClipboard(queriesText);\n dispatch(\n notifyApp(\n createSuccessNotification(t('explore.rich-history-notification.query-copied', 'Query copied to clipboard'))\n )\n );\n };\n\n const onCreateShortLink = async () => {\n const link = createUrlFromRichHistory(queryHistoryItem);\n await createAndCopyShortLink(link);\n };\n\n const onDeleteQuery = () => {\n const performDelete = (queryId: string) => {\n deleteHistoryItem(queryId);\n dispatch(\n notifyApp(createSuccessNotification(t('explore.rich-history-notification.query-deleted', 'Query deleted')))\n );\n reportInteraction('grafana_explore_query_history_deleted', {\n queryHistoryEnabled: config.queryHistoryEnabled,\n });\n };\n\n // For starred queries, we want confirmation. For non-starred, we don't.\n if (queryHistoryItem.starred) {\n getAppEvents().publish(\n new ShowConfirmModalEvent({\n title: t('explore.rich-history-card.delete-query-confirmation-title', 'Delete'),\n text: t(\n 'explore.rich-history-card.delete-starred-query-confirmation-text',\n 'Are you sure you want to permanently delete your starred query?'\n ),\n yesText: t('explore.rich-history-card.confirm-delete', 'Delete'),\n icon: 'trash-alt',\n onConfirm: () => performDelete(queryHistoryItem.id),\n })\n );\n } else {\n performDelete(queryHistoryItem.id);\n }\n };\n\n const onStarrQuery = () => {\n starHistoryItem(queryHistoryItem.id, !queryHistoryItem.starred);\n reportInteraction('grafana_explore_query_history_starred', {\n queryHistoryEnabled: config.queryHistoryEnabled,\n newValue: !queryHistoryItem.starred,\n });\n };\n\n const toggleActiveUpdateComment = () => setActiveUpdateComment(!activeUpdateComment);\n\n const onUpdateComment = () => {\n commentHistoryItem(queryHistoryItem.id, comment);\n setActiveUpdateComment(false);\n reportInteraction('grafana_explore_query_history_commented', {\n queryHistoryEnabled: config.queryHistoryEnabled,\n });\n };\n\n const onCancelUpdateComment = () => {\n setActiveUpdateComment(false);\n setComment(queryHistoryItem.comment);\n };\n\n const onKeyDown = (keyEvent: React.KeyboardEvent) => {\n if (keyEvent.key === 'Enter' && (keyEvent.shiftKey || keyEvent.ctrlKey)) {\n onUpdateComment();\n }\n\n if (keyEvent.key === 'Escape') {\n onCancelUpdateComment();\n }\n };\n\n const updateComment = (\n \n );\n\n const queryActionButtons = (\n \n 0\n ? t('explore.rich-history-card.edit-comment-tooltip', 'Edit comment')\n : t('explore.rich-history-card.add-comment-tooltip', 'Add comment')\n }\n />\n \n {historyCardData?.datasourceInstance && (\n \n Copy shortened link to clipboard\n \n }\n />\n )}\n \n \n
\n );\n\n return (\n \n
\n \n\n {queryActionButtons}\n
\n
\n
\n {historyCardData?.queries.map((q, i) => {\n return
;\n })}\n {!activeUpdateComment && queryHistoryItem.comment && (\n
\n {queryHistoryItem.comment}\n
\n )}\n {activeUpdateComment && updateComment}\n
\n {!activeUpdateComment && (\n
\n \n
\n )}\n
\n {loading && (\n
\n )}\n
\n );\n}\n\nconst getQueryStyles = (theme: GrafanaTheme2) => ({\n queryRow: css`\n border-top: 1px solid ${theme.colors.border.weak};\n display: flex;\n flex-direction: row;\n padding: 4px 0px;\n gap: 4px;\n :first-child {\n border-top: none;\n }\n `,\n dsInfoContainer: css`\n display: flex;\n align-items: center;\n `,\n queryText: css`\n word-break: break-all;\n `,\n});\n\ninterface QueryProps {\n query: {\n query: DataQuery;\n datasource?: DataSourceApi;\n };\n /** Show datasource info (icon+name) alongside the query text */\n showDsInfo?: boolean;\n}\n\nconst Query = ({ query, showDsInfo = false }: QueryProps) => {\n const styles = useStyles2(getQueryStyles);\n\n return (\n \n {showDsInfo && (\n
\n \n {': '}\n
\n )}\n
\n {createQueryText(query.query, query.datasource)}\n \n
\n );\n};\n\nconst getDsInfoStyles = (size: 'sm' | 'md') => (theme: GrafanaTheme2) => css`\n display: flex;\n align-items: center;\n font-size: ${theme.typography[size === 'sm' ? 'bodySmall' : 'body'].fontSize};\n font-weight: ${theme.typography.fontWeightMedium};\n white-space: nowrap;\n`;\n\nfunction DatasourceInfo({ dsApi, size }: { dsApi?: DataSourceApi; size: 'sm' | 'md' }) {\n const getStyles = useCallback((theme: GrafanaTheme2) => getDsInfoStyles(size)(theme), [size]);\n const styles = useStyles2(getStyles);\n\n return (\n \n

\n
\n {dsApi?.name || t('explore.rich-history-card.datasource-not-exist', 'Data source does not exist anymore')}\n
\n
\n );\n}\n\nexport default connector(RichHistoryCard);\n","import { css } from '@emotion/css';\nimport React, { useEffect } from 'react';\n\nimport { GrafanaTheme2, SelectableValue } from '@grafana/data';\nimport { config } from '@grafana/runtime';\nimport { Button, FilterInput, MultiSelect, RangeSlider, Select, useStyles2 } from '@grafana/ui';\nimport { Trans, t } from 'app/core/internationalization';\nimport {\n createDatasourcesList,\n mapNumbertoTimeInSlider,\n mapQueriesToHeadings,\n SortOrder,\n RichHistorySearchFilters,\n RichHistorySettings,\n} from 'app/core/utils/richHistory';\nimport { RichHistoryQuery } from 'app/types/explore';\n\nimport { getSortOrderOptions } from './RichHistory';\nimport RichHistoryCard from './RichHistoryCard';\n\nexport interface RichHistoryQueriesTabProps {\n queries: RichHistoryQuery[];\n totalQueries: number;\n loading: boolean;\n activeDatasourceInstance: string;\n updateFilters: (filtersToUpdate?: Partial) => void;\n clearRichHistoryResults: () => void;\n loadMoreRichHistory: () => void;\n richHistorySettings: RichHistorySettings;\n richHistorySearchFilters?: RichHistorySearchFilters;\n exploreId: string;\n height: number;\n}\n\nconst getStyles = (theme: GrafanaTheme2, height: number) => {\n return {\n container: css`\n display: flex;\n `,\n labelSlider: css`\n font-size: ${theme.typography.bodySmall.fontSize};\n &:last-of-type {\n margin-top: ${theme.spacing(3)};\n }\n &:first-of-type {\n font-weight: ${theme.typography.fontWeightMedium};\n margin-bottom: ${theme.spacing(2)};\n }\n `,\n containerContent: css`\n /* 134px is based on the width of the Query history tabs bar, so the content is aligned to right side of the tab */\n width: calc(100% - 134px);\n `,\n containerSlider: css`\n width: 129px;\n margin-right: ${theme.spacing(1)};\n `,\n fixedSlider: css`\n position: fixed;\n `,\n slider: css`\n bottom: 10px;\n height: ${height - 180}px;\n width: 129px;\n padding: ${theme.spacing(1)} 0;\n `,\n selectors: css`\n display: flex;\n justify-content: space-between;\n flex-wrap: wrap;\n `,\n filterInput: css`\n margin-bottom: ${theme.spacing(1)};\n `,\n multiselect: css`\n width: 100%;\n margin-bottom: ${theme.spacing(1)};\n `,\n sort: css`\n width: 170px;\n `,\n sessionName: css`\n display: flex;\n align-items: flex-start;\n justify-content: flex-start;\n margin-top: ${theme.spacing(3)};\n h4 {\n margin: 0 10px 0 0;\n }\n `,\n heading: css`\n font-size: ${theme.typography.h4.fontSize};\n margin: ${theme.spacing(2, 0.25, 1, 0.25)};\n `,\n footer: css`\n height: 60px;\n display: flex;\n justify-content: center;\n align-items: center;\n font-weight: ${theme.typography.fontWeightLight};\n font-size: ${theme.typography.bodySmall.fontSize};\n a {\n font-weight: ${theme.typography.fontWeightMedium};\n margin-left: ${theme.spacing(0.25)};\n }\n `,\n queries: css`\n font-size: ${theme.typography.bodySmall.fontSize};\n font-weight: ${theme.typography.fontWeightRegular};\n margin-left: ${theme.spacing(0.5)};\n `,\n };\n};\n\nexport function RichHistoryQueriesTab(props: RichHistoryQueriesTabProps) {\n const {\n queries,\n totalQueries,\n loading,\n richHistorySearchFilters,\n updateFilters,\n clearRichHistoryResults,\n loadMoreRichHistory,\n richHistorySettings,\n exploreId,\n height,\n activeDatasourceInstance,\n } = props;\n\n const styles = useStyles2(getStyles, height);\n\n const listOfDatasources = createDatasourcesList();\n\n useEffect(() => {\n const datasourceFilters =\n !richHistorySettings.activeDatasourceOnly && richHistorySettings.lastUsedDatasourceFilters\n ? richHistorySettings.lastUsedDatasourceFilters\n : [activeDatasourceInstance];\n const filters: RichHistorySearchFilters = {\n search: '',\n sortOrder: SortOrder.Descending,\n datasourceFilters,\n from: 0,\n to: richHistorySettings.retentionPeriod,\n starred: false,\n };\n updateFilters(filters);\n\n return () => {\n clearRichHistoryResults();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n if (!richHistorySearchFilters) {\n return (\n \n Loading...;\n \n );\n }\n\n /* mappedQueriesToHeadings is an object where query headings (stringified dates/data sources)\n * are keys and arrays with queries that belong to that headings are values.\n */\n const mappedQueriesToHeadings = mapQueriesToHeadings(queries, richHistorySearchFilters.sortOrder);\n const sortOrderOptions = getSortOrderOptions();\n const partialResults = queries.length && queries.length !== totalQueries;\n\n return (\n \n
\n
\n
\n Filter history\n
\n
{mapNumbertoTimeInSlider(richHistorySearchFilters.from)}
\n
\n {\n updateFilters({ from: value![0], to: value![1] });\n }}\n />\n
\n
{mapNumbertoTimeInSlider(richHistorySearchFilters.to)}
\n
\n
\n\n
\n
\n {!richHistorySettings.activeDatasourceOnly && (\n
{\n return { value: ds.name, label: ds.name };\n })}\n value={richHistorySearchFilters.datasourceFilters}\n placeholder={t(\n 'explore.rich-history-queries-tab.filter-placeholder',\n 'Filter queries for data sources(s)'\n )}\n aria-label={t('explore.rich-history-queries-tab.filter-aria-label', 'Filter queries for data sources(s)')}\n onChange={(options: SelectableValue[]) => {\n updateFilters({ datasourceFilters: options.map((option) => option.value) });\n }}\n />\n )}\n \n updateFilters({ search })}\n />\n
\n \n
\n \n\n {loading && (\n
\n Loading results...\n \n )}\n\n {!loading &&\n Object.keys(mappedQueriesToHeadings).map((heading) => {\n return (\n
\n
\n {heading}{' '}\n \n {partialResults ? (\n \n ) : (\n \n )}\n \n
\n {mappedQueriesToHeadings[heading].map((q) => {\n return
;\n })}\n
\n );\n })}\n {partialResults ? (\n
\n Load more0>\"\n values={{ shown: queries.length, total: totalQueries }}\n components={[\n ,\n ]}\n />\n
\n ) : null}\n
\n {!config.queryHistoryEnabled\n ? t(\n 'explore.rich-history-queries-tab.history-local',\n 'The history is local to your browser and is not shared with others.'\n )\n : ''}\n
\n
\n
\n );\n}\n","import { css } from '@emotion/css';\nimport React from 'react';\n\nimport { GrafanaTheme2, SelectableValue } from '@grafana/data';\nimport { getAppEvents } from '@grafana/runtime';\nimport { useStyles2, Select, Button, Field, InlineField, InlineSwitch, Alert } from '@grafana/ui';\nimport { notifyApp } from 'app/core/actions';\nimport { createSuccessNotification } from 'app/core/copy/appNotification';\nimport { MAX_HISTORY_ITEMS } from 'app/core/history/RichHistoryLocalStorage';\nimport { Trans, t } from 'app/core/internationalization';\nimport { dispatch } from 'app/store/store';\n\nimport { supportedFeatures } from '../../../core/history/richHistoryStorageProvider';\nimport { ShowConfirmModalEvent } from '../../../types/events';\n\nexport interface RichHistorySettingsProps {\n retentionPeriod: number;\n starredTabAsFirstTab: boolean;\n activeDatasourceOnly: boolean;\n onChangeRetentionPeriod: (option: SelectableValue) => void;\n toggleStarredTabAsFirstTab: () => void;\n toggleactiveDatasourceOnly: () => void;\n deleteRichHistory: () => void;\n}\n\nconst getStyles = (theme: GrafanaTheme2) => {\n return {\n container: css`\n font-size: ${theme.typography.bodySmall.fontSize};\n `,\n spaceBetween: css`\n margin-bottom: ${theme.spacing(3)};\n `,\n input: css`\n max-width: 200px;\n `,\n bold: css`\n font-weight: ${theme.typography.fontWeightBold};\n `,\n bottomMargin: css`\n margin-bottom: ${theme.spacing(1)};\n `,\n };\n};\n\nconst retentionPeriodOptions = [\n { value: 2, label: t('explore.rich-history-settings-tab.retention-period.2-days', '2 days') },\n { value: 5, label: t('explore.rich-history-settings-tab.retention-period.5-days', '5 days') },\n { value: 7, label: t('explore.rich-history-settings-tab.retention-period.1-week', '1 week') },\n { value: 14, label: t('explore.rich-history-settings-tab.retention-period.2-weeks', '2 weeks') },\n];\n\nexport function RichHistorySettingsTab(props: RichHistorySettingsProps) {\n const {\n retentionPeriod,\n starredTabAsFirstTab,\n activeDatasourceOnly,\n onChangeRetentionPeriod,\n toggleStarredTabAsFirstTab,\n toggleactiveDatasourceOnly,\n deleteRichHistory,\n } = props;\n const styles = useStyles2(getStyles);\n const selectedOption = retentionPeriodOptions.find((v) => v.value === retentionPeriod);\n\n const onDelete = () => {\n getAppEvents().publish(\n new ShowConfirmModalEvent({\n title: t('explore.rich-history-settings-tab.delete-title', 'Delete'),\n text: t(\n 'explore.rich-history-settings-tab.delete-confirm-text',\n 'Are you sure you want to permanently delete your query history?'\n ),\n yesText: t('explore.rich-history-settings-tab.delete-confirm', 'Delete'),\n icon: 'trash-alt',\n onConfirm: () => {\n deleteRichHistory();\n dispatch(\n notifyApp(\n createSuccessNotification(\n t('explore.rich-history-settings-tab.query-history-deleted', 'Query history deleted')\n )\n )\n );\n },\n })\n );\n };\n\n return (\n \n {supportedFeatures().changeRetention ? (\n
\n \n \n
\n \n ) : (\n
\n {t(\n 'explore.rich-history-settings-tab.alert-info',\n \"Grafana will keep entries up to {{optionLabel}}.Starred entries won't be deleted.\",\n {\n optionLabel: selectedOption?.label,\n }\n )}\n \n )}\n
\n \n \n {supportedFeatures().onlyActiveDataSource && (\n
\n \n \n )}\n {supportedFeatures().clearHistory && (\n
\n
\n Clear query history\n
\n
\n \n Delete all of your query history, permanently.\n \n
\n
\n
\n )}\n
\n );\n}\n","import { css } from '@emotion/css';\nimport React, { useEffect } from 'react';\n\nimport { GrafanaTheme2, SelectableValue } from '@grafana/data';\nimport { config } from '@grafana/runtime';\nimport { useStyles2, Select, MultiSelect, FilterInput, Button } from '@grafana/ui';\nimport { Trans, t } from 'app/core/internationalization';\nimport {\n createDatasourcesList,\n SortOrder,\n RichHistorySearchFilters,\n RichHistorySettings,\n} from 'app/core/utils/richHistory';\nimport { RichHistoryQuery } from 'app/types/explore';\n\nimport { getSortOrderOptions } from './RichHistory';\nimport RichHistoryCard from './RichHistoryCard';\n\nexport interface RichHistoryStarredTabProps {\n queries: RichHistoryQuery[];\n totalQueries: number;\n loading: boolean;\n activeDatasourceInstance: string;\n updateFilters: (filtersToUpdate: Partial) => void;\n clearRichHistoryResults: () => void;\n loadMoreRichHistory: () => void;\n richHistorySearchFilters?: RichHistorySearchFilters;\n richHistorySettings: RichHistorySettings;\n exploreId: string;\n}\n\nconst getStyles = (theme: GrafanaTheme2) => {\n return {\n container: css`\n display: flex;\n `,\n containerContent: css`\n width: 100%;\n `,\n selectors: css`\n display: flex;\n justify-content: space-between;\n flex-wrap: wrap;\n `,\n multiselect: css`\n width: 100%;\n margin-bottom: ${theme.spacing(1)};\n `,\n filterInput: css`\n margin-bottom: ${theme.spacing(1)};\n `,\n sort: css`\n width: 170px;\n `,\n footer: css`\n height: 60px;\n display: flex;\n justify-content: center;\n align-items: center;\n font-weight: ${theme.typography.fontWeightLight};\n font-size: ${theme.typography.bodySmall.fontSize};\n a {\n font-weight: ${theme.typography.fontWeightMedium};\n margin-left: ${theme.spacing(0.25)};\n }\n `,\n };\n};\n\nexport function RichHistoryStarredTab(props: RichHistoryStarredTabProps) {\n const {\n updateFilters,\n clearRichHistoryResults,\n loadMoreRichHistory,\n activeDatasourceInstance,\n richHistorySettings,\n queries,\n totalQueries,\n loading,\n richHistorySearchFilters,\n exploreId,\n } = props;\n\n const styles = useStyles2(getStyles);\n\n const listOfDatasources = createDatasourcesList();\n\n useEffect(() => {\n const datasourceFilters =\n richHistorySettings.activeDatasourceOnly && richHistorySettings.lastUsedDatasourceFilters\n ? richHistorySettings.lastUsedDatasourceFilters\n : [activeDatasourceInstance];\n const filters: RichHistorySearchFilters = {\n search: '',\n sortOrder: SortOrder.Descending,\n datasourceFilters,\n from: 0,\n to: richHistorySettings.retentionPeriod,\n starred: true,\n };\n updateFilters(filters);\n return () => {\n clearRichHistoryResults();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n if (!richHistorySearchFilters) {\n return (\n \n Loading...;\n \n );\n }\n\n const sortOrderOptions = getSortOrderOptions();\n\n return (\n \n
\n
\n {!richHistorySettings.activeDatasourceOnly && (\n
{\n return { value: ds.name, label: ds.name };\n })}\n value={richHistorySearchFilters.datasourceFilters}\n placeholder={t(\n 'explore.rich-history-starred-tab.filter-queries-placeholder',\n 'Filter queries for data sources(s)'\n )}\n aria-label={t(\n 'explore.rich-history-starred-tab.filter-queries-aria-label',\n 'Filter queries for data sources(s)'\n )}\n onChange={(options: SelectableValue[]) => {\n updateFilters({ datasourceFilters: options.map((option) => option.value) });\n }}\n />\n )}\n \n updateFilters({ search })}\n />\n
\n \n
\n \n {loading && (\n
\n Loading results...\n \n )}\n {!loading &&\n queries.map((q) => {\n return
;\n })}\n {queries.length && queries.length !== totalQueries ? (\n
\n Load more0>\"\n values={{ shown: queries.length, total: totalQueries }}\n components={[\n ,\n ]}\n />\n
\n ) : null}\n
\n {!config.queryHistoryEnabled\n ? t(\n 'explore.rich-history-starred-tab.local-history-message',\n 'The history is local to your browser and is not shared with others.'\n )\n : ''}\n
\n
\n
\n );\n}\n","import { debounce } from 'lodash';\nimport React, { useState, useEffect } from 'react';\n\nimport { SelectableValue } from '@grafana/data';\nimport { TabbedContainer, TabConfig } from '@grafana/ui';\nimport { t } from 'app/core/internationalization';\nimport { SortOrder, RichHistorySearchFilters, RichHistorySettings } from 'app/core/utils/richHistory';\nimport { RichHistoryQuery } from 'app/types/explore';\n\nimport { supportedFeatures } from '../../../core/history/richHistoryStorageProvider';\n\nimport { RichHistoryQueriesTab } from './RichHistoryQueriesTab';\nimport { RichHistorySettingsTab } from './RichHistorySettingsTab';\nimport { RichHistoryStarredTab } from './RichHistoryStarredTab';\n\nexport enum Tabs {\n RichHistory = 'Query history',\n Starred = 'Starred',\n Settings = 'Settings',\n}\n\nexport const getSortOrderOptions = () =>\n [\n { label: t('explore.rich-history.newest-first', 'Newest first'), value: SortOrder.Descending },\n { label: t('explore.rich-history.oldest-first', 'Oldest first'), value: SortOrder.Ascending },\n { label: t('explore.rich-history.datasource-a-z', 'Data source A-Z'), value: SortOrder.DatasourceAZ },\n { label: t('explore.rich-history.datasource-z-a', 'Data source Z-A'), value: SortOrder.DatasourceZA },\n ].filter((option) => supportedFeatures().availableFilters.includes(option.value));\n\nexport interface RichHistoryProps {\n richHistory: RichHistoryQuery[];\n richHistoryTotal?: number;\n richHistorySettings: RichHistorySettings;\n richHistorySearchFilters?: RichHistorySearchFilters;\n updateHistorySettings: (settings: RichHistorySettings) => void;\n updateHistorySearchFilters: (exploreId: string, filters: RichHistorySearchFilters) => void;\n loadRichHistory: (exploreId: string) => void;\n loadMoreRichHistory: (exploreId: string) => void;\n clearRichHistoryResults: (exploreId: string) => void;\n deleteRichHistory: () => void;\n activeDatasourceInstance: string;\n firstTab: Tabs;\n exploreId: string;\n height: number;\n onClose: () => void;\n}\n\nexport function RichHistory(props: RichHistoryProps) {\n const {\n richHistory,\n richHistoryTotal,\n height,\n exploreId,\n deleteRichHistory,\n onClose,\n firstTab,\n activeDatasourceInstance,\n } = props;\n\n const [loading, setLoading] = useState(false);\n\n const updateSettings = (settingsToUpdate: Partial) => {\n props.updateHistorySettings({ ...props.richHistorySettings, ...settingsToUpdate });\n };\n\n const updateFilters = (filtersToUpdate?: Partial) => {\n const filters = {\n ...props.richHistorySearchFilters!,\n ...filtersToUpdate,\n page: 1, // always load fresh results when updating filters\n };\n props.updateHistorySearchFilters(props.exploreId, filters);\n loadRichHistory();\n };\n\n const loadRichHistory = debounce(() => {\n props.loadRichHistory(props.exploreId);\n setLoading(true);\n }, 300);\n\n const onChangeRetentionPeriod = (retentionPeriod: SelectableValue) => {\n if (retentionPeriod.value !== undefined) {\n updateSettings({ retentionPeriod: retentionPeriod.value });\n }\n };\n\n const toggleStarredTabAsFirstTab = () =>\n updateSettings({ starredTabAsFirstTab: !props.richHistorySettings.starredTabAsFirstTab });\n\n const toggleActiveDatasourceOnly = () =>\n updateSettings({ activeDatasourceOnly: !props.richHistorySettings.activeDatasourceOnly });\n\n useEffect(() => {\n setLoading(false);\n }, [richHistory]);\n\n const QueriesTab: TabConfig = {\n label: t('explore.rich-history.query-history', 'Query history'),\n value: Tabs.RichHistory,\n content: (\n props.clearRichHistoryResults(props.exploreId)}\n loadMoreRichHistory={() => props.loadMoreRichHistory(props.exploreId)}\n activeDatasourceInstance={activeDatasourceInstance}\n richHistorySettings={props.richHistorySettings}\n richHistorySearchFilters={props.richHistorySearchFilters}\n exploreId={exploreId}\n height={height}\n />\n ),\n icon: 'history',\n };\n\n const StarredTab: TabConfig = {\n label: t('explore.rich-history.starred', 'Starred'),\n value: Tabs.Starred,\n content: (\n props.clearRichHistoryResults(props.exploreId)}\n loadMoreRichHistory={() => props.loadMoreRichHistory(props.exploreId)}\n richHistorySettings={props.richHistorySettings}\n richHistorySearchFilters={props.richHistorySearchFilters}\n exploreId={exploreId}\n />\n ),\n icon: 'star',\n };\n\n const SettingsTab: TabConfig = {\n label: t('explore.rich-history.settings', 'Settings'),\n value: Tabs.Settings,\n content: (\n \n ),\n icon: 'sliders-v-alt',\n };\n\n let tabs = [QueriesTab, StarredTab, SettingsTab];\n return (\n \n );\n}\n","// Libraries\nimport React, { useEffect, useState } from 'react';\nimport { connect, ConnectedProps } from 'react-redux';\n\nimport { config, reportInteraction } from '@grafana/runtime';\nimport { useTheme2 } from '@grafana/ui';\nimport { Trans } from 'app/core/internationalization';\n// Types\nimport { ExploreItemState, StoreState } from 'app/types';\n\n// Components, enums\nimport { ExploreDrawer } from '../ExploreDrawer';\nimport {\n deleteRichHistory,\n initRichHistory,\n loadRichHistory,\n loadMoreRichHistory,\n clearRichHistoryResults,\n updateHistorySettings,\n updateHistorySearchFilters,\n} from '../state/history';\n\nimport { RichHistory, Tabs } from './RichHistory';\n\n//Actions\n\nfunction mapStateToProps(state: StoreState, { exploreId }: { exploreId: string }) {\n const explore = state.explore;\n const item: ExploreItemState = explore.panes[exploreId]!;\n const richHistorySearchFilters = item.richHistorySearchFilters;\n const richHistorySettings = explore.richHistorySettings;\n const { datasourceInstance } = item;\n const firstTab = richHistorySettings?.starredTabAsFirstTab ? Tabs.Starred : Tabs.RichHistory;\n const { richHistory, richHistoryTotal } = item;\n return {\n richHistory,\n richHistoryTotal,\n firstTab,\n activeDatasourceInstance: datasourceInstance!.name,\n richHistorySettings,\n richHistorySearchFilters,\n };\n}\n\nconst mapDispatchToProps = {\n initRichHistory,\n loadRichHistory,\n loadMoreRichHistory,\n clearRichHistoryResults,\n updateHistorySettings,\n updateHistorySearchFilters,\n deleteRichHistory,\n};\n\nconst connector = connect(mapStateToProps, mapDispatchToProps);\n\ninterface OwnProps {\n width: number;\n exploreId: string;\n onClose: () => void;\n}\nexport type Props = ConnectedProps & OwnProps;\n\nexport function RichHistoryContainer(props: Props) {\n const theme = useTheme2();\n const [height, setHeight] = useState(theme.components.horizontalDrawer.defaultHeight);\n\n const {\n richHistory,\n richHistoryTotal,\n width,\n firstTab,\n activeDatasourceInstance,\n exploreId,\n deleteRichHistory,\n initRichHistory,\n loadRichHistory,\n loadMoreRichHistory,\n clearRichHistoryResults,\n richHistorySettings,\n updateHistorySettings,\n richHistorySearchFilters,\n updateHistorySearchFilters,\n onClose,\n } = props;\n\n useEffect(() => {\n initRichHistory();\n reportInteraction('grafana_explore_query_history_opened', {\n queryHistoryEnabled: config.queryHistoryEnabled,\n });\n }, [initRichHistory]);\n\n if (!richHistorySettings) {\n return (\n \n Loading...\n \n );\n }\n\n return (\n {\n setHeight(Number(ref.style.height.slice(0, -2)));\n }}\n >\n \n \n );\n}\n\nexport default connector(RichHistoryContainer);\n","import { css } from '@emotion/css';\nimport React from 'react';\n\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { Components } from '@grafana/e2e-selectors';\nimport { ToolbarButton, useTheme2 } from '@grafana/ui';\nimport { t, Trans } from 'app/core/internationalization';\n\ntype Props = {\n addQueryRowButtonDisabled?: boolean;\n addQueryRowButtonHidden?: boolean;\n richHistoryRowButtonHidden?: boolean;\n richHistoryButtonActive?: boolean;\n queryInspectorButtonActive?: boolean;\n\n onClickAddQueryRowButton: () => void;\n onClickRichHistoryButton: () => void;\n onClickQueryInspectorButton: () => void;\n};\n\nconst getStyles = (theme: GrafanaTheme2) => {\n return {\n containerMargin: css({\n display: 'flex',\n flexWrap: 'wrap',\n gap: theme.spacing(1),\n marginTop: theme.spacing(2),\n }),\n };\n};\n\nexport function SecondaryActions(props: Props) {\n const theme = useTheme2();\n const styles = getStyles(theme);\n return (\n \n {!props.addQueryRowButtonHidden && (\n \n Add query\n \n )}\n {!props.richHistoryRowButtonHidden && (\n \n Query history\n \n )}\n \n Query inspector\n \n
\n );\n}\n","import { css } from '@emotion/css';\nimport React, { PureComponent } from 'react';\nimport { connect, ConnectedProps } from 'react-redux';\n\nimport { applyFieldOverrides, SplitOpen, DataFrame, LoadingState, FieldType } from '@grafana/data';\nimport { getTemplateSrv } from '@grafana/runtime';\nimport { TimeZone } from '@grafana/schema';\nimport { Table, AdHocFilterItem, PanelChrome, withTheme2, Themeable2 } from '@grafana/ui';\nimport { config } from 'app/core/config';\nimport { t, Trans } from 'app/core/internationalization';\nimport {\n hasDeprecatedParentRowIndex,\n migrateFromParentRowIndexToNestedFrames,\n} from 'app/plugins/panel/table/migrations';\nimport { StoreState } from 'app/types';\nimport { ExploreItemState } from 'app/types/explore';\n\nimport { MetaInfoText } from '../MetaInfoText';\nimport { selectIsWaitingForData } from '../state/query';\nimport { exploreDataLinkPostProcessorFactory } from '../utils/links';\n\ninterface TableContainerProps extends Themeable2 {\n ariaLabel?: string;\n exploreId: string;\n width: number;\n timeZone: TimeZone;\n onCellFilterAdded?: (filter: AdHocFilterItem) => void;\n splitOpenFn: SplitOpen;\n}\n\nfunction mapStateToProps(state: StoreState, { exploreId }: TableContainerProps) {\n const explore = state.explore;\n const item: ExploreItemState = explore.panes[exploreId]!;\n const { tableResult, range } = item;\n const loadingInState = selectIsWaitingForData(exploreId);\n const loading = tableResult && tableResult.length > 0 ? false : loadingInState;\n return { loading, tableResult, range };\n}\n\nconst connector = connect(mapStateToProps, {});\n\ntype Props = TableContainerProps & ConnectedProps;\n\nexport class TableContainer extends PureComponent {\n hasSubFrames = (data: DataFrame) => data.fields.some((f) => f.type === FieldType.nestedFrames);\n\n getTableHeight(rowCount: number, hasSubFrames: boolean) {\n if (rowCount === 0) {\n return 200;\n }\n // tries to estimate table height, with a min of 300 and a max of 600\n // if there are multiple tables, there is no min\n return Math.min(600, Math.max(rowCount * 36, hasSubFrames ? 300 : 0) + 40 + 46);\n }\n\n getTableTitle(dataFrames: DataFrame[] | null, data: DataFrame, i: number) {\n let name = data.name;\n if (!name && (dataFrames?.length ?? 0) > 1) {\n name = data.refId || `${i}`;\n }\n\n return name ? (\n Table - {{ name }}\n ) : (\n t('explore.table.title', 'Table')\n );\n }\n\n render() {\n const { loading, onCellFilterAdded, tableResult, width, splitOpenFn, range, ariaLabel, timeZone, theme } =\n this.props;\n\n let dataFrames = hasDeprecatedParentRowIndex(tableResult)\n ? migrateFromParentRowIndexToNestedFrames(tableResult)\n : tableResult;\n const dataLinkPostProcessor = exploreDataLinkPostProcessorFactory(splitOpenFn, range);\n\n if (dataFrames?.length) {\n dataFrames = applyFieldOverrides({\n data: dataFrames,\n timeZone,\n theme: config.theme2,\n replaceVariables: getTemplateSrv().replace.bind(getTemplateSrv()),\n fieldConfig: {\n defaults: {},\n overrides: [],\n },\n dataLinkPostProcessor,\n });\n }\n\n const frames = dataFrames?.filter(\n (frame: DataFrame | undefined): frame is DataFrame => !!frame && frame.length !== 0\n );\n\n return (\n <>\n {frames && frames.length === 0 && (\n \n {() => }\n \n )}\n {frames && frames.length > 0 && (\n \n {frames.map((data, i) => (\n
\n {(innerWidth, innerHeight) => (\n \n )}\n \n ))}\n
\n )}\n >\n );\n }\n}\n\nexport const TableContainerWithTheme = withTheme2(TableContainer);\n\nexport default withTheme2(connector(TableContainer));\n","import React, { useMemo } from 'react';\n\nimport { DataFrame, SplitOpen } from '@grafana/data';\nimport { PanelChrome } from '@grafana/ui';\nimport { StoreState, useSelector } from 'app/types';\n\nimport { TraceView } from './TraceView';\nimport { transformDataFrames } from './utils/transform';\n\ninterface Props {\n dataFrames: DataFrame[];\n splitOpenFn: SplitOpen;\n exploreId: string;\n scrollElement?: Element;\n}\n\nexport function TraceViewContainer(props: Props) {\n // At this point we only show single trace\n const frame = props.dataFrames[0];\n const { dataFrames, splitOpenFn, exploreId, scrollElement } = props;\n const traceProp = useMemo(() => transformDataFrames(frame), [frame]);\n const datasource = useSelector(\n (state: StoreState) => state.explore.panes[props.exploreId]?.datasourceInstance ?? undefined\n );\n\n if (!traceProp) {\n return null;\n }\n\n return (\n \n \n \n );\n}\n","import { css, cx } from '@emotion/css';\nimport { get, groupBy } from 'lodash';\nimport memoizeOne from 'memoize-one';\nimport React from 'react';\nimport { connect, ConnectedProps } from 'react-redux';\nimport AutoSizer, { HorizontalSize } from 'react-virtualized-auto-sizer';\n\nimport {\n AbsoluteTimeRange,\n DataFrame,\n EventBus,\n GrafanaTheme2,\n hasToggleableQueryFiltersSupport,\n LoadingState,\n QueryFixAction,\n RawTimeRange,\n SplitOpenOptions,\n SupplementaryQueryType,\n} from '@grafana/data';\nimport { selectors } from '@grafana/e2e-selectors';\nimport { getDataSourceSrv, reportInteraction } from '@grafana/runtime';\nimport { DataQuery } from '@grafana/schema';\nimport {\n AdHocFilterItem,\n CustomScrollbar,\n ErrorBoundaryAlert,\n PanelContainer,\n Themeable2,\n withTheme2,\n} from '@grafana/ui';\nimport { FILTER_FOR_OPERATOR, FILTER_OUT_OPERATOR } from '@grafana/ui/src/components/Table/types';\nimport { supportedFeatures } from 'app/core/history/richHistoryStorageProvider';\nimport { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';\nimport { getNodeGraphDataFrames } from 'app/plugins/panel/nodeGraph/utils';\nimport { StoreState } from 'app/types';\n\nimport { getTimeZone } from '../profile/state/selectors';\n\nimport { ContentOutline } from './ContentOutline/ContentOutline';\nimport { ContentOutlineContextProvider } from './ContentOutline/ContentOutlineContext';\nimport { ContentOutlineItem } from './ContentOutline/ContentOutlineItem';\nimport { CorrelationHelper } from './CorrelationHelper';\nimport { CustomContainer } from './CustomContainer';\nimport ExploreQueryInspector from './ExploreQueryInspector';\nimport { ExploreToolbar } from './ExploreToolbar';\nimport { FlameGraphExploreContainer } from './FlameGraph/FlameGraphExploreContainer';\nimport { GraphContainer } from './Graph/GraphContainer';\nimport LogsContainer from './Logs/LogsContainer';\nimport { LogsSamplePanel } from './Logs/LogsSamplePanel';\nimport { NoData } from './NoData';\nimport { NoDataSourceCallToAction } from './NoDataSourceCallToAction';\nimport { NodeGraphContainer } from './NodeGraph/NodeGraphContainer';\nimport { QueryRows } from './QueryRows';\nimport RawPrometheusContainer from './RawPrometheus/RawPrometheusContainer';\nimport { ResponseErrorContainer } from './ResponseErrorContainer';\nimport RichHistoryContainer from './RichHistory/RichHistoryContainer';\nimport { SecondaryActions } from './SecondaryActions';\nimport TableContainer from './Table/TableContainer';\nimport { TraceViewContainer } from './TraceView/TraceViewContainer';\nimport { changeSize } from './state/explorePane';\nimport { splitOpen } from './state/main';\nimport {\n addQueryRow,\n modifyQueries,\n scanStart,\n scanStopAction,\n selectIsWaitingForData,\n setQueries,\n setSupplementaryQueryEnabled,\n} from './state/query';\nimport { isSplit } from './state/selectors';\nimport { updateTimeRange } from './state/time';\n\nconst getStyles = (theme: GrafanaTheme2) => {\n return {\n exploreMain: css({\n label: 'exploreMain',\n // Is needed for some transition animations to work.\n position: 'relative',\n marginTop: '21px',\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(1),\n }),\n queryContainer: css({\n label: 'queryContainer',\n padding: theme.spacing(1),\n }),\n exploreContainer: css({\n label: 'exploreContainer',\n display: 'flex',\n flexDirection: 'column',\n paddingRight: theme.spacing(2),\n marginBottom: theme.spacing(2),\n }),\n left: css({\n marginBottom: theme.spacing(2),\n }),\n wrapper: css({\n position: 'absolute',\n top: 0,\n left: theme.spacing(2),\n right: 0,\n bottom: 0,\n display: 'flex',\n }),\n };\n};\n\nexport interface ExploreProps extends Themeable2 {\n exploreId: string;\n theme: GrafanaTheme2;\n eventBus: EventBus;\n}\n\nenum ExploreDrawer {\n RichHistory,\n QueryInspector,\n}\n\ninterface ExploreState {\n openDrawer?: ExploreDrawer;\n contentOutlineVisible: boolean;\n}\n\nexport type Props = ExploreProps & ConnectedProps;\n\n/**\n * Explore provides an area for quick query iteration for a given datasource.\n * Once a datasource is selected it populates the query section at the top.\n * When queries are run, their results are being displayed in the main section.\n * The datasource determines what kind of query editor it brings, and what kind\n * of results viewers it supports. The state is managed entirely in Redux.\n *\n * SPLIT VIEW\n *\n * Explore can have two Explore areas side-by-side. This is handled in `Wrapper.tsx`.\n * Since there can be multiple Explores (e.g., left and right) each action needs\n * the `exploreId` as first parameter so that the reducer knows which Explore state\n * is affected.\n *\n * DATASOURCE REQUESTS\n *\n * A click on Run Query creates transactions for all DataQueries for all expanded\n * result viewers. New runs are discarding previous runs. Upon completion a transaction\n * saves the result. The result viewers construct their data from the currently existing\n * transactions.\n *\n * The result viewers determine some of the query options sent to the datasource, e.g.,\n * `format`, to indicate eventual transformations by the datasources' result transformers.\n */\n\nexport class Explore extends React.PureComponent {\n scrollElement: HTMLDivElement | undefined;\n graphEventBus: EventBus;\n logsEventBus: EventBus;\n memoizedGetNodeGraphDataFrames = memoizeOne(getNodeGraphDataFrames);\n\n constructor(props: Props) {\n super(props);\n this.state = {\n openDrawer: undefined,\n contentOutlineVisible: false,\n };\n this.graphEventBus = props.eventBus.newScopedBus('graph', { onlyLocal: false });\n this.logsEventBus = props.eventBus.newScopedBus('logs', { onlyLocal: false });\n }\n\n onChangeTime = (rawRange: RawTimeRange) => {\n const { updateTimeRange, exploreId } = this.props;\n updateTimeRange({ exploreId, rawRange });\n };\n\n // Use this in help pages to set page to a single query\n onClickExample = (query: DataQuery) => {\n this.props.setQueries(this.props.exploreId, [query]);\n };\n\n onCellFilterAdded = (filter: AdHocFilterItem) => {\n const { value, key, operator } = filter;\n if (operator === FILTER_FOR_OPERATOR) {\n this.onClickFilterLabel(key, value);\n }\n\n if (operator === FILTER_OUT_OPERATOR) {\n this.onClickFilterOutLabel(key, value);\n }\n };\n\n onContentOutlineToogle = () => {\n this.setState((state) => {\n reportInteraction('explore_toolbar_contentoutline_clicked', {\n item: 'outline',\n type: state.contentOutlineVisible ? 'close' : 'open',\n });\n return {\n contentOutlineVisible: !state.contentOutlineVisible,\n };\n });\n };\n\n /**\n * Used by Logs details.\n * Returns true if all queries have the filter, otherwise false.\n * TODO: In the future, we would like to return active filters based the query that produced the log line.\n * @alpha\n */\n isFilterLabelActive = async (key: string, value: string | number, refId?: string) => {\n const query = this.props.queries.find((q) => q.refId === refId);\n if (!query) {\n return false;\n }\n const ds = await getDataSourceSrv().get(query.datasource);\n if (hasToggleableQueryFiltersSupport(ds) && ds.queryHasFilter(query, { key, value: value.toString() })) {\n return true;\n }\n return false;\n };\n\n /**\n * Used by Logs details.\n */\n onClickFilterLabel = (key: string, value: string | number, frame?: DataFrame) => {\n this.onModifyQueries(\n {\n type: 'ADD_FILTER',\n options: { key, value: value.toString() },\n frame,\n },\n frame?.refId\n );\n };\n\n /**\n * Used by Logs details.\n */\n onClickFilterOutLabel = (key: string, value: string | number, frame?: DataFrame) => {\n this.onModifyQueries(\n {\n type: 'ADD_FILTER_OUT',\n options: { key, value: value.toString() },\n frame,\n },\n frame?.refId\n );\n };\n\n /**\n * Used by Logs Popover Menu.\n */\n onClickFilterValue = (value: string | number, refId?: string) => {\n this.onModifyQueries({ type: 'ADD_STRING_FILTER', options: { value: value.toString() } }, refId);\n };\n\n /**\n * Used by Logs Popover Menu.\n */\n onClickFilterOutValue = (value: string | number, refId?: string) => {\n this.onModifyQueries({ type: 'ADD_STRING_FILTER_OUT', options: { value: value.toString() } }, refId);\n };\n\n onClickAddQueryRowButton = () => {\n const { exploreId, queryKeys } = this.props;\n this.props.addQueryRow(exploreId, queryKeys.length);\n };\n\n /**\n * Used by Logs details.\n */\n onModifyQueries = (action: QueryFixAction, refId?: string) => {\n const modifier = async (query: DataQuery, modification: QueryFixAction) => {\n // This gives Logs Details support to modify the query that produced the log line.\n // If not present, all queries are modified.\n if (refId && refId !== query.refId) {\n return query;\n }\n const { datasource } = query;\n if (datasource == null) {\n return query;\n }\n const ds = await getDataSourceSrv().get(datasource);\n const toggleableFilters = ['ADD_FILTER', 'ADD_FILTER_OUT'];\n if (hasToggleableQueryFiltersSupport(ds) && toggleableFilters.includes(modification.type)) {\n return ds.toggleQueryFilter(query, {\n type: modification.type === 'ADD_FILTER' ? 'FILTER_FOR' : 'FILTER_OUT',\n options: modification.options ?? {},\n frame: modification.frame,\n });\n }\n if (ds.modifyQuery) {\n return ds.modifyQuery(query, modification);\n } else {\n return query;\n }\n };\n this.props.modifyQueries(this.props.exploreId, action, modifier);\n };\n\n onResize = (size: HorizontalSize) => {\n this.props.changeSize(this.props.exploreId, size);\n };\n\n onStartScanning = () => {\n // Scanner will trigger a query\n this.props.scanStart(this.props.exploreId);\n };\n\n onStopScanning = () => {\n this.props.scanStopAction({ exploreId: this.props.exploreId });\n };\n\n onUpdateTimeRange = (absoluteRange: AbsoluteTimeRange) => {\n const { exploreId, updateTimeRange } = this.props;\n updateTimeRange({ exploreId, absoluteRange });\n };\n\n toggleShowRichHistory = () => {\n this.setState((state) => {\n return {\n openDrawer: state.openDrawer === ExploreDrawer.RichHistory ? undefined : ExploreDrawer.RichHistory,\n };\n });\n };\n\n toggleShowQueryInspector = () => {\n this.setState((state) => {\n return {\n openDrawer: state.openDrawer === ExploreDrawer.QueryInspector ? undefined : ExploreDrawer.QueryInspector,\n };\n });\n };\n\n onSplitOpen = (panelType: string) => {\n return async (options?: SplitOpenOptions) => {\n this.props.splitOpen(options);\n if (options && this.props.datasourceInstance) {\n const target = (await getDataSourceSrv().get(options.datasourceUid)).type;\n const source =\n this.props.datasourceInstance.uid === MIXED_DATASOURCE_NAME\n ? get(this.props.queries, '0.datasource.type')\n : this.props.datasourceInstance.type;\n const tracking = {\n origin: 'panel',\n panelType,\n source,\n target,\n exploreId: this.props.exploreId,\n };\n reportInteraction('grafana_explore_split_view_opened', tracking);\n }\n };\n };\n\n renderEmptyState(exploreContainerStyles: string) {\n return (\n \n \n
\n );\n }\n\n renderNoData() {\n return ;\n }\n\n renderCustom(width: number) {\n const { timeZone, queryResponse, absoluteRange, eventBus } = this.props;\n\n const groupedByPlugin = groupBy(queryResponse?.customFrames, 'meta.preferredVisualisationPluginId');\n\n return Object.entries(groupedByPlugin).map(([pluginId, frames], index) => {\n return (\n \n \n \n );\n });\n }\n\n renderGraphPanel(width: number) {\n const { graphResult, absoluteRange, timeZone, queryResponse, showFlameGraph } = this.props;\n\n return (\n \n \n \n );\n }\n\n renderTablePanel(width: number) {\n const { exploreId, timeZone } = this.props;\n return (\n \n \n \n );\n }\n\n renderRawPrometheus(width: number) {\n const { exploreId, datasourceInstance, timeZone } = this.props;\n return (\n \n \n \n );\n }\n\n renderLogsPanel(width: number) {\n const { exploreId, syncedTimes, theme, queryResponse } = this.props;\n const spacing = parseInt(theme.spacing(2).slice(0, -2), 10);\n // Need to make ContentOutlineItem a flex container so the gap works\n const logsContentOutlineWrapper = css({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(1),\n });\n return (\n \n \n \n );\n }\n\n renderLogsSamplePanel() {\n const { logsSample, timeZone, setSupplementaryQueryEnabled, exploreId, datasourceInstance, queries } = this.props;\n\n return (\n \n \n setSupplementaryQueryEnabled(exploreId, enabled, SupplementaryQueryType.LogsSample)\n }\n />\n \n );\n }\n\n renderNodeGraphPanel() {\n const { exploreId, showTrace, queryResponse, datasourceInstance } = this.props;\n const datasourceType = datasourceInstance ? datasourceInstance?.type : 'unknown';\n\n return (\n \n \n \n );\n }\n\n renderFlameGraphPanel() {\n const { queryResponse } = this.props;\n return (\n \n \n \n );\n }\n\n renderTraceViewPanel() {\n const { queryResponse, exploreId } = this.props;\n const dataFrames = queryResponse.series.filter((series) => series.meta?.preferredVisualisationType === 'trace');\n\n return (\n // If there is no data (like 404) we show a separate error so no need to show anything here\n dataFrames.length && (\n \n \n \n )\n );\n }\n\n render() {\n const {\n datasourceInstance,\n exploreId,\n graphResult,\n queryResponse,\n isLive,\n theme,\n showMetrics,\n showTable,\n showRawPrometheus,\n showLogs,\n showTrace,\n showCustom,\n showNodeGraph,\n showFlameGraph,\n timeZone,\n showLogsSample,\n correlationEditorDetails,\n correlationEditorHelperData,\n } = this.props;\n const { openDrawer, contentOutlineVisible } = this.state;\n const styles = getStyles(theme);\n const showPanels = queryResponse && queryResponse.state !== LoadingState.NotStarted;\n const showRichHistory = openDrawer === ExploreDrawer.RichHistory;\n const richHistoryRowButtonHidden = !supportedFeatures().queryHistoryAvailable;\n const showQueryInspector = openDrawer === ExploreDrawer.QueryInspector;\n const showNoData =\n queryResponse.state === LoadingState.Done &&\n [\n queryResponse.logsFrames,\n queryResponse.graphFrames,\n queryResponse.nodeGraphFrames,\n queryResponse.flameGraphFrames,\n queryResponse.tableFrames,\n queryResponse.rawPrometheusFrames,\n queryResponse.traceFrames,\n queryResponse.customFrames,\n ].every((e) => e.length === 0);\n\n let correlationsBox = undefined;\n const isCorrelationsEditorMode = correlationEditorDetails?.editorMode;\n const showCorrelationHelper = Boolean(isCorrelationsEditorMode || correlationEditorDetails?.correlationDirty);\n if (showCorrelationHelper && correlationEditorHelperData !== undefined) {\n correlationsBox = ;\n }\n\n return (\n \n \n \n
\n {contentOutlineVisible && (\n
\n \n
\n )}\n
(this.scrollElement = scrollElement || undefined)}\n hideHorizontalTrack\n >\n \n {datasourceInstance ? (\n <>\n
\n \n {correlationsBox}\n \n \n \n \n \n
\n {({ width }) => {\n if (width === 0) {\n return null;\n }\n\n return (\n \n \n {showPanels && (\n <>\n {showMetrics && graphResult && (\n {this.renderGraphPanel(width)}\n )}\n {showRawPrometheus && (\n {this.renderRawPrometheus(width)}\n )}\n {showTable && {this.renderTablePanel(width)}}\n {showLogs && {this.renderLogsPanel(width)}}\n {showNodeGraph && (\n {this.renderNodeGraphPanel()}\n )}\n {showFlameGraph && (\n {this.renderFlameGraphPanel()}\n )}\n {showTrace && {this.renderTraceViewPanel()}}\n {showLogsSample && (\n {this.renderLogsSamplePanel()}\n )}\n {showCustom && {this.renderCustom(width)}}\n {showNoData && {this.renderNoData()}}\n >\n )}\n {showRichHistory && (\n \n )}\n {showQueryInspector && (\n \n )}\n \n \n );\n }}\n \n >\n ) : (\n this.renderEmptyState(styles.exploreContainer)\n )}\n
\n \n
\n
\n \n );\n }\n}\n\nfunction mapStateToProps(state: StoreState, { exploreId }: ExploreProps) {\n const explore = state.explore;\n const { syncedTimes } = explore;\n const item = explore.panes[exploreId]!;\n\n const timeZone = getTimeZone(state.user);\n const {\n datasourceInstance,\n queryKeys,\n queries,\n isLive,\n graphResult,\n tableResult,\n logsResult,\n showLogs,\n showMetrics,\n showTable,\n showTrace,\n showCustom,\n absoluteRange,\n queryResponse,\n showNodeGraph,\n showFlameGraph,\n showRawPrometheus,\n supplementaryQueries,\n correlationEditorHelperData,\n } = item;\n\n const loading = selectIsWaitingForData(exploreId)(state);\n const logsSample = supplementaryQueries[SupplementaryQueryType.LogsSample];\n // We want to show logs sample only if there are no log results and if there is already graph or table result\n const showLogsSample = !!(logsSample.dataProvider !== undefined && !logsResult && (graphResult || tableResult));\n\n return {\n datasourceInstance,\n queryKeys,\n queries,\n isLive,\n graphResult,\n logsResult: logsResult ?? undefined,\n absoluteRange,\n queryResponse,\n syncedTimes,\n timeZone,\n showLogs,\n showMetrics,\n showTable,\n showTrace,\n showCustom,\n showNodeGraph,\n showRawPrometheus,\n showFlameGraph,\n splitted: isSplit(state),\n loading,\n logsSample,\n showLogsSample,\n correlationEditorHelperData,\n correlationEditorDetails: explore.correlationEditorDetails,\n };\n}\n\nconst mapDispatchToProps = {\n changeSize,\n modifyQueries,\n scanStart,\n scanStopAction,\n setQueries,\n updateTimeRange,\n addQueryRow,\n splitOpen,\n setSupplementaryQueryEnabled,\n};\n\nconst connector = connect(mapStateToProps, mapDispatchToProps);\n\nexport default withTheme2(connector(Explore));\n","import { css } from '@emotion/css';\nimport React, { useEffect, useMemo, useRef } from 'react';\nimport { connect } from 'react-redux';\n\nimport { EventBusSrv } from '@grafana/data';\nimport { selectors } from '@grafana/e2e-selectors';\nimport { CustomScrollbar } from '@grafana/ui';\nimport { stopQueryState } from 'app/core/utils/explore';\nimport { StoreState, useSelector } from 'app/types';\n\nimport Explore from './Explore';\nimport { getExploreItemSelector } from './state/selectors';\n\nconst containerStyles = css({\n label: 'explorePaneContainer',\n display: 'flex',\n flexDirection: 'column',\n minWidth: '600px',\n height: '100%',\n});\n\ninterface Props {\n exploreId: string;\n}\n\n/*\n Connected components subscribe to the store before function components (using hooks) and can react to store changes. Thus, this connector function is called before the parent component (ExplorePage) is rerendered.\n This means that child components' mapStateToProps will be executed with a zombie `exploreId` that is not present anymore in the store if the pane gets closed.\n By connecting this component and returning the pane we workaround the zombie children issue here instead of modifying every children.\n This is definitely not the ideal solution and we should in the future invest more time in exploring other approaches to better handle this scenario, potentially by refactoring panels to be function components \n (therefore immune to this behaviour), or by forbidding them to access the store directly and instead pass them all the data they need via props or context.\n\n You can read more about this issue here: https://react-redux.js.org/api/hooks#stale-props-and-zombie-children\n*/\nfunction ExplorePaneContainerUnconnected({ exploreId }: Props) {\n useStopQueries(exploreId);\n const eventBus = useRef(new EventBusSrv());\n const ref = useRef(null);\n\n useEffect(() => {\n const bus = eventBus.current;\n return () => bus.removeAllListeners();\n }, []);\n\n return (\n \n \n \n
\n \n );\n}\n\nfunction mapStateToProps(state: StoreState, props: Props) {\n const pane = state.explore.panes[props.exploreId];\n\n return { pane };\n}\n\nconst connector = connect(mapStateToProps);\n\nexport const ExplorePaneContainer = connector(ExplorePaneContainerUnconnected);\n\nfunction useStopQueries(exploreId: string) {\n const paneSelector = useMemo(() => getExploreItemSelector(exploreId), [exploreId]);\n const paneRef = useRef>();\n paneRef.current = useSelector(paneSelector);\n\n useEffect(() => {\n return () => {\n stopQueryState(paneRef.current?.querySubscription);\n };\n }, []);\n}\n","import { useEffect, useRef } from 'react';\n\nimport { NavModel } from '@grafana/data';\nimport { Branding } from 'app/core/components/Branding/Branding';\nimport { useNavModel } from 'app/core/hooks/useNavModel';\nimport { getDatasourceSrv } from 'app/features/plugins/datasource_srv';\nimport { ExploreQueryParams } from 'app/types';\n\nimport { isFulfilled, hasKey } from './utils';\n\nexport function useExplorePageTitle(params: ExploreQueryParams) {\n const navModel = useRef();\n navModel.current = useNavModel('explore');\n const dsService = useRef(getDatasourceSrv());\n\n useEffect(() => {\n if (!params.panes || typeof params.panes !== 'string') {\n return;\n }\n\n let panesObject: unknown;\n try {\n panesObject = JSON.parse(params.panes);\n } catch {\n return;\n }\n\n if (typeof panesObject !== 'object' || panesObject === null) {\n return;\n }\n\n Promise.allSettled(\n Object.values(panesObject).map((pane) => {\n if (\n !pane ||\n typeof pane !== 'object' ||\n !hasKey('datasource', pane) ||\n !pane.datasource ||\n typeof pane.datasource !== 'string'\n ) {\n return Promise.reject();\n }\n\n return dsService.current.get(pane.datasource);\n })\n )\n .then((results) => results.filter(isFulfilled).map((result) => result.value))\n .then((datasources) => {\n if (!navModel.current) {\n return;\n }\n\n const names = datasources.map((ds) => ds.name);\n\n if (names.length === 0) {\n global.document.title = `${navModel.current.main.text} - ${Branding.AppTitle}`;\n return;\n }\n\n global.document.title = `${navModel.current.main.text} - ${names.join(' | ')} - ${Branding.AppTitle}`;\n });\n }, [params.panes]);\n}\n","import { useEffect } from 'react';\nimport { Unsubscribable } from 'rxjs';\n\nimport { getAppEvents } from '@grafana/runtime';\nimport { useGrafana } from 'app/core/context/GrafanaContext';\nimport { useDispatch } from 'app/types';\nimport { AbsoluteTimeEvent, CopyTimeEvent, PasteTimeEvent, ShiftTimeEvent, ZoomOutEvent } from 'app/types/events';\n\nimport {\n copyTimeRangeToClipboard,\n makeAbsoluteTime,\n pasteTimeRangeFromClipboard,\n shiftTime,\n zoomOut,\n} from '../state/time';\n\nexport function useKeyboardShortcuts() {\n const { keybindings } = useGrafana();\n const dispatch = useDispatch();\n\n useEffect(() => {\n keybindings.setupTimeRangeBindings(false);\n\n const tearDown: Unsubscribable[] = [];\n\n tearDown.push(\n getAppEvents().subscribe(AbsoluteTimeEvent, () => {\n dispatch(makeAbsoluteTime());\n })\n );\n\n tearDown.push(\n getAppEvents().subscribe(ShiftTimeEvent, (event) => {\n dispatch(shiftTime(event.payload.direction));\n })\n );\n\n tearDown.push(\n getAppEvents().subscribe(ZoomOutEvent, (event) => {\n dispatch(zoomOut(event.payload.scale));\n })\n );\n\n tearDown.push(\n getAppEvents().subscribe(CopyTimeEvent, () => {\n dispatch(copyTimeRangeToClipboard());\n })\n );\n\n tearDown.push(\n getAppEvents().subscribe(PasteTimeEvent, () => {\n dispatch(pasteTimeRangeFromClipboard());\n })\n );\n\n return () => {\n tearDown.forEach((u) => u.unsubscribe());\n };\n }, [dispatch, keybindings]);\n}\n","import { inRange } from 'lodash';\nimport { useState } from 'react';\nimport { useWindowSize } from 'react-use';\n\nimport { useDispatch, useSelector } from 'app/types';\n\nimport { splitSizeUpdateAction } from '../state/main';\nimport { isSplit, selectPanesEntries } from '../state/selectors';\n\nexport const useSplitSizeUpdater = (minWidth: number) => {\n const dispatch = useDispatch();\n const { width: windowWidth } = useWindowSize();\n const panes = useSelector(selectPanesEntries);\n const hasSplit = useSelector(isSplit);\n const [rightPaneWidthRatio, setRightPaneWidthRatio] = useState(0.5);\n\n const exploreState = useSelector((state) => state.explore);\n\n const updateSplitSize = (size: number) => {\n const evenSplitWidth = windowWidth / 2;\n const areBothSimilar = inRange(size, evenSplitWidth - 100, evenSplitWidth + 100);\n if (areBothSimilar) {\n dispatch(splitSizeUpdateAction({ largerExploreId: undefined }));\n } else {\n dispatch(\n splitSizeUpdateAction({\n largerExploreId: size > evenSplitWidth ? panes[1][0] : panes[0][0],\n })\n );\n }\n\n setRightPaneWidthRatio(size / windowWidth);\n };\n\n let widthCalc = 0;\n if (hasSplit) {\n if (!exploreState.evenSplitPanes && exploreState.maxedExploreId) {\n widthCalc = exploreState.maxedExploreId === panes[1][0] ? windowWidth - minWidth : minWidth;\n } else if (exploreState.evenSplitPanes) {\n widthCalc = Math.floor(windowWidth / 2);\n } else if (rightPaneWidthRatio !== undefined) {\n widthCalc = windowWidth * rightPaneWidthRatio;\n }\n }\n\n return { updateSplitSize, widthCalc };\n};\n","import { useEffect } from 'react';\n\nimport { useGrafana } from 'app/core/context/GrafanaContext';\n\n/**\n * timeSrv (which is used internally) on init reads `from` and `to` param from the URL and updates itself\n * using those value regardless of what is passed to the init method.\n * The updated value is then used by Explore to get the range for each pane.\n * This means that if `from` and `to` parameters are present in the URL,\n * it would be impossible to change the time range in Explore.\n * We are only doing this on mount for 2 reasons:\n * 1: Doing it on update means we'll enter a render loop.\n * 2: when parsing time in Explore (before feeding it to timeSrv) we make sure `from` is before `to` inside\n * each pane state in order to not trigger un URL update from timeSrv.\n */\nexport function useTimeSrvFix() {\n const { location } = useGrafana();\n\n useEffect(() => {\n const searchParams = location.getSearchObject();\n if (searchParams.from || searchParams.to) {\n location.partial({ from: undefined, to: undefined }, true);\n }\n }, [location]);\n}\n","import { css, cx } from '@emotion/css';\nimport React, { useEffect } from 'react';\n\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { config } from '@grafana/runtime';\nimport { ErrorBoundaryAlert, useStyles2, useTheme2 } from '@grafana/ui';\nimport { SplitPaneWrapper } from 'app/core/components/SplitPaneWrapper/SplitPaneWrapper';\nimport { useGrafana } from 'app/core/context/GrafanaContext';\nimport { useNavModel } from 'app/core/hooks/useNavModel';\nimport { GrafanaRouteComponentProps } from 'app/core/navigation/types';\nimport { useSelector } from 'app/types';\nimport { ExploreQueryParams } from 'app/types/explore';\n\nimport { CorrelationEditorModeBar } from './CorrelationEditorModeBar';\nimport { ExploreActions } from './ExploreActions';\nimport { ExplorePaneContainer } from './ExplorePaneContainer';\nimport { useExplorePageTitle } from './hooks/useExplorePageTitle';\nimport { useKeyboardShortcuts } from './hooks/useKeyboardShortcuts';\nimport { useSplitSizeUpdater } from './hooks/useSplitSizeUpdater';\nimport { useStateSync } from './hooks/useStateSync';\nimport { useTimeSrvFix } from './hooks/useTimeSrvFix';\nimport { isSplit, selectCorrelationDetails, selectPanesEntries } from './state/selectors';\n\nconst MIN_PANE_WIDTH = 200;\n\nexport default function ExplorePage(props: GrafanaRouteComponentProps<{}, ExploreQueryParams>) {\n const styles = useStyles2(getStyles);\n const theme = useTheme2();\n useTimeSrvFix();\n useStateSync(props.queryParams);\n // We want to set the title according to the URL and not to the state because the URL itself may lag\n // (due to how useStateSync above works) by a few milliseconds.\n // When a URL is pushed to the history, the browser also saves the title of the page and\n // if we were to update the URL on state change, the title would not match the URL.\n // Ultimately the URL is the single source of truth from which state is derived, the page title is not different\n useExplorePageTitle(props.queryParams);\n const { chrome } = useGrafana();\n const navModel = useNavModel('explore');\n const { updateSplitSize, widthCalc } = useSplitSizeUpdater(MIN_PANE_WIDTH);\n\n const panes = useSelector(selectPanesEntries);\n const hasSplit = useSelector(isSplit);\n const correlationDetails = useSelector(selectCorrelationDetails);\n const showCorrelationEditorBar = config.featureToggles.correlations && (correlationDetails?.editorMode || false);\n\n useEffect(() => {\n //This is needed for breadcrumbs and topnav.\n //We should probably abstract this out at some point\n chrome.update({ sectionNav: navModel });\n }, [chrome, navModel]);\n\n useKeyboardShortcuts();\n\n return (\n \n \n {showCorrelationEditorBar && }\n size && updateSplitSize(size)}\n >\n {panes.map(([exploreId]) => {\n return (\n \n \n \n );\n })}\n \n
\n );\n}\n\nconst getStyles = (theme: GrafanaTheme2) => {\n return {\n pageScrollbarWrapper: css({\n width: '100%',\n flexGrow: 1,\n minHeight: 0,\n height: '100%',\n position: 'relative',\n }),\n correlationsEditorIndicator: css({\n borderLeft: `4px solid ${theme.colors.primary.main}`,\n borderRight: `4px solid ${theme.colors.primary.main}`,\n borderBottom: `4px solid ${theme.colors.primary.main}`,\n overflow: 'scroll',\n }),\n };\n};\n","import { useEffect, useRef } from 'react';\nvar useInterval = function (callback, delay) {\n var savedCallback = useRef(function () { });\n useEffect(function () {\n savedCallback.current = callback;\n });\n useEffect(function () {\n if (delay !== null) {\n var interval_1 = setInterval(function () { return savedCallback.current(); }, delay || 0);\n return function () { return clearInterval(interval_1); };\n }\n return undefined;\n }, [delay]);\n};\nexport default useInterval;\n"],"names":["getSupportedTransTypeDetails","transType","getTransformOptions","transformationType","useBeforeUnload","enabled","message","handler","event","finalEnabled","CorrelationUnsavedChangesModal","onSave","onDiscard","onCancel","Modal","Button","CONSEQUENCES","showModalMessage","action","isActionLeft","dirtyCorrelation","dirtyQueryEditor","messageTemplate","actionStr","consequenceStr","CorrelationEditorModeBar","panes","dispatch","styles","getStyles","correlationDetails","isHelperShowing","saveMessage","setSaveMessage","correlationDirty","queryEditorDirty","modalMessage","exploreId","changeDatasourceUid","useUnmount","pane","resetEditor","closePane","changeDatasourcePostAction","datasourceUid","saveCorrelationPostAction","skipPostConfirmAction","location","Tooltip","Icon","theme","contrastColor","lighterBackgroundColor","colorManipulator","darkerBackgroundColor","disabledColor","ExploreActions","actions","setActions","query","splitted","canWriteCorrelations","keys","exploreSection","actionsArr","hasMixed","config","useScroll","ref","_a","useRafState","state","setState","ContentOutlineContext","ContentOutlineContextProvider","children","outlineItems","setOutlineItems","register","title","icon","id","prevItems","a","b","diff","unregister","item","useContentOutlineContext","ctx","ContentOutlineItemButton","tooltip","className","isActive","rest","buttonStyles","body","renderIcon","ContentOutline","scroller","panelId","expanded","toggleExpanded","useToggle","activeItemId","setActiveItemId","scrollerRef","verticalScroll","scrollIntoView","buttonTitle","scrollValue","el","toggle","activeItem","top","PanelContainer","CustomScrollbar","ContentOutlineItem","LabelWithTooltip","label","tooltipText","Stack","Label","CorrelationTransformationAddModal","fieldList","transformationToEdit","exampleValue","setExampleValue","transformationVars","setTransformationVars","formFieldsVis","setFormFieldsVis","isExpValid","setIsExpValid","validToSave","setValidToSave","getValues","control","watch","exampleVal","transformationTypeDetails","subscription","formValues","expression","isExpressionValid","transKeys","Field","InputControl","onChange","field","Select","value","entry","Input","CorrelationHelper","correlations","panesVals","defaultLabel","loadingLabel","useAsync","setValue","isLabelDescOpen","setIsLabelDescOpen","isTransformOpen","setIsTransformOpen","showTransformationAddModal","setShowTransformationAddModal","transformations","setTransformations","transformationIdxToEdit","setTransformationIdxToEdit","dirty","description","transVarRecords","transformation","key","editTransformations","Alert","Collapse","i","type","mapValue","detailsString","val","Card","IconButton","DeleteButton","_","idx","CustomContainer","width","height","timeZone","pluginId","frames","absoluteRange","splitOpenFn","eventBus","timeRange","plugin","panelContext","useExploreDataLinkPostProcessor","PanelContext","PanelChrome","innerWidth","innerHeight","PanelRenderer","__extends","extendStatics","d","p","__","__assign","t","s","n","rowSizeBase","colSizeBase","edgeBase","Resizer","_super","_this","e","DEFAULT_SIZE","clamp","min","max","snap","size","hasDirection","dir","target","isTouchEvent","isMouseEvent","findClosestSnap","snapArray","snapGap","closestGapIndex","prev","curr","index","gap","getStringSize","getPixelSize","parentSize","ratio","calculateNewMax","maxWidth","maxHeight","minWidth","minHeight","definedProps","baseClassName","Resizable","props","parent","element","base","c","orgWidth","orgHeight","orgPosition","getSize","percent","wrapChanged","wrap","computedStyle","newSize","kind","propsSize","boundsByDirection","direction","widthByDirection","heightByDirection","boundWidth","boundHeight","parent_1","clientX","clientY","scale","resizeRatio","original","_b","lockAspectRatio","lockAspectRatioExtraHeight","lockAspectRatioExtraWidth","newWidth","newHeight","extraHeight","extraWidth","computedMinWidth","computedMaxWidth","computedMinHeight","computedMaxHeight","extraMinWidth","extraMaxWidth","extraMinHeight","extraMaxHeight","lockedMinWidth","lockedMaxWidth","lockedMinHeight","lockedMaxHeight","parent_2","parentRect","targetRect","left","top_1","right","bottom","startResize","flexBasis","parent_3","_c","boundaryMax","newGridWidth","newGridHeight","delta","vw","vh","newState","isResizing","enable","handleStyles","handleClasses","handleWrapperStyle","handleWrapperClass","handleComponent","resizers","extendsProps","acc","style","Wrapper","ExploreDrawer","onResize","dragStyles","drawerWidth","drawerSlide","ExploreQueryInspector","onClose","queryResponse","isMixed","dataOptions","setDataOptions","dataFrames","errors","statsTab","InspectStatsTab","jsonTab","InspectJSONTab","dataTab","InspectDataTab","queryTab","QueryInspector","tabs","errorTab","InspectErrorTab","TabbedContainer","mapStateToProps","mapDispatchToProps","TimeSyncButton","onClick","isSynced","syncTimesTooltip","ToolbarButton","ExploreTimeControls","range","onChangeTime","from","to","nextTimeRange","adjustedFrom","adjustedTo","fiscalYearStartMonth","syncedTimes","onChangeTimeSync","hideText","onChangeTimeZone","onChangeFiscalYearStartMonth","timeSyncButton","timePickerCommonProps","TimePickerWithHistory","LiveTailButton","start","pause","resume","isLive","isPaused","stop","buttonVariant","onClickMain","ButtonGroup","CSSTransition","defaultMode","ShortLinkButtonMenu","isOpen","setIsOpen","lastSelected","setLastSelected","onCopyLink","shorten","absTime","url","menuOptions","MenuActions","Menu","groupOption","MenuGroup","option","ToolbarButtonRow","Dropdown","AddToDashboard","ToolbarExtensionPoint","selectedExtension","setSelectedExtension","context","useExtensionPointContext","extensions","useExtensionLinks","selectExploreItem","noQueriesInPane","menu","ToolbarExtensionPointMenu","ConfirmNavigationModal","isCorrelationsEditorMode","queries","isLeftPane","datasourceUids","uid","numUniqueIds","useLiveTailControls","RefreshPicker","clear","LiveTailControls","controls","ExploreToolbar","onContentOutlineToogle","isContentOutlineOpen","refreshInterval","datasourceInstance","loading","isLargerPane","showSmallTimePicker","showSmallDataSourcePicker","shouldRotateSplitIcon","refreshPickerLabel","onChangeDatasource","dsSettings","onRunQuery","timezone","onOpenSplitView","onCloseSplitView","onClickResize","fiscalyearStartMonth","onChangeRefreshInterval","navBarActions","SetInterval","AppChromeUpdate","PageToolbar","DataSourcePicker","interaction","name","FlameGraphExploreContainer","view","align","sort","INTERVAL","ElapsedTime","resetKey","humanize","elapsed","setElapsed","useInterval","Time","tinycolor","LiveLogs","onPause","scrollTop","clientHeight","scrollHeight","rowsToRender","nextProps","onResume","onClear","logsRow","logsRowLocalTime","logsRowMessage","getLogRowStyles","row","LogMessageAnsi","LiveLogsWithTheme","InfiniteScroll","loadMoreLogs","rows","scrollElement","sortOrder","upperOutOfRange","setUpperOutOfRange","lowerOutOfRange","setLowerOutOfRange","upperLoading","setUpperLoading","lowerLoading","setLowerLoading","rowsRef","lastScroll","handleScroll","scrollDirection","shouldLoadMore","scrollBottom","newRange","canScrollTop","getVisibleRange","canScrollBottom","hideTopMessage","hideBottomMessage","LoadingIndicator","outOfRangeMessage","ScrollDirection","firstTimeStamp","lastTimeStamp","getPrevRange","visibleRange","currentRange","getNextRange","updateCurrentRange","SCROLLING_THRESHOLD","LogsFeedback","feedbackUrl","MetaInfoItem","MetaInfoText","metaItems","LogsTable","splitOpen","logsSortOrder","dataFrame","columnsWithMeta","logsFrame","tableFrame","setTableFrame","timeIndex","prepareTableFrame","frame","sortedFrame","frameWithOverrides","v","getInitialFieldWidth","isFieldFilterable","getLogsExtractFields","labelFilters","buildLabelFilters","transform","getLabelFiltersTransform","transformedDataFrame","lastValueFrom","transformDataFrame","onCellFilterAdded","filter","operator","onClickFilterLabel","onClickFilterOutLabel","Table","bodyName","timeName","isFieldLokiLabels","isFieldDataplaneLabels","labelFiltersInclude","DownloadFormat","LogsMetaRow","meta","dedupStrategy","dedupCount","displayedFields","clearDetectedFields","hasUnescapedContent","forceEscape","onEscapeNewlines","logRows","downloadLogs","format","download","jsonLogs","blob","fileName","dataFrameMap","transforms","logsMetaItem","r","renderMetaItem","downloadMenu","LogLabels","LogsNavigationPages","pages","currentPageIndex","oldestLogsFirst","formatTime","time","createPageContent","page","Spinner","topContent","bottomContent","LogsNavigation","scrollToTopLogs","clearCache","addResultsToCache","setPages","expectedQueriesRef","expectedRangeRef","rangeSpanRef","onFirstPage","onLastPage","newPage","newPages","sortPages","changeTime","olderLogsButton","indexChange","newerLogsButton","onPageClick","pageNumber","navContainerHeight","LogsColumnSearch","LogsTableEmptyFields","LogsTableNavField","Checkbox","getLogsFieldsStyles","sortLabels","labels","la","lb","LogsTableActiveFields","reorderColumn","valueFilter","toggleColumn","labelKeys","labelName","onDragEnd","result","renderTitle","provided","snapshot","collator","LogsTableAvailableFields","LogsTableMultiSelect","uf","fuzzySearch","haystack","dispatcher","idxs","info","order","haystackOrder","matchesSet","mark","part","matched","infoIdx","debouncedFuzzySearch","LogsTableWrap","logsFrames","updatePanelState","panelState","propsColumns","setColumnsWithMeta","filteredColumnsWithMeta","setFilteredColumnsWithMeta","searchValue","setSearchValue","getLogsTableHeight","panelStateRefId","currentDataFrame","setCurrentDataFrame","f","getColumnsFromProps","fieldNames","previouslySelected","defaultColumns","newFrame","newFiltered","flag","numberOfLogLines","otherFields","labelCardinality","pendingLabelState","normalize","sidebarWidth","setSidebarWidth","tableWidth","columnFilterEvent","columnName","priorActiveCount","column","searchFilterEvent","searchResultCount","clearSelection","isDefaultField","sourceIndex","destinationIndex","source","updateExploreState","newColumnsArray","pa","pb","newColumns","newPanelState","length","active","pendingFilteredLabelState","data","matches","newColumnsWithMeta","numberOfResults","match","search","needle","onSearchInputChange","onFrameSelectorChange","getOnResize","newSidebarWidth","InlineField","total","SupplementaryResultError","SHORT_ERROR_MESSAGE_LIMIT","error","suggestedAction","onSuggestedAction","onRemove","severity","showButton","LogsVolumePanel","onUpdateTimeRange","onHiddenSeriesChanged","allLogsVolumeMaximum","spacing","logsVolumeData","logsVolumeInfo","extraInfo","extraInfoComponent","ExploreGraph","isTimeoutErrorResponse","response","LogsVolumePanelList","onLoadLogsVolume","logVolumes","allLogsVolumeMaximumValue","allLogsVolumeMaximumRange","annotations","maximumValue","sorted","grouped","mergedData","maximumRange","numberOfLogVolumes","containsZoomed","zoomRatio","logsLevelZoomRatio","timeoutError","selectedTimeRange","dataRange","DEDUP_OPTIONS","getDefaultVisualisationType","UnthemedLogs","logsPanelState","node","prevState","newSortOrder","visualisation","payload","showLabels","showTime","wrapLogMessage","prettifyLogMessage","hiddenRawLevels","hiddenLogLevels","level","collapsed","k","urlState","serializedState","baseUrl","dedupedRows","sum","prevProps","visualisationType","allLogs","logRow","prevLog","logsMeta","logsVolumeEnabled","loadLogsVolumeData","scanning","scanRange","showContextToggle","getFieldLinks","logsQueries","getRowContext","getLogRowContextUi","getRowContextQuery","isFlipping","contextOpen","contextRow","tableHeight","hasData","filteredLogs","navigationRange","scanText","LogRowContextModal","options","RadioButtonGroup","InlineFieldRow","dedupType","LogRows","Logs","transitionDuration","transitionDelay","LogsCrossFadeTransition","visible","LogsContainer","updateTimeRange","origRow","ds","cacheFilters","runContextQuery","rowIndex","dsInstances","refId","dsPromises","resolve","instances","q","loadingState","logsSeries","loadSupplementaryQueryData","setSupplementaryQueryEnabled","onStartScanning","onStopScanning","logsVolume","logsResult","clearedAtIndex","supplementaryQueries","LogsSamplePanel","setLogsSampleEnabled","onToggleLogsSampleCollapse","OpenInSplitViewButton","logSampleQueries","onSplitOpen","LogsSamplePanelContent","logs","NoData","css","getCardStyles","NoDataSourceCallToAction","cardStyles","canCreateDataSource","footer","ctaElement","CallToActionCard","UnconnectedNodeGraphContainer","withTraceView","datasourceType","getLinks","nodes","useCategorizeFrames","toggleCollapsed","toggled","windowHeight","useWindowSize","containerRef","setTop","countWarning","NodeGraph","NodeGraphContainer","makeSelectors","exploreItemSelector","QueryRows","getQueries","getDatasourceInstanceSettings","getQueryResponse","getHistory","getEventBridge","history","eventBridge","onRunQueries","newQueries","onAddQuery","onQueryCopied","onQueryRemoved","onQueryToggled","queryStatus","QueryEditorRows","mobileWidthThreshold","numberOfColumnsBeforeExpandedViewIsDefault","tableResult","listRef","valueLabels","items","getRawPrometheusListItemsFromDataFrame","isExpandedView","setIsExpandedView","onContentClick","calculateInitialHeight","getListItemHeight","itemIndex","switchId","Switch","ItemLabels","filteredValueLabels","valueLabel","itemWithValue","RawListItem","rawPrometheusResult","rawPrometheusFrame","RawPrometheusContainer","resultsStyle","ALL_GRAPH_STYLE_OPTIONS","ariaLabel","dataLinkPostProcessor","renderTable","FadeIn","defaultStyle","transitionStyles","Transition","ErrorContainer","queryError","showError","duration","ResponseErrorContainer","explore","rightColumnWidth","rightColumnContentWidth","cardColor","RichHistoryCard","queryHistoryItem","commentHistoryItem","starHistoryItem","deleteHistoryItem","changeDatasource","setQueries","activeUpdateComment","setActiveUpdateComment","comment","setComment","historyCardData","datasource","queriesToRun","differentDataSource","onCopyQuery","datasources","queriesText","onCreateShortLink","link","onDeleteQuery","performDelete","queryId","onStarrQuery","toggleActiveUpdateComment","onUpdateComment","onCancelUpdateComment","onKeyDown","keyEvent","updateComment","TextArea","queryActionButtons","DatasourceInfo","Query","LoadingPlaceholder","getQueryStyles","showDsInfo","getDsInfoStyles","dsApi","RichHistoryQueriesTab","totalQueries","richHistorySearchFilters","updateFilters","clearRichHistoryResults","loadMoreRichHistory","richHistorySettings","activeDatasourceInstance","listOfDatasources","datasourceFilters","filters","mappedQueriesToHeadings","sortOrderOptions","getSortOrderOptions","partialResults","RangeSlider","FilterInput","heading","retentionPeriodOptions","RichHistorySettingsTab","retentionPeriod","starredTabAsFirstTab","activeDatasourceOnly","onChangeRetentionPeriod","toggleStarredTabAsFirstTab","toggleactiveDatasourceOnly","deleteRichHistory","selectedOption","onDelete","RichHistoryStarredTab","Tabs","RichHistory","richHistory","richHistoryTotal","firstTab","setLoading","updateSettings","settingsToUpdate","filtersToUpdate","loadRichHistory","toggleActiveDatasourceOnly","QueriesTab","StarredTab","SettingsTab","RichHistoryContainer","setHeight","initRichHistory","updateHistorySettings","updateHistorySearchFilters","_e","_dir","SecondaryActions","loadingInState","TableContainer","rowCount","hasSubFrames","TableContainerWithTheme","TraceViewContainer","traceProp","TraceView","Explore","rawRange","queryKeys","modifier","modification","toggleableFilters","panelType","tracking","exploreContainerStyles","groupedByPlugin","graphResult","showFlameGraph","GraphContainer","logsContentOutlineWrapper","logsSample","showTrace","series","showMetrics","showTable","showRawPrometheus","showLogs","showCustom","showNodeGraph","showLogsSample","correlationEditorDetails","correlationEditorHelperData","openDrawer","contentOutlineVisible","showPanels","showRichHistory","richHistoryRowButtonHidden","showQueryInspector","showNoData","correlationsBox","ErrorBoundary","containerStyles","ExplorePaneContainerUnconnected","useStopQueries","EventBus","bus","ExplorePaneContainer","paneSelector","paneRef","useExplorePageTitle","params","navModel","useNavModel","dsService","panesObject","results","names","Branding","useKeyboardShortcuts","keybindings","tearDown","u","useSplitSizeUpdater","windowWidth","hasSplit","rightPaneWidthRatio","setRightPaneWidthRatio","exploreState","updateSplitSize","evenSplitWidth","areBothSimilar","widthCalc","useTimeSrvFix","searchParams","MIN_PANE_WIDTH","ExplorePage","useStateSync","chrome","showCorrelationEditorBar","SplitPaneWrapper","callback","delay","savedCallback","interval_1"],"sourceRoot":""}