Skip to content
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/fix-tanstack-query-edit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rozenite/tanstack-query-plugin': patch
---

Fix TanStack Query devtools data edits so query data changes made in the panel sync back to the device without breaking existing loading and error actions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import {
QueryObserver,
onlineManager,
} from '@tanstack/react-query';
import {
applyTanStackQueryDevtoolsAction,
} from '../../devtools-actions';
import { applyTanStackQueryDevtoolsAction } from '../../devtools-actions';
import {
createTanStackQueryAgentController,
serializeForAgent,
Expand All @@ -30,7 +28,7 @@ const createQueryClient = () =>

const subscribeController = (
queryClient: QueryClient,
controller: ReturnType<typeof createTanStackQueryAgentController>
controller: ReturnType<typeof createTanStackQueryAgentController>,
) => {
const unsubscribeQuery = queryClient
.getQueryCache()
Expand Down Expand Up @@ -58,7 +56,7 @@ const createMutation = (
context?: unknown;
failureCount?: number;
failureReason?: Error | null;
}
},
) => {
return queryClient.getMutationCache().build(
queryClient,
Expand All @@ -78,7 +76,7 @@ const createMutation = (
status: options?.status ?? 'success',
submittedAt: options?.submittedAt ?? Date.now(),
variables: options?.variables,
} as any
} as any,
) as Mutation<unknown, Error, unknown, unknown>;
};

Expand Down Expand Up @@ -126,8 +124,10 @@ describe('tanstack query agent controller', () => {
controller.listQueries({
limit: 1,
cursor: firstPage.page.nextCursor,
})
).toThrow('Cursor does not match the requested listing. Run the command again.');
}),
).toThrow(
'Cursor does not match the requested listing. Run the command again.',
);

unsubscribe();
});
Expand All @@ -147,8 +147,10 @@ describe('tanstack query agent controller', () => {
controller.listQueries({
limit: 1,
cursor: firstPage.page.nextCursor,
})
).toThrow('Cursor does not match the requested listing. Run the command again.');
}),
).toThrow(
'Cursor does not match the requested listing. Run the command again.',
);

queryClient.setQueryData(['third'], { value: 3 });
queryClient.setQueryData(['fourth'], { value: 4 });
Expand All @@ -159,8 +161,10 @@ describe('tanstack query agent controller', () => {
controller.listQueries({
limit: 1,
cursor: secondPageSeed.page.nextCursor,
})
).toThrow('Cursor does not match the requested listing. Run the command again.');
}),
).toThrow(
'Cursor does not match the requested listing. Run the command again.',
);

unsubscribe();
});
Expand Down Expand Up @@ -194,8 +198,10 @@ describe('tanstack query agent controller', () => {
controller.listMutations({
limit: 1,
cursor: firstPage.page.nextCursor,
})
).toThrow('Cursor does not match the requested listing. Run the command again.');
}),
).toThrow(
'Cursor does not match the requested listing. Run the command again.',
);

const mutation = queryClient.getMutationCache().getAll()[0];
queryClient.getMutationCache().remove(mutation);
Expand All @@ -207,8 +213,10 @@ describe('tanstack query agent controller', () => {
controller.listMutations({
limit: 1,
cursor: secondPageSeed.page.nextCursor,
})
).toThrow('Cursor does not match the requested listing. Run the command again.');
}),
).toThrow(
'Cursor does not match the requested listing. Run the command again.',
);

unsubscribe();
});
Expand All @@ -234,8 +242,9 @@ describe('tanstack query agent controller', () => {
queryFn,
});

const queryHash = queryClient.getQueryCache().find({ queryKey: ['todos', 1] })!
.queryHash;
const queryHash = queryClient
.getQueryCache()
.find({ queryKey: ['todos', 1] })!.queryHash;
const details = controller.getQueryDetails({ queryHash });

expect(details.query).toMatchObject({
Expand Down Expand Up @@ -299,9 +308,9 @@ describe('tanstack query agent controller', () => {
},
});

expect(() =>
controller.getMutationDetails({ mutationId: 9999 })
).toThrow('Unknown mutationId "9999"');
expect(() => controller.getMutationDetails({ mutationId: 9999 })).toThrow(
'Unknown mutationId "9999"',
);

unsubscribe();
});
Expand All @@ -310,9 +319,9 @@ describe('tanstack query agent controller', () => {
const queryClient = createQueryClient();
const controller = createTanStackQueryAgentController(queryClient);

expect(() =>
controller.getQueryDetails({ queryHash: 'missing' })
).toThrow('Unknown queryHash "missing"');
expect(() => controller.getQueryDetails({ queryHash: 'missing' })).toThrow(
'Unknown queryHash "missing"',
);
});

it('gets and sets the online manager status', () => {
Expand Down Expand Up @@ -461,6 +470,37 @@ describe('tanstack query agent actions', () => {
});
});

it('sets query data through the shared UI dispatcher', async () => {
const queryClient = createQueryClient();

await queryClient.fetchQuery({
queryKey: ['editable-query'],
queryFn: async () => ({ value: 'initial' }),
initialData: { value: 'initial' },
});

const query = queryClient.getQueryCache().find({
queryKey: ['editable-query'],
})!;

const result = await applyTanStackQueryDevtoolsAction(queryClient, {
type: 'SET_QUERY_DATA',
queryHash: query.queryHash,
metadata: {
data: { value: 'changed' },
},
});

expect(result).toMatchObject({
applied: true,
action: 'SET_QUERY_DATA',
queryHash: query.queryHash,
});
expect(queryClient.getQueryData(['editable-query'])).toEqual({
value: 'changed',
});
});

it('clears mutation cache through the shared UI/agent dispatcher', async () => {
const queryClient = createQueryClient();
createMutation(queryClient, {
Expand Down Expand Up @@ -501,8 +541,6 @@ describe('serializeForAgent', () => {
ok: true,
self: '[circular]',
});
expect(serializeForAgent(new Example())).toBe(
'[non-serializable:Example]'
);
expect(serializeForAgent(new Example())).toBe('[non-serializable:Example]');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ type QueryScopedActionInput = {
'CLEAR_MUTATION_CACHE' | 'CLEAR_QUERY_CACHE'
>;
queryHash: string;
metadata?: {
data?: unknown;
};
};

type CacheScopedActionInput = {
Expand All @@ -33,7 +36,7 @@ const getActiveQuery = (queryClient: QueryClient, queryHash?: string) => {

export const applyTanStackQueryDevtoolsAction = async (
queryClient: QueryClient,
input: TanStackQueryDevtoolsActionInput
input: TanStackQueryDevtoolsActionInput,
) => {
switch (input.type) {
case 'CLEAR_QUERY_CACHE': {
Expand All @@ -49,8 +52,9 @@ export const applyTanStackQueryDevtoolsAction = async (
}

case 'CLEAR_MUTATION_CACHE': {
const mutationCountBefore =
queryClient.getMutationCache().getAll().length;
const mutationCountBefore = queryClient
.getMutationCache()
.getAll().length;
queryClient.getMutationCache().clear();
return {
applied: true,
Expand All @@ -61,6 +65,16 @@ export const applyTanStackQueryDevtoolsAction = async (
};
}

case 'SET_QUERY_DATA': {
const activeQuery = getActiveQuery(queryClient, input.queryHash);
queryClient.setQueryData(activeQuery.queryKey, input.metadata?.data);
return {
applied: true,
action: input.type,
queryHash: activeQuery.queryHash,
};
}

case 'TRIGGER_ERROR': {
const activeQuery = getActiveQuery(queryClient, input.queryHash);
const previousQueryOptions = activeQuery.options;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { applyTanStackQueryDevtoolsAction } from './devtools-actions';

export const useHandleDevToolsMessages = (
queryClient: QueryClient,
client: TanStackQueryPluginClient | null
client: TanStackQueryPluginClient | null,
) => {
useEffect(() => {
if (!client) {
Expand All @@ -14,16 +14,19 @@ export const useHandleDevToolsMessages = (

const subscription = client.onMessage(
'devtools-action',
({ type, queryHash }) => {
void applyTanStackQueryDevtoolsAction(queryClient, { type, queryHash })
.catch((error) => {
const message =
error instanceof Error ? error.message : String(error);
console.warn(
`[Rozenite, tanstack-query-plugin] Failed to apply devtools action "${type}": ${message}`
);
});
}
({ type, queryHash, metadata }) => {
void applyTanStackQueryDevtoolsAction(queryClient, {
type,
queryHash,
metadata,
}).catch((error) => {
const message =
error instanceof Error ? error.message : String(error);
console.warn(
`[Rozenite, tanstack-query-plugin] Failed to apply devtools action "${type}": ${message}`,
);
});
},
);

return () => {
Expand Down
Loading
Loading