mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2025-07-27 08:30:02 +03:00
feat(rtk-query): display mutations in queryList
This commit is contained in:
parent
95da893616
commit
e4c5720d87
|
@ -1,18 +1,18 @@
|
||||||
import React, { PureComponent, ReactNode } from 'react';
|
import React, { PureComponent, ReactNode } from 'react';
|
||||||
import { StyleUtilsContext } from '../styles/createStylingFromTheme';
|
import { StyleUtilsContext } from '../styles/createStylingFromTheme';
|
||||||
import { QueryInfo, RtkQueryMonitorState } from '../types';
|
import { RtkResourceInfo, RtkQueryMonitorState } from '../types';
|
||||||
import { isQuerySelected } from '../utils/rtk-query';
|
import { isQuerySelected } from '../utils/rtk-query';
|
||||||
|
|
||||||
export interface QueryListProps {
|
export interface QueryListProps {
|
||||||
queryInfos: QueryInfo[];
|
resInfos: RtkResourceInfo[];
|
||||||
selectedQueryKey: RtkQueryMonitorState['selectedQueryKey'];
|
selectedQueryKey: RtkQueryMonitorState['selectedQueryKey'];
|
||||||
onSelectQuery: (query: QueryInfo) => void;
|
onSelectQuery: (query: RtkResourceInfo) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class QueryList extends PureComponent<QueryListProps> {
|
export class QueryList extends PureComponent<QueryListProps> {
|
||||||
static isItemSelected(
|
static isItemSelected(
|
||||||
selectedQueryKey: QueryListProps['selectedQueryKey'],
|
selectedQueryKey: QueryListProps['selectedQueryKey'],
|
||||||
queryInfo: QueryInfo
|
queryInfo: RtkResourceInfo
|
||||||
): boolean {
|
): boolean {
|
||||||
return (
|
return (
|
||||||
!!selectedQueryKey &&
|
!!selectedQueryKey &&
|
||||||
|
@ -21,27 +21,43 @@ export class QueryList extends PureComponent<QueryListProps> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static formatQuery(resInfo: RtkResourceInfo): string {
|
||||||
|
const key =
|
||||||
|
resInfo.type === 'query'
|
||||||
|
? resInfo.queryKey
|
||||||
|
: `${resInfo.state.endpointName ?? ''} ${resInfo.queryKey}`;
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
render(): ReactNode {
|
render(): ReactNode {
|
||||||
const { queryInfos, selectedQueryKey, onSelectQuery } = this.props;
|
const { resInfos, selectedQueryKey, onSelectQuery } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyleUtilsContext.Consumer>
|
<StyleUtilsContext.Consumer>
|
||||||
{({ styling }) => (
|
{({ styling }) => (
|
||||||
<ul {...styling('queryList')}>
|
<ul {...styling('queryList')}>
|
||||||
{queryInfos.map((queryInfo) => {
|
{resInfos.map((resInfo) => {
|
||||||
const isSelected = isQuerySelected(selectedQueryKey, queryInfo);
|
const isSelected = isQuerySelected(selectedQueryKey, resInfo);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li
|
<li
|
||||||
key={queryInfo.queryKey}
|
key={resInfo.queryKey}
|
||||||
onClick={() => onSelectQuery(queryInfo)}
|
onClick={() => onSelectQuery(resInfo)}
|
||||||
{...styling(
|
{...styling(
|
||||||
['queryListItem', isSelected && 'queryListItemSelected'],
|
['queryListItem', isSelected && 'queryListItemSelected'],
|
||||||
isSelected
|
isSelected
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<p {...styling('queryListItemKey')}>{queryInfo.queryKey}</p>
|
<p {...styling('queryListItemKey')}>
|
||||||
<p {...styling('queryStatus')}>{queryInfo.query.status}</p>
|
{QueryList.formatQuery(resInfo)}
|
||||||
|
</p>
|
||||||
|
<div {...styling('queryStatusWrapper')}>
|
||||||
|
<strong {...styling(['queryStatus', 'queryType'])}>
|
||||||
|
{resInfo.type === 'query' ? 'Q' : 'M'}
|
||||||
|
</strong>
|
||||||
|
<p {...styling('queryStatus')}>{resInfo.state.status}</p>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -4,7 +4,9 @@ import { QueryPreviewTabs, TabOption } from '../types';
|
||||||
import { emptyArray } from '../utils/object';
|
import { emptyArray } from '../utils/object';
|
||||||
|
|
||||||
export interface QueryPreviewHeaderProps {
|
export interface QueryPreviewHeaderProps {
|
||||||
tabs: ReadonlyArray<TabOption<QueryPreviewTabs, unknown>>;
|
tabs: ReadonlyArray<
|
||||||
|
TabOption<QueryPreviewTabs, unknown, 'query' | 'mutation'>
|
||||||
|
>;
|
||||||
onTabChange: (tab: QueryPreviewTabs) => void;
|
onTabChange: (tab: QueryPreviewTabs) => void;
|
||||||
selectedTab: QueryPreviewTabs;
|
selectedTab: QueryPreviewTabs;
|
||||||
renderTabLabel?: (tab: QueryPreviewHeaderProps['tabs'][number]) => ReactNode;
|
renderTabLabel?: (tab: QueryPreviewHeaderProps['tabs'][number]) => ReactNode;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { createSelector, Selector } from '@reduxjs/toolkit';
|
import { createSelector, Selector } from '@reduxjs/toolkit';
|
||||||
import { QueryStatus } from '@reduxjs/toolkit/dist/query';
|
import { QueryStatus } from '@reduxjs/toolkit/dist/query';
|
||||||
import React, { ReactNode, PureComponent } from 'react';
|
import React, { ReactNode, PureComponent } from 'react';
|
||||||
import { QueryInfo, RtkQueryState, RTKStatusFlags } from '../types';
|
import { RtkResourceInfo, RTKStatusFlags } from '../types';
|
||||||
import { formatMs } from '../utils/formatters';
|
import { formatMs } from '../utils/formatters';
|
||||||
import { identity } from '../utils/object';
|
import { identity } from '../utils/object';
|
||||||
import { getQueryStatusFlags } from '../utils/rtk-query';
|
import { getQueryStatusFlags } from '../utils/rtk-query';
|
||||||
|
@ -13,16 +13,18 @@ type QueryTimings = {
|
||||||
duration: string;
|
duration: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface FormattedQuery {
|
type FormattedQuery = {
|
||||||
queryKey: string;
|
key: string;
|
||||||
reducerPath: string;
|
reducerPath: string;
|
||||||
timings: QueryTimings;
|
timings: QueryTimings;
|
||||||
statusFlags: RTKStatusFlags;
|
statusFlags: RTKStatusFlags;
|
||||||
query: RtkQueryState;
|
} & (
|
||||||
}
|
| { mutation: RtkResourceInfo['state'] }
|
||||||
|
| { query: RtkResourceInfo['state'] }
|
||||||
|
);
|
||||||
|
|
||||||
export interface QueryPreviewInfoProps {
|
export interface QueryPreviewInfoProps {
|
||||||
queryInfo: QueryInfo;
|
resInfo: RtkResourceInfo;
|
||||||
isWideLayout: boolean;
|
isWideLayout: boolean;
|
||||||
}
|
}
|
||||||
export class QueryPreviewInfo extends PureComponent<QueryPreviewInfoProps> {
|
export class QueryPreviewInfo extends PureComponent<QueryPreviewInfoProps> {
|
||||||
|
@ -33,23 +35,22 @@ export class QueryPreviewInfo extends PureComponent<QueryPreviewInfoProps> {
|
||||||
): boolean => {
|
): boolean => {
|
||||||
const lastKey = keyPath[keyPath.length - 1];
|
const lastKey = keyPath[keyPath.length - 1];
|
||||||
|
|
||||||
return layer <= 1 && lastKey !== 'query';
|
return layer <= 1 && lastKey !== 'query' && lastKey !== 'mutation';
|
||||||
};
|
};
|
||||||
|
|
||||||
selectFormattedQuery: Selector<QueryInfo, FormattedQuery> = createSelector(
|
selectFormattedQuery: Selector<RtkResourceInfo, FormattedQuery> =
|
||||||
identity,
|
createSelector(identity, (resInfo: RtkResourceInfo): FormattedQuery => {
|
||||||
(queryInfo: QueryInfo): FormattedQuery => {
|
const { state, queryKey, reducerPath } = resInfo;
|
||||||
const { query, queryKey, reducerPath } = queryInfo;
|
|
||||||
|
|
||||||
const startedAt = query.startedTimeStamp
|
const startedAt = state.startedTimeStamp
|
||||||
? new Date(query.startedTimeStamp).toISOString()
|
? new Date(state.startedTimeStamp).toISOString()
|
||||||
: '-';
|
: '-';
|
||||||
|
|
||||||
const loadedAt = query.fulfilledTimeStamp
|
const loadedAt = state.fulfilledTimeStamp
|
||||||
? new Date(query.fulfilledTimeStamp).toISOString()
|
? new Date(state.fulfilledTimeStamp).toISOString()
|
||||||
: '-';
|
: '-';
|
||||||
|
|
||||||
const statusFlags = getQueryStatusFlags(query);
|
const statusFlags = getQueryStatusFlags(state);
|
||||||
|
|
||||||
const timings = {
|
const timings = {
|
||||||
startedAt,
|
startedAt,
|
||||||
|
@ -58,29 +59,38 @@ export class QueryPreviewInfo extends PureComponent<QueryPreviewInfoProps> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (
|
if (
|
||||||
query.fulfilledTimeStamp &&
|
state.fulfilledTimeStamp &&
|
||||||
query.startedTimeStamp &&
|
state.startedTimeStamp &&
|
||||||
query.status !== QueryStatus.pending &&
|
state.status !== QueryStatus.pending &&
|
||||||
query.startedTimeStamp <= query.fulfilledTimeStamp
|
state.startedTimeStamp <= state.fulfilledTimeStamp
|
||||||
) {
|
) {
|
||||||
timings.duration = formatMs(
|
timings.duration = formatMs(
|
||||||
query.fulfilledTimeStamp - query.startedTimeStamp
|
state.fulfilledTimeStamp - state.startedTimeStamp
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resInfo.type === 'query') {
|
||||||
return {
|
return {
|
||||||
queryKey,
|
key: queryKey,
|
||||||
reducerPath,
|
reducerPath,
|
||||||
query: queryInfo.query,
|
query: resInfo.state,
|
||||||
statusFlags,
|
statusFlags,
|
||||||
timings,
|
timings,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
return {
|
||||||
|
key: queryKey,
|
||||||
|
reducerPath,
|
||||||
|
mutation: resInfo.state,
|
||||||
|
statusFlags,
|
||||||
|
timings,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
render(): ReactNode {
|
render(): ReactNode {
|
||||||
const { queryInfo, isWideLayout } = this.props;
|
const { resInfo, isWideLayout } = this.props;
|
||||||
const formattedQuery = this.selectFormattedQuery(queryInfo);
|
const formattedQuery = this.selectFormattedQuery(resInfo);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TreeView
|
<TreeView
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { StyleUtilsContext } from '../styles/createStylingFromTheme';
|
||||||
import { createTreeItemLabelRenderer } from '../styles/tree';
|
import { createTreeItemLabelRenderer } from '../styles/tree';
|
||||||
import {
|
import {
|
||||||
QueryPreviewTabs,
|
QueryPreviewTabs,
|
||||||
QueryInfo,
|
RtkResourceInfo,
|
||||||
SelectorsSource,
|
SelectorsSource,
|
||||||
TabOption,
|
TabOption,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
|
@ -32,12 +32,13 @@ import {
|
||||||
QueryPreviewActions,
|
QueryPreviewActions,
|
||||||
QueryPreviewActionsProps,
|
QueryPreviewActionsProps,
|
||||||
} from '../components/QueryPreviewActions';
|
} from '../components/QueryPreviewActions';
|
||||||
|
import { isTabVisible } from '../utils/tabs';
|
||||||
|
|
||||||
export interface QueryPreviewProps<S = unknown> {
|
export interface QueryPreviewProps<S = unknown> {
|
||||||
readonly selectedTab: QueryPreviewTabs;
|
readonly selectedTab: QueryPreviewTabs;
|
||||||
readonly hasNoApis: boolean;
|
readonly hasNoApis: boolean;
|
||||||
readonly onTabChange: (tab: QueryPreviewTabs) => void;
|
readonly onTabChange: (tab: QueryPreviewTabs) => void;
|
||||||
readonly queryInfo: QueryInfo | null;
|
readonly resInfo: RtkResourceInfo | null;
|
||||||
readonly styling: StylingFunction;
|
readonly styling: StylingFunction;
|
||||||
readonly isWideLayout: boolean;
|
readonly isWideLayout: boolean;
|
||||||
readonly selectorsSource: SelectorsSource<S>;
|
readonly selectorsSource: SelectorsSource<S>;
|
||||||
|
@ -47,15 +48,15 @@ export interface QueryPreviewProps<S = unknown> {
|
||||||
/**
|
/**
|
||||||
* Tab content is not rendered if there's no selected query.
|
* Tab content is not rendered if there's no selected query.
|
||||||
*/
|
*/
|
||||||
type QueryPreviewTabProps = Omit<QueryPreviewProps<unknown>, 'queryInfo'> & {
|
type QueryPreviewTabProps = Omit<QueryPreviewProps<unknown>, 'resInfo'> & {
|
||||||
queryInfo: QueryInfo;
|
resInfo: RtkResourceInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MappedQueryPreviewTags = mapProps<
|
const MappedQueryPreviewTags = mapProps<
|
||||||
QueryPreviewTabProps,
|
QueryPreviewTabProps,
|
||||||
QueryPreviewTagsProps
|
QueryPreviewTagsProps
|
||||||
>(({ selectors, selectorsSource, isWideLayout, queryInfo }) => ({
|
>(({ selectors, selectorsSource, isWideLayout, resInfo }) => ({
|
||||||
queryInfo,
|
resInfo,
|
||||||
tags: selectors.selectCurrentQueryTags(selectorsSource),
|
tags: selectors.selectCurrentQueryTags(selectorsSource),
|
||||||
isWideLayout,
|
isWideLayout,
|
||||||
}))(QueryPreviewTags);
|
}))(QueryPreviewTags);
|
||||||
|
@ -63,9 +64,7 @@ const MappedQueryPreviewTags = mapProps<
|
||||||
const MappedQueryPreviewInfo = mapProps<
|
const MappedQueryPreviewInfo = mapProps<
|
||||||
QueryPreviewTabProps,
|
QueryPreviewTabProps,
|
||||||
QueryPreviewInfoProps
|
QueryPreviewInfoProps
|
||||||
>(({ queryInfo, isWideLayout }) => ({ queryInfo, isWideLayout }))(
|
>(({ resInfo, isWideLayout }) => ({ resInfo, isWideLayout }))(QueryPreviewInfo);
|
||||||
QueryPreviewInfo
|
|
||||||
);
|
|
||||||
|
|
||||||
const MappedQuerySubscriptipns = mapProps<
|
const MappedQuerySubscriptipns = mapProps<
|
||||||
QueryPreviewTabProps,
|
QueryPreviewTabProps,
|
||||||
|
@ -91,26 +90,48 @@ const MappedQueryPreviewActions = mapProps<
|
||||||
actionsOfQuery: selectors.selectActionsOfCurrentQuery(selectorsSource),
|
actionsOfQuery: selectors.selectActionsOfCurrentQuery(selectorsSource),
|
||||||
}))(QueryPreviewActions);
|
}))(QueryPreviewActions);
|
||||||
|
|
||||||
const tabs: ReadonlyArray<TabOption<QueryPreviewTabs, QueryPreviewTabProps>> = [
|
const tabs: ReadonlyArray<
|
||||||
|
TabOption<QueryPreviewTabs, QueryPreviewTabProps, RtkResourceInfo['type']>
|
||||||
|
> = [
|
||||||
{
|
{
|
||||||
label: 'query',
|
label: 'query',
|
||||||
value: QueryPreviewTabs.queryinfo,
|
value: QueryPreviewTabs.queryinfo,
|
||||||
component: MappedQueryPreviewInfo,
|
component: MappedQueryPreviewInfo,
|
||||||
|
visible: {
|
||||||
|
query: true,
|
||||||
|
mutation: true,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'actions',
|
label: 'actions',
|
||||||
value: QueryPreviewTabs.actions,
|
value: QueryPreviewTabs.actions,
|
||||||
component: MappedQueryPreviewActions,
|
component: MappedQueryPreviewActions,
|
||||||
|
visible: {
|
||||||
|
query: true,
|
||||||
|
mutation: true,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'tags',
|
label: 'tags',
|
||||||
value: QueryPreviewTabs.queryTags,
|
value: QueryPreviewTabs.queryTags,
|
||||||
component: MappedQueryPreviewTags,
|
component: MappedQueryPreviewTags,
|
||||||
|
visible: {
|
||||||
|
query: true,
|
||||||
|
mutation: false,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'subs',
|
label: 'subs',
|
||||||
value: QueryPreviewTabs.querySubscriptions,
|
value: QueryPreviewTabs.querySubscriptions,
|
||||||
component: MappedQuerySubscriptipns,
|
component: MappedQuerySubscriptipns,
|
||||||
|
visible: {
|
||||||
|
query: true,
|
||||||
|
mutation: false,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'api',
|
label: 'api',
|
||||||
|
@ -141,24 +162,32 @@ export class QueryPreview<S> extends React.PureComponent<QueryPreviewProps<S>> {
|
||||||
return `${label}(${counterAsString})`;
|
return `${label}(${counterAsString})`;
|
||||||
};
|
};
|
||||||
|
|
||||||
renderTabLabel = (tab: TabOption<QueryPreviewTabs, unknown>): ReactNode => {
|
renderTabLabel = (
|
||||||
const { selectors, selectorsSource } = this.props;
|
tab: TabOption<QueryPreviewTabs, unknown, 'query' | 'mutation'>
|
||||||
|
): ReactNode => {
|
||||||
|
const { selectors, selectorsSource, resInfo } = this.props;
|
||||||
const tabCount = selectors.selectTabCounters(selectorsSource)[tab.value];
|
const tabCount = selectors.selectTabCounters(selectorsSource)[tab.value];
|
||||||
|
|
||||||
if (tabCount > 0) {
|
let tabLabel = tab.label;
|
||||||
return this.renderLabelWithCounter(tab.label, tabCount);
|
|
||||||
|
if (tabLabel === 'query' && resInfo?.type === 'mutation') {
|
||||||
|
tabLabel = resInfo.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tab.label;
|
if (tabCount > 0) {
|
||||||
|
return this.renderLabelWithCounter(tabLabel, tabCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tabLabel;
|
||||||
};
|
};
|
||||||
|
|
||||||
render(): ReactNode {
|
render(): ReactNode {
|
||||||
const { queryInfo, selectedTab, onTabChange, hasNoApis } = this.props;
|
const { resInfo, selectedTab, onTabChange, hasNoApis } = this.props;
|
||||||
|
|
||||||
const { component: TabComponent } =
|
const { component: TabComponent } =
|
||||||
tabs.find((tab) => tab.value === selectedTab) || tabs[0];
|
tabs.find((tab) => tab.value === selectedTab) || tabs[0];
|
||||||
|
|
||||||
if (!queryInfo) {
|
if (!resInfo) {
|
||||||
return (
|
return (
|
||||||
<StyleUtilsContext.Consumer>
|
<StyleUtilsContext.Consumer>
|
||||||
{({ styling }) => (
|
{({ styling }) => (
|
||||||
|
@ -167,7 +196,15 @@ export class QueryPreview<S> extends React.PureComponent<QueryPreviewProps<S>> {
|
||||||
selectedTab={selectedTab}
|
selectedTab={selectedTab}
|
||||||
onTabChange={onTabChange}
|
onTabChange={onTabChange}
|
||||||
tabs={
|
tabs={
|
||||||
tabs as ReadonlyArray<TabOption<QueryPreviewTabs, unknown>>
|
tabs.filter((tab) =>
|
||||||
|
isTabVisible(tab, 'default')
|
||||||
|
) as ReadonlyArray<
|
||||||
|
TabOption<
|
||||||
|
QueryPreviewTabs,
|
||||||
|
unknown,
|
||||||
|
RtkResourceInfo['type']
|
||||||
|
>
|
||||||
|
>
|
||||||
}
|
}
|
||||||
renderTabLabel={this.renderTabLabel}
|
renderTabLabel={this.renderTabLabel}
|
||||||
/>
|
/>
|
||||||
|
@ -187,7 +224,15 @@ export class QueryPreview<S> extends React.PureComponent<QueryPreviewProps<S>> {
|
||||||
selectedTab={selectedTab}
|
selectedTab={selectedTab}
|
||||||
onTabChange={onTabChange}
|
onTabChange={onTabChange}
|
||||||
tabs={
|
tabs={
|
||||||
tabs as ReadonlyArray<TabOption<QueryPreviewTabs, unknown>>
|
tabs.filter((tab) =>
|
||||||
|
isTabVisible(tab, resInfo.type)
|
||||||
|
) as ReadonlyArray<
|
||||||
|
TabOption<
|
||||||
|
QueryPreviewTabs,
|
||||||
|
unknown,
|
||||||
|
RtkResourceInfo['type']
|
||||||
|
>
|
||||||
|
>
|
||||||
}
|
}
|
||||||
renderTabLabel={this.renderTabLabel}
|
renderTabLabel={this.renderTabLabel}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -3,11 +3,11 @@ import type { AnyAction, Dispatch, Action } from '@reduxjs/toolkit';
|
||||||
import type { LiftedAction, LiftedState } from '@redux-devtools/core';
|
import type { LiftedAction, LiftedState } from '@redux-devtools/core';
|
||||||
import {
|
import {
|
||||||
QueryFormValues,
|
QueryFormValues,
|
||||||
QueryInfo,
|
|
||||||
QueryPreviewTabs,
|
QueryPreviewTabs,
|
||||||
RtkQueryMonitorState,
|
RtkQueryMonitorState,
|
||||||
StyleUtils,
|
StyleUtils,
|
||||||
SelectorsSource,
|
SelectorsSource,
|
||||||
|
RtkResourceInfo,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { createInspectorSelectors, computeSelectorSource } from '../selectors';
|
import { createInspectorSelectors, computeSelectorSource } from '../selectors';
|
||||||
import {
|
import {
|
||||||
|
@ -101,7 +101,7 @@ class RtkQueryInspector<S, A extends Action<unknown>> extends PureComponent<
|
||||||
this.props.dispatch(changeQueryFormValues(values) as AnyAction);
|
this.props.dispatch(changeQueryFormValues(values) as AnyAction);
|
||||||
};
|
};
|
||||||
|
|
||||||
handleSelectQuery = (queryInfo: QueryInfo): void => {
|
handleSelectQuery = (queryInfo: RtkResourceInfo): void => {
|
||||||
this.props.dispatch(selectQueryKey(queryInfo) as AnyAction);
|
this.props.dispatch(selectQueryKey(queryInfo) as AnyAction);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -114,10 +114,10 @@ class RtkQueryInspector<S, A extends Action<unknown>> extends PureComponent<
|
||||||
const {
|
const {
|
||||||
styleUtils: { styling },
|
styleUtils: { styling },
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const allVisibleQueries =
|
const allVisibleRtkResourceInfos =
|
||||||
this.selectors.selectAllVisbileQueries(selectorsSource);
|
this.selectors.selectAllVisbileQueries(selectorsSource);
|
||||||
|
|
||||||
const currentQueryInfo =
|
const currentResInfo =
|
||||||
this.selectors.selectCurrentQueryInfo(selectorsSource);
|
this.selectors.selectCurrentQueryInfo(selectorsSource);
|
||||||
|
|
||||||
const apiStates = this.selectors.selectApiStates(selectorsSource);
|
const apiStates = this.selectors.selectApiStates(selectorsSource);
|
||||||
|
@ -144,14 +144,14 @@ class RtkQueryInspector<S, A extends Action<unknown>> extends PureComponent<
|
||||||
/>
|
/>
|
||||||
<QueryList
|
<QueryList
|
||||||
onSelectQuery={this.handleSelectQuery}
|
onSelectQuery={this.handleSelectQuery}
|
||||||
queryInfos={allVisibleQueries}
|
resInfos={allVisibleRtkResourceInfos}
|
||||||
selectedQueryKey={selectorsSource.monitorState.selectedQueryKey}
|
selectedQueryKey={selectorsSource.monitorState.selectedQueryKey}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<QueryPreview<S>
|
<QueryPreview<S>
|
||||||
selectorsSource={this.state.selectorsSource}
|
selectorsSource={this.state.selectorsSource}
|
||||||
selectors={this.selectors}
|
selectors={this.selectors}
|
||||||
queryInfo={currentQueryInfo}
|
resInfo={currentResInfo}
|
||||||
selectedTab={selectorsSource.monitorState.selectedPreviewTab}
|
selectedTab={selectorsSource.monitorState.selectedPreviewTab}
|
||||||
onTabChange={this.handleTabChange}
|
onTabChange={this.handleTabChange}
|
||||||
styling={styling}
|
styling={styling}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
SelectorsSource,
|
SelectorsSource,
|
||||||
RtkQueryProvided,
|
RtkQueryProvided,
|
||||||
QueryPreviewTabs,
|
QueryPreviewTabs,
|
||||||
|
RtkResourceInfo,
|
||||||
} from './types';
|
} from './types';
|
||||||
import { Comparator, queryComparators } from './utils/comparators';
|
import { Comparator, queryComparators } from './utils/comparators';
|
||||||
import { FilterList, queryListFilters } from './utils/filters';
|
import { FilterList, queryListFilters } from './utils/filters';
|
||||||
|
@ -20,6 +21,7 @@ import {
|
||||||
getQueryTagsOf,
|
getQueryTagsOf,
|
||||||
generateApiStatsOfCurrentQuery,
|
generateApiStatsOfCurrentQuery,
|
||||||
getActionsOfCurrentQuery,
|
getActionsOfCurrentQuery,
|
||||||
|
extractAllApiMutations,
|
||||||
} from './utils/rtk-query';
|
} from './utils/rtk-query';
|
||||||
|
|
||||||
type InspectorSelector<S, Output> = Selector<SelectorsSource<S>, Output>;
|
type InspectorSelector<S, Output> = Selector<SelectorsSource<S>, Output>;
|
||||||
|
@ -60,8 +62,8 @@ export interface InspectorSelectors<S> {
|
||||||
S,
|
S,
|
||||||
ReturnType<typeof extractAllApiQueries>
|
ReturnType<typeof extractAllApiQueries>
|
||||||
>;
|
>;
|
||||||
readonly selectAllVisbileQueries: InspectorSelector<S, QueryInfo[]>;
|
readonly selectAllVisbileQueries: InspectorSelector<S, RtkResourceInfo[]>;
|
||||||
readonly selectCurrentQueryInfo: InspectorSelector<S, QueryInfo | null>;
|
readonly selectCurrentQueryInfo: InspectorSelector<S, RtkResourceInfo | null>;
|
||||||
readonly selectSearchQueryRegex: InspectorSelector<S, RegExp | null>;
|
readonly selectSearchQueryRegex: InspectorSelector<S, RegExp | null>;
|
||||||
readonly selectCurrentQueryTags: InspectorSelector<S, RtkQueryTag[]>;
|
readonly selectCurrentQueryTags: InspectorSelector<S, RtkQueryTag[]>;
|
||||||
readonly selectApiStatsOfCurrentQuery: InspectorSelector<S, ApiStats | null>;
|
readonly selectApiStatsOfCurrentQuery: InspectorSelector<S, ApiStats | null>;
|
||||||
|
@ -86,13 +88,13 @@ export interface InspectorSelectors<S> {
|
||||||
export function createInspectorSelectors<S>(): InspectorSelectors<S> {
|
export function createInspectorSelectors<S>(): InspectorSelectors<S> {
|
||||||
const selectQueryComparator = ({
|
const selectQueryComparator = ({
|
||||||
monitorState,
|
monitorState,
|
||||||
}: SelectorsSource<S>): Comparator<QueryInfo> => {
|
}: SelectorsSource<S>): Comparator<RtkResourceInfo> => {
|
||||||
return queryComparators[monitorState.queryForm.values.queryComparator];
|
return queryComparators[monitorState.queryForm.values.queryComparator];
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectQueryListFilter = ({
|
const selectQueryListFilter = ({
|
||||||
monitorState,
|
monitorState,
|
||||||
}: SelectorsSource<S>): FilterList<QueryInfo> => {
|
}: SelectorsSource<S>): FilterList<RtkResourceInfo> => {
|
||||||
return queryListFilters[monitorState.queryForm.values.queryFilter];
|
return queryListFilters[monitorState.queryForm.values.queryFilter];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -108,6 +110,11 @@ export function createInspectorSelectors<S>(): InspectorSelectors<S> {
|
||||||
extractAllApiQueries
|
extractAllApiQueries
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const selectAllMutations = createSelector(
|
||||||
|
selectApiStates,
|
||||||
|
extractAllApiMutations
|
||||||
|
);
|
||||||
|
|
||||||
const selectSearchQueryRegex = createSelector(
|
const selectSearchQueryRegex = createSelector(
|
||||||
({ monitorState }: SelectorsSource<S>) =>
|
({ monitorState }: SelectorsSource<S>) =>
|
||||||
monitorState.queryForm.values.searchValue,
|
monitorState.queryForm.values.searchValue,
|
||||||
|
@ -138,13 +145,21 @@ export function createInspectorSelectors<S>(): InspectorSelectors<S> {
|
||||||
selectQueryComparator,
|
selectQueryComparator,
|
||||||
selectQueryListFilter,
|
selectQueryListFilter,
|
||||||
selectAllQueries,
|
selectAllQueries,
|
||||||
|
selectAllMutations,
|
||||||
selectComparatorOrder,
|
selectComparatorOrder,
|
||||||
selectSearchQueryRegex,
|
selectSearchQueryRegex,
|
||||||
],
|
],
|
||||||
(comparator, queryListFilter, queryList, isAscending, searchRegex) => {
|
(
|
||||||
|
comparator,
|
||||||
|
queryListFilter,
|
||||||
|
queryList,
|
||||||
|
mutationsList,
|
||||||
|
isAscending,
|
||||||
|
searchRegex
|
||||||
|
) => {
|
||||||
const filteredList = queryListFilter(
|
const filteredList = queryListFilter(
|
||||||
searchRegex,
|
searchRegex,
|
||||||
queryList as QueryInfo[]
|
(queryList as RtkResourceInfo[]).concat(mutationsList)
|
||||||
);
|
);
|
||||||
|
|
||||||
const computedComparator = isAscending
|
const computedComparator = isAscending
|
||||||
|
@ -157,19 +172,29 @@ export function createInspectorSelectors<S>(): InspectorSelectors<S> {
|
||||||
|
|
||||||
const selectCurrentQueryInfo = createSelector(
|
const selectCurrentQueryInfo = createSelector(
|
||||||
selectAllQueries,
|
selectAllQueries,
|
||||||
|
selectAllMutations,
|
||||||
({ monitorState }: SelectorsSource<S>) => monitorState.selectedQueryKey,
|
({ monitorState }: SelectorsSource<S>) => monitorState.selectedQueryKey,
|
||||||
(allQueries, selectedQueryKey) => {
|
(allQueries, allMutations, selectedQueryKey) => {
|
||||||
if (!selectedQueryKey) {
|
if (!selectedQueryKey) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentQueryInfo =
|
let currentQueryInfo: null | RtkResourceInfo =
|
||||||
allQueries.find(
|
allQueries.find(
|
||||||
(query) =>
|
(query) =>
|
||||||
query.queryKey === selectedQueryKey.queryKey &&
|
query.queryKey === selectedQueryKey.queryKey &&
|
||||||
selectedQueryKey.reducerPath === query.reducerPath
|
selectedQueryKey.reducerPath === query.reducerPath
|
||||||
) || null;
|
) || null;
|
||||||
|
|
||||||
|
if (!currentQueryInfo) {
|
||||||
|
currentQueryInfo =
|
||||||
|
allMutations.find(
|
||||||
|
(mutation) =>
|
||||||
|
mutation.queryKey === selectedQueryKey.queryKey &&
|
||||||
|
selectedQueryKey.reducerPath === mutation.reducerPath
|
||||||
|
) || null;
|
||||||
|
}
|
||||||
|
|
||||||
return currentQueryInfo;
|
return currentQueryInfo;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -139,8 +139,10 @@ const getSheetFromColorMap = (map: ColorMap) => {
|
||||||
'-webkit-line-clamp': 2,
|
'-webkit-line-clamp': 2,
|
||||||
whiteSpace: 'normal',
|
whiteSpace: 'normal',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
|
width: '100%',
|
||||||
maxWidth: 'calc(100% - 70px)',
|
maxWidth: 'calc(100% - 70px)',
|
||||||
wordBreak: 'break-all',
|
wordBreak: 'break-all',
|
||||||
|
margin: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
queryListHeader: {
|
queryListHeader: {
|
||||||
|
@ -154,6 +156,20 @@ const getSheetFromColorMap = (map: ColorMap) => {
|
||||||
'border-color': map.LIST_BORDER_COLOR,
|
'border-color': map.LIST_BORDER_COLOR,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
queryStatusWrapper: {
|
||||||
|
display: 'flex',
|
||||||
|
width: 'auto',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
margin: 0,
|
||||||
|
flex: '0 0 auto',
|
||||||
|
overflow: 'hidden',
|
||||||
|
},
|
||||||
|
|
||||||
|
queryType: {
|
||||||
|
marginRight: 4,
|
||||||
|
},
|
||||||
|
|
||||||
queryStatus: {
|
queryStatus: {
|
||||||
display: 'inline-flex',
|
display: 'inline-flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
@ -164,6 +180,7 @@ const getSheetFromColorMap = (map: ColorMap) => {
|
||||||
'font-size': '0.7em',
|
'font-size': '0.7em',
|
||||||
'line-height': '1em',
|
'line-height': '1em',
|
||||||
'flex-shrink': 0,
|
'flex-shrink': 0,
|
||||||
|
fontWeight: 700,
|
||||||
'background-color': map.ACTION_TIME_BACK_COLOR,
|
'background-color': map.ACTION_TIME_BACK_COLOR,
|
||||||
color: map.ACTION_TIME_COLOR,
|
color: map.ACTION_TIME_COLOR,
|
||||||
},
|
},
|
||||||
|
|
|
@ -61,25 +61,33 @@ export interface ExternalProps<S, A extends Action<unknown>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface QueryInfo {
|
export interface QueryInfo {
|
||||||
query: RtkQueryState;
|
type: 'query';
|
||||||
|
state: RtkQueryState;
|
||||||
queryKey: string;
|
queryKey: string;
|
||||||
reducerPath: string;
|
reducerPath: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MutationInfo {
|
export interface MutationInfo {
|
||||||
mutation: RtkMutationState;
|
type: 'mutation';
|
||||||
|
state: RtkMutationState;
|
||||||
queryKey: string;
|
queryKey: string;
|
||||||
reducerPath: string;
|
reducerPath: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type RtkResourceInfo = QueryInfo | MutationInfo;
|
||||||
|
|
||||||
export interface ApiInfo {
|
export interface ApiInfo {
|
||||||
reducerPath: string;
|
reducerPath: string;
|
||||||
apiState: RtkQueryApiState;
|
apiState: RtkQueryApiState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelectOption<T = string> {
|
export interface SelectOption<
|
||||||
|
T = string,
|
||||||
|
VisConfig extends string = 'default'
|
||||||
|
> {
|
||||||
label: string;
|
label: string;
|
||||||
value: T;
|
value: T;
|
||||||
|
visible?: Record<VisConfig | 'default', boolean> | boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelectorsSource<S> {
|
export interface SelectorsSource<S> {
|
||||||
|
@ -136,7 +144,8 @@ export interface ApiStats {
|
||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TabOption<S, P> extends SelectOption<S> {
|
export interface TabOption<S, P, V extends string = 'default'>
|
||||||
|
extends SelectOption<S, V> {
|
||||||
component: ComponentType<P>;
|
component: ComponentType<P>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { QueryStatus } from '@reduxjs/toolkit/query';
|
import { QueryStatus } from '@reduxjs/toolkit/query';
|
||||||
import { QueryInfo, SelectOption } from '../types';
|
import { RtkResourceInfo, SelectOption } from '../types';
|
||||||
|
|
||||||
export interface Comparator<T> {
|
export interface Comparator<T> {
|
||||||
(a: T, b: T): number;
|
(a: T, b: T): number;
|
||||||
|
@ -22,11 +22,11 @@ export const sortQueryOptions: SelectOption<QueryComparators>[] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
function sortQueryByFulfilled(
|
function sortQueryByFulfilled(
|
||||||
thisQueryInfo: QueryInfo,
|
thisQueryInfo: RtkResourceInfo,
|
||||||
thatQueryInfo: QueryInfo
|
thatQueryInfo: RtkResourceInfo
|
||||||
): number {
|
): number {
|
||||||
const thisFulfilled = thisQueryInfo.query.fulfilledTimeStamp ?? -1;
|
const thisFulfilled = thisQueryInfo.state.fulfilledTimeStamp ?? -1;
|
||||||
const thatFulfilled = thatQueryInfo.query.fulfilledTimeStamp ?? -1;
|
const thatFulfilled = thatQueryInfo.state.fulfilledTimeStamp ?? -1;
|
||||||
|
|
||||||
return thisFulfilled - thatFulfilled;
|
return thisFulfilled - thatFulfilled;
|
||||||
}
|
}
|
||||||
|
@ -39,11 +39,11 @@ const mapStatusToFactor = {
|
||||||
};
|
};
|
||||||
|
|
||||||
function sortQueryByStatus(
|
function sortQueryByStatus(
|
||||||
thisQueryInfo: QueryInfo,
|
thisQueryInfo: RtkResourceInfo,
|
||||||
thatQueryInfo: QueryInfo
|
thatQueryInfo: RtkResourceInfo
|
||||||
): number {
|
): number {
|
||||||
const thisTerm = mapStatusToFactor[thisQueryInfo.query.status] || -1;
|
const thisTerm = mapStatusToFactor[thisQueryInfo.state.status] || -1;
|
||||||
const thatTerm = mapStatusToFactor[thatQueryInfo.query.status] || -1;
|
const thatTerm = mapStatusToFactor[thatQueryInfo.state.status] || -1;
|
||||||
|
|
||||||
return thisTerm - thatTerm;
|
return thisTerm - thatTerm;
|
||||||
}
|
}
|
||||||
|
@ -60,25 +60,25 @@ function compareJSONPrimitive<T extends string | number | boolean | null>(
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortByQueryKey(
|
function sortByQueryKey(
|
||||||
thisQueryInfo: QueryInfo,
|
thisQueryInfo: RtkResourceInfo,
|
||||||
thatQueryInfo: QueryInfo
|
thatQueryInfo: RtkResourceInfo
|
||||||
): number {
|
): number {
|
||||||
return compareJSONPrimitive(thisQueryInfo.queryKey, thatQueryInfo.queryKey);
|
return compareJSONPrimitive(thisQueryInfo.queryKey, thatQueryInfo.queryKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortQueryByEndpointName(
|
function sortQueryByEndpointName(
|
||||||
thisQueryInfo: QueryInfo,
|
thisQueryInfo: RtkResourceInfo,
|
||||||
thatQueryInfo: QueryInfo
|
thatQueryInfo: RtkResourceInfo
|
||||||
): number {
|
): number {
|
||||||
const thisEndpointName = thisQueryInfo.query.endpointName ?? '';
|
const thisEndpointName = thisQueryInfo.state.endpointName ?? '';
|
||||||
const thatEndpointName = thatQueryInfo.query.endpointName ?? '';
|
const thatEndpointName = thatQueryInfo.state.endpointName ?? '';
|
||||||
|
|
||||||
return compareJSONPrimitive(thisEndpointName, thatEndpointName);
|
return compareJSONPrimitive(thisEndpointName, thatEndpointName);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortByApiReducerPath(
|
function sortByApiReducerPath(
|
||||||
thisQueryInfo: QueryInfo,
|
thisQueryInfo: RtkResourceInfo,
|
||||||
thatQueryInfo: QueryInfo
|
thatQueryInfo: RtkResourceInfo
|
||||||
): number {
|
): number {
|
||||||
return compareJSONPrimitive(
|
return compareJSONPrimitive(
|
||||||
thisQueryInfo.reducerPath,
|
thisQueryInfo.reducerPath,
|
||||||
|
@ -87,7 +87,7 @@ function sortByApiReducerPath(
|
||||||
}
|
}
|
||||||
|
|
||||||
export const queryComparators: Readonly<
|
export const queryComparators: Readonly<
|
||||||
Record<QueryComparators, Comparator<QueryInfo>>
|
Record<QueryComparators, Comparator<RtkResourceInfo>>
|
||||||
> = {
|
> = {
|
||||||
[QueryComparators.fulfilledTimeStamp]: sortQueryByFulfilled,
|
[QueryComparators.fulfilledTimeStamp]: sortQueryByFulfilled,
|
||||||
[QueryComparators.status]: sortQueryByStatus,
|
[QueryComparators.status]: sortQueryByStatus,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { QueryInfo, SelectOption } from '../types';
|
import { RtkResourceInfo, SelectOption } from '../types';
|
||||||
|
|
||||||
export interface FilterList<T> {
|
export interface FilterList<T> {
|
||||||
(regex: RegExp | null, list: T[]): T[];
|
(regex: RegExp | null, list: T[]): T[];
|
||||||
|
@ -13,45 +13,52 @@ export enum QueryFilters {
|
||||||
|
|
||||||
function filterByQueryKey(
|
function filterByQueryKey(
|
||||||
regex: RegExp | null,
|
regex: RegExp | null,
|
||||||
list: QueryInfo[]
|
list: RtkResourceInfo[]
|
||||||
): QueryInfo[] {
|
): RtkResourceInfo[] {
|
||||||
if (!regex) {
|
if (!regex) {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
return list.filter((queryInfo) => regex.test(queryInfo.queryKey));
|
return list.filter((RtkResourceInfo) => regex.test(RtkResourceInfo.queryKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterByReducerPath(
|
function filterByReducerPath(
|
||||||
regex: RegExp | null,
|
regex: RegExp | null,
|
||||||
list: QueryInfo[]
|
list: RtkResourceInfo[]
|
||||||
): QueryInfo[] {
|
): RtkResourceInfo[] {
|
||||||
if (!regex) {
|
if (!regex) {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
return list.filter((queryInfo) => regex.test(queryInfo.reducerPath));
|
return list.filter((RtkResourceInfo) =>
|
||||||
|
regex.test(RtkResourceInfo.reducerPath)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterByEndpointName(
|
function filterByEndpointName(
|
||||||
regex: RegExp | null,
|
regex: RegExp | null,
|
||||||
list: QueryInfo[]
|
list: RtkResourceInfo[]
|
||||||
): QueryInfo[] {
|
): RtkResourceInfo[] {
|
||||||
if (!regex) {
|
if (!regex) {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
return list.filter((queryInfo) =>
|
return list.filter((RtkResourceInfo) =>
|
||||||
regex.test(queryInfo.query.endpointName ?? 'undefined')
|
regex.test(RtkResourceInfo.state.endpointName ?? 'undefined')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterByStatus(regex: RegExp | null, list: QueryInfo[]): QueryInfo[] {
|
function filterByStatus(
|
||||||
|
regex: RegExp | null,
|
||||||
|
list: RtkResourceInfo[]
|
||||||
|
): RtkResourceInfo[] {
|
||||||
if (!regex) {
|
if (!regex) {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
return list.filter((queryInfo) => regex.test(queryInfo.query.status));
|
return list.filter((RtkResourceInfo) =>
|
||||||
|
regex.test(RtkResourceInfo.state.status)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const filterQueryOptions: SelectOption<QueryFilters>[] = [
|
export const filterQueryOptions: SelectOption<QueryFilters>[] = [
|
||||||
|
@ -62,7 +69,7 @@ export const filterQueryOptions: SelectOption<QueryFilters>[] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
export const queryListFilters: Readonly<
|
export const queryListFilters: Readonly<
|
||||||
Record<QueryFilters, FilterList<QueryInfo>>
|
Record<QueryFilters, FilterList<RtkResourceInfo>>
|
||||||
> = {
|
> = {
|
||||||
[QueryFilters.queryKey]: filterByQueryKey,
|
[QueryFilters.queryKey]: filterByQueryKey,
|
||||||
[QueryFilters.endpointName]: filterByEndpointName,
|
[QueryFilters.endpointName]: filterByEndpointName,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { AnyAction, isAnyOf, isPlainObject } from '@reduxjs/toolkit';
|
import { AnyAction, isAllOf, isAnyOf, isPlainObject } from '@reduxjs/toolkit';
|
||||||
import { QueryStatus } from '@reduxjs/toolkit/query';
|
import { QueryStatus } from '@reduxjs/toolkit/query';
|
||||||
import {
|
import {
|
||||||
QueryInfo,
|
QueryInfo,
|
||||||
|
@ -15,6 +15,8 @@ import {
|
||||||
ApiTimings,
|
ApiTimings,
|
||||||
QueryTimings,
|
QueryTimings,
|
||||||
SelectorsSource,
|
SelectorsSource,
|
||||||
|
RtkMutationState,
|
||||||
|
RtkResourceInfo,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { missingTagId } from '../monitor-config';
|
import { missingTagId } from '../monitor-config';
|
||||||
import { Comparator } from './comparators';
|
import { Comparator } from './comparators';
|
||||||
|
@ -104,13 +106,14 @@ export function extractAllApiQueries(
|
||||||
|
|
||||||
for (let j = 0, qKeysLen = queryKeys.length; j < qKeysLen; j++) {
|
for (let j = 0, qKeysLen = queryKeys.length; j < qKeysLen; j++) {
|
||||||
const queryKey = queryKeys[j];
|
const queryKey = queryKeys[j];
|
||||||
const query = api.queries[queryKey];
|
const state = api.queries[queryKey];
|
||||||
|
|
||||||
if (query) {
|
if (state) {
|
||||||
output.push({
|
output.push({
|
||||||
|
type: 'query',
|
||||||
reducerPath,
|
reducerPath,
|
||||||
queryKey,
|
queryKey,
|
||||||
query,
|
state,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,13 +139,14 @@ export function extractAllApiMutations(
|
||||||
|
|
||||||
for (let j = 0, mKeysLen = mutationKeys.length; j < mKeysLen; j++) {
|
for (let j = 0, mKeysLen = mutationKeys.length; j < mKeysLen; j++) {
|
||||||
const queryKey = mutationKeys[j];
|
const queryKey = mutationKeys[j];
|
||||||
const mutation = api.queries[queryKey];
|
const state = api.mutations[queryKey];
|
||||||
|
|
||||||
if (mutation) {
|
if (state) {
|
||||||
output.push({
|
output.push({
|
||||||
|
type: 'mutation',
|
||||||
reducerPath,
|
reducerPath,
|
||||||
queryKey,
|
queryKey,
|
||||||
mutation,
|
state,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -333,7 +337,7 @@ export function flipComparator<T>(comparator: Comparator<T>): Comparator<T> {
|
||||||
|
|
||||||
export function isQuerySelected(
|
export function isQuerySelected(
|
||||||
selectedQueryKey: RtkQueryMonitorState['selectedQueryKey'],
|
selectedQueryKey: RtkQueryMonitorState['selectedQueryKey'],
|
||||||
queryInfo: QueryInfo
|
queryInfo: RtkResourceInfo
|
||||||
): boolean {
|
): boolean {
|
||||||
return (
|
return (
|
||||||
!!selectedQueryKey &&
|
!!selectedQueryKey &&
|
||||||
|
@ -343,7 +347,7 @@ export function isQuerySelected(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getApiStateOf(
|
export function getApiStateOf(
|
||||||
queryInfo: QueryInfo | null,
|
queryInfo: RtkResourceInfo | null,
|
||||||
apiStates: ReturnType<typeof getApiStatesOf>
|
apiStates: ReturnType<typeof getApiStatesOf>
|
||||||
): RtkQueryApiState | null {
|
): RtkQueryApiState | null {
|
||||||
if (!apiStates || !queryInfo) {
|
if (!apiStates || !queryInfo) {
|
||||||
|
@ -379,10 +383,10 @@ export function getProvidedOf(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getQueryTagsOf(
|
export function getQueryTagsOf(
|
||||||
queryInfo: QueryInfo | null,
|
resInfo: RtkResourceInfo | null,
|
||||||
provided: RtkQueryProvided | null
|
provided: RtkQueryProvided | null
|
||||||
): RtkQueryTag[] {
|
): RtkQueryTag[] {
|
||||||
if (!queryInfo || !provided) {
|
if (!resInfo || resInfo.type === 'mutation' || !provided) {
|
||||||
return emptyArray;
|
return emptyArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,7 +401,7 @@ export function getQueryTagsOf(
|
||||||
for (const [type, tagIds] of Object.entries(provided)) {
|
for (const [type, tagIds] of Object.entries(provided)) {
|
||||||
if (tagIds) {
|
if (tagIds) {
|
||||||
for (const [id, queryKeys] of Object.entries(tagIds)) {
|
for (const [id, queryKeys] of Object.entries(tagIds)) {
|
||||||
if ((queryKeys as unknown[]).includes(queryInfo.queryKey)) {
|
if ((queryKeys as unknown[]).includes(resInfo.queryKey)) {
|
||||||
const tag: RtkQueryTag = { type };
|
const tag: RtkQueryTag = { type };
|
||||||
|
|
||||||
if (id !== missingTagId) {
|
if (id !== missingTagId) {
|
||||||
|
@ -422,7 +426,7 @@ export function getQueryTagsOf(
|
||||||
export function getQueryStatusFlags({
|
export function getQueryStatusFlags({
|
||||||
status,
|
status,
|
||||||
data,
|
data,
|
||||||
}: RtkQueryState): RTKStatusFlags {
|
}: RtkQueryState | RtkMutationState): RTKStatusFlags {
|
||||||
return {
|
return {
|
||||||
isUninitialized: status === QueryStatus.uninitialized,
|
isUninitialized: status === QueryStatus.uninitialized,
|
||||||
isFetching: status === QueryStatus.pending,
|
isFetching: status === QueryStatus.pending,
|
||||||
|
@ -446,15 +450,37 @@ function matchesQueryKey(queryKey: string) {
|
||||||
action?.meta?.arg?.queryCacheKey === queryKey;
|
action?.meta?.arg?.queryCacheKey === queryKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function macthesRequestId(requestId: string) {
|
||||||
|
return (action: any): action is AnyAction =>
|
||||||
|
action?.meta?.requestId === requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchesReducerPath(reducerPath: string) {
|
||||||
|
return (action: any): action is AnyAction =>
|
||||||
|
typeof action?.type === 'string' && action.type.startsWith(reducerPath);
|
||||||
|
}
|
||||||
|
|
||||||
export function getActionsOfCurrentQuery(
|
export function getActionsOfCurrentQuery(
|
||||||
currentQuery: QueryInfo | null,
|
currentQuery: RtkResourceInfo | null,
|
||||||
actionById: SelectorsSource<unknown>['actionsById']
|
actionById: SelectorsSource<unknown>['actionsById']
|
||||||
): AnyAction[] {
|
): AnyAction[] {
|
||||||
if (!currentQuery) {
|
if (!currentQuery) {
|
||||||
return emptyArray;
|
return emptyArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
const matcher = isAnyOf(matchesQueryKey(currentQuery.queryKey));
|
let matcher: ReturnType<typeof macthesRequestId>;
|
||||||
|
|
||||||
|
if (currentQuery.type === 'mutation') {
|
||||||
|
matcher = isAllOf(
|
||||||
|
matchesReducerPath(currentQuery.reducerPath),
|
||||||
|
macthesRequestId(currentQuery.queryKey)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
matcher = isAllOf(
|
||||||
|
matchesReducerPath(currentQuery.reducerPath),
|
||||||
|
matchesQueryKey(currentQuery.queryKey)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const output: AnyAction[] = [];
|
const output: AnyAction[] = [];
|
||||||
|
|
||||||
|
|
16
packages/redux-devtools-rtk-query-monitor/src/utils/tabs.ts
Normal file
16
packages/redux-devtools-rtk-query-monitor/src/utils/tabs.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { TabOption } from '../types';
|
||||||
|
|
||||||
|
export function isTabVisible<St, Props, Vis extends string>(
|
||||||
|
tab: TabOption<St, Props, Vis>,
|
||||||
|
visKey: Vis | 'default'
|
||||||
|
): boolean {
|
||||||
|
if (typeof tab.visible === 'boolean') {
|
||||||
|
return tab.visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof tab.visible === 'object' && tab.visible) {
|
||||||
|
return !!tab.visible[visKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user