Chore: Update and enforce usage of typed react-redux hooks (#55349)

* Chore: Update and enforce usage of typed react-redux hooks
This commit is contained in:
kay delaney 2022-09-19 10:49:35 +01:00 committed by GitHub
parent a3ff758874
commit 64bbb7a7ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
85 changed files with 207 additions and 247 deletions

View File

@ -19,6 +19,18 @@
"alphabetize": { "order": "asc" }
}
],
"no-restricted-imports": [
"warn",
{
"paths": [
{
"name": "react-redux",
"importNames": ["useDispatch", "useSelector"],
"message": "Please import from app/types instead."
}
]
}
],
// Use typescript's no-redeclare for compatibility with overrides
"no-redeclare": "off",

View File

@ -21,9 +21,14 @@ export interface ExploreTracePanelState {
spanId?: string;
}
export interface SplitOpenOptions<T> {
datasourceUid: string;
query: T;
range?: TimeRange;
panelsState?: ExplorePanelsState;
}
/**
* SplitOpen type is used in Explore and related components.
*/
export type SplitOpen = <T extends DataQuery = any>(
options?: { datasourceUid: string; query: T; range?: TimeRange; panelsState?: ExplorePanelsState } | undefined
) => void;
export type SplitOpen = <T extends DataQuery = any>(options?: SplitOpenOptions<T> | undefined) => void;

View File

@ -1,7 +1,6 @@
import { css } from '@emotion/css';
import { cloneDeep } from 'lodash';
import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { GrafanaTheme2, NavSection } from '@grafana/data';
@ -9,7 +8,7 @@ import { locationService } from '@grafana/runtime';
import { Dropdown, FilterInput, Icon, Tooltip, useStyles2 } from '@grafana/ui';
import { contextSrv } from 'app/core/core';
import { useSearchQuery } from 'app/features/search/hooks/useSearchQuery';
import { StoreState } from 'app/types';
import { useSelector } from 'app/types';
import { enrichConfigItems, enrichWithInteractionTracking } from '../NavBar/utils';
import { OrgSwitcher } from '../OrgSwitcher';
@ -21,7 +20,7 @@ export function TopSearchBar() {
const styles = useStyles2(getStyles);
const location = useLocation();
const { query, onQueryChange } = useSearchQuery({});
const navBarTree = useSelector((state: StoreState) => state.navBarTree);
const navBarTree = useSelector((state) => state.navBarTree);
const navTree = cloneDeep(navBarTree);
const [showSwitcherModal, setShowSwitcherModal] = useState(false);
const toggleSwitcherModal = () => {

View File

@ -1,13 +1,12 @@
import { css } from '@emotion/css';
import { cloneDeep } from 'lodash';
import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { GrafanaTheme2, NavModelItem, NavSection } from '@grafana/data';
import { config } from '@grafana/runtime';
import { useTheme2 } from '@grafana/ui';
import { StoreState } from 'app/types';
import { useSelector } from 'app/types';
import { enrichConfigItems, enrichWithInteractionTracking, getActiveItem } from '../NavBar/utils';
@ -19,7 +18,7 @@ export interface Props {
}
export const MegaMenu = React.memo<Props>(({ onClose, searchBarHidden }) => {
const navBarTree = useSelector((state: StoreState) => state.navBarTree);
const navBarTree = useSelector((state) => state.navBarTree);
const theme = useTheme2();
const styles = getStyles(theme);
const location = useLocation();

View File

@ -3,14 +3,13 @@ import { FocusScope } from '@react-aria/focus';
import { Location as HistoryLocation } from 'history';
import { cloneDeep } from 'lodash';
import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { GrafanaTheme2, NavModelItem, NavSection } from '@grafana/data';
import { config, locationSearchToObject, locationService, reportInteraction } from '@grafana/runtime';
import { Icon, useTheme2, CustomScrollbar } from '@grafana/ui';
import { getKioskMode } from 'app/core/navigation/kiosk';
import { StoreState } from 'app/types';
import { useSelector } from 'app/types';
import { OrgSwitcher } from '../OrgSwitcher';
@ -35,7 +34,7 @@ const onOpenSearch = () => {
};
export const NavBar = React.memo(() => {
const navBarTree = useSelector((state: StoreState) => state.navBarTree);
const navBarTree = useSelector((state) => state.navBarTree);
const theme = useTheme2();
const styles = getStyles(theme);
const location = useLocation();

View File

@ -1,10 +1,9 @@
import { useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import { NavModel } from '@grafana/data';
import { getNavModel } from 'app/core/selectors/navModel';
import { store } from 'app/store/store';
import { StoreState } from 'app/types';
import { StoreState, useSelector } from 'app/types';
export function usePageNav(navId?: string, oldProp?: NavModel): NavModel | undefined {
if (oldProp) {

View File

@ -1,6 +1,8 @@
import hoistNonReactStatics from 'hoist-non-react-statics';
import React, { ComponentType, FunctionComponent, useEffect } from 'react';
import { connect, MapDispatchToPropsParam, MapStateToPropsParam, useDispatch } from 'react-redux';
import { connect, MapDispatchToPropsParam, MapStateToPropsParam } from 'react-redux';
import { useDispatch } from 'app/types';
import { cleanUpAction, CleanUpAction } from '../actions/cleanUp';

View File

@ -1,5 +1,6 @@
import { useEffect, useRef } from 'react';
import { useDispatch } from 'react-redux';
import { useDispatch } from 'app/types';
import { cleanUpAction, CleanUpAction } from '../actions/cleanUp';

View File

@ -1,11 +1,9 @@
import { useSelector } from 'react-redux';
import { NavModel } from '@grafana/data';
import { StoreState } from 'app/types/store';
import { useSelector } from 'app/types';
import { getNavModel } from '../selectors/navModel';
export const useNavModel = (id: string): NavModel => {
const navIndex = useSelector((state: StoreState) => state.navIndex);
const navIndex = useSelector((state) => state.navIndex);
return getNavModel(navIndex, id);
};

View File

@ -1,10 +1,10 @@
import { css } from '@emotion/css';
import React, { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { GrafanaTheme2 } from '@grafana/data';
import { Alert, LoadingPlaceholder, useStyles2 } from '@grafana/ui';
import { useQueryParams } from 'app/core/hooks/useQueryParams';
import { useDispatch } from 'app/types';
import { AlertingPageWrapper } from './components/AlertingPageWrapper';
import { NoAlertManagerWarning } from './components/NoAlertManagerWarning';

View File

@ -1,14 +1,13 @@
import { css } from '@emotion/css';
import { isEqual, orderBy, uniqWith } from 'lodash';
import React, { useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import { useDebounce } from 'react-use';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Card, FilterInput, Icon, Pagination, Select, Stack, TagList, useStyles2 } from '@grafana/ui';
import { DEFAULT_PER_PAGE_PAGINATION } from 'app/core/constants';
import { getQueryParamValue } from 'app/core/utils/query';
import { FolderState } from 'app/types';
import { FolderState, useDispatch } from 'app/types';
import { CombinedRule } from 'app/types/unified-alerting';
import { useCombinedRuleNamespaces } from './hooks/useCombinedRuleNamespaces';

View File

@ -1,10 +1,10 @@
import { css } from '@emotion/css';
import React, { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { useDispatch } from 'react-redux';
import { GrafanaTheme2 } from '@grafana/data';
import { Alert, LoadingPlaceholder, useStyles2, withErrorBoundary } from '@grafana/ui';
import { Receiver } from 'app/plugins/datasource/alertmanager/types';
import { useDispatch } from 'app/types';
import { useCleanup } from '../../../core/hooks/useCleanup';

View File

@ -1,10 +1,10 @@
import React, { useCallback, useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { Route, Redirect, Switch } from 'react-router-dom';
import { Alert, LoadingPlaceholder } from '@grafana/ui';
import { useQueryParams } from 'app/core/hooks/useQueryParams';
import { MuteTimeInterval } from 'app/plugins/datasource/alertmanager/types';
import { useDispatch } from 'app/types';
import MuteTimingForm from './components/amroutes/MuteTimingForm';
import { useAlertManagerSourceName } from './hooks/useAlertManagerSourceName';

View File

@ -1,9 +1,9 @@
import React, { FC, useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { Redirect, Route, RouteChildrenProps, Switch, useLocation, useParams } from 'react-router-dom';
import { NavModelItem } from '@grafana/data';
import { Alert, LoadingPlaceholder, withErrorBoundary } from '@grafana/ui';
import { useDispatch } from 'app/types';
import { AlertManagerPicker } from './components/AlertManagerPicker';
import { AlertingPageWrapper } from './components/AlertingPageWrapper';

View File

@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import React, { FC, useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { useAsync } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
@ -8,6 +7,7 @@ import { Alert, LinkButton, LoadingPlaceholder, useStyles2, withErrorBoundary }
import { Page } from 'app/core/components/Page/Page';
import { useCleanup } from 'app/core/hooks/useCleanup';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import { useDispatch } from 'app/types';
import { RuleIdentifier } from 'app/types/unified-alerting';
import { AlertRuleForm } from './components/rule-editor/AlertRuleForm';

View File

@ -1,11 +1,11 @@
import { css } from '@emotion/css';
import React, { useEffect, useMemo, useState } from 'react';
import { useDispatch } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { GrafanaTheme2, urlUtil } from '@grafana/data';
import { Button, LinkButton, useStyles2, withErrorBoundary } from '@grafana/ui';
import { useQueryParams } from 'app/core/hooks/useQueryParams';
import { useDispatch } from 'app/types';
import { AlertingPageWrapper } from './components/AlertingPageWrapper';
import { NoRulesSplash } from './components/rules/NoRulesCTA';

View File

@ -1,9 +1,9 @@
import React, { FC, useCallback, useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { Redirect, Route, RouteChildrenProps, Switch, useLocation } from 'react-router-dom';
import { Alert, LoadingPlaceholder, withErrorBoundary } from '@grafana/ui';
import { Silence } from 'app/plugins/datasource/alertmanager/types';
import { useDispatch } from 'app/types';
import { featureDiscoveryApi } from './api/featureDiscoveryApi';
import { AlertManagerPicker } from './components/AlertManagerPicker';

View File

@ -1,9 +1,9 @@
import { css } from '@emotion/css';
import React, { useEffect, useState, useMemo } from 'react';
import { useDispatch } from 'react-redux';
import { GrafanaTheme2 } from '@grafana/data';
import { Alert, Button, ConfirmModal, TextArea, HorizontalGroup, Field, Form, useStyles2 } from '@grafana/ui';
import { useDispatch } from 'app/types';
import { useAlertManagerSourceName } from '../../hooks/useAlertManagerSourceName';
import { useAlertManagersByPermission } from '../../hooks/useAlertManagerSources';

View File

@ -1,6 +1,5 @@
import { css, cx } from '@emotion/css';
import React, { useCallback, useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import {
@ -18,6 +17,7 @@ import {
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
import { loadDataSources } from 'app/features/datasources/state/actions';
import { AlertmanagerChoice } from 'app/plugins/datasource/alertmanager/types';
import { useDispatch, useSelector } from 'app/types';
import { StoreState } from 'app/types/store';
import { useExternalAmSelector, useExternalDataSourceAlertmanagers } from '../../hooks/useExternalAmSelector';

View File

@ -1,7 +1,6 @@
import { css } from '@emotion/css';
import React, { useMemo } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { useDispatch } from 'react-redux';
import { GrafanaTheme2 } from '@grafana/data';
import { Alert, Field, FieldSet, Input, Button, LinkButton, useStyles2 } from '@grafana/ui';
@ -10,6 +9,7 @@ import {
AlertManagerCortexConfig,
MuteTimeInterval,
} from 'app/plugins/datasource/alertmanager/types';
import { useDispatch } from 'app/types';
import { useAlertManagerSourceName } from '../../hooks/useAlertManagerSourceName';
import { useAlertManagersByPermission } from '../../hooks/useAlertManagerSources';

View File

@ -1,11 +1,11 @@
import { css } from '@emotion/css';
import React, { FC, useMemo, useState } from 'react';
import { useDispatch } from 'react-redux';
import { GrafanaTheme2 } from '@grafana/data';
import { IconButton, LinkButton, Link, useStyles2, ConfirmModal } from '@grafana/ui';
import { contextSrv } from 'app/core/services/context_srv';
import { AlertManagerCortexConfig, MuteTimeInterval, TimeInterval } from 'app/plugins/datasource/alertmanager/types';
import { useDispatch } from 'app/types';
import { Authorize } from '../../components/Authorize';
import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';

View File

@ -1,12 +1,11 @@
import React, { FC } from 'react';
import { useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { useAsync } from 'react-use';
import { urlUtil } from '@grafana/data';
import { Alert, Button, LinkButton } from '@grafana/ui';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { StoreState } from 'app/types';
import { useSelector } from 'app/types';
import { panelToRuleFormValues } from '../../utils/rule-form';
@ -17,7 +16,7 @@ interface Props {
}
export const NewRuleFromPanelButton: FC<Props> = ({ dashboard, panel, className }) => {
const templating = useSelector((state: StoreState) => {
const templating = useSelector((state) => {
return state.templating;
});

View File

@ -1,10 +1,10 @@
import React, { FC } from 'react';
import { useForm, FormProvider } from 'react-hook-form';
import { useDispatch } from 'react-redux';
import { Alert, Button, HorizontalGroup, LinkButton } from '@grafana/ui';
import { useCleanup } from 'app/core/hooks/useCleanup';
import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
import { useDispatch } from 'app/types';
import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';
import { updateAlertManagerConfigAction } from '../../state/actions';

View File

@ -1,11 +1,11 @@
import { css } from '@emotion/css';
import React, { FC, useMemo, useState } from 'react';
import { useDispatch } from 'react-redux';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, ConfirmModal, Modal, useStyles2 } from '@grafana/ui';
import { contextSrv } from 'app/core/services/context_srv';
import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
import { useDispatch } from 'app/types';
import { Authorize } from '../../components/Authorize';
import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';

View File

@ -1,13 +1,13 @@
import { css } from '@emotion/css';
import React, { FC } from 'react';
import { useForm, Validate } from 'react-hook-form';
import { useDispatch } from 'react-redux';
import AutoSizer from 'react-virtualized-auto-sizer';
import { GrafanaTheme2 } from '@grafana/data';
import { Alert, Button, Field, FieldSet, Input, LinkButton, useStyles2 } from '@grafana/ui';
import { useCleanup } from 'app/core/hooks/useCleanup';
import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
import { useDispatch } from 'app/types';
import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';
import { updateAlertManagerConfigAction } from '../../state/actions';

View File

@ -1,9 +1,9 @@
import React, { FC, Fragment, useMemo, useState } from 'react';
import { useDispatch } from 'react-redux';
import { ConfirmModal, useStyles2 } from '@grafana/ui';
import { contextSrv } from 'app/core/services/context_srv';
import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
import { useDispatch } from 'app/types';
import { Authorize } from '../../components/Authorize';
import { deleteTemplateAction } from '../../state/actions';

View File

@ -1,8 +1,8 @@
import React, { FC, useMemo } from 'react';
import { useDispatch } from 'react-redux';
import { Alert } from '@grafana/ui';
import { AlertManagerCortexConfig, Receiver } from 'app/plugins/datasource/alertmanager/types';
import { useDispatch } from 'app/types';
import { updateAlertManagerConfigAction } from '../../../state/actions';
import { CloudChannelValues, ReceiverFormValues, CloudChannelMap } from '../../../types/receiver-form';

View File

@ -1,5 +1,4 @@
import React, { FC, useEffect, useMemo, useState } from 'react';
import { useDispatch } from 'react-redux';
import { LoadingPlaceholder } from '@grafana/ui';
import {
@ -8,6 +7,7 @@ import {
Receiver,
TestReceiversAlert,
} from 'app/plugins/datasource/alertmanager/types';
import { useDispatch } from 'app/types';
import { useUnifiedAlertingSelector } from '../../../hooks/useUnifiedAlertingSelector';
import {

View File

@ -1,7 +1,6 @@
import { css } from '@emotion/css';
import React, { FC, useMemo, useState } from 'react';
import { FormProvider, useForm, UseFormWatch } from 'react-hook-form';
import { useDispatch } from 'react-redux';
import { Link } from 'react-router-dom';
import { GrafanaTheme2 } from '@grafana/data';
@ -9,6 +8,7 @@ import { Button, ConfirmModal, CustomScrollbar, PageToolbar, Spinner, useStyles2
import { useAppNotification } from 'app/core/copy/appNotification';
import { useCleanup } from 'app/core/hooks/useCleanup';
import { useQueryParams } from 'app/core/hooks/useQueryParams';
import { useDispatch } from 'app/types';
import { RuleWithLocation } from 'app/types/unified-alerting';
import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';

View File

@ -1,10 +1,10 @@
import { css } from '@emotion/css';
import React, { FC, useEffect, useMemo, useState } from 'react';
import { useFormContext } from 'react-hook-form';
import { useDispatch } from 'react-redux';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Field, InputControl, useStyles2 } from '@grafana/ui';
import { useDispatch } from 'app/types';
import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';
import { fetchRulerRulesAction } from '../../state/actions';

View File

@ -1,10 +1,10 @@
import { css } from '@emotion/css';
import React, { useEffect, useMemo } from 'react';
import { useDispatch } from 'react-redux';
import { isValidGoDuration } from '@grafana/data';
import { Modal, Button, Form, Field, Input, useStyles2 } from '@grafana/ui';
import { useCleanup } from 'app/core/hooks/useCleanup';
import { useDispatch } from 'app/types';
import { CombinedRuleGroup, CombinedRuleNamespace } from 'app/types/unified-alerting';
import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';

View File

@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import React, { FC, Fragment, useState } from 'react';
import { useDispatch } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { GrafanaTheme2, urlUtil } from '@grafana/data';
@ -8,7 +7,7 @@ import { config } from '@grafana/runtime';
import { Button, ClipboardButton, ConfirmModal, HorizontalGroup, LinkButton, useStyles2 } from '@grafana/ui';
import { useAppNotification } from 'app/core/copy/appNotification';
import { contextSrv } from 'app/core/services/context_srv';
import { AccessControlAction } from 'app/types';
import { AccessControlAction, useDispatch } from 'app/types';
import { CombinedRule, RulesSource } from 'app/types/unified-alerting';
import { useIsRuleEditable } from '../../hooks/useIsRuleEditable';

View File

@ -1,10 +1,10 @@
import { css } from '@emotion/css';
import pluralize from 'pluralize';
import React, { FC, useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import { GrafanaTheme2 } from '@grafana/data';
import { Badge, ConfirmModal, HorizontalGroup, Icon, Spinner, Tooltip, useStyles2 } from '@grafana/ui';
import { useDispatch } from 'app/types';
import { CombinedRuleGroup, CombinedRuleNamespace } from 'app/types/unified-alerting';
import { useFolder } from '../../hooks/useFolder';

View File

@ -1,11 +1,11 @@
import { css } from '@emotion/css';
import React, { useEffect, useState } from 'react';
import { useFormContext } from 'react-hook-form';
import { useDispatch } from 'react-redux';
import { useDebounce } from 'react-use';
import { dateTime, GrafanaTheme2 } from '@grafana/data';
import { Badge, useStyles2 } from '@grafana/ui';
import { useDispatch } from 'app/types';
import { Alert, AlertingRule } from 'app/types/unified-alerting';
import { useCombinedRuleNamespaces } from '../../hooks/useCombinedRuleNamespaces';

View File

@ -1,11 +1,11 @@
import { css, cx } from '@emotion/css';
import React, { FC, Fragment, useState } from 'react';
import { useDispatch } from 'react-redux';
import { dateMath, GrafanaTheme, intervalToAbbreviatedDurationString } from '@grafana/data';
import { useStyles, Link } from '@grafana/ui';
import { contextSrv } from 'app/core/services/context_srv';
import { Silence, AlertmanagerAlert } from 'app/plugins/datasource/alertmanager/types';
import { useDispatch } from 'app/types';
import { expireSilenceAction } from '../../state/actions';
import { makeAMLink } from '../../utils/misc';

View File

@ -2,7 +2,6 @@ import { css, cx } from '@emotion/css';
import { pickBy } from 'lodash';
import React, { FC, useMemo, useState } from 'react';
import { useForm, FormProvider } from 'react-hook-form';
import { useDispatch } from 'react-redux';
import { useDebounce } from 'react-use';
import {
@ -18,6 +17,7 @@ import { config } from '@grafana/runtime';
import { Button, Field, FieldSet, Input, LinkButton, TextArea, useStyles2 } from '@grafana/ui';
import { useCleanup } from 'app/core/hooks/useCleanup';
import { MatcherOperator, Silence, SilenceCreatePayload } from 'app/plugins/datasource/alertmanager/types';
import { useDispatch } from 'app/types';
import { useURLSearchParams } from '../../hooks/useURLSearchParams';
import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';

View File

@ -1,12 +1,12 @@
import { css } from '@emotion/css';
import React, { FC, useMemo } from 'react';
import { useDispatch } from 'react-redux';
import { GrafanaTheme2, dateMath } from '@grafana/data';
import { Icon, useStyles2, Link, Button, Stack } from '@grafana/ui';
import { useQueryParams } from 'app/core/hooks/useQueryParams';
import { contextSrv } from 'app/core/services/context_srv';
import { AlertmanagerAlert, Silence, SilenceState } from 'app/plugins/datasource/alertmanager/types';
import { useDispatch } from 'app/types';
import { expireSilenceAction } from '../../state/actions';
import { getInstancesPermissions } from '../../utils/access-control';

View File

@ -1,7 +1,7 @@
import { useMemo } from 'react';
import { useDispatch } from 'react-redux';
import { useAsync } from 'react-use';
import { useDispatch } from 'app/types';
import { CombinedRule, RuleIdentifier, RuleNamespace } from 'app/types/unified-alerting';
import { RulerRulesConfigDTO } from 'app/types/unified-alerting-dto';

View File

@ -1,6 +1,6 @@
import { renderHook } from '@testing-library/react-hooks';
import React from 'react';
import * as reactRedux from 'react-redux';
import { Provider } from 'react-redux';
import { DataSourceJsonData, DataSourceSettings } from '@grafana/data';
import { config } from '@grafana/runtime';
@ -10,17 +10,12 @@ import { mockDataSource, mockDataSourcesStore, mockStore } from '../mocks';
import { useExternalAmSelector, useExternalDataSourceAlertmanagers } from './useExternalAmSelector';
const useSelectorMock = jest.spyOn(reactRedux, 'useSelector');
describe('useExternalAmSelector', () => {
beforeEach(() => {
useSelectorMock.mockClear();
});
it('should have one in pending', () => {
useSelectorMock.mockImplementation((callback) => {
return callback(createMockStoreState([], [], ['some/url/to/am']));
});
const alertmanagers = useExternalAmSelector();
const store = createMockStoreState([], [], ['some/url/to/am']);
const wrapper = ({ children }: React.PropsWithChildren<{}>) => <Provider store={store}>{children}</Provider>;
const { result } = renderHook(() => useExternalAmSelector(), { wrapper });
const alertmanagers = result.current;
expect(alertmanagers).toEqual([
{
@ -32,13 +27,14 @@ describe('useExternalAmSelector', () => {
});
it('should have one active, one pending', () => {
useSelectorMock.mockImplementation((callback) => {
return callback(
createMockStoreState([{ url: 'some/url/to/am/api/v2/alerts' }], [], ['some/url/to/am', 'some/url/to/am1'])
);
});
const alertmanagers = useExternalAmSelector();
const store = createMockStoreState(
[{ url: 'some/url/to/am/api/v2/alerts' }],
[],
['some/url/to/am', 'some/url/to/am1']
);
const wrapper = ({ children }: React.PropsWithChildren<{}>) => <Provider store={store}>{children}</Provider>;
const { result } = renderHook(() => useExternalAmSelector(), { wrapper });
const alertmanagers = result.current;
expect(alertmanagers).toEqual([
{
@ -55,17 +51,14 @@ describe('useExternalAmSelector', () => {
});
it('should have two active', () => {
useSelectorMock.mockImplementation((callback) => {
return callback(
createMockStoreState(
[{ url: 'some/url/to/am/api/v2/alerts' }, { url: 'some/url/to/am1/api/v2/alerts' }],
[],
['some/url/to/am', 'some/url/to/am1']
)
);
});
const alertmanagers = useExternalAmSelector();
const store = createMockStoreState(
[{ url: 'some/url/to/am/api/v2/alerts' }, { url: 'some/url/to/am1/api/v2/alerts' }],
[],
['some/url/to/am', 'some/url/to/am1']
);
const wrapper = ({ children }: React.PropsWithChildren<{}>) => <Provider store={store}>{children}</Provider>;
const { result } = renderHook(() => useExternalAmSelector(), { wrapper });
const alertmanagers = result.current;
expect(alertmanagers).toEqual([
{
@ -82,18 +75,15 @@ describe('useExternalAmSelector', () => {
});
it('should have one active, one dropped, one pending', () => {
useSelectorMock.mockImplementation((callback) => {
return callback(
createMockStoreState(
[{ url: 'some/url/to/am/api/v2/alerts' }],
[{ url: 'some/dropped/url/api/v2/alerts' }],
['some/url/to/am', 'some/url/to/am1']
)
);
});
const alertmanagers = useExternalAmSelector();
const store = createMockStoreState(
[{ url: 'some/url/to/am/api/v2/alerts' }],
[{ url: 'some/dropped/url/api/v2/alerts' }],
['some/url/to/am', 'some/url/to/am1']
);
const wrapper = ({ children }: React.PropsWithChildren<{}>) => <Provider store={store}>{children}</Provider>;
const { result } = renderHook(() => useExternalAmSelector(), { wrapper });
const alertmanagers = result.current;
expect(alertmanagers).toEqual([
{
url: 'some/url/to/am',
@ -114,21 +104,19 @@ describe('useExternalAmSelector', () => {
});
it('The number of alert managers should match config entries when there are multiple entries of the same url', () => {
useSelectorMock.mockImplementation((callback) => {
return callback(
createMockStoreState(
[
{ url: 'same/url/to/am/api/v2/alerts' },
{ url: 'same/url/to/am/api/v2/alerts' },
{ url: 'same/url/to/am/api/v2/alerts' },
],
[],
['same/url/to/am', 'same/url/to/am', 'same/url/to/am']
)
);
});
const store = createMockStoreState(
[
{ url: 'same/url/to/am/api/v2/alerts' },
{ url: 'same/url/to/am/api/v2/alerts' },
{ url: 'same/url/to/am/api/v2/alerts' },
],
[],
['same/url/to/am', 'same/url/to/am', 'same/url/to/am']
);
const wrapper = ({ children }: React.PropsWithChildren<{}>) => <Provider store={store}>{children}</Provider>;
const alertmanagers = useExternalAmSelector();
const { result } = renderHook(() => useExternalAmSelector(), { wrapper });
const alertmanagers = result.current;
expect(alertmanagers.length).toBe(3);
expect(alertmanagers).toEqual([
@ -152,10 +140,6 @@ describe('useExternalAmSelector', () => {
});
describe('useExternalDataSourceAlertmanagers', () => {
beforeEach(() => {
useSelectorMock.mockRestore();
});
it('Should merge data sources information from config and api responses', () => {
// Arrange
const { dsSettings, dsInstanceSettings } = setupAlertmanagerDataSource({ url: 'http://grafana.com' });
@ -168,7 +152,7 @@ describe('useExternalDataSourceAlertmanagers', () => {
dataSources: [dsSettings],
});
const wrapper: React.FC = ({ children }) => <reactRedux.Provider store={store}>{children}</reactRedux.Provider>;
const wrapper: React.FC = ({ children }) => <Provider store={store}>{children}</Provider>;
// Act
const {
@ -199,7 +183,7 @@ describe('useExternalDataSourceAlertmanagers', () => {
};
});
const wrapper: React.FC = ({ children }) => <reactRedux.Provider store={store}>{children}</reactRedux.Provider>;
const wrapper: React.FC = ({ children }) => <Provider store={store}>{children}</Provider>;
// Act
const {
@ -230,7 +214,7 @@ describe('useExternalDataSourceAlertmanagers', () => {
};
});
const wrapper: React.FC = ({ children }) => <reactRedux.Provider store={store}>{children}</reactRedux.Provider>;
const wrapper: React.FC = ({ children }) => <Provider store={store}>{children}</Provider>;
// Act
const {
@ -261,7 +245,7 @@ describe('useExternalDataSourceAlertmanagers', () => {
};
});
const wrapper: React.FC = ({ children }) => <reactRedux.Provider store={store}>{children}</reactRedux.Provider>;
const wrapper: React.FC = ({ children }) => <Provider store={store}>{children}</Provider>;
// Act
const {
@ -292,7 +276,7 @@ describe('useExternalDataSourceAlertmanagers', () => {
};
});
const wrapper: React.FC = ({ children }) => <reactRedux.Provider store={store}>{children}</reactRedux.Provider>;
const wrapper: React.FC = ({ children }) => <Provider store={store}>{children}</Provider>;
// Act
const {
@ -326,7 +310,7 @@ describe('useExternalDataSourceAlertmanagers', () => {
};
});
const wrapper: React.FC = ({ children }) => <reactRedux.Provider store={store}>{children}</reactRedux.Provider>;
const wrapper: React.FC = ({ children }) => <Provider store={store}>{children}</Provider>;
// Act
const {
@ -389,28 +373,16 @@ const createMockStoreState = (
droppedAlertmanagers: Array<{ url: string }>,
alertmanagerConfig: string[]
) => {
return {
unifiedAlerting: {
externalAlertmanagers: {
discoveredAlertmanagers: {
result: {
data: {
activeAlertManagers: activeAlertmanagers,
droppedAlertManagers: droppedAlertmanagers,
},
},
dispatched: false,
loading: false,
},
alertmanagerConfig: {
result: {
alertmanagers: alertmanagerConfig,
alertmanagersChoice: AlertmanagerChoice.All,
},
dispatched: false,
loading: false,
},
return mockStore((state) => {
state.unifiedAlerting.externalAlertmanagers.alertmanagerConfig.result = {
alertmanagers: alertmanagerConfig,
alertmanagersChoice: AlertmanagerChoice.All,
};
state.unifiedAlerting.externalAlertmanagers.discoveredAlertmanagers.result = {
data: {
activeAlertManagers: activeAlertmanagers,
droppedAlertManagers: droppedAlertmanagers,
},
},
};
};
});
};

View File

@ -1,10 +1,9 @@
import { countBy, keyBy } from 'lodash';
import { useSelector } from 'react-redux';
import { DataSourceInstanceSettings, DataSourceJsonData, DataSourceSettings } from '@grafana/data';
import { AlertManagerDataSourceJsonData } from 'app/plugins/datasource/alertmanager/types';
import { useSelector } from 'app/types';
import { StoreState } from '../../../../types';
import { getAlertManagerDataSources } from '../utils/datasource';
import { useUnifiedAlertingSelector } from './useUnifiedAlertingSelector';
@ -14,10 +13,10 @@ type AlertmanagerConfig = { url: string; status: string; actualUrl: string };
export function useExternalAmSelector(): AlertmanagerConfig[] | [] {
const discoveredAlertmanagers = useSelector(
(state: StoreState) => state.unifiedAlerting.externalAlertmanagers.discoveredAlertmanagers.result?.data
(state) => state.unifiedAlerting.externalAlertmanagers.discoveredAlertmanagers.result?.data
);
const alertmanagerConfig = useSelector(
(state: StoreState) => state.unifiedAlerting.externalAlertmanagers.alertmanagerConfig.result?.alertmanagers
(state) => state.unifiedAlerting.externalAlertmanagers.alertmanagerConfig.result?.alertmanagers
);
if (!discoveredAlertmanagers || !alertmanagerConfig) {
@ -69,7 +68,7 @@ export interface ExternalDataSourceAM {
export function useExternalDataSourceAlertmanagers(): ExternalDataSourceAM[] {
const externalDsAlertManagers = getAlertManagerDataSources().filter((ds) => ds.jsonData.handleGrafanaManagedAlerts);
const alertmanagerDatasources = useSelector((state: StoreState) =>
const alertmanagerDatasources = useSelector((state) =>
keyBy(
state.dataSources.dataSources.filter((ds) => ds.type === 'alertmanager'),
(ds) => ds.uid

View File

@ -1,7 +1,6 @@
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { FolderDTO } from 'app/types';
import { FolderDTO, useDispatch } from 'app/types';
import { fetchFolderIfNotFetchedAction } from '../state/actions';
import { initialAsyncRequestState } from '../utils/redux';

View File

@ -1,6 +1,6 @@
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { useDispatch } from 'app/types';
import { StateHistoryItem } from 'app/types/unified-alerting';
import { fetchGrafanaAnnotationsAction } from '../state/actions';

View File

@ -1,8 +1,8 @@
import { SerializedError } from '@reduxjs/toolkit';
import { useEffect, useMemo } from 'react';
import { useDispatch } from 'react-redux';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { useDispatch } from 'app/types';
import { CombinedRule } from 'app/types/unified-alerting';
import { fetchPromRulesAction, fetchRulerRulesAction } from '../state/actions';

View File

@ -1,6 +1,4 @@
import { useSelector } from 'react-redux';
import { StoreState } from 'app/types';
import { useSelector } from 'app/types';
import { UnifiedAlertingState } from '../state/reducers';
@ -8,5 +6,5 @@ export function useUnifiedAlertingSelector<TSelected = unknown>(
selector: (state: UnifiedAlertingState) => TSelected,
equalityFn?: (left: TSelected, right: TSelected) => boolean
): TSelected {
return useSelector((state: StoreState) => selector(state.unifiedAlerting), equalityFn);
return useSelector((state) => selector(state.unifiedAlerting), equalityFn);
}

View File

@ -13,13 +13,12 @@ import {
useKBar,
} from 'kbar';
import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { GrafanaTheme2 } from '@grafana/data';
import { reportInteraction, locationService } from '@grafana/runtime';
import { useStyles2 } from '@grafana/ui';
import { useGrafana } from 'app/core/context/GrafanaContext';
import { StoreState } from 'app/types';
import { useSelector } from 'app/types';
import { ResultItem } from './ResultItem';
import getDashboardNavActions from './actions/dashboard.nav.actions';
@ -40,7 +39,7 @@ export const CommandPalette = () => {
}));
const isNotLogin = locationService.getLocation().pathname !== '/login';
const { navBarTree } = useSelector((state: StoreState) => {
const { navBarTree } = useSelector((state) => {
return {
navBarTree: state.navBarTree,
};

View File

@ -1,7 +1,6 @@
import * as H from 'history';
import { each, find } from 'lodash';
import React, { useContext, useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import { Prompt } from 'react-router-dom';
import { locationService } from '@grafana/runtime';
@ -10,6 +9,7 @@ import { appEvents } from 'app/core/app_events';
import { contextSrv } from 'app/core/services/context_srv';
import { SaveLibraryPanelModal } from 'app/features/library-panels/components/SaveLibraryPanelModal/SaveLibraryPanelModal';
import { PanelModelWithLibraryPanel } from 'app/features/library-panels/types';
import { useDispatch } from 'app/types';
import { DashboardSavedEvent } from 'app/types/events';
import { DashboardModel } from '../../state/DashboardModel';

View File

@ -1,11 +1,10 @@
import { css } from '@emotion/css';
import React from 'react';
import { useSelector } from 'react-redux';
import { GrafanaTheme } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useStyles } from '@grafana/ui';
import { StoreState } from 'app/types';
import { useSelector } from 'app/types';
import { OptionsPaneOptions } from './OptionsPaneOptions';
import { VisualizationButton } from './VisualizationButton';
@ -23,7 +22,7 @@ export const OptionsPane: React.FC<OptionPaneRenderProps> = ({
instanceState,
}) => {
const styles = useStyles(getStyles);
const isVizPickerOpen = useSelector((state: StoreState) => state.panelEditor.isVizPickerOpen);
const isVizPickerOpen = useSelector((state) => state.panelEditor.isVizPickerOpen);
const { data } = usePanelLatestData(panel, { withTransforms: true, withFieldConfig: false }, true);
return (

View File

@ -1,11 +1,10 @@
import { css } from '@emotion/css';
import React, { FC } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { GrafanaTheme } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { ToolbarButton, ButtonGroup, useStyles } from '@grafana/ui';
import { StoreState } from 'app/types';
import { useDispatch, useSelector } from 'app/types';
import { PanelModel } from '../../state';
import { getPanelPluginWithFallback } from '../../state/selectors';
@ -20,8 +19,8 @@ export const VisualizationButton: FC<Props> = ({ panel }) => {
const styles = useStyles(getStyles);
const dispatch = useDispatch();
const plugin = useSelector(getPanelPluginWithFallback(panel.type));
const isPanelOptionsVisible = useSelector((state: StoreState) => state.panelEditor.ui.isPanelOptionsVisible);
const isVizPickerOpen = useSelector((state: StoreState) => state.panelEditor.isVizPickerOpen);
const isPanelOptionsVisible = useSelector((state) => state.panelEditor.ui.isPanelOptionsVisible);
const isVizPickerOpen = useSelector((state) => state.panelEditor.isVizPickerOpen);
const onToggleOpen = () => {
dispatch(toggleVizPicker(!isVizPickerOpen));

View File

@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import React, { FC, useCallback, useRef, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useLocalStorage } from 'react-use';
import { GrafanaTheme, PanelData, SelectableValue } from '@grafana/data';
@ -11,6 +10,7 @@ import { LS_VISUALIZATION_SELECT_TAB_KEY } from 'app/core/constants';
import { PanelLibraryOptionsGroup } from 'app/features/library-panels/components/PanelLibraryOptionsGroup/PanelLibraryOptionsGroup';
import { VisualizationSuggestions } from 'app/features/panel/components/VizTypePicker/VisualizationSuggestions';
import { VizTypeChangeDetails } from 'app/features/panel/components/VizTypePicker/types';
import { useDispatch, useSelector } from 'app/types';
import { VizTypePicker } from '../../../panel/components/VizTypePicker/VizTypePicker';
import { changePanelPlugin } from '../../../panel/state/actions';

View File

@ -1,10 +1,9 @@
import React, { FC, useCallback, useMemo } from 'react';
import { useSelector } from 'react-redux';
import { SelectableValue } from '@grafana/data';
import { Select } from '@grafana/ui';
import { useSelector } from 'app/types';
import { StoreState } from '../../../../types';
import { getLastKey, getVariablesByKey } from '../../../variables/state/selectors';
export interface Props {
@ -14,7 +13,7 @@ export interface Props {
}
export const RepeatRowSelect: FC<Props> = ({ repeat, onChange, id }) => {
const variables = useSelector((state: StoreState) => {
const variables = useSelector((state) => {
return getVariablesByKey(getLastKey(state), state);
});

View File

@ -1,5 +1,4 @@
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import useAsyncFn from 'react-use/lib/useAsyncFn';
import { locationUtil } from '@grafana/data';
@ -10,6 +9,7 @@ import { contextSrv } from 'app/core/core';
import { updateDashboardName } from 'app/core/reducers/navBarTree';
import { DashboardModel } from 'app/features/dashboard/state';
import { saveDashboard as saveDashboardApiCall } from 'app/features/manage-dashboards/state/actions';
import { useDispatch } from 'app/types';
import { DashboardSavedEvent } from 'app/types/events';
import { SaveDashboardOptions } from './types';

View File

@ -1,11 +1,10 @@
import { useEffect } from 'react';
import { useSelector } from 'react-redux';
import { useAsyncFn } from 'react-use';
import { locationUtil } from '@grafana/data';
import { locationService } from '@grafana/runtime';
import { useAppNotification } from 'app/core/copy/appNotification';
import { StoreState } from 'app/types';
import { useSelector } from 'app/types';
import { DashboardModel } from '../../state';
@ -16,7 +15,7 @@ const restoreDashboard = async (version: number, dashboard: DashboardModel) => {
};
export const useDashboardRestore = (version: number) => {
const dashboard = useSelector((state: StoreState) => state.dashboard.getModel());
const dashboard = useSelector((state) => state.dashboard.getModel());
const [state, onRestoreDashboard] = useAsyncFn(async () => await restoreDashboard(version, dashboard!), []);
const notifyApp = useAppNotification();

View File

@ -1,10 +1,9 @@
import { FC, ReactElement, useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { PanelMenuItem } from '@grafana/data';
import { getPanelStateForModel } from 'app/features/panel/state/selectors';
import { useSelector } from 'app/types';
import { StoreState } from '../../../../types';
import { DashboardModel, PanelModel } from '../../state';
import { getPanelMenu } from '../../utils/getPanelMenu';
@ -20,7 +19,7 @@ interface Props {
export const PanelHeaderMenuProvider: FC<Props> = ({ panel, dashboard, children }) => {
const [items, setItems] = useState<PanelMenuItem[]>([]);
const angularComponent = useSelector((state: StoreState) => getPanelStateForModel(state, panel)?.angularComponent);
const angularComponent = useSelector((state) => getPanelStateForModel(state, panel)?.angularComponent);
useEffect(() => {
setItems(getPanelMenu(dashboard, panel, angularComponent));

View File

@ -1,8 +1,7 @@
import { useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { NavModelItem } from '@grafana/data';
import { StoreState } from 'app/types/store';
import { useSelector } from 'app/types';
import { ROUTE_BASE_ID } from '../constants';
@ -11,7 +10,7 @@ import { ROUTE_BASE_ID } from '../constants';
// the child nav-model-item's ID on the call-site.)
export const useNavModel = () => {
const { pathname: currentPath } = useLocation();
const navIndex = useSelector((state: StoreState) => state.navIndex);
const navIndex = useSelector((state) => state.navIndex);
const node = navIndex[ROUTE_BASE_ID];
const main = node;
const isDefaultRoute = (item: NavModelItem) =>

View File

@ -1,10 +1,9 @@
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import PageLoader from 'app/core/components/PageLoader/PageLoader';
import { importDashboard, removeDashboard } from 'app/features/dashboard/state/actions';
import { loadPluginDashboards } from 'app/features/plugins/admin/state/actions';
import { PluginDashboard, StoreState } from 'app/types';
import { PluginDashboard, StoreState, useDispatch, useSelector } from 'app/types';
import DashboardTable from '../components/DashboardsTable';
import { useLoadDataSource } from '../state';

View File

@ -1,13 +1,12 @@
import { css } from '@emotion/css';
import React from 'react';
import { useSelector } from 'react-redux';
import { DataSourceSettings } from '@grafana/data';
import { Card, Tag, useStyles } from '@grafana/ui';
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
import PageLoader from 'app/core/components/PageLoader/PageLoader';
import { contextSrv } from 'app/core/core';
import { StoreState, AccessControlAction } from 'app/types';
import { StoreState, AccessControlAction, useSelector } from 'app/types';
import { getDataSources, getDataSourcesCount, useDataSourcesRoutes, useLoadDataSources } from '../state';
@ -16,7 +15,7 @@ import { DataSourcesListHeader } from './DataSourcesListHeader';
export function DataSourcesList() {
useLoadDataSources();
const dataSources = useSelector((state: StoreState) => getDataSources(state.dataSources));
const dataSources = useSelector((state) => getDataSources(state.dataSources));
const dataSourcesCount = useSelector(({ dataSources }: StoreState) => getDataSourcesCount(dataSources));
const hasFetched = useSelector(({ dataSources }: StoreState) => dataSources.hasFetched);
const hasCreateRights = contextSrv.hasPermission(AccessControlAction.DataSourcesCreate);

View File

@ -1,10 +1,9 @@
import React, { useCallback } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { AnyAction } from 'redux';
import PageActionBar from 'app/core/components/PageActionBar/PageActionBar';
import { contextSrv } from 'app/core/core';
import { AccessControlAction, StoreState } from 'app/types';
import { AccessControlAction, StoreState, useSelector, useDispatch } from 'app/types';
import { getDataSourcesSearchQuery, setDataSourcesSearchQuery, useDataSourcesRoutes } from '../state';

View File

@ -1,10 +1,9 @@
import { AnyAction } from '@reduxjs/toolkit';
import React from 'react';
import { useDispatch } from 'react-redux';
import { DataSourcePluginMeta, DataSourceSettings as DataSourceSettingsType } from '@grafana/data';
import PageLoader from 'app/core/components/PageLoader/PageLoader';
import { DataSourceSettingsState, ThunkResult } from 'app/types';
import { DataSourceSettingsState, useDispatch } from 'app/types';
import {
dataSourceLoaded,
@ -85,8 +84,8 @@ export type ViewProps = {
onDefaultChange: (isDefault: boolean) => AnyAction;
onNameChange: (name: string) => AnyAction;
onOptionsChange: (dataSource: DataSourceSettingsType) => AnyAction;
onTest: () => ThunkResult<void>;
onUpdate: (dataSource: DataSourceSettingsType) => ThunkResult<void>;
onTest: () => void;
onUpdate: (dataSource: DataSourceSettingsType) => Promise<void>;
};
export function EditDataSourceView({

View File

@ -1,12 +1,11 @@
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { AnyAction } from 'redux';
import { DataSourcePluginMeta } from '@grafana/data';
import { LinkButton, FilterInput } from '@grafana/ui';
import PageLoader from 'app/core/components/PageLoader/PageLoader';
import { PluginsErrorsInfo } from 'app/features/plugins/components/PluginsErrorsInfo';
import { DataSourcePluginCategory, StoreState } from 'app/types';
import { DataSourcePluginCategory, StoreState, useDispatch, useSelector } from 'app/types';
import { DataSourceCategories } from '../components/DataSourceCategories';
import { DataSourceTypeCardList } from '../components/DataSourceTypeCardList';

View File

@ -1,12 +1,11 @@
import { useContext, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { DataSourcePluginMeta, DataSourceSettings, NavModelItem, urlUtil } from '@grafana/data';
import { cleanUpAction } from 'app/core/actions/cleanUp';
import appEvents from 'app/core/app_events';
import { contextSrv } from 'app/core/core';
import { getNavModel } from 'app/core/selectors/navModel';
import { AccessControlAction, StoreState } from 'app/types';
import { AccessControlAction, useDispatch, useSelector } from 'app/types';
import { ShowConfirmModalEvent } from 'app/types/events';
import { DataSourceRights } from '../types';
@ -83,12 +82,12 @@ export const useAddDatasource = () => {
export const useUpdateDatasource = () => {
const dispatch = useDispatch();
return (dataSource: DataSourceSettings) => dispatch(updateDataSource(dataSource));
return async (dataSource: DataSourceSettings) => dispatch(updateDataSource(dataSource));
};
export const useDeleteLoadedDataSource = () => {
const dispatch = useDispatch();
const { name } = useSelector((state: StoreState) => state.dataSources.dataSource);
const { name } = useSelector((state) => state.dataSources.dataSource);
return () => {
appEvents.publish(
@ -104,7 +103,7 @@ export const useDeleteLoadedDataSource = () => {
};
export const useDataSource = (uid: string) => {
return useSelector((state: StoreState) => getDataSource(state.dataSources, uid));
return useSelector((state) => getDataSource(state.dataSources, uid));
};
export const useDataSourceExploreUrl = (uid: string) => {
@ -116,17 +115,17 @@ export const useDataSourceExploreUrl = (uid: string) => {
};
export const useDataSourceMeta = (pluginType: string): DataSourcePluginMeta => {
return useSelector((state: StoreState) => getDataSourceMeta(state.dataSources, pluginType));
return useSelector((state) => getDataSourceMeta(state.dataSources, pluginType));
};
export const useDataSourceSettings = () => {
return useSelector((state: StoreState) => state.dataSourceSettings);
return useSelector((state) => state.dataSourceSettings);
};
export const useDataSourceSettingsNav = (dataSourceId: string, pageId: string | null) => {
const dataSource = useDataSource(dataSourceId);
const { plugin, loadError, loading } = useDataSourceSettings();
const navIndex = useSelector((state: StoreState) => state.navIndex);
const navIndex = useSelector((state) => state.navIndex);
const navIndexId = pageId ? `datasource-${pageId}-${dataSourceId}` : `datasource-settings-${dataSourceId}`;
if (loadError) {

View File

@ -1,7 +1,6 @@
import { partial } from 'lodash';
import React, { useEffect, useState } from 'react';
import { DeepMap, FieldError, useForm } from 'react-hook-form';
import { useSelector } from 'react-redux';
import { locationUtil, SelectableValue } from '@grafana/data';
import { config, locationService, reportInteraction } from '@grafana/runtime';
@ -9,7 +8,7 @@ import { Alert, Button, Field, InputControl, Modal, RadioButtonGroup } from '@gr
import { DashboardPicker } from 'app/core/components/Select/DashboardPicker';
import { contextSrv } from 'app/core/services/context_srv';
import { removeDashboardToFetchFromLocalStorage } from 'app/features/dashboard/state/initDashboard';
import { ExploreId, AccessControlAction } from 'app/types';
import { ExploreId, AccessControlAction, useSelector } from 'app/types';
import { getExploreItemSelector } from '../state/selectors';

View File

@ -1,8 +1,7 @@
import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import { ToolbarButton } from '@grafana/ui';
import { ExploreId } from 'app/types';
import { ExploreId, useSelector } from 'app/types';
import { getExploreItemSelector } from '../state/selectors';

View File

@ -1,8 +1,7 @@
import { useRegisterActions, useKBar, Action, Priority } from 'kbar';
import { FC, useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { ExploreId } from 'app/types';
import { ExploreId, useDispatch, useSelector } from 'app/types';
import { splitOpen, splitClose } from './state/main';
import { runQueries } from './state/query';

View File

@ -1,10 +1,10 @@
import { createSelector } from '@reduxjs/toolkit';
import React, { useCallback, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { CoreApp, DataQuery, DataSourceInstanceSettings } from '@grafana/data';
import { getDataSourceSrv } from '@grafana/runtime';
import { getNextRefIdChar } from 'app/core/utils/query';
import { useDispatch, useSelector } from 'app/types';
import { ExploreId } from 'app/types/explore';
import { getDatasourceSrv } from '../plugins/datasource_srv';

View File

@ -1,9 +1,9 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { LoadingState } from '@grafana/data';
import { useSelector } from 'app/types';
import { ExploreId, StoreState } from '../../types';
import { ExploreId } from '../../types';
import { ErrorContainer } from './ErrorContainer';
@ -11,7 +11,7 @@ interface Props {
exploreId: ExploreId;
}
export function ResponseErrorContainer(props: Props) {
const queryResponse = useSelector((state: StoreState) => state.explore[props.exploreId]?.queryResponse);
const queryResponse = useSelector((state) => state.explore[props.exploreId]?.queryResponse);
const queryError = queryResponse?.state === LoadingState.Error ? queryResponse?.error : undefined;
// Errors with ref ids are shown below the corresponding query

View File

@ -1,7 +1,6 @@
import { css } from '@emotion/css';
import { TopOfViewRefType } from '@jaegertracing/jaeger-ui-components/src/TraceTimelineViewer/VirtualizedTraceView';
import React, { RefObject, useCallback, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
DataFrame,
@ -30,7 +29,7 @@ import { TraceToMetricsData } from 'app/core/components/TraceToMetrics/TraceToMe
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
import { getTimeZone } from 'app/features/profile/state/selectors';
import { TempoQuery } from 'app/plugins/datasource/tempo/types';
import { StoreState } from 'app/types';
import { useDispatch, useSelector } from 'app/types';
import { ExploreId } from 'app/types/explore';
import { changePanelState } from '../state/explorePane';
@ -138,7 +137,7 @@ export function TraceView(props: Props) {
[props.splitOpenFn, traceToLogsOptions, traceToMetricsOptions, props.dataFrames, createFocusSpanLink]
);
const onSlimViewClicked = useCallback(() => setSlim(!slim), [slim]);
const timeZone = useSelector((state: StoreState) => getTimeZone(state.user));
const timeZone = useSelector((state) => getTimeZone(state.user));
const datasourceType = datasource ? datasource?.type : 'unknown';
return (
@ -218,7 +217,7 @@ function useFocusSpanLink(options: {
refId?: string;
datasource?: DataSourceApi;
}): [string | undefined, (traceId: string, spanId: string) => LinkModel<Field>] {
const panelState = useSelector((state: StoreState) => state.explore[options.exploreId]?.panelsState.trace);
const panelState = useSelector((state) => state.explore[options.exploreId]?.panelsState.trace);
const focusedSpanId = panelState?.spanId;
const dispatch = useDispatch();
@ -230,7 +229,7 @@ function useFocusSpanLink(options: {
})
);
const query = useSelector((state: StoreState) =>
const query = useSelector((state) =>
state.explore[options.exploreId]?.queries.find((query) => query.refId === options.refId)
);

View File

@ -1,11 +1,10 @@
import TracePageSearchBar from '@jaegertracing/jaeger-ui-components/src/TracePageHeader/TracePageSearchBar';
import { TopOfViewRefType } from '@jaegertracing/jaeger-ui-components/src/TraceTimelineViewer/VirtualizedTraceView';
import React, { RefObject, useMemo, useState } from 'react';
import { useSelector } from 'react-redux';
import { DataFrame, SplitOpen, PanelData } from '@grafana/data';
import { Collapse } from '@grafana/ui';
import { StoreState } from 'app/types';
import { StoreState, useSelector } from 'app/types';
import { ExploreId } from 'app/types/explore';
import { TraceView } from './TraceView';

View File

@ -1,7 +1,7 @@
import { createAction } from '@reduxjs/toolkit';
import { AnyAction } from 'redux';
import { ExploreUrlState, serializeStateToUrlParam, SplitOpen, UrlQueryMap } from '@grafana/data';
import { DataQuery, ExploreUrlState, serializeStateToUrlParam, SplitOpenOptions, UrlQueryMap } from '@grafana/data';
import { DataSourceSrv, locationService } from '@grafana/runtime';
import { GetExploreUrlArguments, stopQueryState } from 'app/core/utils/explore';
import { PanelModel } from 'app/features/dashboard/state';
@ -101,7 +101,7 @@ export const lastSavedUrl: UrlQueryMap = {};
* or uses values from options arg. This does only navigation each pane is then responsible for initialization from
* the URL.
*/
export const splitOpen: SplitOpen = (options): ThunkResult<void> => {
export const splitOpen = <T extends DataQuery = DataQuery>(options?: SplitOpenOptions<T>): ThunkResult<void> => {
return async (dispatch, getState) => {
const leftState: ExploreItemState = getState().explore[ExploreId.left];
const leftUrlState = getUrlStateFromPaneState(leftState);

View File

@ -1,7 +1,7 @@
import React, { useCallback } from 'react';
import { useDispatch } from 'react-redux';
import { RefreshPicker } from '@grafana/ui';
import { useDispatch } from 'app/types';
import { ExploreId } from '../../types';

View File

@ -1,11 +1,10 @@
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useAsync } from 'react-use';
import { Page } from 'app/core/components/Page/Page';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import { getNavModel } from 'app/core/selectors/navModel';
import { StoreState } from 'app/types';
import { useDispatch, useSelector } from 'app/types';
import { AlertsFolderView } from '../alerting/unified/AlertsFolderView';
@ -16,8 +15,8 @@ export interface OwnProps extends GrafanaRouteComponentProps<{ uid: string }> {}
const FolderAlerting = ({ match }: OwnProps) => {
const dispatch = useDispatch();
const navIndex = useSelector((state: StoreState) => state.navIndex);
const folder = useSelector((state: StoreState) => state.folder);
const navIndex = useSelector((state) => state.navIndex);
const folder = useSelector((state) => state.folder);
const uid = match.params.uid;
const pageNav = getNavModel(navIndex, `folder-alerting-${uid}`, getLoadingNav(1));

View File

@ -1,12 +1,12 @@
import { css } from '@emotion/css';
import React, { FC, useCallback, useState } from 'react';
import { useDispatch } from 'react-redux';
import { GrafanaTheme2, PanelPluginMeta } from '@grafana/data';
import { Button, useStyles2, VerticalGroup } from '@grafana/ui';
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
import { PanelModel } from 'app/features/dashboard/state';
import { changeToLibraryPanel } from 'app/features/panel/state/actions';
import { useDispatch } from 'app/types';
import { PanelTypeFilter } from '../../../../core/components/PanelTypeFilter/PanelTypeFilter';
import { LibraryElementDTO } from '../../types';

View File

@ -1,11 +1,11 @@
import { t } from '@lingui/macro';
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import useAsyncFn from 'react-use/lib/useAsyncFn';
import { isFetchError } from '@grafana/runtime';
import { notifyApp } from 'app/core/actions';
import { PanelModel } from 'app/features/dashboard/state';
import { useDispatch } from 'app/types';
import {
createPanelLibraryErrorNotification,

View File

@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import React from 'react';
import { useDispatch } from 'react-redux';
import { CoreApp, GrafanaTheme2, PanelDataSummary, VisualizationSuggestionsBuilder } from '@grafana/data';
import { PanelDataErrorViewProps } from '@grafana/runtime';
@ -11,6 +10,7 @@ import store from 'app/core/store';
import { toggleVizPicker } from 'app/features/dashboard/components/PanelEditor/state/reducers';
import { VisualizationSelectPaneTab } from 'app/features/dashboard/components/PanelEditor/types';
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
import { useDispatch } from 'app/types';
import { changePanelPlugin } from '../state/actions';

View File

@ -1,9 +1,9 @@
import React, { useCallback } from 'react';
import { useDispatch } from 'react-redux';
import { DataSourcePluginMeta } from '@grafana/data';
import { Button } from '@grafana/ui';
import { addDataSource } from 'app/features/datasources/state/actions';
import { useDispatch } from 'app/types';
import { isDataSourceEditor } from '../../permissions';
import { CatalogPlugin } from '../../types';

View File

@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import React, { ReactElement } from 'react';
import { useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { SelectableValue, GrafanaTheme2 } from '@grafana/data';
@ -9,7 +8,7 @@ import { LoadingPlaceholder, Select, RadioButtonGroup, useStyles2, Tooltip } fro
import { Page } from 'app/core/components/Page/Page';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import { getNavModel } from 'app/core/selectors/navModel';
import { StoreState } from 'app/types/store';
import { useSelector } from 'app/types';
import { HorizontalGroup } from '../components/HorizontalGroup';
import { PluginList } from '../components/PluginList';
@ -22,7 +21,7 @@ import { PluginListDisplayMode } from '../types';
export default function Browse({ route }: GrafanaRouteComponentProps): ReactElement | null {
const location = useLocation();
const locationSearch = locationSearchToObject(location.search);
const navModel = useSelector((state: StoreState) => getNavModel(state.navIndex, 'plugins'));
const navModel = useSelector((state) => getNavModel(state.navIndex, 'plugins'));
const { displayMode, setDisplayMode } = useDisplayMode();
const styles = useStyles2(getStyles);
const history = useHistory();

View File

@ -1,10 +1,10 @@
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { PluginError } from '@grafana/data';
import { useDispatch, useSelector } from 'app/types';
import { sortPlugins, Sorters } from '../helpers';
import { CatalogPlugin, PluginCatalogStoreState, PluginListDisplayMode } from '../types';
import { CatalogPlugin, PluginListDisplayMode } from '../types';
import { fetchAll, fetchDetails, fetchRemotePlugins, install, uninstall } from './actions';
import { setDisplayMode } from './reducer';
@ -55,7 +55,7 @@ export const useGetSingle = (id: string): CatalogPlugin | undefined => {
useFetchAll();
useFetchDetails(id);
return useSelector((state: PluginCatalogStoreState) => selectById(state, id));
return useSelector((state) => selectById(state, id));
};
export const useGetErrors = (): PluginError[] => {
@ -120,7 +120,7 @@ export const useFetchAll = () => {
export const useFetchDetails = (id: string) => {
const dispatch = useDispatch();
const plugin = useSelector((state: PluginCatalogStoreState) => selectById(state, id));
const plugin = useSelector((state) => selectById(state, id));
const isNotFetching = !useSelector(selectIsRequestPending(fetchDetails.typePrefix));
const shouldFetch = isNotFetching && plugin && !plugin.details;

View File

@ -6,7 +6,7 @@ import moment from 'moment'; // eslint-disable-line no-restricted-imports
import prismjs from 'prismjs';
import react from 'react';
import reactDom from 'react-dom';
import * as reactRedux from 'react-redux';
import * as reactRedux from 'react-redux'; // eslint-disable-line no-restricted-imports
import * as reactRouter from 'react-router-dom';
import * as redux from 'redux';
import * as rxjs from 'rxjs';

View File

@ -1,10 +1,9 @@
import { debounce } from 'lodash';
import { FormEvent } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { SelectableValue } from '@grafana/data';
import { locationService } from '@grafana/runtime';
import { StoreState } from 'app/types';
import { useDispatch, useSelector } from 'app/types';
import {
defaultQueryParams,
@ -24,7 +23,7 @@ import { hasFilters } from '../utils';
const updateLocation = debounce((query) => locationService.partial(query, true), 300);
export const useSearchQuery = (defaults: Partial<DashboardQuery>) => {
const query = useSelector((state: StoreState) => state.searchQuery);
const query = useSelector((state) => state.searchQuery);
const dispatch = useDispatch();
const onQueryChange = (query: string) => {

View File

@ -1,7 +1,7 @@
import React, { ChangeEvent, FocusEvent, KeyboardEvent, ReactElement, useCallback, useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import { Input } from '@grafana/ui';
import { useDispatch } from 'app/types';
import { variableAdapters } from '../adapters';
import { VariablePickerProps } from '../pickers/types';

View File

@ -1,5 +1,4 @@
import React, { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { PanelProps } from '@grafana/data';
import { config } from '@grafana/runtime';
@ -10,6 +9,7 @@ import { parseMatchers } from 'app/features/alerting/unified/utils/alertmanager'
import { NOTIFICATIONS_POLL_INTERVAL_MS } from 'app/features/alerting/unified/utils/constants';
import { initialAsyncRequestState } from 'app/features/alerting/unified/utils/redux';
import { AlertmanagerGroup, Matcher } from 'app/plugins/datasource/alertmanager/types';
import { useDispatch } from 'app/types';
import { AlertGroup } from './AlertGroup';
import { AlertGroupPanelOptions } from './types';

View File

@ -1,6 +1,5 @@
import { isEmpty, uniq } from 'lodash';
import React, { FC, useEffect, useMemo } from 'react';
import { useDispatch } from 'react-redux';
import { SelectableValue } from '@grafana/data';
import { Icon, MultiSelect } from '@grafana/ui';
@ -11,6 +10,7 @@ import {
isAsyncRequestMapSliceFulfilled,
isAsyncRequestMapSlicePending,
} from 'app/features/alerting/unified/utils/redux';
import { useDispatch } from 'app/types';
import { AlertingRule } from 'app/types/unified-alerting';
import { PromRuleType } from 'app/types/unified-alerting-dto';

View File

@ -1,7 +1,6 @@
import { css } from '@emotion/css';
import { sortBy } from 'lodash';
import React, { useEffect, useMemo } from 'react';
import { useDispatch } from 'react-redux';
import { GrafanaTheme2, PanelProps } from '@grafana/data';
import {
@ -28,7 +27,7 @@ import {
} from 'app/features/alerting/unified/utils/datasource';
import { flattenRules, getFirstActiveAt } from 'app/features/alerting/unified/utils/rules';
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
import { AccessControlAction } from 'app/types';
import { useDispatch, AccessControlAction } from 'app/types';
import { PromRuleWithLocation } from 'app/types/unified-alerting';
import { PromAlertingRuleState } from 'app/types/unified-alerting-dto';

View File

@ -1,7 +1,6 @@
import { css, cx } from '@emotion/css';
import { take } from 'lodash';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useDispatch } from 'react-redux';
import { GrafanaTheme2, InterpolateFunction, PanelProps } from '@grafana/data';
import { CustomScrollbar, stylesFactory, useStyles2 } from '@grafana/ui';
@ -13,6 +12,7 @@ import impressionSrv from 'app/core/services/impression_srv';
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
import { SearchCard } from 'app/features/search/components/SearchCard';
import { DashboardSearchItem } from 'app/features/search/types';
import { useDispatch } from 'app/types';
import { PanelLayout, PanelOptions } from './models.gen';
import { getStyles } from './styles';

View File

@ -33,6 +33,9 @@ export function configureStore(initialState?: Partial<StoreState>) {
return store;
}
export type RootState = ReturnType<ReturnType<typeof configureStore>['getState']>;
export type AppDispatch = ReturnType<typeof configureStore>['dispatch'];
/*
function getActionsToIgnoreSerializableCheckOn() {
return [

View File

@ -1,3 +1,4 @@
/* eslint-disable no-restricted-imports */
import {
Action,
AsyncThunk,
@ -14,7 +15,7 @@ import {
import { ThunkAction, ThunkDispatch as GenericThunkDispatch } from 'redux-thunk';
import type { createRootReducer } from 'app/core/reducers/root';
import { configureStore } from 'app/store/configureStore';
import { AppDispatch, RootState } from 'app/store/configureStore';
export type StoreState = ReturnType<ReturnType<typeof createRootReducer>>;
@ -26,9 +27,8 @@ export type ThunkResult<R> = ThunkAction<R, StoreState, undefined, PayloadAction
export type ThunkDispatch = GenericThunkDispatch<StoreState, undefined, Action>;
// Typed useDispatch & useSelector hooks
export type AppDispatch = ReturnType<typeof configureStore>['dispatch'];
export const useDispatch = () => useDispatchUntyped<AppDispatch>();
export const useSelector: TypedUseSelectorHook<StoreState> = useSelectorUntyped;
export const useDispatch: () => AppDispatch = useDispatchUntyped;
export const useSelector: TypedUseSelectorHook<RootState> = useSelectorUntyped;
type DefaultThunkApiConfig = { dispatch: AppDispatch; state: StoreState };
export const createAsyncThunk = <Returned, ThunkArg = void, ThunkApiConfig extends {} = DefaultThunkApiConfig>(