Skip to content

Commit

Permalink
Merge branch 'TanStack:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Naymi committed Nov 13, 2022
2 parents a534eb4 + f65e7af commit 280e915
Show file tree
Hide file tree
Showing 26 changed files with 680 additions and 112 deletions.
2 changes: 1 addition & 1 deletion docs/guides/query-invalidation.md
Expand Up @@ -48,7 +48,7 @@ You can even invalidate queries with specific variables by passing a more specif

```tsx
queryClient.invalidateQueries({
queryKey: ['todos', { type: 'done' },
queryKey: ['todos', { type: 'done' }],
})

// The query below will be invalidated
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin-query/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/eslint-plugin-query",
"version": "4.14.6",
"version": "4.15.1",
"description": "ESLint plugin for TanStack Query",
"author": "Eliya Cohen",
"license": "MIT",
Expand Down
Expand Up @@ -56,13 +56,26 @@ export const rule = createRule({
return
}

if (queryKey.value.type !== AST_NODE_TYPES.ArrayExpression) {
let queryKeyNode = queryKey.value

if (queryKeyNode.type === AST_NODE_TYPES.Identifier) {
const expression = ASTUtils.getReferencedExpressionByIdentifier({
context,
node: queryKeyNode,
})

if (expression?.type === AST_NODE_TYPES.ArrayExpression) {
queryKeyNode = expression
}
}

if (queryKeyNode.type !== AST_NODE_TYPES.ArrayExpression) {
// TODO support query key factory
return
}

const sourceCode = context.getSourceCode()
const queryKeyValue = queryKey.value
const queryKeyValue = queryKeyNode
const refs = ASTUtils.getExternalRefs({
scopeManager,
node: queryFn.value,
Expand Down
Expand Up @@ -181,6 +181,7 @@ ruleTester.run('exhaustive-deps', rule, {
suggestions: [
{
messageId: 'fixTo',
// eslint-disable-next-line no-template-curly-in-string
data: { result: '["entity/${id}", id]' },
output: normalizeIndent`
const id = 1;
Expand All @@ -205,6 +206,7 @@ ruleTester.run('exhaustive-deps', rule, {
suggestions: [
{
messageId: 'fixTo',
// eslint-disable-next-line no-template-curly-in-string
data: { result: '[`entity/${a}`, b]' },
output: normalizeIndent`
const a = 1;
Expand Down Expand Up @@ -343,5 +345,32 @@ ruleTester.run('exhaustive-deps', rule, {
},
],
},
{
name: 'should fail when a queryKey is a reference of an array expression with a missing dep',
code: normalizeIndent`
const x = 5;
const queryKey = ['foo']
useQuery({ queryKey, queryFn: () => x })
`,
errors: [
{
messageId: 'missingDeps',
data: { deps: 'x' },
suggestions: [
{
messageId: 'fixTo',
data: {
result: "['foo', x]",
},
output: normalizeIndent`
const x = 5;
const queryKey = ['foo', x]
useQuery({ queryKey, queryFn: () => x })
`,
},
],
},
],
},
],
})
Expand Up @@ -26,6 +26,8 @@ export function detectTanstackQueryImports(create: EnhancedCreate): Create {
if (specifier.type === 'ImportSpecifier') {
return node.name === specifier.local.name
}

return false
})
},
}
Expand Down
2 changes: 1 addition & 1 deletion packages/query-async-storage-persister/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/query-async-storage-persister",
"version": "4.14.5",
"version": "4.15.1",
"description": "A persister for asynchronous storages, to be used with TanStack/Query",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/query-broadcast-client-experimental/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/query-broadcast-client-experimental",
"version": "4.14.5",
"version": "4.15.1",
"description": "An experimental plugin to for broadcasting the state of your queryClient between browser tabs/windows",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/query-core/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/query-core",
"version": "4.14.5",
"version": "4.15.1",
"description": "The framework agnostic core that powers TanStack Query",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
4 changes: 4 additions & 0 deletions packages/query-core/src/queriesObserver.ts
Expand Up @@ -117,6 +117,10 @@ export class QueriesObserver extends Subscribable<QueriesObserverListener> {
return this.observers.map((observer) => observer.getCurrentQuery())
}

getObservers() {
return this.observers
}

getOptimisticResult(queries: QueryObserverOptions[]): QueryObserverResult[] {
return this.findMatchingObservers(queries).map((match) =>
match.observer.getOptimisticResult(match.defaultedQueryOptions),
Expand Down
2 changes: 1 addition & 1 deletion packages/query-persist-client-core/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/query-persist-client-core",
"version": "4.14.5",
"version": "4.15.1",
"description": "Set of utilities for interacting with persisters, which can save your queryClient for later use",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/query-sync-storage-persister/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/query-sync-storage-persister",
"version": "4.14.5",
"version": "4.15.1",
"description": "A persister for synchronous storages, to be used with TanStack/Query",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
4 changes: 2 additions & 2 deletions packages/react-query-devtools/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/react-query-devtools",
"version": "4.14.6",
"version": "4.16.0",
"description": "Developer tools to interact with and visualize the TanStack/react-query cache",
"author": "tannerlinsley",
"license": "MIT",
Expand Down Expand Up @@ -55,7 +55,7 @@
"@tanstack/react-query": "workspace:*"
},
"dependencies": {
"@tanstack/match-sorter-utils": "^8.1.1",
"@tanstack/match-sorter-utils": "8.1.1",
"superjson": "^1.10.0",
"use-sync-external-store": "^1.2.0"
},
Expand Down
127 changes: 127 additions & 0 deletions packages/react-query-devtools/src/Explorer.tsx
@@ -1,6 +1,7 @@
import * as React from 'react'

import { displayValue, styled } from './utils'
import superjson from 'superjson'

export const Entry = styled('div', {
fontFamily: 'Menlo, monospace',
Expand Down Expand Up @@ -29,6 +30,55 @@ export const ExpandButton = styled('button', {
padding: 0,
})

type CopyState = 'NoCopy' | 'SuccessCopy' | 'ErrorCopy'

export const CopyButton = ({ value }: { value: unknown }) => {
const [copyState, setCopyState] = React.useState<CopyState>('NoCopy')

return (
<button
onClick={
copyState === 'NoCopy'
? () => {
navigator.clipboard.writeText(superjson.stringify(value)).then(
() => {
setCopyState('SuccessCopy')
setTimeout(() => {
setCopyState('NoCopy')
}, 1500)
},
(err) => {
console.error('Failed to copy: ', err)
setCopyState('ErrorCopy')
setTimeout(() => {
setCopyState('NoCopy')
}, 1500)
},
)
}
: undefined
}
style={{
cursor: 'pointer',
color: 'inherit',
font: 'inherit',
outline: 'inherit',
background: 'transparent',
border: 'none',
padding: 0,
}}
>
{copyState === 'NoCopy' ? (
<Copier />
) : copyState === 'SuccessCopy' ? (
<CopiedCopier />
) : (
<ErrorCopier />
)}
</button>
)
}

export const Value = styled('span', (_props, theme) => ({
color: theme.danger,
}))
Expand Down Expand Up @@ -62,6 +112,76 @@ export const Expander = ({ expanded, style = {} }: ExpanderProps) => (
</span>
)

const Copier = () => (
<span
aria-label="Copy object to clipboard"
title="Copy object to clipboard"
style={{
paddingLeft: '1em',
}}
>
<svg height="12" viewBox="0 0 16 12" width="10">
<path
fill="currentColor"
d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 010 1.5h-1.5a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-1.5a.75.75 0 011.5 0v1.5A1.75 1.75 0 019.25 16h-7.5A1.75 1.75 0 010 14.25v-7.5z"
></path>
<path
fill="currentColor"
d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0114.25 11h-7.5A1.75 1.75 0 015 9.25v-7.5zm1.75-.25a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-7.5a.25.25 0 00-.25-.25h-7.5z"
></path>
</svg>
</span>
)

const ErrorCopier = () => (
<span
aria-label="Failed copying to clipboard"
title="Failed copying to clipboard"
style={{
paddingLeft: '1em',
display: 'flex',
alignItems: 'center',
}}
>
<svg height="12" viewBox="0 0 16 12" width="10" display="block">
<path
fill="red"
d="M3.72 3.72a.75.75 0 011.06 0L8 6.94l3.22-3.22a.75.75 0 111.06 1.06L9.06 8l3.22 3.22a.75.75 0 11-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 01-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 010-1.06z"
></path>
</svg>
<span
style={{
color: 'red',
fontSize: '12px',
paddingLeft: '4px',
position: 'relative',
top: '2px',
}}
>
See console
</span>
</span>
)

const CopiedCopier = () => (
<span
aria-label="Object copied to clipboard"
title="Object copied to clipboard"
style={{
paddingLeft: '1em',
display: 'inline-block',
verticalAlign: 'middle',
}}
>
<svg height="16" viewBox="0 0 16 16" width="16" display="block">
<path
fill="green"
d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z"
></path>
</svg>
</span>
)

type Entry = {
label: string
}
Expand All @@ -74,6 +194,7 @@ type RendererProps = {
subEntryPages: Entry[][]
type: string
expanded: boolean
copyable: boolean
toggleExpanded: () => void
pageSize: number
}
Expand Down Expand Up @@ -108,6 +229,7 @@ export const DefaultRenderer: Renderer = ({
subEntryPages = [],
type,
expanded = false,
copyable = false,
toggleExpanded,
pageSize,
}) => {
Expand All @@ -124,6 +246,7 @@ export const DefaultRenderer: Renderer = ({
{subEntries.length} {subEntries.length > 1 ? `items` : `item`}
</Info>
</ExpandButton>
{copyable ? <CopyButton value={value} /> : null}
{expanded ? (
subEntryPages.length === 1 ? (
<SubEntries>{subEntries.map(handleEntry)}</SubEntries>
Expand Down Expand Up @@ -166,6 +289,7 @@ export const DefaultRenderer: Renderer = ({
type ExplorerProps = Partial<RendererProps> & {
renderer?: Renderer
defaultExpanded?: true | Record<string, boolean>
copyable?: boolean
}

type Property = {
Expand All @@ -183,6 +307,7 @@ export default function Explorer({
defaultExpanded,
renderer = DefaultRenderer,
pageSize = 100,
copyable = false,
...rest
}: ExplorerProps) {
const [expanded, setExpanded] = React.useState(Boolean(defaultExpanded))
Expand Down Expand Up @@ -241,6 +366,7 @@ export default function Explorer({
key={entry.label}
value={value}
renderer={renderer}
copyable={copyable}
{...rest}
{...entry}
/>
Expand All @@ -250,6 +376,7 @@ export default function Explorer({
subEntryPages,
value,
expanded,
copyable,
toggleExpanded,
pageSize,
...rest,
Expand Down

0 comments on commit 280e915

Please sign in to comment.