diff --git a/package.json b/package.json index d0aae173d..7a839220a 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "rimraf": "^3.0.0", - "typescript": "^4.0.5" + "typescript": "^4.9.5" }, "scripts": { "install:examples": "loop \"yarn install --force --check-files\" --cwd ./examples --exit-on-aggregate-error", @@ -48,17 +48,12 @@ "start": "yarn build && cd examples/query-playground && yarn start", "docs:build": "mkdir -p dist && cp docs/index.html dist/ && yarn build:playground", "docs:serve": "d2-utils-docsite serve ./docs -o ./dist", - "lint": "d2-style check js && d2-style check text", - "postinstall": "patch-package" + "lint": "d2-style check js && d2-style check text" }, "d2": { "docsite": { "name": "DHIS2 Application Runtime", "description": "A singular runtime dependency for applications on the [DHIS2 platform](https://platform.dhis2.nu)" } - }, - "dependencies": { - "patch-package": "^8.0.0", - "postinstall-postinstall": "^2.1.0" } } diff --git a/patches/react-query+3.13.11.patch b/patches/react-query+3.13.11.patch deleted file mode 100644 index 0522a6f6a..000000000 --- a/patches/react-query+3.13.11.patch +++ /dev/null @@ -1,10 +0,0 @@ -diff --git a/node_modules/react-query/types/react/QueryClientProvider.d.ts b/node_modules/react-query/types/react/QueryClientProvider.d.ts -index 65e1214..ea9fbf0 100644 ---- a/node_modules/react-query/types/react/QueryClientProvider.d.ts -+++ b/node_modules/react-query/types/react/QueryClientProvider.d.ts -@@ -10,4 +10,4 @@ export interface QueryClientProviderProps { - client: QueryClient; - contextSharing?: boolean; - } --export declare const QueryClientProvider: React.FC; -+export declare const QueryClientProvider: React.FC>; diff --git a/services/data/package.json b/services/data/package.json index ee5fe62a4..3447f2f52 100644 --- a/services/data/package.json +++ b/services/data/package.json @@ -32,7 +32,7 @@ "coverage": "yarn test --coverage" }, "dependencies": { - "react-query": "^3.13.11" + "@tanstack/react-query": "^4.36.1" }, "peerDependencies": { "@dhis2/app-service-config": "3.12.0-alpha.1", diff --git a/services/data/src/react/components/CustomDataProvider.tsx b/services/data/src/react/components/CustomDataProvider.tsx index 52ac4bc9e..de8b08f4c 100644 --- a/services/data/src/react/components/CustomDataProvider.tsx +++ b/services/data/src/react/components/CustomDataProvider.tsx @@ -1,5 +1,5 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import React from 'react' -import { QueryClient, QueryClientProvider } from 'react-query' import { DataEngine } from '../../engine' import { CustomDataLink, CustomData, CustomLinkOptions } from '../../links' import { DataContext } from '../context/DataContext' diff --git a/services/data/src/react/components/DataProvider.tsx b/services/data/src/react/components/DataProvider.tsx index f069e722f..1ce7ac092 100644 --- a/services/data/src/react/components/DataProvider.tsx +++ b/services/data/src/react/components/DataProvider.tsx @@ -1,8 +1,12 @@ /* eslint-disable react/no-unused-prop-types */ import { useConfig } from '@dhis2/app-service-config' +import { + QueryClient, + QueryClientProvider, + type QueryClientConfig, +} from '@tanstack/react-query' import React from 'react' -import { QueryClient, QueryClientProvider } from 'react-query' import { DataEngine } from '../../engine' import { RestAPILink } from '../../links' import { DataContext } from '../context/DataContext' @@ -13,7 +17,7 @@ export interface ProviderInput { children: React.ReactNode } -export const queryClientOptions = { +export const queryClientOptions: QueryClientConfig = { defaultOptions: { queries: { // Disable automatic error retries @@ -26,6 +30,10 @@ export const queryClientOptions = { refetchOnWindowFocus: false, // Don't refetch after connection issues refetchOnReconnect: false, + // RQv4 uses 'online' as the default, which pauses queries without network connection. + // 'always' reestablishes behavior from v3, and lets requests fire when offline + // https://tanstack.com/query/latest/docs/framework/react/guides/network-mode + networkMode: 'always', }, }, } diff --git a/services/data/src/react/hooks/useDataQuery.ts b/services/data/src/react/hooks/useDataQuery.ts index a7d16fb20..eb4986caa 100644 --- a/services/data/src/react/hooks/useDataQuery.ts +++ b/services/data/src/react/hooks/useDataQuery.ts @@ -1,5 +1,5 @@ +import { useQuery } from '@tanstack/react-query' import { useState, useRef, useCallback, useDebugValue } from 'react' -import { useQuery, setLogger } from 'react-query' import type { Query, QueryOptions, @@ -12,20 +12,6 @@ import { mergeAndCompareVariables } from './mergeAndCompareVariables' import { useDataEngine } from './useDataEngine' import { useStaticInput } from './useStaticInput' -const noop = () => { - /** - * Used to silence the default react-query logger. Eventually we - * could expose the setLogger functionality and remove the call - * to setLogger here. - */ -} - -setLogger({ - log: noop, - warn: noop, - error: noop, -}) - type QueryState = { enabled: boolean variables?: QueryVariables @@ -100,13 +86,14 @@ export const useDataQuery = ( engine.query(staticQuery, { variables: queryState.current.variables }) const { - isIdle, - isFetching, - isLoading, + status, + fetchStatus, error, data, refetch: queryRefetch, - } = useQuery(queryKey, queryFn, { + } = useQuery({ + queryKey, + queryFn, enabled: queryState.current.enabled, onSuccess, onError, @@ -135,10 +122,9 @@ export const useDataQuery = ( * we'll need to call react-query's refetch directly */ if (queryState.current.enabled && identical) { - return queryRefetch({ - cancelRefetch: true, - throwOnError: false, - }).then(({ data }) => data) + return queryRefetch({ throwOnError: false }).then( + ({ data }) => data + ) } queryState.current.variables = mergedVariables @@ -168,10 +154,15 @@ export const useDataQuery = ( return { engine, - // A query is idle if it is lazy and no initial data is available. - called: !isIdle, - loading: isLoading, - fetching: isFetching, + // A query has not been called if it is lazy (fetchStatus = 'idle') and no initial data is available (status = 'loading'). + // https://tanstack.com/query/v4/docs/framework/react/guides/queries + called: !(status === 'loading' && fetchStatus === 'idle'), + // 'loading' should only be true when actively fetching (fetchStatus = 'fetching') while there is no data yet (status = 'loading'). + // If there is already data for the query, then 'loading' will not become 'true' when refetching, so the previous data can still be + // displayed while new data is fetched in the background + loading: fetchStatus === 'fetching' && status === 'loading', + // 'fetching' reflects the fetching behavior behind the scenes + fetching: fetchStatus === 'fetching', error: ourError, data, refetch, diff --git a/yarn.lock b/yarn.lock index 64acc1246..aa8e3f0b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2758,6 +2758,19 @@ dependencies: defer-to-connect "^1.0.1" +"@tanstack/query-core@4.36.1": + version "4.36.1" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.36.1.tgz#79f8c1a539d47c83104210be2388813a7af2e524" + integrity sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA== + +"@tanstack/react-query@^4.36.1": + version "4.36.1" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.36.1.tgz#acb589fab4085060e2e78013164868c9c785e5d2" + integrity sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw== + dependencies: + "@tanstack/query-core" "4.36.1" + use-sync-external-store "^1.2.0" + "@testing-library/dom@^8.0.0": version "8.1.0" resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.1.0.tgz#f8358b1883844ea569ba76b7e94582168df5370d" @@ -4496,11 +4509,6 @@ ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.7.0.tgz#6d01b3696c59915b6ce057e4aa4adfc2fa25f5ef" integrity sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog== -ci-info@^3.7.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" - integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== - cjs-module-lexer@^1.0.0: version "1.2.2" resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" @@ -6505,13 +6513,6 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -find-yarn-workspace-root@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" - integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== - dependencies: - micromatch "^4.0.2" - findup-sync@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-4.0.0.tgz#956c9cdde804052b881b428512905c4a5f2cdef0" @@ -8644,16 +8645,6 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= -json-stable-stringify@^1.0.2: - version "1.1.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz#52d4361b47d49168bcc4e564189a42e5a7439454" - integrity sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg== - dependencies: - call-bind "^1.0.5" - isarray "^2.0.5" - jsonify "^0.0.1" - object-keys "^1.1.1" - json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -8687,11 +8678,6 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -jsonify@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978" - integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== - jsonparse@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" @@ -8751,13 +8737,6 @@ kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== -klaw-sync@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" - integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== - dependencies: - graceful-fs "^4.1.11" - klaw@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/klaw/-/klaw-3.0.0.tgz#b11bec9cf2492f06756d6e809ab73a2910259146" @@ -9343,11 +9322,6 @@ minimist@^1.2.0, minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== -minimist@^1.2.6: - version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" @@ -9728,7 +9702,7 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" -open@^7.3.1, open@^7.4.2: +open@^7.3.1: version "7.4.2" resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== @@ -9955,27 +9929,6 @@ pascalcase@^0.1.1: resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= -patch-package@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-8.0.0.tgz#d191e2f1b6e06a4624a0116bcb88edd6714ede61" - integrity sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA== - dependencies: - "@yarnpkg/lockfile" "^1.1.0" - chalk "^4.1.2" - ci-info "^3.7.0" - cross-spawn "^7.0.3" - find-yarn-workspace-root "^2.0.0" - fs-extra "^9.0.0" - json-stable-stringify "^1.0.2" - klaw-sync "^6.0.0" - minimist "^1.2.6" - open "^7.4.2" - rimraf "^2.6.3" - semver "^7.5.3" - slash "^2.0.0" - tmp "^0.0.33" - yaml "^2.2.2" - path-dirname@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" @@ -10378,11 +10331,6 @@ postcss@^8.3.5, postcss@^8.4.19, postcss@^8.4.43: picocolors "^1.1.0" source-map-js "^1.2.1" -postinstall-postinstall@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postinstall-postinstall/-/postinstall-postinstall-2.1.0.tgz#4f7f77441ef539d1512c40bd04c71b06a4704ca3" - integrity sha512-7hQX6ZlZXIoRiWNrbMQaLzUUfH+sSx39u8EJ9HYuDc1kLo9IXKWjM5RSquZN1ad5GnH8CGFM78fsAAQi3OKEEQ== - prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -11142,13 +11090,6 @@ rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" -rimraf@^2.6.3: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - rimraf@~2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" @@ -11337,7 +11278,7 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0, semve resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.2.1, semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3: +semver@^7.2.1, semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: version "7.6.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== @@ -11567,11 +11508,6 @@ sisteransi@^1.0.5: resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== -slash@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" - integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== - slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -12646,7 +12582,7 @@ typeface-roboto@^0.0.75: resolved "https://registry.yarnpkg.com/typeface-roboto/-/typeface-roboto-0.0.75.tgz#98d5ba35ec234bbc7172374c8297277099cc712b" integrity sha512-VrR/IiH00Z1tFP4vDGfwZ1esNqTiDMchBEXYY9kilT6wRGgFoCAlgkEUMHb1E3mB0FsfZhv756IF0+R+SFPfdg== -typescript@^4.0.5: +typescript@^4.9.5: version "4.9.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== @@ -12869,6 +12805,11 @@ url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" +use-sync-external-store@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9" + integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw== + use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" @@ -13566,11 +13507,6 @@ yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yaml@^2.2.2: - version "2.6.0" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.6.0.tgz#14059ad9d0b1680d0f04d3a60fe00f3a857303c3" - integrity sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ== - yargs-parser@^13.1.2: version "13.1.2" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38"