CodeEditor: Improved styles when the code editor is loading (#88102)

* fix: monaco loading state

* chore: betterer

* test: leverage e2e selectors

* refactor: prefer HOC to wrap with testid

* refactor: add clarity

* docs: add clarity

* refactor: loading messaging

* test: rename vars to improve clarity

* test: rename vars to improve clarity
pull/85832/head^2
Nick Richmond 1 year ago committed by GitHub
parent 5de7d4d06d
commit 7334f71e09
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      .betterer.results
  2. 3
      packages/grafana-e2e-selectors/src/selectors/components.ts
  3. 2
      packages/grafana-prometheus/src/components/PromQueryField.tsx
  4. 5
      packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryField.tsx
  5. 36
      packages/grafana-ui/src/components/Monaco/ReactMonacoEditorLazy.tsx
  6. 5
      public/app/plugins/datasource/loki/components/monaco-query-field/MonacoFieldWrapper.test.tsx
  7. 5
      public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryField.test.tsx
  8. 8
      public/app/plugins/datasource/loki/querybuilder/components/LokiQueryCodeEditor.test.tsx

@ -5054,8 +5054,6 @@ exports[`no gf-form usage`] = {
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"]
],
"packages/grafana-prometheus/src/components/PromQueryField.tsx:5381": [
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],

@ -526,6 +526,9 @@ export const Components = {
CodeEditor: {
container: 'data-testid Code editor container',
},
ReactMonacoEditor: {
container: 'data-testid ReactMonacoEditor container',
},
DashboardImportPage: {
textarea: 'data-testid-import-dashboard-textarea',
submit: 'data-testid-load-dashboard',

@ -238,7 +238,7 @@ class PromQueryFieldClass extends React.PureComponent<PromQueryFieldProps, PromQ
<Icon name={labelBrowserVisible ? 'angle-down' : 'angle-right'} />
</button>
<div className="gf-form gf-form--grow flex-shrink-1 min-width-15">
<div className="flex-grow-1 min-width-15">
<MonacoQueryFieldWrapper
languageProvider={languageProvider}
history={history}

@ -83,6 +83,11 @@ const getStyles = (theme: GrafanaTheme2, placeholder: string) => {
container: css({
borderRadius: theme.shape.radius.default,
border: `1px solid ${theme.components.input.borderColor}`,
display: 'flex',
flexDirection: 'row',
justifyContent: 'start',
alignItems: 'center',
height: '100%',
}),
placeholder: css({
'::after': {

@ -1,5 +1,10 @@
import { css } from '@emotion/css';
import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useStyles2 } from '../../themes';
import { useAsyncDependency } from '../../utils/useAsyncDependency';
import { ErrorWithStack } from '../ErrorBoundary/ErrorWithStack';
import { LoadingPlaceholder } from '../LoadingPlaceholder/LoadingPlaceholder';
@ -11,13 +16,14 @@ import type { ReactMonacoEditorProps } from './types';
* @internal
* Experimental export
**/
export const ReactMonacoEditorLazy = (props: ReactMonacoEditorProps) => {
const MonacoEditorLazy = (props: ReactMonacoEditorProps) => {
const styles = useStyles2(getStyles);
const { loading, error, dependency } = useAsyncDependency(
import(/* webpackChunkName: "react-monaco-editor" */ './ReactMonacoEditor')
);
if (loading) {
return <LoadingPlaceholder text={''} />;
return <LoadingPlaceholder text={'Loading editor'} className={styles.container} />;
}
if (error) {
@ -31,5 +37,29 @@ export const ReactMonacoEditorLazy = (props: ReactMonacoEditorProps) => {
}
const ReactMonacoEditor = dependency.ReactMonacoEditor;
return <ReactMonacoEditor {...props} />;
return <ReactMonacoEditor {...props} loading={props.loading ?? null} />;
};
const getStyles = (theme: GrafanaTheme2) => {
return {
container: css({
marginBottom: 'unset',
marginLeft: theme.spacing(1),
}),
};
};
const withContainer = <P extends object>(Component: React.ComponentType<P>): React.ComponentType<P> => {
const WithContainer = (props: P) => (
// allow tests to easily determine if the code editor has rendered in any of its three states (loading, error, or ready)
<div data-testid={selectors.components.ReactMonacoEditor.container}>
<Component {...props} />
</div>
);
WithContainer.displayName = Component.displayName;
return WithContainer;
};
export const ReactMonacoEditorLazy = withContainer(MonacoEditorLazy);

@ -1,6 +1,8 @@
import { render, screen, waitFor } from '@testing-library/react';
import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { createLokiDatasource } from '../../__mocks__/datasource';
import { MonacoQueryFieldWrapper, Props } from './MonacoQueryFieldWrapper';
@ -25,7 +27,8 @@ describe('MonacoFieldWrapper', () => {
renderComponent();
await waitFor(async () => {
expect(await screen.findByText('Loading...')).toBeInTheDocument();
const monacoEditor = await screen.findByTestId(selectors.components.ReactMonacoEditor.container);
expect(monacoEditor).toBeInTheDocument();
});
});
});

@ -1,6 +1,8 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { createLokiDatasource } from '../../__mocks__/datasource';
import MonacoQueryField from './MonacoQueryField';
@ -31,6 +33,7 @@ describe('MonacoQueryField', () => {
test('Renders with no errors', async () => {
renderComponent();
expect(await screen.findByText('Loading...')).toBeInTheDocument();
const monacoEditor = await screen.findByTestId(selectors.components.ReactMonacoEditor.container);
expect(monacoEditor).toBeInTheDocument();
});
});

@ -1,6 +1,8 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { createLokiDatasource } from '../../__mocks__/datasource';
import { LokiQuery } from '../../types';
@ -32,7 +34,8 @@ describe('LokiQueryCodeEditor', () => {
props.showExplain = true;
props.datasource.metadataRequest = jest.fn().mockResolvedValue([]);
render(<LokiQueryCodeEditor {...props} query={defaultQuery} />);
expect(await screen.findByText('Loading...')).toBeInTheDocument();
const monacoEditor = await screen.findByTestId(selectors.components.ReactMonacoEditor.container);
expect(monacoEditor).toBeInTheDocument();
expect(screen.getByText(EXPLAIN_LABEL_FILTER_CONTENT)).toBeInTheDocument();
});
@ -40,7 +43,8 @@ describe('LokiQueryCodeEditor', () => {
const props = createDefaultProps();
props.datasource.metadataRequest = jest.fn().mockResolvedValue([]);
render(<LokiQueryCodeEditor {...props} query={defaultQuery} />);
expect(await screen.findByText('Loading...')).toBeInTheDocument();
const monacoEditor = await screen.findByTestId(selectors.components.ReactMonacoEditor.container);
expect(monacoEditor).toBeInTheDocument();
expect(screen.queryByText(EXPLAIN_LABEL_FILTER_CONTENT)).not.toBeInTheDocument();
});
});

Loading…
Cancel
Save