mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2025-12-10 11:44:32 +03:00
260 lines
6.9 KiB
TypeScript
260 lines
6.9 KiB
TypeScript
import React, { ReactNode } from 'react';
|
|
import type { Interpolation, Theme } from '@emotion/react';
|
|
import { Dispatch, AnyAction } from 'redux';
|
|
import {
|
|
QueryPreviewTabs,
|
|
RtkResourceInfo,
|
|
SelectorsSource,
|
|
TabOption,
|
|
} from '../types';
|
|
import { QueryPreviewHeader } from '../components/QueryPreviewHeader';
|
|
import {
|
|
QueryPreviewInfo,
|
|
QueryPreviewInfoProps,
|
|
} from '../components/QueryPreviewInfo';
|
|
import {
|
|
QueryPreviewApi,
|
|
QueryPreviewApiProps,
|
|
} from '../components/QueryPreviewApi';
|
|
import {
|
|
QueryPreviewSubscriptions,
|
|
QueryPreviewSubscriptionsProps,
|
|
} from '../components/QueryPreviewSubscriptions';
|
|
import {
|
|
QueryPreviewTags,
|
|
QueryPreviewTagsProps,
|
|
} from '../components/QueryPreviewTags';
|
|
import { NoRtkQueryApi } from '../components/NoRtkQueryApi';
|
|
import { InspectorSelectors } from '../selectors';
|
|
import { mapProps } from './mapProps';
|
|
import {
|
|
QueryPreviewActions,
|
|
QueryPreviewActionsProps,
|
|
} from '../components/QueryPreviewActions';
|
|
import { isTabVisible } from '../utils/tabs';
|
|
import {
|
|
QueryPreviewData,
|
|
QueryPreviewDataProps,
|
|
} from '../components/QueryPreviewData';
|
|
|
|
const queryPreviewCss: Interpolation<Theme> = (theme) => ({
|
|
flex: '1 1 50%',
|
|
overflowX: 'hidden',
|
|
oveflowY: 'auto',
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
overflowY: 'hidden',
|
|
'& pre': {
|
|
border: 'inherit',
|
|
borderRadius: '3px',
|
|
lineHeight: 'inherit',
|
|
color: 'inherit',
|
|
},
|
|
|
|
backgroundColor: theme.BACKGROUND_COLOR,
|
|
});
|
|
|
|
export interface QueryPreviewProps<S = unknown> {
|
|
readonly selectedTab: QueryPreviewTabs;
|
|
readonly hasNoApis: boolean;
|
|
readonly onTabChange: (tab: QueryPreviewTabs) => void;
|
|
readonly resInfo: RtkResourceInfo | null;
|
|
readonly isWideLayout: boolean;
|
|
readonly selectorsSource: SelectorsSource<S>;
|
|
readonly selectors: InspectorSelectors<S>;
|
|
readonly dispatch?: Dispatch<AnyAction>;
|
|
readonly liftedDispatch?: Dispatch<AnyAction>;
|
|
}
|
|
|
|
/**
|
|
* Tab content is not rendered if there's no selected query.
|
|
*/
|
|
type QueryPreviewTabProps = Omit<QueryPreviewProps<unknown>, 'resInfo'> & {
|
|
resInfo: RtkResourceInfo;
|
|
};
|
|
|
|
const MappedQueryPreviewTags = mapProps<
|
|
QueryPreviewTabProps,
|
|
QueryPreviewTagsProps
|
|
>(({ selectors, selectorsSource, isWideLayout, resInfo }) => ({
|
|
resInfo,
|
|
tags: selectors.selectCurrentQueryTags(selectorsSource),
|
|
isWideLayout,
|
|
}))(QueryPreviewTags);
|
|
|
|
const MappedQueryPreviewInfo = mapProps<
|
|
QueryPreviewTabProps,
|
|
QueryPreviewInfoProps
|
|
>(({ resInfo, isWideLayout }) => ({ resInfo, isWideLayout }))(QueryPreviewInfo);
|
|
|
|
const MappedQueryPreviewData = mapProps<
|
|
QueryPreviewTabProps,
|
|
QueryPreviewDataProps
|
|
>(({ resInfo, isWideLayout }) => ({
|
|
data: resInfo?.state?.data,
|
|
isWideLayout,
|
|
}))(QueryPreviewData);
|
|
|
|
const MappedQuerySubscriptipns = mapProps<
|
|
QueryPreviewTabProps,
|
|
QueryPreviewSubscriptionsProps
|
|
>(({ selectors, selectorsSource, isWideLayout }) => ({
|
|
isWideLayout,
|
|
subscriptions: selectors.selectSubscriptionsOfCurrentQuery(selectorsSource),
|
|
}))(QueryPreviewSubscriptions);
|
|
|
|
const MappedApiPreview = mapProps<QueryPreviewTabProps, QueryPreviewApiProps>(
|
|
({ isWideLayout, selectors, selectorsSource }) => ({
|
|
isWideLayout,
|
|
apiState: selectors.selectApiOfCurrentQuery(selectorsSource),
|
|
apiStats: selectors.selectApiStatsOfCurrentQuery(selectorsSource),
|
|
}),
|
|
)(QueryPreviewApi);
|
|
|
|
const MappedQueryPreviewActions = mapProps<
|
|
QueryPreviewTabProps,
|
|
QueryPreviewActionsProps
|
|
>(({ isWideLayout, selectorsSource, selectors, resInfo, ...props }) => ({
|
|
isWideLayout,
|
|
actionsOfQuery: selectors.selectActionsOfCurrentQuery(selectorsSource),
|
|
dispatch: (props as any).dispatch,
|
|
liftedDispatch: (props as any).liftedDispatch,
|
|
resInfo,
|
|
}))(QueryPreviewActions);
|
|
|
|
const tabs: ReadonlyArray<
|
|
TabOption<QueryPreviewTabs, QueryPreviewTabProps, RtkResourceInfo['type']>
|
|
> = [
|
|
{
|
|
label: 'Data',
|
|
value: QueryPreviewTabs.data,
|
|
component: MappedQueryPreviewData,
|
|
visible: {
|
|
query: true,
|
|
mutation: true,
|
|
default: true,
|
|
},
|
|
},
|
|
{
|
|
label: 'Query',
|
|
value: QueryPreviewTabs.queryinfo,
|
|
component: MappedQueryPreviewInfo,
|
|
visible: {
|
|
query: true,
|
|
mutation: true,
|
|
default: true,
|
|
},
|
|
},
|
|
{
|
|
label: 'Actions',
|
|
value: QueryPreviewTabs.actions,
|
|
component: MappedQueryPreviewActions,
|
|
visible: {
|
|
query: true,
|
|
mutation: true,
|
|
default: true,
|
|
},
|
|
},
|
|
{
|
|
label: 'Tags',
|
|
value: QueryPreviewTabs.queryTags,
|
|
component: MappedQueryPreviewTags,
|
|
visible: {
|
|
query: true,
|
|
mutation: false,
|
|
default: true,
|
|
},
|
|
},
|
|
{
|
|
label: 'Subs',
|
|
value: QueryPreviewTabs.querySubscriptions,
|
|
component: MappedQuerySubscriptipns,
|
|
visible: {
|
|
query: true,
|
|
mutation: false,
|
|
default: true,
|
|
},
|
|
},
|
|
{
|
|
label: 'Api',
|
|
value: QueryPreviewTabs.apiConfig,
|
|
component: MappedApiPreview,
|
|
},
|
|
];
|
|
|
|
export class QueryPreview<S> extends React.PureComponent<QueryPreviewProps<S>> {
|
|
renderLabelWithCounter = (label: string, counter: number): string => {
|
|
let counterAsString = counter.toFixed(0);
|
|
|
|
if (counterAsString.length > 3) {
|
|
counterAsString = counterAsString.slice(0, 2) + '...';
|
|
}
|
|
|
|
return `${label}(${counterAsString})`;
|
|
};
|
|
|
|
renderTabLabel = (
|
|
tab: TabOption<QueryPreviewTabs, unknown, 'query' | 'mutation'>,
|
|
): ReactNode => {
|
|
const { selectors, selectorsSource, resInfo } = this.props;
|
|
const tabCount = selectors.selectTabCounters(selectorsSource)[tab.value];
|
|
|
|
let tabLabel = tab.label;
|
|
|
|
if (tabLabel === 'query' && resInfo?.type === 'mutation') {
|
|
tabLabel = resInfo.type;
|
|
}
|
|
|
|
if (tabCount > 0) {
|
|
return this.renderLabelWithCounter(tabLabel, tabCount);
|
|
}
|
|
|
|
return tabLabel;
|
|
};
|
|
|
|
render(): ReactNode {
|
|
const { resInfo, selectedTab, onTabChange, hasNoApis } = this.props;
|
|
|
|
const { component: TabComponent } =
|
|
tabs.find((tab) => tab.value === selectedTab) || tabs[0];
|
|
|
|
if (!resInfo) {
|
|
return (
|
|
<div css={queryPreviewCss}>
|
|
<QueryPreviewHeader
|
|
selectedTab={selectedTab}
|
|
onTabChange={onTabChange}
|
|
tabs={
|
|
tabs.filter((tab) =>
|
|
isTabVisible(tab, 'default'),
|
|
) as ReadonlyArray<
|
|
TabOption<QueryPreviewTabs, unknown, RtkResourceInfo['type']>
|
|
>
|
|
}
|
|
renderTabLabel={this.renderTabLabel}
|
|
/>
|
|
{hasNoApis && <NoRtkQueryApi />}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div css={queryPreviewCss}>
|
|
<QueryPreviewHeader
|
|
selectedTab={selectedTab}
|
|
onTabChange={onTabChange}
|
|
tabs={
|
|
tabs.filter((tab) =>
|
|
isTabVisible(tab, resInfo.type),
|
|
) as ReadonlyArray<
|
|
TabOption<QueryPreviewTabs, unknown, RtkResourceInfo['type']>
|
|
>
|
|
}
|
|
renderTabLabel={this.renderTabLabel}
|
|
/>
|
|
<TabComponent {...(this.props as QueryPreviewTabProps)} />
|
|
</div>
|
|
);
|
|
}
|
|
}
|