Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle api.provided state changes in RTKQ 2.6.2 #1848

Merged
merged 3 commits into from
Apr 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/little-melons-grow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@redux-devtools/rtk-query-monitor': minor
---

Handle api.provided state changes in RTKQ 2.6.2
5 changes: 3 additions & 2 deletions packages/redux-devtools-rtk-query-monitor/src/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import {
RtkQueryApiState,
RtkQueryTag,
SelectorsSource,
RtkQueryProvided,
RtkQueryProvidedTagsState,
QueryPreviewTabs,
RtkResourceInfo,
RtkQuery262ProvidedState,
} from './types';
import { Comparator, queryComparators } from './utils/comparators';
import { FilterList, queryListFilters } from './utils/filters';
Expand Down Expand Up @@ -216,7 +217,7 @@ export function createInspectorSelectors<S>(): InspectorSelectors<S> {

const selectProvidedOfCurrentQuery: InspectorSelector<
S,
null | RtkQueryProvided
null | RtkQueryProvidedTagsState | RtkQuery262ProvidedState
> = (selectorsSource: SelectorsSource<S>) => {
return selectApiOfCurrentQuery(selectorsSource)?.provided ?? null;
};
Expand Down
38 changes: 36 additions & 2 deletions packages/redux-devtools-rtk-query-monitor/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import type { LiftedAction, LiftedState } from '@redux-devtools/core';
import type { createApi, QueryStatus } from '@reduxjs/toolkit/query';
import type {
createApi,
QueryCacheKey,
QueryStatus,
} from '@reduxjs/toolkit/query';
import type { Action, AnyAction, Dispatch } from '@reduxjs/toolkit';
import type { ComponentType } from 'react';
import { base16Themes } from 'react-base16-styling';
Expand Down Expand Up @@ -52,7 +56,37 @@ export type RtkMutationState = NonNullable<

export type RtkQueryApiConfig = RtkQueryApiState['config'];

export type RtkQueryProvided = RtkQueryApiState['provided'];
export type FullTagDescription<TagType> = {
type: TagType;
id?: number | string;
};

// This is the actual tags structure, and was the entire `api.provided`
// field up through 2.6.1
export type RtkQueryProvidedTagsState = {
[x: string]: {
[id: string]: QueryCacheKey[];
[id: number]: QueryCacheKey[];
};
};

// As of 2.6.2, the `api.provided` field is split into `tags` and `keys` fields,
// with the old data nested in `tags`.
export type RtkQuery262ProvidedState = {
keys: Record<QueryCacheKey, FullTagDescription<any>[]>;
tags: RtkQueryProvidedTagsState;
};

export function isRtkQuery262Provided(
provided: Record<string, unknown>,
): provided is RtkQuery262ProvidedState {
return (
'tags' in provided &&
'keys' in provided &&
typeof provided.tags === 'object' &&
typeof provided.keys === 'object'
);
}

export interface ExternalProps<S, A extends Action<string>> {
dispatch: Dispatch<Action | LiftedAction<S, A, RtkQueryMonitorState>>;
Expand Down
26 changes: 20 additions & 6 deletions packages/redux-devtools-rtk-query-monitor/src/utils/rtk-query.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Action, AnyAction, isAllOf, isPlainObject } from '@reduxjs/toolkit';
import { QueryStatus } from '@reduxjs/toolkit/query';
import { QueryCacheKey, QueryStatus } from '@reduxjs/toolkit/query';
import {
QueryInfo,
RtkQueryMonitorState,
Expand All @@ -11,14 +11,16 @@ import {
MutationInfo,
ApiStats,
QueryTally,
RtkQueryProvided,
RtkQueryProvidedTagsState,
RtkQuery262ProvidedState,
ApiTimings,
QueryTimings,
SelectorsSource,
RtkMutationState,
RtkResourceInfo,
RtkRequest,
RtkRequestTiming,
isRtkQuery262Provided,
} from '../types';
import { missingTagId } from '../monitor-config';
import { Comparator, compareJSONPrimitive } from './comparators';
Expand Down Expand Up @@ -529,24 +531,36 @@ export function getProvidedOf(

export function getQueryTagsOf(
resInfo: RtkResourceInfo | null,
provided: RtkQueryProvided | null,
provided: RtkQueryProvidedTagsState | RtkQuery262ProvidedState | null,
): RtkQueryTag[] {
if (!resInfo || resInfo.type === 'mutation' || !provided) {
return emptyArray;
}

const tagTypes = Object.keys(provided);
// Handle `api.provided` schema change with RTK Query tag handling.
// Originally, `api.provided` was a `Record<string, Record<string, string[]>>`,
// directly containing the tag names.
// With https://github.com/reduxjs/redux-toolkit/pull/4910 , that changes to
// change the top level to be `{tags, keys}`, with `tags` containing the tag names.
// Handle the newer structure by extracting the right field if it exists.
const actualProvided: RtkQueryProvidedTagsState = isRtkQuery262Provided(
provided,
)
? provided.tags
: provided;

const tagTypes = Object.keys(actualProvided);

if (tagTypes.length < 1) {
return emptyArray;
}

const output: RtkQueryTag[] = [];

for (const [type, tagIds] of Object.entries(provided)) {
for (const [type, tagIds] of Object.entries(actualProvided)) {
if (tagIds) {
for (const [id, queryKeys] of Object.entries(tagIds)) {
if ((queryKeys as unknown[]).includes(resInfo.queryKey)) {
if (queryKeys.includes(resInfo.queryKey as QueryCacheKey)) {
const tag: RtkQueryTag = { type };

if (id !== missingTagId) {
Expand Down