LokiQueryBuilderContainer.tsx 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import { createSlice, PayloadAction } from '@reduxjs/toolkit';
  2. import React, { useEffect, useReducer } from 'react';
  3. import { LokiDatasource } from '../../datasource';
  4. import { LokiQuery } from '../../types';
  5. import { lokiQueryModeller } from '../LokiQueryModeller';
  6. import { buildVisualQueryFromString } from '../parsing';
  7. import { LokiVisualQuery } from '../types';
  8. import { LokiQueryBuilder } from './LokiQueryBuilder';
  9. import { QueryPreview } from './QueryPreview';
  10. export interface Props {
  11. query: LokiQuery;
  12. datasource: LokiDatasource;
  13. onChange: (update: LokiQuery) => void;
  14. onRunQuery: () => void;
  15. showRawQuery: boolean;
  16. }
  17. export interface State {
  18. visQuery?: LokiVisualQuery;
  19. expr: string;
  20. }
  21. /**
  22. * This component is here just to contain the translation logic between string query and the visual query builder model.
  23. */
  24. export function LokiQueryBuilderContainer(props: Props) {
  25. const { query, onChange, onRunQuery, datasource, showRawQuery } = props;
  26. const [state, dispatch] = useReducer(stateSlice.reducer, {
  27. expr: query.expr,
  28. // Use initial visual query only if query.expr is empty string
  29. visQuery:
  30. query.expr === ''
  31. ? {
  32. labels: [],
  33. operations: [{ id: '__line_contains', params: [''] }],
  34. }
  35. : undefined,
  36. });
  37. // Only rebuild visual query if expr changes from outside
  38. useEffect(() => {
  39. dispatch(exprChanged(query.expr));
  40. }, [query.expr]);
  41. const onVisQueryChange = (visQuery: LokiVisualQuery) => {
  42. const expr = lokiQueryModeller.renderQuery(visQuery);
  43. dispatch(visualQueryChange({ visQuery, expr }));
  44. onChange({ ...props.query, expr: expr });
  45. };
  46. if (!state.visQuery) {
  47. return null;
  48. }
  49. return (
  50. <>
  51. <LokiQueryBuilder
  52. query={state.visQuery}
  53. datasource={datasource}
  54. onChange={onVisQueryChange}
  55. onRunQuery={onRunQuery}
  56. />
  57. {showRawQuery && <QueryPreview query={query.expr} />}
  58. </>
  59. );
  60. }
  61. const stateSlice = createSlice({
  62. name: 'loki-builder-container',
  63. initialState: { expr: '' } as State,
  64. reducers: {
  65. visualQueryChange: (state, action: PayloadAction<{ visQuery: LokiVisualQuery; expr: string }>) => {
  66. state.expr = action.payload.expr;
  67. state.visQuery = action.payload.visQuery;
  68. },
  69. exprChanged: (state, action: PayloadAction<string>) => {
  70. if (!state.visQuery || state.expr !== action.payload) {
  71. state.expr = action.payload;
  72. const parseResult = buildVisualQueryFromString(action.payload);
  73. state.visQuery = parseResult.query;
  74. }
  75. },
  76. },
  77. });
  78. const { visualQueryChange, exprChanged } = stateSlice.actions;