refactor(rtk-query): add custom logic for TreeView shouldExpandNode

Other changes:

* feat: added duration in QueryPreviewInfo tab

* refactor: TreeView component
This commit is contained in:
FaberVitale 2021-06-27 13:00:29 +02:00
parent 7a274d9025
commit dc5045f280
3 changed files with 143 additions and 23 deletions

View File

@ -1,5 +1,7 @@
import { createSelector } from '@reduxjs/toolkit';
import React, { ReactNode, PureComponent } from 'react';
import { AnyAction } from 'redux';
import { Action, AnyAction } from 'redux';
import { emptyRecord, identity } from '../utils/object';
import { TreeView } from './TreeView';
export interface QueryPreviewActionsProps {
@ -7,10 +9,59 @@ export interface QueryPreviewActionsProps {
actionsOfQuery: AnyAction[];
}
const keySep = ' - ';
export class QueryPreviewActions extends PureComponent<QueryPreviewActionsProps> {
selectFormattedActions = createSelector<
AnyAction[],
AnyAction[],
Record<string, AnyAction>
>(identity, (actions) => {
const output: Record<string, AnyAction> = {};
if (actions.length === 0) {
return emptyRecord;
}
for (let i = 0, len = actions.length; i < len; i++) {
const action = actions[i];
const key = `${i}${keySep}${(action as Action<string>)?.type ?? ''}`;
output[key] = action;
}
return output;
});
shouldExpandNode = (
keyPath: (string | number)[],
value: unknown,
layer: number
): boolean => {
if (layer === 1) {
const len = this.props.actionsOfQuery.length;
const lastKey = keyPath[keyPath.length - 1];
if (typeof lastKey === 'string') {
const index = Number(lastKey.split(keySep)[0]);
return len - index < 2;
}
return false;
}
return layer <= 1;
};
render(): ReactNode {
const { isWideLayout, actionsOfQuery } = this.props;
return <TreeView data={actionsOfQuery} isWideLayout={isWideLayout} />;
return (
<TreeView
data={this.selectFormattedActions(actionsOfQuery)}
isWideLayout={isWideLayout}
shouldExpandNode={this.shouldExpandNode}
/>
);
}
}

View File

@ -1,18 +1,22 @@
import { createSelector, Selector } from '@reduxjs/toolkit';
import { QueryStatus } from '@reduxjs/toolkit/dist/query';
import React, { ReactNode, PureComponent } from 'react';
import { QueryInfo, RtkQueryState, RTKStatusFlags } from '../types';
import { formatMs } from '../utils/formatters';
import { identity } from '../utils/object';
import { getQueryStatusFlags } from '../utils/rtk-query';
import { TreeView } from './TreeView';
type ComputedQueryInfo = {
type QueryTimings = {
startedAt: string;
latestFetchAt: string;
duration: string;
};
interface FormattedQuery extends ComputedQueryInfo {
interface FormattedQuery {
queryKey: string;
reducerPath: string;
timings: QueryTimings;
statusFlags: RTKStatusFlags;
query: RtkQueryState;
}
@ -22,6 +26,16 @@ export interface QueryPreviewInfoProps {
isWideLayout: boolean;
}
export class QueryPreviewInfo extends PureComponent<QueryPreviewInfoProps> {
shouldExpandNode = (
keyPath: (string | number)[],
value: unknown,
layer: number
): boolean => {
const lastKey = keyPath[keyPath.length - 1];
return layer <= 1 && lastKey !== 'query';
};
selectFormattedQuery: Selector<QueryInfo, FormattedQuery> = createSelector(
identity,
(queryInfo: QueryInfo): FormattedQuery => {
@ -37,13 +51,29 @@ export class QueryPreviewInfo extends PureComponent<QueryPreviewInfoProps> {
const statusFlags = getQueryStatusFlags(query);
const timings = {
startedAt,
latestFetchAt,
duration: '-',
};
if (
query.fulfilledTimeStamp &&
query.startedTimeStamp &&
query.status !== QueryStatus.pending &&
query.startedTimeStamp <= query.fulfilledTimeStamp
) {
timings.duration = formatMs(
query.fulfilledTimeStamp - query.startedTimeStamp
);
}
return {
queryKey,
reducerPath,
startedAt,
latestFetchAt,
statusFlags,
query: queryInfo.query,
statusFlags,
timings,
};
}
);
@ -52,6 +82,12 @@ export class QueryPreviewInfo extends PureComponent<QueryPreviewInfoProps> {
const { queryInfo, isWideLayout } = this.props;
const formattedQuery = this.selectFormattedQuery(queryInfo);
return <TreeView data={formattedQuery} isWideLayout={isWideLayout} />;
return (
<TreeView
data={formattedQuery}
isWideLayout={isWideLayout}
shouldExpandNode={this.shouldExpandNode}
/>
);
}
}

View File

@ -1,7 +1,7 @@
import { createSelector } from '@reduxjs/toolkit';
import React, { ComponentProps, ReactNode } from 'react';
import JSONTree from 'react-json-tree';
import { StylingFunction } from 'react-base16-styling';
import { Base16Theme, StylingFunction } from 'react-base16-styling';
import { DATA_TYPE_KEY } from '../monitor-config';
import {
getJsonTreeTheme,
@ -10,28 +10,68 @@ import {
import { createTreeItemLabelRenderer, getItemString } from '../styles/tree';
import { identity } from '../utils/object';
export interface TreeViewProps {
export interface TreeViewProps
extends Partial<
Pick<
ComponentProps<typeof JSONTree>,
'keyPath' | 'shouldExpandNode' | 'hideRoot'
>
> {
data: unknown;
isWideLayout: boolean;
before?: ReactNode;
after?: ReactNode;
children?: ReactNode;
keyPath?: ComponentProps<typeof JSONTree>['keyPath'];
}
export class TreeView extends React.PureComponent<TreeViewProps> {
static defaultProps = {
hideRoot: true,
shouldExpandNode: (
keyPath: (string | number)[],
value: unknown,
layer: number
): boolean => {
return layer < 2;
},
};
readonly selectLabelRenderer = createSelector<
StylingFunction,
StylingFunction,
ReturnType<typeof createTreeItemLabelRenderer>
>(identity, createTreeItemLabelRenderer);
readonly selectGetItemString = createSelector(
[
(styling: StylingFunction, _: boolean) => styling,
(_: StylingFunction, isWideLayout: boolean) => isWideLayout,
],
(styling, isWideLayout) => (type: string, data: any) =>
getItemString(styling, type, data, DATA_TYPE_KEY, isWideLayout)
);
readonly selectTheme = createSelector<
Base16Theme,
Base16Theme,
ReturnType<typeof getJsonTreeTheme>
>(identity, getJsonTreeTheme);
constructor(props: TreeViewProps) {
super(props);
}
render(): ReactNode {
const { isWideLayout, data, before, after, children, keyPath } = this.props;
const {
isWideLayout,
data,
before,
after,
children,
keyPath,
shouldExpandNode,
hideRoot,
} = this.props;
return (
<StyleUtilsContext.Consumer>
@ -41,20 +81,13 @@ export class TreeView extends React.PureComponent<TreeViewProps> {
{before}
<JSONTree
keyPath={keyPath}
shouldExpandNode={shouldExpandNode}
data={data}
labelRenderer={this.selectLabelRenderer(styling)}
theme={getJsonTreeTheme(base16Theme)}
theme={this.selectTheme(base16Theme)}
invertTheme={invertTheme}
getItemString={(type, data) =>
getItemString(
styling,
type,
data,
DATA_TYPE_KEY,
isWideLayout
)
}
hideRoot
getItemString={this.selectGetItemString(styling, isWideLayout)}
hideRoot={hideRoot}
/>
{after}
{children}