mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2025-07-26 07:59:48 +03:00
refactor(rtk-query): improve UI of api tab
This commit is contained in:
parent
0ae7deb8d6
commit
6a87019cb7
|
@ -8,8 +8,8 @@ import { DevToolsSelector } from 'features/DevTools/DevToolsSelector';
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
return (
|
return (
|
||||||
<article>
|
<main className="rtk-query-demo-app">
|
||||||
<Heading as="h1" p="0">
|
<Heading as="h1" p="2">
|
||||||
RTK Query inspector monitor demo
|
RTK Query inspector monitor demo
|
||||||
</Heading>
|
</Heading>
|
||||||
<PokemonView />
|
<PokemonView />
|
||||||
|
@ -66,6 +66,6 @@ export function App() {
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</UnorderedList>
|
</UnorderedList>
|
||||||
</Flex>
|
</Flex>
|
||||||
</article>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,27 +12,6 @@ code {
|
||||||
monospace;
|
monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 1.4em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 1.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1,
|
|
||||||
h2,
|
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6 {
|
|
||||||
text-align: left;
|
|
||||||
font-family: inherit;
|
|
||||||
padding: 0.5em;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
section {
|
section {
|
||||||
display: block;
|
display: block;
|
||||||
max-width: 65%;
|
max-width: 65%;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import React, { ReactNode, PureComponent } from 'react';
|
import React, { ReactNode, PureComponent } from 'react';
|
||||||
import { ApiStats, RtkQueryApiState } from '../types';
|
import { ApiStats, RtkQueryApiState } from '../types';
|
||||||
|
import { StyleUtilsContext } from '../styles/createStylingFromTheme';
|
||||||
import { TreeView } from './TreeView';
|
import { TreeView } from './TreeView';
|
||||||
|
|
||||||
export interface QueryPreviewApiProps {
|
export interface QueryPreviewApiProps {
|
||||||
|
@ -10,24 +10,63 @@ export interface QueryPreviewApiProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class QueryPreviewApi extends PureComponent<QueryPreviewApiProps> {
|
export class QueryPreviewApi extends PureComponent<QueryPreviewApiProps> {
|
||||||
selectData = createSelector(
|
shouldExpandApiStateNode = (
|
||||||
[
|
keyPath: (string | number)[],
|
||||||
({ apiState }: QueryPreviewApiProps) => apiState,
|
value: unknown,
|
||||||
({ apiStats }: QueryPreviewApiProps) => apiStats,
|
layer: number
|
||||||
],
|
): boolean => {
|
||||||
(apiState, apiStats) => ({
|
const lastKey = keyPath[keyPath.length - 1];
|
||||||
reducerPath: apiState?.config?.reducerPath ?? null,
|
|
||||||
apiState: apiState,
|
return layer <= 1 && lastKey !== 'config';
|
||||||
stats: apiStats,
|
};
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
render(): ReactNode {
|
render(): ReactNode {
|
||||||
|
const { apiStats, isWideLayout, apiState } = this.props;
|
||||||
|
|
||||||
|
if (!apiState) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasMutations = Object.keys(apiState.mutations).length > 0;
|
||||||
|
const hasQueries = Object.keys(apiState.queries).length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TreeView
|
<StyleUtilsContext.Consumer>
|
||||||
data={this.selectData(this.props)}
|
{({ styling }) => (
|
||||||
isWideLayout={this.props.isWideLayout}
|
<article {...styling('tabContent')}>
|
||||||
/>
|
<h2>{apiState.config.reducerPath}</h2>
|
||||||
|
<TreeView
|
||||||
|
before={<h3>State</h3>}
|
||||||
|
data={apiState}
|
||||||
|
shouldExpandNode={this.shouldExpandApiStateNode}
|
||||||
|
isWideLayout={isWideLayout}
|
||||||
|
/>
|
||||||
|
{apiStats && (
|
||||||
|
<>
|
||||||
|
<TreeView
|
||||||
|
before={<h3>Tally</h3>}
|
||||||
|
data={apiStats.tally}
|
||||||
|
isWideLayout={isWideLayout}
|
||||||
|
/>
|
||||||
|
{hasQueries && (
|
||||||
|
<TreeView
|
||||||
|
before={<h3>Queries Timings</h3>}
|
||||||
|
data={apiStats.timings.queries}
|
||||||
|
isWideLayout={isWideLayout}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{hasMutations && (
|
||||||
|
<TreeView
|
||||||
|
before={<h3>Mutations Timings</h3>}
|
||||||
|
data={apiStats.timings.mutations}
|
||||||
|
isWideLayout={isWideLayout}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</article>
|
||||||
|
)}
|
||||||
|
</StyleUtilsContext.Consumer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import { StyleUtilsContext } from '../styles/createStylingFromTheme';
|
||||||
|
|
||||||
|
export type UListProps = React.HTMLAttributes<HTMLUListElement>;
|
||||||
|
|
||||||
|
export function UList(props: UListProps): JSX.Element {
|
||||||
|
return (
|
||||||
|
<StyleUtilsContext.Consumer>
|
||||||
|
{({ styling }) => <ul {...props} {...styling('uList')} />}
|
||||||
|
</StyleUtilsContext.Consumer>
|
||||||
|
);
|
||||||
|
}
|
|
@ -39,6 +39,10 @@ export const colorMap = (theme: reduxThemes.Base16Theme) =>
|
||||||
LINK_COLOR: rgba(theme.base0E, 90),
|
LINK_COLOR: rgba(theme.base0E, 90),
|
||||||
LINK_HOVER_COLOR: theme.base0E,
|
LINK_HOVER_COLOR: theme.base0E,
|
||||||
ERROR_COLOR: theme.base08,
|
ERROR_COLOR: theme.base08,
|
||||||
|
ULIST_DISC_COLOR: theme.base0D,
|
||||||
|
ULIST_COLOR: rgba(theme.base06, 60),
|
||||||
|
ULIST_STRONG_COLOR: theme.base0B,
|
||||||
|
TAB_CONTENT_COLOR: rgba(theme.base06, 60),
|
||||||
} as const);
|
} as const);
|
||||||
|
|
||||||
type Color = keyof ReturnType<typeof colorMap>;
|
type Color = keyof ReturnType<typeof colorMap>;
|
||||||
|
@ -400,7 +404,42 @@ const getSheetFromColorMap = (map: ColorMap) => {
|
||||||
treeWrapper: {
|
treeWrapper: {
|
||||||
overflowX: 'auto',
|
overflowX: 'auto',
|
||||||
overflowY: 'auto',
|
overflowY: 'auto',
|
||||||
padding: '1em',
|
padding: '0.5em 1em',
|
||||||
|
},
|
||||||
|
|
||||||
|
tabContent: {
|
||||||
|
display: 'block',
|
||||||
|
overflowY: 'auto',
|
||||||
|
padding: '0.5em 0',
|
||||||
|
color: map.TAB_CONTENT_COLOR,
|
||||||
|
'& h2': {
|
||||||
|
color: map.ULIST_STRONG_COLOR,
|
||||||
|
padding: '0.5em 1em',
|
||||||
|
fontWeight: 700,
|
||||||
|
},
|
||||||
|
'& h3': {
|
||||||
|
color: map.ULIST_STRONG_COLOR,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
uList: {
|
||||||
|
listStyle: 'none',
|
||||||
|
padding: '0 0 0 1em',
|
||||||
|
color: map.ULIST_COLOR,
|
||||||
|
'& > li': {
|
||||||
|
listStyle: 'none',
|
||||||
|
},
|
||||||
|
'& > li::before': {
|
||||||
|
content: '"\\2022"',
|
||||||
|
display: 'inline-block',
|
||||||
|
paddingRight: '0.5em',
|
||||||
|
color: map.ULIST_DISC_COLOR,
|
||||||
|
fontSize: '0.8em',
|
||||||
|
},
|
||||||
|
|
||||||
|
'& strong': {
|
||||||
|
color: map.ULIST_STRONG_COLOR,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -112,8 +112,8 @@ export type QueryTally = {
|
||||||
Tally;
|
Tally;
|
||||||
|
|
||||||
export interface QueryTimings {
|
export interface QueryTimings {
|
||||||
readonly oldestFetch: { key: string; at: string } | null;
|
readonly oldest: { key: string; at: string } | null;
|
||||||
readonly latestFetch: { key: string; at: string } | null;
|
readonly latest: { key: string; at: string } | null;
|
||||||
readonly slowest: { key: string; duration: string } | null;
|
readonly slowest: { key: string; duration: string } | null;
|
||||||
readonly fastest: { key: string; duration: string } | null;
|
readonly fastest: { key: string; duration: string } | null;
|
||||||
readonly average: string;
|
readonly average: string;
|
||||||
|
@ -128,9 +128,9 @@ export interface ApiTimings {
|
||||||
export interface ApiStats {
|
export interface ApiStats {
|
||||||
readonly timings: ApiTimings;
|
readonly timings: ApiTimings;
|
||||||
readonly tally: Readonly<{
|
readonly tally: Readonly<{
|
||||||
subscriptions: Tally;
|
subscriptions: number;
|
||||||
queries: QueryTally;
|
queries: QueryTally;
|
||||||
tagTypes: Tally;
|
tagTypes: number;
|
||||||
mutations: QueryTally;
|
mutations: QueryTally;
|
||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,18 +179,16 @@ function computeQueryTallyOf(
|
||||||
|
|
||||||
function tallySubscriptions(
|
function tallySubscriptions(
|
||||||
subsState: RtkQueryApiState['subscriptions']
|
subsState: RtkQueryApiState['subscriptions']
|
||||||
): ApiStats['tally']['subscriptions'] {
|
): number {
|
||||||
const subsOfQueries = Object.values(subsState);
|
const subsOfQueries = Object.values(subsState);
|
||||||
|
|
||||||
const output: ApiStats['tally']['subscriptions'] = {
|
let output = 0;
|
||||||
count: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (let i = 0, len = subsOfQueries.length; i < len; i++) {
|
for (let i = 0, len = subsOfQueries.length; i < len; i++) {
|
||||||
const subsOfQuery = subsOfQueries[i];
|
const subsOfQuery = subsOfQueries[i];
|
||||||
|
|
||||||
if (subsOfQuery) {
|
if (subsOfQuery) {
|
||||||
output.count += Object.keys(subsOfQuery).length;
|
output += Object.keys(subsOfQuery).length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,8 +202,8 @@ function computeQueryApiTimings(
|
||||||
): QueryTimings {
|
): QueryTimings {
|
||||||
type SpeedReport = { key: string | null; at: string | number };
|
type SpeedReport = { key: string | null; at: string | number };
|
||||||
type DurationReport = { key: string | null; duration: string | number };
|
type DurationReport = { key: string | null; duration: string | number };
|
||||||
let latestFetch: null | SpeedReport = { key: null, at: -1 };
|
let latest: null | SpeedReport = { key: null, at: -1 };
|
||||||
let oldestFetch: null | SpeedReport = {
|
let oldest: null | SpeedReport = {
|
||||||
key: null,
|
key: null,
|
||||||
at: Number.MAX_SAFE_INTEGER,
|
at: Number.MAX_SAFE_INTEGER,
|
||||||
};
|
};
|
||||||
|
@ -227,14 +225,14 @@ function computeQueryApiTimings(
|
||||||
const startedTimeStamp = query?.startedTimeStamp;
|
const startedTimeStamp = query?.startedTimeStamp;
|
||||||
|
|
||||||
if (typeof fulfilledTimeStamp === 'number') {
|
if (typeof fulfilledTimeStamp === 'number') {
|
||||||
if (fulfilledTimeStamp > latestFetch.at) {
|
if (fulfilledTimeStamp > latest.at) {
|
||||||
latestFetch.key = queryKey;
|
latest.key = queryKey;
|
||||||
latestFetch.at = fulfilledTimeStamp;
|
latest.at = fulfilledTimeStamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fulfilledTimeStamp < oldestFetch.at) {
|
if (fulfilledTimeStamp < oldest.at) {
|
||||||
oldestFetch.key = queryKey;
|
oldest.key = queryKey;
|
||||||
oldestFetch.at = fulfilledTimeStamp;
|
oldest.at = fulfilledTimeStamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -258,16 +256,16 @@ function computeQueryApiTimings(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (latestFetch.key !== null) {
|
if (latest.key !== null) {
|
||||||
latestFetch.at = new Date(latestFetch.at).toISOString();
|
latest.at = new Date(latest.at).toISOString();
|
||||||
} else {
|
} else {
|
||||||
latestFetch = null;
|
latest = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldestFetch.key !== null) {
|
if (oldest.key !== null) {
|
||||||
oldestFetch.at = new Date(oldestFetch.at).toISOString();
|
oldest.at = new Date(oldest.at).toISOString();
|
||||||
} else {
|
} else {
|
||||||
oldestFetch = null;
|
oldest = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slowest.key !== null) {
|
if (slowest.key !== null) {
|
||||||
|
@ -293,8 +291,8 @@ function computeQueryApiTimings(
|
||||||
: '-';
|
: '-';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
latestFetch,
|
latest,
|
||||||
oldestFetch,
|
oldest,
|
||||||
slowest,
|
slowest,
|
||||||
fastest,
|
fastest,
|
||||||
average,
|
average,
|
||||||
|
@ -319,10 +317,10 @@ export function generateApiStatsOfCurrentQuery(
|
||||||
return {
|
return {
|
||||||
timings: computeApiTimings(api),
|
timings: computeApiTimings(api),
|
||||||
tally: {
|
tally: {
|
||||||
subscriptions: tallySubscriptions(api.subscriptions),
|
|
||||||
queries: computeQueryTallyOf(api.queries),
|
queries: computeQueryTallyOf(api.queries),
|
||||||
tagTypes: { count: Object.keys(api.provided).length },
|
|
||||||
mutations: computeQueryTallyOf(api.mutations),
|
mutations: computeQueryTallyOf(api.mutations),
|
||||||
|
tagTypes: Object.keys(api.provided).length,
|
||||||
|
subscriptions: tallySubscriptions(api.subscriptions),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user