diff --git a/ui/packages/app/web/src/App.tsx b/ui/packages/app/web/src/App.tsx index 7885161e8d9..61e181f0c76 100644 --- a/ui/packages/app/web/src/App.tsx +++ b/ui/packages/app/web/src/App.tsx @@ -27,6 +27,7 @@ import TargetsPage from './pages/targets'; import Component404 from './pages/layouts/Component404'; import {isDevMode} from '@parca/functions'; import {Provider} from 'react-redux'; +import {QueryClient, QueryClientProvider} from 'react-query'; declare global { interface Window { @@ -45,6 +46,14 @@ function getBasename() { return window.PATH_PREFIX; } +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + refetchOnWindowFocus: false, + }, + }, +}); + const {store: reduxStore, persistor} = store(); const App = () => { @@ -52,19 +61,21 @@ const App = () => { - -
-
- - } /> - } /> - {isDevMode() && ( - } /> - )} - } /> - -
- + + +
+
+ + } /> + } /> + {isDevMode() && ( + } /> + )} + } /> + +
+ + diff --git a/ui/packages/shared/profile/package.json b/ui/packages/shared/profile/package.json index 44a96042b38..80538508062 100644 --- a/ui/packages/shared/profile/package.json +++ b/ui/packages/shared/profile/package.json @@ -16,7 +16,8 @@ "konva": "8.3.14", "react-copy-to-clipboard": "^5.1.0", "react-cytoscapejs": "1.2.1", - "react-konva": "18.2.3" + "react-konva": "18.2.3", + "react-query": "^3.39.2" }, "devDependencies": { "@types/d3": "7.4.0", diff --git a/ui/packages/shared/profile/src/useGrpcQuery/index.ts b/ui/packages/shared/profile/src/useGrpcQuery/index.ts new file mode 100644 index 00000000000..3731df2028a --- /dev/null +++ b/ui/packages/shared/profile/src/useGrpcQuery/index.ts @@ -0,0 +1,42 @@ +// Copyright 2022 The Parca Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import {useQuery, UseQueryResult} from 'react-query'; + +interface Props { + key: string | any[]; + queryFn: () => Promise; + options?: { + enabled?: boolean | undefined; + staleTime?: number | undefined; + }; +} + +const useGrpcQuery = ({ + key, + queryFn, + options: {enabled = true, staleTime} = {}, +}: Props): UseQueryResult => { + return useQuery( + key, + async () => { + return await queryFn(); + }, + { + enabled, + staleTime, + } + ); +}; + +export default useGrpcQuery; diff --git a/ui/packages/shared/profile/src/useQuery.tsx b/ui/packages/shared/profile/src/useQuery.tsx index 341bd950b49..78f1772ad73 100644 --- a/ui/packages/shared/profile/src/useQuery.tsx +++ b/ui/packages/shared/profile/src/useQuery.tsx @@ -11,13 +11,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -import {useEffect, useState} from 'react'; - import {QueryServiceClient, QueryResponse, QueryRequest_ReportType} from '@parca/client'; import {RpcError} from '@protobuf-ts/runtime-rpc'; import {useGrpcMetadata} from '@parca/components'; import {ProfileSource} from './ProfileSource'; +import useGrpcQuery from './useGrpcQuery'; export interface IQueryResult { response: QueryResponse | null; @@ -36,31 +35,21 @@ export const useQuery = ( options?: UseQueryOptions ): IQueryResult => { const {skip = false} = options ?? {}; - const [result, setResult] = useState({ - response: null, - error: null, - isLoading: false, - }); const metadata = useGrpcMetadata(); + const {data, isLoading, error} = useGrpcQuery({ + key: ['query', profileSource, reportType], + queryFn: async () => { + const req = profileSource.QueryRequest(); + req.reportType = reportType; + + const {response} = await client.query(req, {meta: metadata}); + return response; + }, + options: { + enabled: !skip, + staleTime: 1000 * 60 * 5, // 5 minutes + }, + }); - useEffect(() => { - if (skip) { - return; - } - setResult({ - response: null, - error: null, - isLoading: true, - }); - const req = profileSource.QueryRequest(); - req.reportType = reportType; - - const call = client.query(req, {meta: metadata}); - - call.response - .then(response => setResult({response, error: null, isLoading: false})) - .catch(error => setResult({error, response: null, isLoading: false})); - }, [skip, client, profileSource, metadata, reportType]); - - return result; + return {isLoading, error: error as RpcError | null, response: data ?? null}; }; diff --git a/ui/yarn.lock b/ui/yarn.lock index e3509fd85fb..77b3088a447 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -8527,7 +8527,7 @@ bfj@^7.0.2: hoopy "^0.1.4" tryer "^1.0.1" -big-integer@^1.6.7: +big-integer@^1.6.16, big-integer@^1.6.7: version "1.6.51" resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== @@ -8701,6 +8701,20 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" +broadcast-channel@^3.4.1: + version "3.7.0" + resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937" + integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg== + dependencies: + "@babel/runtime" "^7.7.2" + detect-node "^2.1.0" + js-sha3 "0.8.0" + microseconds "0.2.0" + nano-time "1.0.0" + oblivious-set "1.0.0" + rimraf "3.0.2" + unload "2.2.0" + brorand@^1.0.1, brorand@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" @@ -11277,7 +11291,7 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -detect-node@^2.0.4: +detect-node@^2.0.4, detect-node@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== @@ -16247,6 +16261,11 @@ js-sdsl@^4.1.4: resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.1.5.tgz#1ff1645e6b4d1b028cd3f862db88c9d887f26e2a" integrity sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q== +js-sha3@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + js-string-escape@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" @@ -17297,6 +17316,14 @@ marked@4.1.0: resolved "https://registry.yarnpkg.com/marked/-/marked-4.1.0.tgz#3fc6e7485f21c1ca5d6ec4a39de820e146954796" integrity sha512-+Z6KDjSPa6/723PQYyc1axYZpYYpDnECDaU6hkaf5gqBieBkMKYReL5hteF2QizhlMbgbo8umXl/clZ67+GlsA== +match-sorter@^6.0.2: + version "6.3.1" + resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.1.tgz#98cc37fda756093424ddf3cbc62bfe9c75b92bda" + integrity sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw== + dependencies: + "@babel/runtime" "^7.12.5" + remove-accents "0.4.2" + md5-file@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/md5-file/-/md5-file-5.0.0.tgz#e519f631feca9c39e7f9ea1780b63c4745012e20" @@ -17901,6 +17928,11 @@ micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: braces "^3.0.2" picomatch "^2.3.1" +microseconds@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39" + integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA== + miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -18261,6 +18293,13 @@ nano-css@^5.3.1: stacktrace-js "^2.0.2" stylis "^4.0.6" +nano-time@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef" + integrity sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA== + dependencies: + big-integer "^1.6.16" + nanoid@^3.3.1, nanoid@^3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" @@ -18866,6 +18905,11 @@ objectorarray@^1.0.5: resolved "https://registry.yarnpkg.com/objectorarray/-/objectorarray-1.0.5.tgz#2c05248bbefabd8f43ad13b41085951aac5e68a5" integrity sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg== +oblivious-set@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566" + integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw== + obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" @@ -21365,6 +21409,15 @@ react-popper@2.3.0, react-popper@^2.2.5, react-popper@^2.3.0: react-fast-compare "^3.0.1" warning "^4.0.2" +react-query@^3.39.2: + version "3.39.2" + resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.39.2.tgz#9224140f0296f01e9664b78ed6e4f69a0cc9216f" + integrity sha512-F6hYDKyNgDQfQOuR1Rsp3VRzJnWHx6aRnnIZHMNGGgbL3SBgpZTDg8MQwmxOgpCAoqZJA+JSNCydF1xGJqKOCA== + dependencies: + "@babel/runtime" "^7.5.5" + broadcast-channel "^3.4.1" + match-sorter "^6.0.2" + react-reconciler@~0.29.0: version "0.29.0" resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.29.0.tgz#ee769bd362915076753f3845822f2d1046603de7" @@ -22002,6 +22055,11 @@ remark-squeeze-paragraphs@4.0.0: dependencies: mdast-squeeze-paragraphs "^4.0.0" +remove-accents@0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5" + integrity sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA== + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" @@ -24728,6 +24786,14 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== +unload@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7" + integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA== + dependencies: + "@babel/runtime" "^7.6.2" + detect-node "^2.0.4" + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"