mirror of https://github.com/grafana/grafana.git
				
				
				
			Loki: Add functionality to revert to initial query in log context (#68484)
* Loki: Add functionality to revert to initial query * Add tests and fix button in button * Use usereven instead of fireEvent * Shortern onClick * Add feature tracking * Use testid instead of title * Always show revert button * Remove unused imports
This commit is contained in:
		
							parent
							
								
									14fb4ff779
								
							
						
					
					
						commit
						1462ae91da
					
				|  | @ -206,4 +206,33 @@ describe('LokiContextUi', () => { | |||
|       expect(screen.queryByText('Refine the search')).not.toBeInTheDocument(); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   it('should revert to original query when revert button clicked', async () => { | ||||
|     const props = setupProps(); | ||||
|     const newProps = { | ||||
|       ...props, | ||||
|       origQuery: { | ||||
|         expr: '{label1="value1"} | logfmt', | ||||
|         refId: 'A', | ||||
|       }, | ||||
|     }; | ||||
|     render(<LokiContextUi {...newProps} />); | ||||
|     // In initial query, label3 is not selected
 | ||||
|     await waitFor(() => { | ||||
|       expect(screen.queryByText('label3="value3"')).not.toBeInTheDocument(); | ||||
|     }); | ||||
| 
 | ||||
|     // We select parsed label and label3="value3" should appear
 | ||||
|     const parsedLabelsInput = screen.getAllByRole('combobox')[1]; | ||||
|     await userEvent.click(parsedLabelsInput); | ||||
|     await userEvent.type(parsedLabelsInput, '{enter}'); | ||||
|     expect(screen.getByText('label3="value3"')).toBeInTheDocument(); | ||||
| 
 | ||||
|     // We click on revert button and label3="value3" should disappear
 | ||||
|     const revertButton = screen.getByTestId('revert-button'); | ||||
|     await userEvent.click(revertButton); | ||||
|     await waitFor(() => { | ||||
|       expect(screen.queryByText('label3="value3"')).not.toBeInTheDocument(); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|  |  | |||
|  | @ -1,10 +1,10 @@ | |||
| import { css } from '@emotion/css'; | ||||
| import React, { useCallback, useEffect, useState } from 'react'; | ||||
| import React, { useCallback, useEffect, useMemo, useState } from 'react'; | ||||
| import { useAsync } from 'react-use'; | ||||
| 
 | ||||
| import { GrafanaTheme2, LogRowModel, SelectableValue } from '@grafana/data'; | ||||
| import { reportInteraction } from '@grafana/runtime'; | ||||
| import { Collapse, Icon, Label, MultiSelect, Tooltip, useStyles2 } from '@grafana/ui'; | ||||
| import { Button, Collapse, Icon, Label, MultiSelect, Spinner, Tooltip, useStyles2 } from '@grafana/ui'; | ||||
| import store from 'app/core/store'; | ||||
| 
 | ||||
| import { RawQuery } from '../../prometheus/querybuilder/shared/RawQuery'; | ||||
|  | @ -33,6 +33,7 @@ function getStyles(theme: GrafanaTheme2) { | |||
|       flex-direction: column; | ||||
|       flex: 1; | ||||
|       gap: ${theme.spacing(0.5)}; | ||||
|       position: relative; | ||||
|     `,
 | ||||
|     textWrapper: css` | ||||
|       display: flex; | ||||
|  | @ -50,10 +51,11 @@ function getStyles(theme: GrafanaTheme2) { | |||
|         margin: ${theme.spacing(2)} 0; | ||||
|       } | ||||
|     `,
 | ||||
|     query: css` | ||||
|     rawQueryContainer: css` | ||||
|       text-align: start; | ||||
|       line-break: anywhere; | ||||
|       margin-top: -${theme.spacing(0.25)}; | ||||
|       width: calc(100% - 20px); | ||||
|     `,
 | ||||
|     ui: css` | ||||
|       background-color: ${theme.colors.background.secondary}; | ||||
|  | @ -65,6 +67,12 @@ function getStyles(theme: GrafanaTheme2) { | |||
|     queryDescription: css` | ||||
|       margin-left: ${theme.spacing(0.5)}; | ||||
|     `,
 | ||||
|     iconButton: css` | ||||
|       position: absolute; | ||||
|       top: ${theme.spacing(1)}; | ||||
|       right: ${theme.spacing(1)}; | ||||
|       z-index: ${theme.zIndex.navbarFixed}; | ||||
|     `,
 | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
|  | @ -83,6 +91,16 @@ export function LokiContextUi(props: LokiContextUiProps) { | |||
|   const timerHandle = React.useRef<number>(); | ||||
|   const previousInitialized = React.useRef<boolean>(false); | ||||
|   const previousContextFilters = React.useRef<ContextFilter[]>([]); | ||||
| 
 | ||||
|   const isInitialQuery = useMemo(() => { | ||||
|     // Initial query has all regular labels enabled and all parsed labels disabled
 | ||||
|     if (initialized && contextFilters.some((filter) => filter.fromParser === filter.enabled)) { | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
|   }, [contextFilters, initialized]); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     if (!initialized) { | ||||
|       return; | ||||
|  | @ -163,6 +181,29 @@ export function LokiContextUi(props: LokiContextUiProps) { | |||
| 
 | ||||
|   return ( | ||||
|     <div className={styles.wrapper}> | ||||
|       <Tooltip content={'Revert to initial log context query.'}> | ||||
|         <div className={styles.iconButton}> | ||||
|           <Button | ||||
|             data-testid="revert-button" | ||||
|             icon="history-alt" | ||||
|             variant="secondary" | ||||
|             disabled={isInitialQuery} | ||||
|             onClick={(e) => { | ||||
|               reportInteraction('grafana_explore_logs_loki_log_context_reverted', { | ||||
|                 logRowUid: row.uid, | ||||
|               }); | ||||
|               setContextFilters((contextFilters) => { | ||||
|                 return contextFilters.map((contextFilter) => ({ | ||||
|                   ...contextFilter, | ||||
|                   // For revert to initial query we need to enable all labels and disable all parsed labels
 | ||||
|                   enabled: !contextFilter.fromParser, | ||||
|                 })); | ||||
|               }); | ||||
|             }} | ||||
|           /> | ||||
|         </div> | ||||
|       </Tooltip> | ||||
| 
 | ||||
|       <Collapse | ||||
|         collapsible={true} | ||||
|         isOpen={isOpen} | ||||
|  | @ -175,7 +216,9 @@ export function LokiContextUi(props: LokiContextUiProps) { | |||
|           }); | ||||
|         }} | ||||
|         label={ | ||||
|           <div className={styles.query}> | ||||
|           <div className={styles.rawQueryContainer}> | ||||
|             {initialized ? ( | ||||
|               <> | ||||
|                 <RawQuery | ||||
|                   lang={{ grammar: lokiGrammar, name: 'loki' }} | ||||
|                   query={logContextProvider.processContextFiltersToExpr( | ||||
|  | @ -188,6 +231,10 @@ export function LokiContextUi(props: LokiContextUiProps) { | |||
|                 <Tooltip content="The initial log context query is created from all labels defining the stream for the selected log line. Use the editor below to customize the log context query."> | ||||
|                   <Icon name="info-circle" size="sm" className={styles.queryDescription} /> | ||||
|                 </Tooltip> | ||||
|               </> | ||||
|             ) : ( | ||||
|               <Spinner /> | ||||
|             )} | ||||
|           </div> | ||||
|         } | ||||
|       > | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue