diff --git a/package.json b/package.json index 158203b..cd24993 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ }, "devDependencies": { "@babel/core": "^7.13.16", - "@patternfly/react-core": "^4.115.1", + "@patternfly/react-core": "^4.157.3", "@patternfly/react-table": "^4.26.6", "@patternfly/react-tokens": "^4.11.2", "@rollup/plugin-commonjs": "^18.0.0", @@ -90,6 +90,7 @@ }, "dependencies": { "fast-deep-equal": "^3.1.3", + "react-query": "^3.26.0", "yup": "^0.32.9" } } diff --git a/src/common/types.ts b/src/common/types.ts new file mode 100644 index 0000000..cba6c86 --- /dev/null +++ b/src/common/types.ts @@ -0,0 +1,13 @@ +import { UseMutationResult, UseQueryResult } from 'react-query'; + +export type UnknownResult = Pick< + UseQueryResult, + 'isError' | 'isLoading' | 'isIdle' | 'error' +>; + +export type UnknownMutationResult = Pick< + UseMutationResult, + 'isError' | 'isLoading' | 'isIdle' | 'error' | 'reset' +>; + +export type ResultsWithErrorTitles = { result: UnknownResult; errorTitle: string }; diff --git a/src/components/LoadingEmptyState.tsx b/src/components/LoadingEmptyState.tsx new file mode 100644 index 0000000..7737545 --- /dev/null +++ b/src/components/LoadingEmptyState.tsx @@ -0,0 +1,35 @@ +import { + Bullseye, + EmptyState, + EmptyStateBody, + Spinner, + SpinnerProps, + Title, +} from '@patternfly/react-core'; +import * as React from 'react'; + +interface ILoadingEmptyStateProps { + className?: string; + spinnerProps?: Partial; + body?: React.ReactNode; +} + +const LoadingEmptyState: React.FunctionComponent = ({ + className = '', + spinnerProps = {}, + body = null, +}: ILoadingEmptyStateProps) => ( + + +
+ +
+ + Loading... + + {body ? {body} : null} +
+
+); + +export default LoadingEmptyState; diff --git a/src/components/ResolvedQuery/ResolvedQueries.tsx b/src/components/ResolvedQuery/ResolvedQueries.tsx new file mode 100644 index 0000000..4585fbc --- /dev/null +++ b/src/components/ResolvedQuery/ResolvedQueries.tsx @@ -0,0 +1,106 @@ +import * as React from 'react'; +import { UseMutationResult } from 'react-query'; +import { + Spinner, + Alert, + AlertActionCloseButton, + SpinnerProps, + AlertProps, + AlertGroup, +} from '@patternfly/react-core'; +import spacing from '@patternfly/react-styles/css/utilities/Spacing/spacing'; +import { getAggregateQueryStatus } from '../../queries/helpers'; +import { ResultsWithErrorTitles } from '../../common/types'; +import { KubeClientError } from '../../modules/kube-client/types'; +import LoadingEmptyState from '../LoadingEmptyState'; + +export type QuerySpinnerMode = 'inline' | 'emptyState' | 'none'; + +export interface IResolvedQueriesProps { + resultsWithErrorTitles: ResultsWithErrorTitles[]; + errorsInline?: boolean; + spinnerMode?: QuerySpinnerMode; + emptyStateBody?: React.ReactNode; + spinnerProps?: Partial; + alertProps?: Partial; + className?: string; + forceLoadingState?: boolean; + children?: React.ReactNode; +} + +export const ResolvedQueries: React.FunctionComponent = ({ + resultsWithErrorTitles, + errorsInline = true, + spinnerMode = 'emptyState', + emptyStateBody = null, + spinnerProps = {}, + alertProps = {}, + className = '', + forceLoadingState = false, + children = null, +}: IResolvedQueriesProps) => { + const status = getAggregateQueryStatus(resultsWithErrorTitles.map((r) => r.result)); + const erroredResults = resultsWithErrorTitles.filter( + (resultWithErrorTitle) => resultWithErrorTitle.result.isError + ); + let spinner: React.ReactNode = null; + if (spinnerMode === 'inline') { + spinner = ; + } else if (spinnerMode === 'emptyState') { + spinner = ; + } + + return ( + <> + {status === 'loading' || forceLoadingState ? ( + spinner + ) : status === 'error' ? ( + + {erroredResults.map((resultWithErrorTitle, index) => { + const { result, errorTitle } = resultWithErrorTitle; + return ( + void }).reset ? ( + ).reset} + /> + ) : null + } + {...alertProps} + > + {result.error ? ( + <> + {(result.error as Error).message || null} + {(result.error as KubeClientError).response ? ( + <> +
+ {(result.error as KubeClientError).response?.data?.message} + + ) : null} + {(result.error as Response).status + ? `${(result.error as Response).status}: ${ + (result.error as Response).statusText + }` + : null} + {typeof result.error === 'string' ? result.error : null} + + ) : null} +
+ ); + })} +
+ ) : ( + children + )} + + ); +}; diff --git a/src/components/ResolvedQuery/ResolvedQuery.tsx b/src/components/ResolvedQuery/ResolvedQuery.tsx new file mode 100644 index 0000000..bebbe97 --- /dev/null +++ b/src/components/ResolvedQuery/ResolvedQuery.tsx @@ -0,0 +1,16 @@ +import * as React from 'react'; +import { UnknownResult } from '../../common/types'; +import { ResolvedQueries, IResolvedQueriesProps } from './ResolvedQueries'; + +export interface IResolvedQueryProps extends Omit { + result: UnknownResult; + errorTitle: string; +} + +export const ResolvedQuery: React.FunctionComponent = ({ + result, + errorTitle, + ...props +}: IResolvedQueryProps) => ( + +); diff --git a/src/components/ResolvedQuery/index.ts b/src/components/ResolvedQuery/index.ts new file mode 100644 index 0000000..d805142 --- /dev/null +++ b/src/components/ResolvedQuery/index.ts @@ -0,0 +1,2 @@ +export * from './ResolvedQueries'; +export * from './ResolvedQuery'; diff --git a/src/index.ts b/src/index.ts index 1516be5..00b4d7d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,7 @@ export * from './components/StatusIcon'; export * from './components/ValidatedTextInput'; +export * from './components/ResolvedQuery'; +export * from './components/LoadingEmptyState'; export * from './hooks/useSelectionState'; export * from './hooks/useFormState'; diff --git a/src/modules/kube-client/types.ts b/src/modules/kube-client/types.ts new file mode 100644 index 0000000..45a5eef --- /dev/null +++ b/src/modules/kube-client/types.ts @@ -0,0 +1,3 @@ +import { AxiosError } from 'axios'; + +export type KubeClientError = AxiosError<{ message: string }>; diff --git a/src/queries/helpers.ts b/src/queries/helpers.ts new file mode 100644 index 0000000..1e60474 --- /dev/null +++ b/src/queries/helpers.ts @@ -0,0 +1,9 @@ +import { QueryStatus } from 'react-query'; +import { UnknownResult } from '../common/types'; + +export const getAggregateQueryStatus = (queryResults: UnknownResult[]): QueryStatus => { + if (queryResults.some((result) => result.isError)) return 'error'; + if (queryResults.some((result) => result.isLoading)) return 'loading'; + if (queryResults.every((result) => result.isIdle)) return 'idle'; + return 'success'; +}; diff --git a/yarn.lock b/yarn.lock index f06fe45..c557eca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1436,6 +1436,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.6.2": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a" + integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.10.4", "@babel/template@^7.3.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" @@ -2076,16 +2083,39 @@ tippy.js "5.1.2" tslib "1.13.0" +"@patternfly/react-core@^4.157.3": + version "4.157.3" + resolved "https://registry.yarnpkg.com/@patternfly/react-core/-/react-core-4.157.3.tgz#038c98b21ef4d7459f2120c27be4518afbcf1395" + integrity sha512-vP4/lZLTy0U4jmVP7ZO8I7EX1qSyVyFFbay01Pj1pVGHo74gP7yaUFwMvAvURGYmNeWdAhxgIBfYV8VimkSwLg== + dependencies: + "@patternfly/react-icons" "^4.11.17" + "@patternfly/react-styles" "^4.11.16" + "@patternfly/react-tokens" "^4.12.18" + focus-trap "6.2.2" + react-dropzone "9.0.0" + tippy.js "5.1.2" + tslib "^2.0.0" + "@patternfly/react-icons@^4.10.1": version "4.10.1" resolved "https://registry.yarnpkg.com/@patternfly/react-icons/-/react-icons-4.10.1.tgz#687a36a22c357e79662d8e20f93267a81a553f9b" integrity sha512-PDljCqWk+Jld8VJI0zMbigmKh0NhnSl/paXFU8cawZYt4dczbLjvj5kTMqqSOt0/DmvstcMXIvhXxL9SoYAuIA== +"@patternfly/react-icons@^4.11.17": + version "4.11.17" + resolved "https://registry.yarnpkg.com/@patternfly/react-icons/-/react-icons-4.11.17.tgz#61f27cb638f7417734dbc2c0e557760df6e28e5f" + integrity sha512-T6HriEy2SgVxlQxPL0FTHQqBYdPbaMeEiK4CzIAPQvCuCT3kRUEEGNyG+VVEvc+XU8ndSiTJdOkHaq08onFvsg== + "@patternfly/react-styles@^4.10.1": version "4.10.1" resolved "https://registry.yarnpkg.com/@patternfly/react-styles/-/react-styles-4.10.1.tgz#551353d67c01234f08e5e1e2a2947c8865751a7e" integrity sha512-nrxKeu4ftZArswT0azcZB2r6eV4d5bs4L9HrwHnElMte+6fsUmXbuaBxCVfHh/aHxZSIIxqDElEHNaOqcs7SWg== +"@patternfly/react-styles@^4.11.16": + version "4.11.16" + resolved "https://registry.yarnpkg.com/@patternfly/react-styles/-/react-styles-4.11.16.tgz#55327c57d086aadb9f0f4c0e67ab38856c3ca165" + integrity sha512-4ZFynQuJmRF7VbZeQSs44MX6MEvW7l7ZR8lMeChd8mxnQpG8pWtVUbcHdj9FFHPZVa+sPrgrZQl8QmhbqYyOsg== + "@patternfly/react-table@^4.26.6": version "4.26.6" resolved "https://registry.yarnpkg.com/@patternfly/react-table/-/react-table-4.26.6.tgz#39e7293b7ff424d98ff29beabcc1a31daff1b7e6" @@ -2103,6 +2133,11 @@ resolved "https://registry.yarnpkg.com/@patternfly/react-tokens/-/react-tokens-4.11.2.tgz#9d200883f177d1dfd0aecd832caa877bc337feb6" integrity sha512-uLEj6mUknX2vE1z79c28cY+/GBVh0SjS3T6s+bG9ZVP7rGopSgtEQDfejSIEBAwD/t0u1gHW/ncWZ1kyIeVMGg== +"@patternfly/react-tokens@^4.12.18": + version "4.12.18" + resolved "https://registry.yarnpkg.com/@patternfly/react-tokens/-/react-tokens-4.12.18.tgz#e8c75f19ecc33de180cef6cb3e9a6679c5ffeb7c" + integrity sha512-3bNUOSOMLmhxPku4fvopxt3StotaHGqHvlIDMxp9pGIgb0o02RyZ8JIioCCO1GkvPPIn6pKs/cGJDlB7zHV48Q== + "@pmmmwh/react-refresh-webpack-plugin@^0.4.3": version "0.4.3" resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.3.tgz#1eec460596d200c0236bf195b078a5d1df89b766" @@ -4368,6 +4403,11 @@ better-opn@^2.1.1: dependencies: open "^7.0.3" +big-integer@^1.6.16: + version "1.6.50" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.50.tgz#299a4be8bd441c73dcc492ed46b7169c34e92e70" + integrity sha512-+O2uoQWFRo8ysZNo/rjtri2jIwjr3XfeAgRjAUADRqGG+ZITvyn8J1kvXLTaKVr3hhGXk+f23tKfdzmklVM9vQ== + big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -4501,6 +4541,20 @@ braces@^3.0.1, 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: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" @@ -6192,6 +6246,11 @@ 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.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== + detect-port-alt@1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/detect-port-alt/-/detect-port-alt-1.1.6.tgz#24707deabe932d4a3cf621302027c2b266568275" @@ -9747,6 +9806,11 @@ js-base64@^2.1.8: resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4" integrity sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ== +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" @@ -10567,6 +10631,14 @@ marked@^2.0.0: resolved "https://registry.yarnpkg.com/marked/-/marked-2.0.3.tgz#3551c4958c4da36897bda2a16812ef1399c8d6b0" integrity sha512-5otztIIcJfPc2qGTN8cVtOJEjNJZ0jwa46INMagrYfk0EvqtRuEHLsEe0LrFS0/q+ZRKT0+kXK7P2T1AN5lWRA== +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.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -10761,6 +10833,11 @@ micromatch@^4.0.2: braces "^3.0.1" picomatch "^2.0.5" +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" @@ -10990,6 +11067,13 @@ nan@^2.12.1, nan@^2.13.2: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== +nano-time@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef" + integrity sha1-sFVPaa2J4i0JB/ehKwmTpdlhN+8= + dependencies: + big-integer "^1.6.16" + nanoclone@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/nanoclone/-/nanoclone-0.2.1.tgz#dd4090f8f1a110d26bb32c49ed2f5b9235209ed4" @@ -11676,6 +11760,11 @@ objectorarray@^1.0.4: resolved "https://registry.yarnpkg.com/objectorarray/-/objectorarray-1.0.4.tgz#d69b2f0ff7dc2701903d308bb85882f4ddb49483" integrity sha512-91k8bjcldstRz1bG6zJo8lWD7c6QXcB4nTDUqiEvIL1xAsLoZlOOZZG+nd6YPz+V7zY1580J4Xxh1vZtyv4i/w== +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== + on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -13231,6 +13320,15 @@ react-popper@^2.2.4: react-fast-compare "^3.0.1" warning "^4.0.2" +react-query@^3.26.0: + version "3.26.0" + resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.26.0.tgz#7083a8622afdf946ee6d8f3a6d94591b980c1aa0" + integrity sha512-wFPnL9Y+9xf6gJHAQ8ue+vBurciJ4cfQL4dhsI0x3YyRaEXlyklUQpJzbR63CfFULVekP3iWoyFxhaNVS9RFDw== + dependencies: + "@babel/runtime" "^7.5.5" + broadcast-channel "^3.4.1" + match-sorter "^6.0.2" + react-refresh@^0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" @@ -13662,6 +13760,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 sha1-CkPTqq4egNuRngeuJUsoXZ4ce7U= + 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" @@ -13865,6 +13968,13 @@ rgba-regex@^1.0.0: resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= +rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@^2.7.1: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -13872,13 +13982,6 @@ rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3, rimra dependencies: glob "^7.1.3" -rimraf@^3.0.0, rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" @@ -15750,6 +15853,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"