Chore: Enable eslint-plugin-react partial rules (#29428)

* Chore: Enable eslint react/display-name

Enable react/display-name and fixed the corresponding linting issue

part of: #29201

* Chore: Enable eslint react/no-deprecated

Enable react/no-deprecated and add the UNSAFE_ prefix for deprected methods

part of: #29201

* Chore: Enable eslint react/no-find-dom-node

Enable react/no-find-dom-node rule and use ref instead

part of: #29201

* Test: Update TeamGroupSync test snapshot

Since we added the displayName for ToolTip compontent and tag name is changed.

* Fix: Fixed ClickOutsideWrapper render

The props.children might contains numbers of nodes which make cloneElement failed. Change to simply use a div to wrapper
the children and assign the ref to div for this feature

* Style: Use shorthand method definition style for inline component

* Fix: Rebase master and fix linting

Rebase from master branch and fix new displayName linting warning
This commit is contained in:
Chi-Hsuan Huang 2020-12-01 23:19:52 +08:00 committed by GitHub
parent ccac8d2294
commit 546f569e0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
60 changed files with 193 additions and 97 deletions

View File

@ -16,11 +16,8 @@
"react-hooks/exhaustive-deps": "off",
"react/prop-types": "off",
"react/no-unescaped-entities": "off",
"react/display-name": "off",
"react/no-deprecated": "off",
"react/no-unknown-property": "off",
"react/no-children-prop": "off",
"react/no-find-dom-node": "off",
"react/no-render-return-value": "off",
"no-only-tests/no-only-tests": "error"
}

View File

@ -1,5 +1,4 @@
import { PureComponent } from 'react';
import ReactDOM from 'react-dom';
import React, { PureComponent, createRef } from 'react';
export interface Props {
/**
@ -28,6 +27,7 @@ export class ClickOutsideWrapper extends PureComponent<Props, State> {
parent: window,
useCapture: false,
};
myRef = createRef<HTMLDivElement>();
state = {
hasEventListener: false,
};
@ -48,7 +48,7 @@ export class ClickOutsideWrapper extends PureComponent<Props, State> {
}
onOutsideClick = (event: any) => {
const domNode = ReactDOM.findDOMNode(this) as Element;
const domNode = this.myRef.current;
if (!domNode || !domNode.contains(event.target)) {
this.props.onClick();
@ -56,6 +56,6 @@ export class ClickOutsideWrapper extends PureComponent<Props, State> {
};
render() {
return this.props.children;
return <div ref={this.myRef}>{this.props.children}</div>;
}
}

View File

@ -19,20 +19,22 @@ export const SeriesColorPickerPopover: FunctionComponent<SeriesColorPickerPopove
customPickers={{
yaxis: {
name: 'Y-Axis',
tabComponent: () => (
<Switch
key="yaxisSwitch"
label="Use right y-axis"
className="ColorPicker__axisSwitch"
labelClass="ColorPicker__axisSwitchLabel"
checked={yaxis === 2}
onChange={() => {
if (onToggleAxis) {
onToggleAxis();
}
}}
/>
),
tabComponent() {
return (
<Switch
key="yaxisSwitch"
label="Use right y-axis"
className="ColorPicker__axisSwitch"
labelClass="ColorPicker__axisSwitchLabel"
checked={yaxis === 2}
onChange={() => {
if (onToggleAxis) {
onToggleAxis();
}
}}
/>
);
},
},
}}
/>

View File

@ -13,6 +13,7 @@ export interface SpectrumPaletteProps extends Themeable {
onChange: (color: string) => void;
}
// eslint-disable-next-line react/display-name
const renderPointer = (theme: GrafanaTheme) => (props: SpectrumPalettePointerProps) => (
<SpectrumPalettePointer {...props} theme={theme} />
);

View File

@ -191,6 +191,7 @@ const ContextMenuItemComponent: React.FC<ContextMenuItemProps> = React.memo(
);
}
);
ContextMenuItemComponent.displayName = 'ContextMenuItemComponent';
interface ContextMenuGroupProps {
group: ContextMenuGroup;

View File

@ -11,6 +11,7 @@ interface ButtonComponentProps {
iconClass?: string;
}
// eslint-disable-next-line react/display-name
const ButtonComponent = (buttonProps: ButtonComponentProps) => (props: any) => {
const { label, className, iconClass } = buttonProps;

View File

@ -28,6 +28,7 @@ export const FeatureInfoBox = React.memo(
return <InfoBox branded title={titleEl} urlTitle="Read documentation" {...otherProps} />;
})
);
FeatureInfoBox.displayName = 'FeatureInfoBox';
const getFeatureInfoBoxStyles = stylesFactory((theme: GrafanaTheme) => {
return {

View File

@ -55,6 +55,7 @@ export const InfoBox = React.memo(
}
)
);
InfoBox.displayName = 'InfoBox';
const getInfoBoxStyles = stylesFactory((theme: GrafanaTheme, severity: AlertVariant) => ({
wrapper: css`

View File

@ -15,6 +15,7 @@ export const FieldNameByRegexMatcherEditor = memo<MatcherUIProps<string>>(props
return <Input placeholder="Enter regular expression" defaultValue={options} onBlur={onBlur} />;
});
FieldNameByRegexMatcherEditor.displayName = 'FieldNameByRegexMatcherEditor';
export const fieldNameByRegexMatcherItem: FieldMatcherUIRegistryItem<string> = {
id: FieldMatcherID.byRegexp,

View File

@ -21,6 +21,7 @@ export const FieldNameMatcherEditor = memo<MatcherUIProps<string>>(props => {
const selectedOption = selectOptions.find(v => v.value === options);
return <Select value={selectedOption} options={selectOptions} onChange={onChange} />;
});
FieldNameMatcherEditor.displayName = 'FieldNameMatcherEditor';
export const fieldNameMatcherItem: FieldMatcherUIRegistryItem<string> = {
id: FieldMatcherID.byName,

View File

@ -18,6 +18,7 @@ export const FieldTypeMatcherEditor = memo<MatcherUIProps<string>>(props => {
const selectedOption = selectOptions.find(v => v.value === options);
return <Select value={selectedOption} options={selectOptions} onChange={onChange} />;
});
FieldTypeMatcherEditor.displayName = 'FieldTypeMatcherEditor';
const allTypes: Array<SelectableValue<FieldType>> = [
{ value: FieldType.number, label: 'Numeric' },

View File

@ -26,6 +26,8 @@ export const FieldsByFrameRefIdMatcher = memo<MatcherUIProps<string>>(props => {
return <Select value={selectedOption} options={selectOptions} onChange={onChange} />;
});
FieldsByFrameRefIdMatcher.displayName = 'FieldsByFrameRefIdMatcher';
/**
* Registry item for UI to configure "fields by frame refId"-matcher.
* @public

View File

@ -36,7 +36,9 @@ export const FieldColorEditor: React.FC<FieldConfigEditorProps<FieldColor | unde
description: mode.description,
isContinuous: mode.isContinuous,
isByValue: mode.isByValue,
component: () => <FieldColorModeViz mode={mode} theme={theme} />,
component() {
return <FieldColorModeViz mode={mode} theme={theme} />;
},
};
});

View File

@ -54,6 +54,7 @@ const SelectButton = React.forwardRef<HTMLButtonElement, SelectButtonProps>(
);
}
);
SelectButton.displayName = 'SelectButton';
export function ButtonSelect<T>({
placeholder,
@ -75,6 +76,7 @@ export function ButtonSelect<T>({
return (
<SelectBase
{...selectProps}
// eslint-disable-next-line react/display-name
renderControl={React.forwardRef<any, CustomControlProps<T>>(({ onBlur, onClick, value, isOpen }, ref) => {
return (
<SelectButton {...buttonProps} ref={ref} onBlur={onBlur} onClick={onClick} isOpen={isOpen}>

View File

@ -237,26 +237,28 @@ export function SelectBase<T>({
MenuList: SelectMenu,
Group: SelectOptionGroup,
ValueContainer,
Placeholder: (props: any) => (
<div
{...props.innerProps}
className={cx(
css(props.getStyles('placeholder', props)),
css`
display: inline-block;
color: ${theme.colors.formInputPlaceholderText};
position: absolute;
top: 50%;
transform: translateY(-50%);
box-sizing: border-box;
line-height: 1;
`
)}
>
{props.children}
</div>
),
IndicatorsContainer: (props: any) => {
Placeholder(props: any) {
return (
<div
{...props.innerProps}
className={cx(
css(props.getStyles('placeholder', props)),
css`
display: inline-block;
color: ${theme.colors.formInputPlaceholderText};
position: absolute;
top: 50%;
transform: translateY(-50%);
box-sizing: border-box;
line-height: 1;
`
)}
>
{props.children}
</div>
);
},
IndicatorsContainer(props: any) {
const { selectProps } = props;
const { value, showAllSelectedWhenOpen, maxVisibleValues, menuIsOpen } = selectProps;
@ -278,10 +280,12 @@ export function SelectBase<T>({
return <IndicatorsContainer {...props} />;
},
IndicatorSeparator: () => <></>,
IndicatorSeparator() {
return <></>;
},
Control: CustomControl,
Option: SelectMenuOptions,
ClearIndicator: (props: any) => {
ClearIndicator(props: any) {
const { clearValue } = props;
return (
<Icon
@ -294,20 +298,22 @@ export function SelectBase<T>({
/>
);
},
LoadingIndicator: (props: any) => {
LoadingIndicator(props: any) {
return <Spinner inline={true} />;
},
LoadingMessage: (props: any) => {
LoadingMessage(props: any) {
return <div className={styles.loadingMessage}>{loadingMessage}</div>;
},
NoOptionsMessage: (props: any) => {
NoOptionsMessage(props: any) {
return (
<div className={styles.loadingMessage} aria-label="No options provided">
{noOptionsMessage}
</div>
);
},
DropdownIndicator: (props: any) => <DropdownIndicator isOpen={props.selectProps.menuIsOpen} />,
DropdownIndicator(props: any) {
return <DropdownIndicator isOpen={props.selectProps.menuIsOpen} />;
},
SingleValue: SingleValue,
MultiValueContainer: MultiValueContainer,
MultiValueRemove: MultiValueRemove,

View File

@ -65,3 +65,5 @@ export const SelectMenuOptions = React.forwardRef<HTMLDivElement, React.PropsWit
);
}
);
SelectMenuOptions.displayName = 'SelectMenuOptions';

View File

@ -40,3 +40,5 @@ export const TabsBar = React.forwardRef<HTMLDivElement, Props>(({ children, clas
</div>
);
});
TabsBar.displayName = 'TabsBar';

View File

@ -40,6 +40,8 @@ export const Tag = forwardRef<HTMLElement, Props>(({ name, onClick, className, c
);
});
Tag.displayName = 'Tag';
const getTagStyles = (theme: GrafanaTheme, name: string, colorIndex?: number) => {
let colors;
if (colorIndex === undefined) {

View File

@ -21,6 +21,8 @@ export const TagList: FC<Props> = memo(({ tags, onClick, className }) => {
);
});
TagList.displayName = 'TagList';
const getStyles = () => {
return {
wrapper: css`

View File

@ -210,6 +210,8 @@ export const TimePickerButtonLabel = memo<LabelProps>(({ hideText, value, timeZo
);
});
TimePickerButtonLabel.displayName = 'TimePickerButtonLabel';
const formattedRange = (value: TimeRange, timeZone?: TimeZone) => {
const adjustedTimeRange = {
to: dateMath.isMathString(value.raw.to) ? value.raw.to : value.to,

View File

@ -231,6 +231,8 @@ export const TimePickerCalendar = memo<Props>(props => {
);
});
TimePickerCalendar.displayName = 'TimePickerCalendar';
const Header = memo<Props>(({ onClose }) => {
const theme = useTheme();
const styles = getHeaderStyles(theme);
@ -243,6 +245,8 @@ const Header = memo<Props>(({ onClose }) => {
);
});
Header.displayName = 'Header';
const Body = memo<Props>(({ onChange, from, to, timeZone }) => {
const value = inputToValue(from, to);
const theme = useTheme();
@ -265,6 +269,8 @@ const Body = memo<Props>(({ onChange, from, to, timeZone }) => {
);
});
Body.displayName = 'Body';
const Footer = memo<Props>(({ onClose, onApply }) => {
const theme = useTheme();
const styles = getFooterStyles(theme);
@ -281,6 +287,8 @@ const Footer = memo<Props>(({ onClose, onApply }) => {
);
});
Footer.displayName = 'Footer';
export function inputToValue(from: DateTime, to: DateTime, invalidDateDefault: Date = new Date()): Date[] {
const fromAsDate = from.toDate();
const toAsDate = to.toDate();

View File

@ -307,3 +307,5 @@ function mapToHistoryOptions(ranges?: TimeRange[], timeZone?: TimeZone): TimeOpt
}
return ranges.slice(ranges.length - 4).map(range => mapRangeToTimeOption(range, timeZone));
}
EmptyRecentList.displayName = 'EmptyRecentList';

View File

@ -19,3 +19,5 @@ export const TimePickerTitle = memo<PropsWithChildren<{}>>(({ children }) => {
return <span className={styles.text}>{children}</span>;
});
TimePickerTitle.displayName = 'TimePickerTitle';

View File

@ -53,3 +53,5 @@ export const TimeRangeOption = memo<Props>(({ value, onSelect, selected = false
</div>
);
});
TimeRangeOption.displayName = 'TimeRangeOption';

View File

@ -53,3 +53,5 @@ export const Tooltip: FC<TooltipProps> = React.memo(({ children, theme, ...contr
</PopoverController>
);
});
Tooltip.displayName = 'Tooltip';

View File

@ -189,7 +189,7 @@ export function SuggestionsPlugin({
},
},
renderEditor: (props, editor, next) => {
renderEditor(props, editor, next) {
if (editor.value.selection.isExpanded) {
return next();
}

View File

@ -259,7 +259,9 @@ export const getStandardOptionEditors = () => {
id: 'boolean',
name: 'Boolean',
description: 'Allows boolean values input',
editor: props => <Switch {...props} onChange={e => props.onChange(e.currentTarget.checked)} />,
editor(props) {
return <Switch {...props} onChange={e => props.onChange(e.currentTarget.checked)} />;
},
};
const select: StandardEditorsRegistryItem<any> = {
@ -273,7 +275,9 @@ export const getStandardOptionEditors = () => {
id: 'radio',
name: 'Radio',
description: 'Allows option selection',
editor: props => <RadioButtonGroup {...props} options={props.item.settings?.options} />,
editor(props) {
return <RadioButtonGroup {...props} options={props.item.settings?.options} />;
},
};
const unit: StandardEditorsRegistryItem<string> = {
@ -301,7 +305,9 @@ export const getStandardOptionEditors = () => {
id: 'color',
name: 'Color',
description: 'Allows color selection',
editor: props => <ColorValueEditor value={props.value} onChange={props.onChange} />,
editor(props) {
return <ColorValueEditor value={props.value} onChange={props.onChange} />;
},
};
const fieldColor: StandardEditorsRegistryItem<FieldColor> = {

View File

@ -32,6 +32,7 @@ export const renderComponentWithTheme = (component: React.ComponentType<any>, pr
);
};
// eslint-disable-next-line react/display-name
export const withTheme = (handleSassThemeChange: SassThemeChangeHandler) => (story: RenderFunction) => (
<ThemeableStory handleSassThemeChange={handleSassThemeChange}>{story()}</ThemeableStory>
);

View File

@ -68,7 +68,7 @@ export default class SpanGraph extends React.PureComponent<SpanGraphProps, SpanG
};
}
componentWillReceiveProps(nextProps: SpanGraphProps) {
UNSAFE_componentWillReceiveProps(nextProps: SpanGraphProps) {
const { trace } = nextProps;
if (this.props.trace !== trace) {
this.setState({

View File

@ -164,7 +164,7 @@ export const HEADER_ITEMS = [
{
key: 'timestamp',
label: 'Trace Start',
renderer: (trace: Trace, styles?: ReturnType<typeof getStyles>) => {
renderer(trace: Trace, styles?: ReturnType<typeof getStyles>) {
const dateStr = formatDatetime(trace.startTime);
const match = dateStr.match(/^(.+)(:\d\d\.\d+)$/);
return match ? (

View File

@ -71,7 +71,9 @@ describe(ReferencesButton, () => {
// here
const menuInstance = shallow(
shallow(dropdown.first().props().overlay).prop('children')({
Menu: ({ children }) => <div>{children}</div>,
Menu({ children }) {
return <div>{children}</div>;
},
})
);
const submenuItems = menuInstance.find(UIMenuItem);

View File

@ -112,7 +112,13 @@ describe('<KeyValuesTable>', () => {
const overlay = shallow(dropdown.prop('overlay'));
// We have some wrappers here that dynamically inject specific component so we need to traverse a bit
// here
const menu = shallow(overlay.prop('children')({ Menu: ({ children }) => <div>{children}</div> }));
const menu = shallow(
overlay.prop('children')({
Menu({ children }) {
return <div>{children}</div>;
},
})
);
const anchors = menu.find(LinkValue);
expect(anchors).toHaveLength(2);
const firstAnchor = anchors.first();

View File

@ -194,7 +194,7 @@ export default class TimelineViewingLayer extends React.PureComponent<TimelineVi
this._root = undefined;
}
componentWillReceiveProps(nextProps: TimelineViewingLayerProps) {
UNSAFE_componentWillReceiveProps(nextProps: TimelineViewingLayerProps) {
const { boundsInvalidator } = this.props;
if (boundsInvalidator !== nextProps.boundsInvalidator) {
this._draggerReframe.resetBounds();

View File

@ -189,7 +189,7 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
return false;
}
componentWillUpdate(nextProps: VirtualizedTraceViewProps) {
UNSAFE_componentWillUpdate(nextProps: VirtualizedTraceViewProps) {
const { childrenHiddenIDs, detailStates, registerAccessors, trace, currentViewRangeTime } = this.props;
const {
currentViewRangeTime: nextViewRangeTime,

View File

@ -84,3 +84,5 @@ export const Footer: FC = React.memo(() => {
</footer>
);
});
Footer.displayName = 'Footer';

View File

@ -1,6 +1,6 @@
import React from 'react';
export default () => (
const PermissionsInfo = () => (
<div>
<h5>What are Permissions?</h5>
<p>
@ -9,3 +9,5 @@ export default () => (
</p>
</div>
);
export default PermissionsInfo;

View File

@ -79,7 +79,7 @@ export const TagFilter: FC<Props> = ({
MultiValueLabel: (): any => {
return null; // We want the whole tag to be clickable so we use MultiValueRemove instead
},
MultiValueRemove: (props: any) => {
MultiValueRemove(props: any) {
const { data } = props;
return (

View File

@ -7,7 +7,7 @@ import { convertToType } from './utils';
export function basicMatcherEditor<T = any>(
config: ValueMatcherEditorConfig
): React.FC<ValueMatcherUIProps<BasicValueMatcherOptions<T>>> {
return ({ options, onChange, field }) => {
return function render({ options, onChange, field }) {
const { validator, converter = convertToType } = config;
const { value } = options;
const [isInvalid, setInvalid] = useState(!validator(value));

View File

@ -73,7 +73,7 @@ export class UserProvider extends PureComponent<Props, State> {
},
};
componentWillMount() {
UNSAFE_componentWillMount() {
if (this.props.userId) {
this.loadUser();
}

View File

@ -5,6 +5,7 @@ import { store } from '../../store/store';
export function connectWithStore(WrappedComponent: any, ...args: any[]) {
const ConnectedWrappedComponent = (connect as any)(...args)(WrappedComponent);
// eslint-disable-next-line react/display-name
return (props: any) => {
return <ConnectedWrappedComponent {...props} store={store} />;
};
@ -12,6 +13,8 @@ export function connectWithStore(WrappedComponent: any, ...args: any[]) {
export function connectWithProvider(WrappedComponent: any, ...args: any[]) {
const ConnectedWrappedComponent = (connect as any)(...args)(WrappedComponent);
// eslint-disable-next-line react/display-name
return (props: any) => {
return (
<Provider store={store}>

View File

@ -30,6 +30,7 @@ export const DynamicConfigValueEditor: React.FC<DynamicConfigValueEditorProps> =
}
let editor;
// eslint-disable-next-line react/display-name
const renderLabel = (includeDescription = true, includeCounter = false) => (isExpanded = false) => (
<HorizontalGroup justify="space-between">
<Label description={includeDescription ? item.description : undefined}>

View File

@ -87,6 +87,9 @@ export const VisualizationTabUnconnected = React.forwardRef<HTMLInputElement, Pr
);
}
);
VisualizationTabUnconnected.displayName = 'VisualizationTabUnconnected';
const getStyles = stylesFactory((theme: GrafanaTheme) => {
return {
icon: css`

View File

@ -1,6 +1,6 @@
import React from 'react';
export default function({ value }: any) {
export default function JSONViewer({ value }: any) {
return (
<div>
<pre>{JSON.stringify(value, undefined, 2)}</pre>

View File

@ -54,3 +54,5 @@ export const ResponsiveButton = forwardRef<HTMLButtonElement, Props>((props, ref
</div>
);
});
ResponsiveButton.displayName = 'ResponsiveButton';

View File

@ -18,18 +18,24 @@ export const UIElements: Elements = {
Dropdown: (() => null as any) as any,
Menu: (() => null as any) as any,
MenuItem: (() => null as any) as any,
Button: ({ onClick, children, className }: ButtonProps) => (
<Button variant={'secondary'} onClick={onClick} className={className}>
{children}
</Button>
),
Button({ onClick, children, className }: ButtonProps) {
return (
<Button variant={'secondary'} onClick={onClick} className={className}>
{children}
</Button>
);
},
Divider,
Input: props => <Input {...props} />,
InputGroup: ({ children, className, style }) => (
<span className={className} style={style}>
{children}
</span>
),
Input(props) {
return <Input {...props} />;
},
InputGroup({ children, className, style }) {
return (
<span className={className} style={style}>
{children}
</span>
);
},
};
const getStyles = stylesFactory((theme: GrafanaTheme) => {

View File

@ -28,7 +28,9 @@ type Mock = jest.Mock;
jest.mock('react-virtualized-auto-sizer', () => {
return {
__esModule: true,
default: (props: any) => <div>{props.children({ width: 1000 })}</div>,
default(props: any) {
return <div>{props.children({ width: 1000 })}</div>;
},
};
});
@ -273,11 +275,13 @@ function makeDatasourceSetup({ name = 'loki', id = 1 }: { name?: string; id?: nu
},
api: {
components: {
QueryEditor: (props: QueryEditorProps<LokiDatasource, LokiQuery>) => (
<div>
{name} Editor input: {props.query.expr}
</div>
),
QueryEditor(props: QueryEditorProps<LokiDatasource, LokiQuery>) {
return (
<div>
{name} Editor input: {props.query.expr}
</div>
);
},
},
name: name,
query: jest.fn(),

View File

@ -41,6 +41,7 @@ export const DashboardListPage: FC<Props> = memo(({ navModel, uid, url }) => {
</Page>
);
});
DashboardListPage.displayName = 'DashboardListPage';
const mapStateToProps: MapStateToProps<Props, {}, StoreState> = state => {
return {

View File

@ -57,6 +57,7 @@ export const DashboardSearch: FC<Props> = memo(({ onCloseSearch, params, updateL
</div>
);
});
DashboardSearch.displayName = 'DashboardSearch';
export default connectWithRouteParams(DashboardSearch);

View File

@ -28,3 +28,5 @@ const getStyles = stylesFactory(() => ({
}
`,
}));
SearchCheckbox.displayName = 'SearchCheckbox';

View File

@ -40,6 +40,8 @@ export const SearchWrapper: FC<Props> = memo(({ search, folder, updateLocation }
return isOpen ? <DashboardSearch onCloseSearch={closeSearch} folder={folder} /> : null;
});
SearchWrapper.displayName = 'SearchWrapper';
const mapStateToProps: MapStateToProps<{}, OwnProps, StoreState> = (state: StoreState) => {
const { search, folder } = getLocationQuery(state.location);
return { search, folder };

View File

@ -10,7 +10,7 @@ exports[`Render should render component 1`] = `
>
External group sync
</h3>
<Memo()
<Tooltip
content="Sync LDAP or OAuth groups with your Grafana teams."
placement="auto"
>
@ -18,7 +18,7 @@ exports[`Render should render component 1`] = `
className="icon--has-hover page-sub-heading-icon"
name="question-circle"
/>
</Memo()>
</Tooltip>
<div
className="page-action-bar__spacer"
/>
@ -92,7 +92,7 @@ exports[`Render should render groups table 1`] = `
>
External group sync
</h3>
<Memo()
<Tooltip
content="Sync LDAP or OAuth groups with your Grafana teams."
placement="auto"
>
@ -100,7 +100,7 @@ exports[`Render should render groups table 1`] = `
className="icon--has-hover page-sub-heading-icon"
name="question-circle"
/>
</Memo()>
</Tooltip>
<div
className="page-action-bar__spacer"
/>

View File

@ -16,7 +16,9 @@ const props: Props = {
} as any,
crossSeriesReducer: '',
groupBys: [],
children: renderProps => <div />,
children(renderProps) {
return <div />;
},
templateVariableOptions: [],
};

View File

@ -42,8 +42,8 @@ const DefaultTarget: State = {
export class AnnotationQueryEditor extends React.Component<Props, State> {
state: State = DefaultTarget;
async UNSAFE_componentWillMount() {
// Unfortunately, migrations like this need to go componentWillMount. As soon as there's
async UNSAFE_UNSAFE_componentWillMount() {
// Unfortunately, migrations like this need to go UNSAFE_componentWillMount. As soon as there's
// migration hook for this module.ts, we can do the migrations there instead.
const { target, datasource } = this.props;
if (!target.projectName) {

View File

@ -18,10 +18,10 @@ interface State {
export class QueryEditor extends PureComponent<Props, State> {
state: State = { lastQueryError: '' };
async UNSAFE_componentWillMount() {
async UNSAFE_UNSAFE_componentWillMount() {
const { datasource, query } = this.props;
// Unfortunately, migrations like this need to go componentWillMount. As soon as there's
// Unfortunately, migrations like this need to go UNSAFE_componentWillMount. As soon as there's
// migration hook for this module.ts, we can do the migrations there instead.
if (!this.props.query.hasOwnProperty('metricQuery')) {
const { hide, refId, datasource, key, queryType, maxLines, metric, ...metricQuery } = this.props.query as any;

View File

@ -13,9 +13,9 @@ const FunctionDescription = React.lazy(async () => {
// @ts-ignore
const { default: rst2html } = await import(/* webpackChunkName: "rst2html" */ 'rst2html');
return {
default: (props: { description?: string }) => (
<div dangerouslySetInnerHTML={{ __html: rst2html(props.description ?? '') }} />
),
default(props: { description?: string }) {
return <div dangerouslySetInnerHTML={{ __html: rst2html(props.description ?? '') }} />;
},
};
});

View File

@ -8,7 +8,7 @@ const CHEAT_SHEET_ITEMS = [
},
];
export default (props: any) => (
const InfluxCheatSheet = (props: any) => (
<div>
<h2>InfluxDB Cheat Sheet</h2>
{CHEAT_SHEET_ITEMS.map(item => (
@ -19,3 +19,5 @@ export default (props: any) => (
))}
</div>
);
export default InfluxCheatSheet;

View File

@ -25,7 +25,7 @@ const CHEAT_SHEET_ITEMS = [
},
];
export default (props: ExploreStartPageProps) => (
const PromCheatSheet = (props: ExploreStartPageProps) => (
<div>
<h2>PromQL Cheat Sheet</h2>
{CHEAT_SHEET_ITEMS.map((item, index) => (
@ -44,3 +44,5 @@ export default (props: ExploreStartPageProps) => (
))}
</div>
);
export default PromCheatSheet;

View File

@ -60,7 +60,7 @@ export const plugin = new PanelPlugin<AnnoOptions>(AnnoListPanel)
path: 'tags',
name: 'Tags',
description: '',
editor: props => {
editor(props) {
return <TagsInput tags={props.value} onChange={props.onChange} />;
},
})

View File

@ -44,7 +44,7 @@ export const plugin = new PanelPlugin<DashListOptions>(DashList)
name: 'Folder',
id: 'folderId',
defaultValue: null,
editor: props => {
editor: function RenderFolderPicker(props) {
return <FolderPicker initialTitle="All" enableReset={true} onChange={({ id }) => props.onChange(id)} />;
},
})
@ -54,7 +54,7 @@ export const plugin = new PanelPlugin<DashListOptions>(DashList)
name: 'Tags',
description: '',
defaultValue: [],
editor: props => {
editor(props) {
return <TagsInput tags={props.value} onChange={props.onChange} />;
},
});

View File

@ -22,6 +22,7 @@ export function WrapInProvider(store: any, Component: any, props: any) {
}
export const provideModalsContext = (component: any) => {
// eslint-disable-next-line react/display-name
return (props: any) => (
<ModalsProvider>
<>