mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
chore: upgrade tanstack/react-query to 5.77.0 (#18039)
This commit is contained in:
@@ -28,7 +28,7 @@ import { DecoratorHelpers } from "@storybook/addon-themes";
|
||||
import isChromatic from "chromatic/isChromatic";
|
||||
import { StrictMode } from "react";
|
||||
import { HelmetProvider } from "react-helmet-async";
|
||||
import { QueryClient, QueryClientProvider, parseQueryArgs } from "react-query";
|
||||
import { QueryClient, QueryClientProvider } from "react-query";
|
||||
import { withRouter } from "storybook-addon-remix-react-router";
|
||||
import "theme/globalFonts";
|
||||
import themes from "../src/theme";
|
||||
@@ -114,20 +114,7 @@ function withQuery(Story, { parameters }) {
|
||||
|
||||
if (parameters.queries) {
|
||||
for (const query of parameters.queries) {
|
||||
if (query.isError) {
|
||||
// Based on `setQueryData`, but modified to set the result as an error.
|
||||
const cache = queryClient.getQueryCache();
|
||||
const parsedOptions = parseQueryArgs(query.key);
|
||||
const defaultedOptions = queryClient.defaultQueryOptions(parsedOptions);
|
||||
// Adds an uninitialized response to the cache, which we can now mutate.
|
||||
const cachedQuery = cache.build(queryClient, defaultedOptions);
|
||||
// Setting `manual` prevents retries.
|
||||
cachedQuery.setData(undefined, { manual: true });
|
||||
// Set the `error` value and the appropriate status.
|
||||
cachedQuery.setState({ error: query.data, status: "error" });
|
||||
} else {
|
||||
queryClient.setQueryData(query.key, query.data);
|
||||
}
|
||||
queryClient.setQueryData(query.key, query.data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -69,7 +69,7 @@
|
||||
"@radix-ui/react-slot": "1.1.1",
|
||||
"@radix-ui/react-switch": "1.1.1",
|
||||
"@radix-ui/react-tooltip": "1.1.7",
|
||||
"@tanstack/react-query-devtools": "4.35.3",
|
||||
"@tanstack/react-query-devtools": "5.77.0",
|
||||
"@xterm/addon-canvas": "0.7.0",
|
||||
"@xterm/addon-fit": "0.10.0",
|
||||
"@xterm/addon-unicode11": "0.8.0",
|
||||
@@ -103,7 +103,7 @@
|
||||
"react-dom": "18.3.1",
|
||||
"react-helmet-async": "2.0.5",
|
||||
"react-markdown": "9.0.3",
|
||||
"react-query": "npm:@tanstack/react-query@4.35.3",
|
||||
"react-query": "npm:@tanstack/react-query@5.77.0",
|
||||
"react-router-dom": "6.26.2",
|
||||
"react-syntax-highlighter": "15.6.1",
|
||||
"react-virtualized-auto-sizer": "1.0.24",
|
||||
|
||||
Generated
+23
-75
@@ -119,8 +119,8 @@ importers:
|
||||
specifier: 1.1.7
|
||||
version: 1.1.7(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@tanstack/react-query-devtools':
|
||||
specifier: 4.35.3
|
||||
version: 4.35.3(@tanstack/react-query@4.35.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
specifier: 5.77.0
|
||||
version: 5.77.0(@tanstack/react-query@5.77.0(react@18.3.1))(react@18.3.1)
|
||||
'@xterm/addon-canvas':
|
||||
specifier: 0.7.0
|
||||
version: 0.7.0(@xterm/xterm@5.5.0)
|
||||
@@ -221,8 +221,8 @@ importers:
|
||||
specifier: 9.0.3
|
||||
version: 9.0.3(@types/react@18.3.12)(react@18.3.1)
|
||||
react-query:
|
||||
specifier: npm:@tanstack/react-query@4.35.3
|
||||
version: '@tanstack/react-query@4.35.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)'
|
||||
specifier: npm:@tanstack/react-query@5.77.0
|
||||
version: '@tanstack/react-query@5.77.0(react@18.3.1)'
|
||||
react-router-dom:
|
||||
specifier: 6.26.2
|
||||
version: 6.26.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@@ -2398,31 +2398,22 @@ packages:
|
||||
peerDependencies:
|
||||
tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
|
||||
|
||||
'@tanstack/match-sorter-utils@8.8.4':
|
||||
resolution: {integrity: sha512-rKH8LjZiszWEvmi01NR72QWZ8m4xmXre0OOwlRGnjU01Eqz/QnN+cqpty2PJ0efHblq09+KilvyR7lsbzmXVEw==, tarball: https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.8.4.tgz}
|
||||
engines: {node: '>=12'}
|
||||
'@tanstack/query-core@5.77.0':
|
||||
resolution: {integrity: sha512-PFeWjgMQjOsnxBwnW/TJoO0pCja2dzuMQoZ3Diho7dPz7FnTUwTrjNmdf08evrhSE5nvPIKeqV6R0fvQfmhGeg==, tarball: https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.77.0.tgz}
|
||||
|
||||
'@tanstack/query-core@4.35.3':
|
||||
resolution: {integrity: sha512-PS+WEjd9wzKTyNjjQymvcOe1yg8f3wYc6mD+vb6CKyZAKvu4sIJwryfqfBULITKCla7P9C4l5e9RXePHvZOZeQ==, tarball: https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.35.3.tgz}
|
||||
'@tanstack/query-devtools@5.76.0':
|
||||
resolution: {integrity: sha512-1p92nqOBPYVqVDU0Ua5nzHenC6EGZNrLnB2OZphYw8CNA1exuvI97FVgIKON7Uug3uQqvH/QY8suUKpQo8qHNQ==, tarball: https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.76.0.tgz}
|
||||
|
||||
'@tanstack/react-query-devtools@4.35.3':
|
||||
resolution: {integrity: sha512-UvLT7qPzCuCZ3NfjwsOqDUVN84JvSOuW6ukrjZmSqgjPqVxD6ra/HUp1CEOatQY2TRvKCp8y1lTVu+trXM30fg==, tarball: https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-4.35.3.tgz}
|
||||
'@tanstack/react-query-devtools@5.77.0':
|
||||
resolution: {integrity: sha512-Dwvs+ksXiK1tW4YnTtHwYPO5+d8IUk1l8QQJ4aGEIqKz6uTLu/67NIo7EnUF0G/Edv+UOn9P1V3tYWuVfvhbmg==, tarball: https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.77.0.tgz}
|
||||
peerDependencies:
|
||||
'@tanstack/react-query': ^4.35.3
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
'@tanstack/react-query': ^5.77.0
|
||||
react: ^18 || ^19
|
||||
|
||||
'@tanstack/react-query@4.35.3':
|
||||
resolution: {integrity: sha512-UgTPioip/rGG3EQilXfA2j4BJkhEQsR+KAbF+KIuvQ7j4MkgnTCJF01SfRpIRNtQTlEfz/+IL7+jP8WA8bFbsw==, tarball: https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.35.3.tgz}
|
||||
'@tanstack/react-query@5.77.0':
|
||||
resolution: {integrity: sha512-jX52ot8WxWzWnAknpRSEWj6PTR/7nkULOfoiaVPk6nKu0otwt30UMBC9PTg/m1x0uhz1g71/imwjViTm/oYHxA==, tarball: https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.77.0.tgz}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
react-native: '*'
|
||||
peerDependenciesMeta:
|
||||
react-dom:
|
||||
optional: true
|
||||
react-native:
|
||||
optional: true
|
||||
react: ^18 || ^19
|
||||
|
||||
'@testing-library/dom@10.4.0':
|
||||
resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==, tarball: https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz}
|
||||
@@ -3258,10 +3249,6 @@ packages:
|
||||
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==, tarball: https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
copy-anything@3.0.5:
|
||||
resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==, tarball: https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz}
|
||||
engines: {node: '>=12.13'}
|
||||
|
||||
core-util-is@1.0.3:
|
||||
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==, tarball: https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz}
|
||||
|
||||
@@ -3635,6 +3622,7 @@ packages:
|
||||
eslint@8.52.0:
|
||||
resolution: {integrity: sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==, tarball: https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
|
||||
hasBin: true
|
||||
|
||||
espree@9.6.1:
|
||||
@@ -4219,10 +4207,6 @@ packages:
|
||||
is-weakset@2.0.2:
|
||||
resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==, tarball: https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz}
|
||||
|
||||
is-what@4.1.16:
|
||||
resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==, tarball: https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz}
|
||||
engines: {node: '>=12.13'}
|
||||
|
||||
is-wsl@2.2.0:
|
||||
resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==, tarball: https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz}
|
||||
engines: {node: '>=8'}
|
||||
@@ -5516,9 +5500,6 @@ packages:
|
||||
remark-stringify@11.0.0:
|
||||
resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==, tarball: https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz}
|
||||
|
||||
remove-accents@0.4.2:
|
||||
resolution: {integrity: sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==, tarball: https://registry.npmjs.org/remove-accents/-/remove-accents-0.4.2.tgz}
|
||||
|
||||
require-directory@2.1.1:
|
||||
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==, tarball: https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -5835,10 +5816,6 @@ packages:
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
hasBin: true
|
||||
|
||||
superjson@1.13.3:
|
||||
resolution: {integrity: sha512-mJiVjfd2vokfDxsQPOwJ/PtanO87LhpYY88ubI5dUB1Ab58Txbyje3+jpm+/83R/fevaq/107NNhtYBLuoTrFg==, tarball: https://registry.npmjs.org/superjson/-/superjson-1.13.3.tgz}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
supports-color@5.5.0:
|
||||
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==, tarball: https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz}
|
||||
engines: {node: '>=4'}
|
||||
@@ -6152,11 +6129,6 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
use-sync-external-store@1.2.0:
|
||||
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==, tarball: https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
|
||||
use-sync-external-store@1.4.0:
|
||||
resolution: {integrity: sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==, tarball: https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz}
|
||||
peerDependencies:
|
||||
@@ -8523,28 +8495,20 @@ snapshots:
|
||||
postcss-selector-parser: 6.0.10
|
||||
tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.3.38)(@types/node@20.17.16)(typescript@5.6.3))
|
||||
|
||||
'@tanstack/match-sorter-utils@8.8.4':
|
||||
dependencies:
|
||||
remove-accents: 0.4.2
|
||||
'@tanstack/query-core@5.77.0': {}
|
||||
|
||||
'@tanstack/query-core@4.35.3': {}
|
||||
'@tanstack/query-devtools@5.76.0': {}
|
||||
|
||||
'@tanstack/react-query-devtools@4.35.3(@tanstack/react-query@4.35.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
'@tanstack/react-query-devtools@5.77.0(@tanstack/react-query@5.77.0(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@tanstack/match-sorter-utils': 8.8.4
|
||||
'@tanstack/react-query': 4.35.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@tanstack/query-devtools': 5.76.0
|
||||
'@tanstack/react-query': 5.77.0(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
superjson: 1.13.3
|
||||
use-sync-external-store: 1.2.0(react@18.3.1)
|
||||
|
||||
'@tanstack/react-query@4.35.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
'@tanstack/react-query@5.77.0(react@18.3.1)':
|
||||
dependencies:
|
||||
'@tanstack/query-core': 4.35.3
|
||||
'@tanstack/query-core': 5.77.0
|
||||
react: 18.3.1
|
||||
use-sync-external-store: 1.2.0(react@18.3.1)
|
||||
optionalDependencies:
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
|
||||
'@testing-library/dom@10.4.0':
|
||||
dependencies:
|
||||
@@ -9447,10 +9411,6 @@ snapshots:
|
||||
|
||||
cookie@0.7.2: {}
|
||||
|
||||
copy-anything@3.0.5:
|
||||
dependencies:
|
||||
is-what: 4.1.16
|
||||
|
||||
core-util-is@1.0.3: {}
|
||||
|
||||
cosmiconfig@7.1.0:
|
||||
@@ -10542,8 +10502,6 @@ snapshots:
|
||||
call-bind: 1.0.8
|
||||
get-intrinsic: 1.3.0
|
||||
|
||||
is-what@4.1.16: {}
|
||||
|
||||
is-wsl@2.2.0:
|
||||
dependencies:
|
||||
is-docker: 2.2.1
|
||||
@@ -12425,8 +12383,6 @@ snapshots:
|
||||
mdast-util-to-markdown: 2.1.0
|
||||
unified: 11.0.5
|
||||
|
||||
remove-accents@0.4.2: {}
|
||||
|
||||
require-directory@2.1.1: {}
|
||||
|
||||
requires-port@1.0.0: {}
|
||||
@@ -12767,10 +12723,6 @@ snapshots:
|
||||
pirates: 4.0.6
|
||||
ts-interface-checker: 0.1.13
|
||||
|
||||
superjson@1.13.3:
|
||||
dependencies:
|
||||
copy-anything: 3.0.5
|
||||
|
||||
supports-color@5.5.0:
|
||||
dependencies:
|
||||
has-flag: 3.0.0
|
||||
@@ -13108,10 +13060,6 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
|
||||
use-sync-external-store@1.2.0(react@18.3.1):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
|
||||
use-sync-external-store@1.4.0(react@18.3.1):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
|
||||
@@ -5,7 +5,7 @@ export const createChat = (queryClient: QueryClient) => {
|
||||
return {
|
||||
mutationFn: API.createChat,
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(["chats"]);
|
||||
await queryClient.invalidateQueries({ queryKey: ["chats"] });
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -13,7 +13,7 @@ export const health = () => ({
|
||||
export const refreshHealth = (queryClient: QueryClient) => {
|
||||
return {
|
||||
mutationFn: async () => {
|
||||
await queryClient.cancelQueries(HEALTH_QUERY_KEY);
|
||||
await queryClient.cancelQueries({ queryKey: HEALTH_QUERY_KEY });
|
||||
const newHealthData = await API.getHealth(true);
|
||||
queryClient.setQueryData(HEALTH_QUERY_KEY, newHealthData);
|
||||
},
|
||||
@@ -38,7 +38,7 @@ export const updateHealthSettings = (
|
||||
return {
|
||||
mutationFn: API.updateHealthSettings,
|
||||
onSuccess: async (_, newSettings) => {
|
||||
await queryClient.invalidateQueries(HEALTH_QUERY_KEY);
|
||||
await queryClient.invalidateQueries({ queryKey: HEALTH_QUERY_KEY });
|
||||
queryClient.setQueryData(HEALTH_QUERY_SETTINGS_KEY, newSettings);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -37,7 +37,9 @@ export const exchangeExternalAuthDevice = (
|
||||
queryKey: ["external-auth", providerId, "device", deviceCode],
|
||||
onSuccess: async () => {
|
||||
// Force a refresh of the Git auth status.
|
||||
await queryClient.invalidateQueries(["external-auth", providerId]);
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["external-auth", providerId],
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -57,7 +59,9 @@ export const unlinkExternalAuths = (queryClient: QueryClient) => {
|
||||
return {
|
||||
mutationFn: API.unlinkExternalAuthProvider,
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(["external-auth"]);
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["external-auth"],
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -117,10 +117,12 @@ export const createGroup = (queryClient: QueryClient, organization: string) => {
|
||||
mutationFn: (request: CreateGroupRequest) =>
|
||||
API.createGroup(organization, request),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(groupsQueryKey);
|
||||
await queryClient.invalidateQueries(
|
||||
getGroupsByOrganizationQueryKey(organization),
|
||||
);
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: groupsQueryKey,
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: getGroupsByOrganizationQueryKey(organization),
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -169,11 +171,13 @@ const invalidateGroup = (
|
||||
groupId: string,
|
||||
) =>
|
||||
Promise.all([
|
||||
queryClient.invalidateQueries(groupsQueryKey),
|
||||
queryClient.invalidateQueries(
|
||||
getGroupsByOrganizationQueryKey(organization),
|
||||
),
|
||||
queryClient.invalidateQueries(getGroupQueryKey(organization, groupId)),
|
||||
queryClient.invalidateQueries({ queryKey: groupsQueryKey }),
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: getGroupsByOrganizationQueryKey(organization),
|
||||
}),
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: getGroupQueryKey(organization, groupId),
|
||||
}),
|
||||
]);
|
||||
|
||||
function sortGroupsByName<T extends Group>(
|
||||
|
||||
@@ -9,7 +9,9 @@ export const patchOrganizationSyncSettings = (queryClient: QueryClient) => {
|
||||
mutationFn: (request: OrganizationSyncSettings) =>
|
||||
API.patchOrganizationIdpSyncSettings(request),
|
||||
onSuccess: async () =>
|
||||
await queryClient.invalidateQueries(getOrganizationIdpSyncSettingsKey()),
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: getOrganizationIdpSyncSettingsKey(),
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
type WorkspacePermissions,
|
||||
workspacePermissionChecks,
|
||||
} from "modules/permissions/workspaces";
|
||||
import type { QueryClient } from "react-query";
|
||||
import type { QueryClient, UseQueryOptions } from "react-query";
|
||||
import { meKey } from "./users";
|
||||
|
||||
export const createOrganization = (queryClient: QueryClient) => {
|
||||
@@ -31,8 +31,8 @@ export const createOrganization = (queryClient: QueryClient) => {
|
||||
API.createOrganization(params),
|
||||
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(meKey);
|
||||
await queryClient.invalidateQueries(organizationsKey);
|
||||
await queryClient.invalidateQueries({ queryKey: meKey });
|
||||
await queryClient.invalidateQueries({ queryKey: organizationsKey });
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -48,7 +48,7 @@ export const updateOrganization = (queryClient: QueryClient) => {
|
||||
API.updateOrganization(variables.organizationId, variables.req),
|
||||
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(organizationsKey);
|
||||
await queryClient.invalidateQueries({ queryKey: organizationsKey });
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -59,8 +59,8 @@ export const deleteOrganization = (queryClient: QueryClient) => {
|
||||
API.deleteOrganization(organizationId),
|
||||
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(meKey);
|
||||
await queryClient.invalidateQueries(organizationsKey);
|
||||
await queryClient.invalidateQueries({ queryKey: meKey });
|
||||
await queryClient.invalidateQueries({ queryKey: organizationsKey });
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -117,7 +117,9 @@ export const addOrganizationMember = (queryClient: QueryClient, id: string) => {
|
||||
},
|
||||
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(["organization", id, "members"]);
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["organization", id, "members"],
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -132,7 +134,9 @@ export const removeOrganizationMember = (
|
||||
},
|
||||
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(["organization", id, "members"]);
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["organization", id, "members"],
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -147,11 +151,9 @@ export const updateOrganizationMemberRoles = (
|
||||
},
|
||||
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries([
|
||||
"organization",
|
||||
organizationId,
|
||||
"members",
|
||||
]);
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["organization", organizationId, "members"],
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -240,9 +242,9 @@ export const patchRoleSyncSettings = (
|
||||
mutationFn: (request: RoleSyncSettings) =>
|
||||
API.patchRoleIdpSyncSettings(request, organization),
|
||||
onSuccess: async () =>
|
||||
await queryClient.invalidateQueries(
|
||||
getRoleIdpSyncSettingsKey(organization),
|
||||
),
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: getRoleIdpSyncSettingsKey(organization),
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -269,12 +271,13 @@ export const provisionerJobs = (
|
||||
export const organizationsPermissions = (
|
||||
organizationIds: string[] | undefined,
|
||||
) => {
|
||||
if (!organizationIds) {
|
||||
return { enabled: false };
|
||||
}
|
||||
|
||||
return {
|
||||
queryKey: ["organizations", [...organizationIds.sort()], "permissions"],
|
||||
enabled: !!organizationIds,
|
||||
queryKey: [
|
||||
"organizations",
|
||||
[...(organizationIds ?? []).sort()],
|
||||
"permissions",
|
||||
],
|
||||
queryFn: async () => {
|
||||
// Only request what we need for the sidebar, which is one edit permission
|
||||
// per sub-link (settings, groups, roles, and members pages) that tells us
|
||||
@@ -283,7 +286,7 @@ export const organizationsPermissions = (
|
||||
|
||||
// The endpoint takes a flat array, so to avoid collisions prepend each
|
||||
// check with the org ID (the key can be anything we want).
|
||||
const prefixedChecks = organizationIds.flatMap((orgId) =>
|
||||
const prefixedChecks = (organizationIds ?? []).flatMap((orgId) =>
|
||||
Object.entries(organizationPermissionChecks(orgId)).map(
|
||||
([key, val]) => [`${orgId}.${key}`, val],
|
||||
),
|
||||
@@ -315,14 +318,15 @@ export const workspacePermissionsByOrganization = (
|
||||
organizationIds: string[] | undefined,
|
||||
userId: string,
|
||||
) => {
|
||||
if (!organizationIds) {
|
||||
return { enabled: false };
|
||||
}
|
||||
|
||||
return {
|
||||
queryKey: ["workspaces", [...organizationIds.sort()], "permissions"],
|
||||
enabled: !!organizationIds,
|
||||
queryKey: [
|
||||
"workspaces",
|
||||
[...(organizationIds ?? []).sort()],
|
||||
"permissions",
|
||||
],
|
||||
queryFn: async () => {
|
||||
const prefixedChecks = organizationIds.flatMap((orgId) =>
|
||||
const prefixedChecks = (organizationIds ?? []).flatMap((orgId) =>
|
||||
Object.entries(workspacePermissionChecks(orgId, userId)).map(
|
||||
([key, val]) => [`${orgId}.${key}`, val],
|
||||
),
|
||||
@@ -346,7 +350,7 @@ export const workspacePermissionsByOrganization = (
|
||||
{} as Record<string, Partial<WorkspacePermissions>>,
|
||||
) as Record<string, WorkspacePermissions>;
|
||||
},
|
||||
};
|
||||
} satisfies UseQueryOptions<Record<string, WorkspacePermissions>>;
|
||||
};
|
||||
|
||||
const getOrganizationIdpSyncClaimFieldValuesKey = (
|
||||
|
||||
@@ -33,9 +33,9 @@ export const createOrganizationRole = (
|
||||
mutationFn: (request: Role) =>
|
||||
API.createOrganizationRole(organization, request),
|
||||
onSuccess: async (updatedRole: Role) =>
|
||||
await queryClient.invalidateQueries(
|
||||
getRoleQueryKey(organization, updatedRole.name),
|
||||
),
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: getRoleQueryKey(organization, updatedRole.name),
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -47,9 +47,9 @@ export const updateOrganizationRole = (
|
||||
mutationFn: (request: Role) =>
|
||||
API.updateOrganizationRole(organization, request),
|
||||
onSuccess: async (updatedRole: Role) =>
|
||||
await queryClient.invalidateQueries(
|
||||
getRoleQueryKey(organization, updatedRole.name),
|
||||
),
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: getRoleQueryKey(organization, updatedRole.name),
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -61,8 +61,8 @@ export const deleteOrganizationRole = (
|
||||
mutationFn: (roleName: string) =>
|
||||
API.deleteOrganizationRole(organization, roleName),
|
||||
onSuccess: async (_: unknown, roleName: string) =>
|
||||
await queryClient.invalidateQueries(
|
||||
getRoleQueryKey(organization, roleName),
|
||||
),
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: getRoleQueryKey(organization, roleName),
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -11,13 +11,11 @@ const userQuietHoursScheduleKey = (userId: string) => [
|
||||
"quietHours",
|
||||
];
|
||||
|
||||
export const userQuietHoursSchedule = (
|
||||
userId: string,
|
||||
): QueryOptions<UserQuietHoursScheduleResponse> => {
|
||||
export const userQuietHoursSchedule = (userId: string) => {
|
||||
return {
|
||||
queryKey: userQuietHoursScheduleKey(userId),
|
||||
queryFn: () => API.getUserQuietHoursSchedule(userId),
|
||||
};
|
||||
} satisfies QueryOptions<UserQuietHoursScheduleResponse>;
|
||||
};
|
||||
|
||||
export const updateUserQuietHoursSchedule = (
|
||||
@@ -28,7 +26,9 @@ export const updateUserQuietHoursSchedule = (
|
||||
mutationFn: (request: UpdateUserQuietHoursScheduleRequest) =>
|
||||
API.updateUserQuietHoursSchedule(userId, request),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(userQuietHoursScheduleKey(userId));
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: userQuietHoursScheduleKey(userId),
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -15,11 +15,11 @@ import { getTemplateVersionFiles } from "utils/templateVersion";
|
||||
|
||||
const templateKey = (templateId: string) => ["template", templateId];
|
||||
|
||||
export const template = (templateId: string): QueryOptions<Template> => {
|
||||
export const template = (templateId: string) => {
|
||||
return {
|
||||
queryKey: templateKey(templateId),
|
||||
queryFn: async () => API.getTemplate(templateId),
|
||||
};
|
||||
} satisfies QueryOptions<Template>;
|
||||
};
|
||||
|
||||
export const templateByNameKey = (organization: string, name: string) => [
|
||||
@@ -28,14 +28,11 @@ export const templateByNameKey = (organization: string, name: string) => [
|
||||
name,
|
||||
];
|
||||
|
||||
export const templateByName = (
|
||||
organization: string,
|
||||
name: string,
|
||||
): QueryOptions<Template> => {
|
||||
export const templateByName = (organization: string, name: string) => {
|
||||
return {
|
||||
queryKey: templateByNameKey(organization, name),
|
||||
queryFn: async () => API.getTemplateByName(organization, name),
|
||||
};
|
||||
} satisfies QueryOptions<Template>;
|
||||
};
|
||||
|
||||
const getTemplatesQueryKey = (
|
||||
@@ -88,7 +85,9 @@ export const setUserRole = (
|
||||
},
|
||||
}),
|
||||
onSuccess: async (_res, { templateId }) => {
|
||||
await queryClient.invalidateQueries(["templateAcl", templateId]);
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["templateAcl", templateId],
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -108,7 +107,9 @@ export const setGroupRole = (
|
||||
},
|
||||
}),
|
||||
onSuccess: async (_res, { templateId }) => {
|
||||
await queryClient.invalidateQueries(["templateAcl", templateId]);
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["templateAcl", templateId],
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -197,9 +198,9 @@ export const updateActiveTemplateVersion = (
|
||||
}),
|
||||
onSuccess: async () => {
|
||||
// invalidated because of `active_version_id`
|
||||
await queryClient.invalidateQueries(
|
||||
templateByNameKey(template.organization_id, template.name),
|
||||
);
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: templateByNameKey(template.organization_id, template.name),
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -51,7 +51,7 @@ export const users = (req: UsersRequest): UseQueryOptions<GetUsersResponse> => {
|
||||
return {
|
||||
queryKey: usersKey(req),
|
||||
queryFn: ({ signal }) => API.getUsers(req, signal),
|
||||
cacheTime: 5 * 1000 * 60,
|
||||
gcTime: 5 * 1000 * 60,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -69,7 +69,7 @@ export const createUser = (queryClient: QueryClient) => {
|
||||
return {
|
||||
mutationFn: API.createUser,
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(["users"]);
|
||||
await queryClient.invalidateQueries({ queryKey: ["users"] });
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -84,7 +84,7 @@ export const suspendUser = (queryClient: QueryClient) => {
|
||||
return {
|
||||
mutationFn: API.suspendUser,
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(["users"]);
|
||||
await queryClient.invalidateQueries({ queryKey: ["users"] });
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -93,7 +93,7 @@ export const activateUser = (queryClient: QueryClient) => {
|
||||
return {
|
||||
mutationFn: API.activateUser,
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(["users"]);
|
||||
await queryClient.invalidateQueries({ queryKey: ["users"] });
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -102,7 +102,7 @@ export const deleteUser = (queryClient: QueryClient) => {
|
||||
return {
|
||||
mutationFn: API.deleteUser,
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(["users"]);
|
||||
await queryClient.invalidateQueries({ queryKey: ["users"] });
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -112,7 +112,7 @@ export const updateRoles = (queryClient: QueryClient) => {
|
||||
mutationFn: ({ userId, roles }: { userId: string; roles: string[] }) =>
|
||||
API.updateUserRoles(roles, userId),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(["users"]);
|
||||
await queryClient.invalidateQueries({ queryKey: ["users"] });
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -257,7 +257,9 @@ export const updateAppearanceSettings = (
|
||||
onSuccess: async () =>
|
||||
// Could technically invalidate more, but we only ever care about the
|
||||
// `theme_preference` for the `me` query.
|
||||
await queryClient.invalidateQueries(myAppearanceKey),
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: myAppearanceKey,
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@ import type { MetadataState, MetadataValue } from "hooks/useEmbeddedMetadata";
|
||||
import type { QueryKey, UseQueryOptions } from "react-query";
|
||||
|
||||
export const disabledRefetchOptions = {
|
||||
cacheTime: Number.POSITIVE_INFINITY,
|
||||
gcTime: Number.POSITIVE_INFINITY,
|
||||
staleTime: Number.POSITIVE_INFINITY,
|
||||
refetchOnMount: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnWindowFocus: false,
|
||||
} as const satisfies UseQueryOptions;
|
||||
} as const satisfies Partial<UseQueryOptions>;
|
||||
|
||||
type UseQueryOptionsWithMetadata<
|
||||
TMetadata extends MetadataValue = MetadataValue,
|
||||
|
||||
@@ -37,7 +37,7 @@ export const workspaceBuildsKey = (workspaceId: string) => [
|
||||
export const infiniteWorkspaceBuilds = (
|
||||
workspaceId: string,
|
||||
req?: WorkspaceBuildsRequest,
|
||||
): UseInfiniteQueryOptions<WorkspaceBuild[]> => {
|
||||
) => {
|
||||
const limit = req?.limit ?? 25;
|
||||
|
||||
return {
|
||||
@@ -48,13 +48,17 @@ export const infiniteWorkspaceBuilds = (
|
||||
}
|
||||
return pages.length + 1;
|
||||
},
|
||||
queryFn: ({ pageParam = 0 }) => {
|
||||
initialPageParam: 0,
|
||||
queryFn: ({ pageParam }) => {
|
||||
if (typeof pageParam !== "number") {
|
||||
throw new Error("pageParam must be a number");
|
||||
}
|
||||
return API.getWorkspaceBuilds(workspaceId, {
|
||||
limit,
|
||||
offset: pageParam <= 0 ? 0 : (pageParam - 1) * limit,
|
||||
});
|
||||
},
|
||||
};
|
||||
} satisfies UseInfiniteQueryOptions<WorkspaceBuild[]>;
|
||||
};
|
||||
|
||||
// We use readyAgentsCount to invalidate the query when an agent connects
|
||||
|
||||
@@ -55,7 +55,7 @@ export const createWorkspace = (queryClient: QueryClient) => {
|
||||
return API.createWorkspace(userId, req);
|
||||
},
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(["workspaces"]);
|
||||
await queryClient.invalidateQueries({ queryKey: ["workspaces"] });
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -114,7 +114,7 @@ export const autoCreateWorkspace = (queryClient: QueryClient) => {
|
||||
});
|
||||
},
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(["workspaces"]);
|
||||
await queryClient.invalidateQueries({ queryKey: ["workspaces"] });
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { SelectFilterOption } from "components/Filter/SelectFilter";
|
||||
import { useMemo, useRef, useState } from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import { keepPreviousData, useQuery } from "react-query";
|
||||
|
||||
export type UseFilterMenuOptions = {
|
||||
id: string;
|
||||
@@ -40,7 +40,7 @@ export const useFilterMenu = ({
|
||||
return getSelectedOption();
|
||||
},
|
||||
enabled,
|
||||
keepPreviousData: true,
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
const selectedOption = selectedOptionQuery.data;
|
||||
const searchOptionsQuery = useQuery({
|
||||
|
||||
@@ -29,24 +29,26 @@ export const OrganizationAutocomplete: FC<OrganizationAutocompleteProps> = ({
|
||||
}) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [selected, setSelected] = useState<Organization | null>(null);
|
||||
|
||||
const organizationsQuery = useQuery(organizations());
|
||||
const checks =
|
||||
check &&
|
||||
organizationsQuery.data &&
|
||||
Object.fromEntries(
|
||||
organizationsQuery.data.map((org) => [
|
||||
org.id,
|
||||
{
|
||||
...check,
|
||||
object: { ...check.object, organization_id: org.id },
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
const permissionsQuery = useQuery(
|
||||
check && organizationsQuery.data
|
||||
? checkAuthorization({
|
||||
checks: Object.fromEntries(
|
||||
organizationsQuery.data.map((org) => [
|
||||
org.id,
|
||||
{
|
||||
...check,
|
||||
object: { ...check.object, organization_id: org.id },
|
||||
},
|
||||
]),
|
||||
),
|
||||
})
|
||||
: { enabled: false },
|
||||
);
|
||||
const permissionsQuery = useQuery({
|
||||
...checkAuthorization({
|
||||
checks: checks ?? {},
|
||||
}),
|
||||
enabled: Boolean(check && organizationsQuery.data),
|
||||
});
|
||||
|
||||
// If an authorization check was provided, filter the organizations based on
|
||||
// the results of that check.
|
||||
|
||||
@@ -9,7 +9,7 @@ import type { PaginationResult } from "./PaginationContainer";
|
||||
|
||||
type ResultBase = Omit<
|
||||
PaginationResult,
|
||||
"isPreviousData" | "currentOffsetStart" | "totalRecords" | "totalPages"
|
||||
"isPlaceholderData" | "currentOffsetStart" | "totalRecords" | "totalPages"
|
||||
>;
|
||||
|
||||
export const mockPaginationResultBase: ResultBase = {
|
||||
@@ -27,7 +27,7 @@ export const mockPaginationResultBase: ResultBase = {
|
||||
export const mockInitialRenderResult: PaginationResult = {
|
||||
...mockPaginationResultBase,
|
||||
isSuccess: false,
|
||||
isPreviousData: false,
|
||||
isPlaceholderData: false,
|
||||
currentOffsetStart: undefined,
|
||||
hasNextPage: false,
|
||||
hasPreviousPage: false,
|
||||
@@ -38,7 +38,7 @@ export const mockInitialRenderResult: PaginationResult = {
|
||||
export const mockSuccessResult: PaginationResult = {
|
||||
...mockPaginationResultBase,
|
||||
isSuccess: true,
|
||||
isPreviousData: false,
|
||||
isPlaceholderData: false,
|
||||
currentOffsetStart: 1,
|
||||
totalPages: 1,
|
||||
totalRecords: 4,
|
||||
|
||||
@@ -49,7 +49,7 @@ export const FirstPageWithData: Story = {
|
||||
totalPages: 4,
|
||||
hasPreviousPage: false,
|
||||
hasNextPage: true,
|
||||
isPreviousData: false,
|
||||
isPlaceholderData: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -65,7 +65,7 @@ export const FirstPageWithLittleData: Story = {
|
||||
totalPages: 1,
|
||||
hasPreviousPage: false,
|
||||
hasNextPage: false,
|
||||
isPreviousData: false,
|
||||
isPlaceholderData: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -81,7 +81,7 @@ export const FirstPageWithNoData: Story = {
|
||||
totalPages: 0,
|
||||
hasPreviousPage: false,
|
||||
hasNextPage: false,
|
||||
isPreviousData: false,
|
||||
isPlaceholderData: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -97,7 +97,7 @@ export const TransitionFromFirstToSecondPage: Story = {
|
||||
totalPages: 4,
|
||||
hasPreviousPage: false,
|
||||
hasNextPage: false,
|
||||
isPreviousData: true,
|
||||
isPlaceholderData: true,
|
||||
},
|
||||
children: <div>Previous data from page 1</div>,
|
||||
},
|
||||
@@ -114,7 +114,7 @@ export const SecondPageWithData: Story = {
|
||||
totalPages: 4,
|
||||
hasPreviousPage: true,
|
||||
hasNextPage: true,
|
||||
isPreviousData: false,
|
||||
isPlaceholderData: false,
|
||||
},
|
||||
children: <div>New data for page 2</div>,
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@ import { PaginationHeader } from "./PaginationHeader";
|
||||
import { PaginationWidgetBase } from "./PaginationWidgetBase";
|
||||
|
||||
export type PaginationResult = PaginationResultInfo & {
|
||||
isPreviousData: boolean;
|
||||
isPlaceholderData: boolean;
|
||||
};
|
||||
|
||||
type PaginationProps = HTMLAttributes<HTMLDivElement> & {
|
||||
|
||||
@@ -2,7 +2,7 @@ import TextField, { type TextFieldProps } from "@mui/material/TextField";
|
||||
import { API } from "api/api";
|
||||
import { useDebouncedValue } from "hooks/debounce";
|
||||
import type { FC } from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import { keepPreviousData, useQuery } from "react-query";
|
||||
|
||||
// TODO: @BrunoQuaresma: Unable to integrate Yup + Formik for validation. The
|
||||
// validation was triggering on the onChange event, but the form.errors were not
|
||||
@@ -19,7 +19,7 @@ export const PasswordField: FC<TextFieldProps> = (props) => {
|
||||
const validatePasswordQuery = useQuery({
|
||||
queryKey: ["validatePassword", debouncedValue],
|
||||
queryFn: () => API.validateUserPassword(debouncedValue),
|
||||
keepPreviousData: true,
|
||||
placeholderData: keepPreviousData,
|
||||
enabled: debouncedValue.length > 0,
|
||||
});
|
||||
const valid = validatePasswordQuery.data?.valid ?? true;
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
type FC,
|
||||
useState,
|
||||
} from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import { keepPreviousData, useQuery } from "react-query";
|
||||
import { prepareQuery } from "utils/filters";
|
||||
|
||||
// The common properties between users and org members that we need.
|
||||
@@ -45,7 +45,7 @@ export const UserAutocomplete: FC<UserAutocompleteProps> = (props) => {
|
||||
limit: 25,
|
||||
}),
|
||||
enabled: filter !== undefined,
|
||||
keepPreviousData: true,
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
return (
|
||||
<InnerAutocomplete<User>
|
||||
@@ -72,7 +72,7 @@ export const MemberAutocomplete: FC<MemberAutocompleteProps> = ({
|
||||
const membersQuery = useQuery({
|
||||
...organizationMembers(organizationId),
|
||||
enabled: filter !== undefined,
|
||||
keepPreviousData: true,
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
return (
|
||||
<InnerAutocomplete<OrganizationMemberWithUserData>
|
||||
|
||||
@@ -72,7 +72,7 @@ export const AuthProvider: FC<PropsWithChildren> = ({ children }) => {
|
||||
userQuery.isError &&
|
||||
isApiError(userQuery.error) &&
|
||||
userQuery.error.response.status === 401;
|
||||
const isSigningOut = logoutMutation.isLoading;
|
||||
const isSigningOut = logoutMutation.isPending;
|
||||
const isLoading =
|
||||
userQuery.isLoading ||
|
||||
hasFirstUserQuery.isLoading ||
|
||||
@@ -80,8 +80,8 @@ export const AuthProvider: FC<PropsWithChildren> = ({ children }) => {
|
||||
const isConfiguringTheFirstUser =
|
||||
!hasFirstUserQuery.isLoading && !hasFirstUserQuery.data;
|
||||
const isSignedIn = userQuery.isSuccess && userQuery.data !== undefined;
|
||||
const isSigningIn = loginMutation.isLoading;
|
||||
const isUpdatingProfile = updateProfileMutation.isLoading;
|
||||
const isSigningIn = loginMutation.isPending;
|
||||
const isUpdatingProfile = updateProfileMutation.isPending;
|
||||
|
||||
const signOut = useCallback(() => {
|
||||
logoutMutation.mutate();
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
type QueryKey,
|
||||
type UseQueryOptions,
|
||||
type UseQueryResult,
|
||||
keepPreviousData,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
} from "react-query";
|
||||
@@ -140,7 +141,7 @@ export function usePaginatedQuery<
|
||||
const query = useQuery<TQueryFnData, TError, TData, TQueryKey>({
|
||||
...extraOptions,
|
||||
...getQueryOptionsFromPage(currentPage),
|
||||
keepPreviousData: true,
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
|
||||
const totalRecords = query.data?.count;
|
||||
|
||||
@@ -47,7 +47,7 @@ export const NotificationsInbox: FC<NotificationsInboxProps> = ({
|
||||
res: ListInboxNotificationsResponse,
|
||||
) => ListInboxNotificationsResponse,
|
||||
) => {
|
||||
await queryClient.cancelQueries(NOTIFICATIONS_QUERY_KEY);
|
||||
await queryClient.cancelQueries({ queryKey: NOTIFICATIONS_QUERY_KEY });
|
||||
queryClient.setQueryData<ListInboxNotificationsResponse>(
|
||||
NOTIFICATIONS_QUERY_KEY,
|
||||
(prev) => {
|
||||
@@ -90,7 +90,7 @@ export const NotificationsInbox: FC<NotificationsInboxProps> = ({
|
||||
|
||||
const {
|
||||
mutate: loadMoreNotifications,
|
||||
isLoading: isLoadingMoreNotifications,
|
||||
isPending: isLoadingMoreNotifications,
|
||||
} = useMutation({
|
||||
mutationFn: async () => {
|
||||
if (!inboxRes || inboxRes.notifications.length === 0) {
|
||||
|
||||
@@ -157,8 +157,8 @@ export const AgentRow: FC<AgentRowProps> = ({
|
||||
select: (res) => res.containers.filter((c) => c.status === "running"),
|
||||
// TODO: Implement a websocket connection to get updates on containers
|
||||
// without having to poll.
|
||||
refetchInterval: (_, query) => {
|
||||
const { error } = query.state;
|
||||
refetchInterval: ({ state }) => {
|
||||
const { error } = state;
|
||||
return isAxiosError(error) && error.response?.status === 403
|
||||
? false
|
||||
: 10_000;
|
||||
|
||||
@@ -152,7 +152,7 @@ export const PortForwardPopoverView: FC<PortForwardPopoverViewProps> = ({
|
||||
// share port form
|
||||
const {
|
||||
mutateAsync: upsertWorkspacePortShareForm,
|
||||
isLoading: isSubmitting,
|
||||
isPending: isSubmitting,
|
||||
error: submitError,
|
||||
} = useMutation(upsertWorkspacePortShare(workspaceID));
|
||||
const validationSchema = getValidationSchema();
|
||||
|
||||
@@ -34,11 +34,10 @@ function getDuplicationUrlParams(
|
||||
export function useWorkspaceDuplication(workspace?: Workspace) {
|
||||
const navigate = useNavigate();
|
||||
const getLink = useLinks();
|
||||
const buildParametersQuery = useQuery(
|
||||
workspace !== undefined
|
||||
? workspaceBuildParameters(workspace.latest_build.id)
|
||||
: { enabled: false },
|
||||
);
|
||||
const buildParametersQuery = useQuery({
|
||||
...workspaceBuildParameters(workspace?.latest_build.id ?? ""),
|
||||
enabled: !!workspace,
|
||||
});
|
||||
|
||||
// Not using useEffectEvent for this, because useEffect isn't really an
|
||||
// intended use case for this custom hook
|
||||
|
||||
@@ -58,7 +58,7 @@ export const useWorkspaceUpdate = ({
|
||||
|
||||
return {
|
||||
update,
|
||||
isUpdating: updateWorkspaceMutation.isLoading,
|
||||
isUpdating: updateWorkspaceMutation.isPending,
|
||||
dialogs: {
|
||||
updateConfirmation: {
|
||||
open: isConfirmingUpdate,
|
||||
|
||||
@@ -170,7 +170,7 @@ export const ChatLayout: FC = () => {
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleNewChat}
|
||||
disabled={createChatMutation.isLoading}
|
||||
disabled={createChatMutation.isPending}
|
||||
>
|
||||
<PlusIcon />
|
||||
New Chat
|
||||
|
||||
@@ -221,14 +221,10 @@ export const CreateTemplateForm: FC<CreateTemplateFormProps> = (props) => {
|
||||
});
|
||||
const getFieldHelpers = getFormHelpers<CreateTemplateFormData>(form, error);
|
||||
|
||||
const { data: provisioners } = useQuery(
|
||||
selectedOrg
|
||||
? {
|
||||
...provisionerDaemons(selectedOrg.id),
|
||||
enabled: showOrganizationPicker,
|
||||
}
|
||||
: { enabled: false },
|
||||
);
|
||||
const { data: provisioners } = useQuery({
|
||||
...provisionerDaemons(selectedOrg?.id ?? ""),
|
||||
enabled: showOrganizationPicker && !!selectedOrg,
|
||||
});
|
||||
|
||||
// TODO: Ideally, we would have a backend endpoint that could notify the
|
||||
// frontend that a provisioner has been connected, so that we could hide
|
||||
|
||||
@@ -40,7 +40,7 @@ const CreateTemplatePage: FC = () => {
|
||||
},
|
||||
onOpenBuildLogsDrawer: () => setIsBuildLogsOpen(true),
|
||||
error: createTemplateMutation.error,
|
||||
isCreating: createTemplateMutation.isLoading,
|
||||
isCreating: createTemplateMutation.isPending,
|
||||
variablesSectionRef,
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
templateVersionLogs,
|
||||
templateVersionVariables,
|
||||
} from "api/queries/templates";
|
||||
import type { Template, TemplateVersion } from "api/typesGenerated";
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
import { useDashboard } from "modules/dashboard/useDashboard";
|
||||
@@ -25,7 +26,9 @@ export const DuplicateTemplateView: FC<CreateTemplatePageViewProps> = ({
|
||||
const navigate = useNavigate();
|
||||
const { entitlements } = useDashboard();
|
||||
const [searchParams] = useSearchParams();
|
||||
const templateQuery = useQuery(template(searchParams.get("fromTemplate")!));
|
||||
const templateQuery = useQuery(
|
||||
template(searchParams.get("fromTemplate") as string),
|
||||
);
|
||||
const activeVersionId = templateQuery.data?.active_version_id ?? "";
|
||||
const templateVersionQuery = useQuery({
|
||||
...templateVersion(activeVersionId),
|
||||
@@ -65,7 +68,7 @@ export const DuplicateTemplateView: FC<CreateTemplatePageViewProps> = ({
|
||||
{...formPermissions}
|
||||
variablesSectionRef={variablesSectionRef}
|
||||
onOpenBuildLogsDrawer={onOpenBuildLogsDrawer}
|
||||
copiedTemplate={templateQuery.data!}
|
||||
copiedTemplate={templateQuery.data as Template}
|
||||
error={error}
|
||||
isSubmitting={isCreating}
|
||||
variables={templateVersionVariablesQuery.data}
|
||||
@@ -74,9 +77,9 @@ export const DuplicateTemplateView: FC<CreateTemplatePageViewProps> = ({
|
||||
logs={templateVersionLogsQuery.data}
|
||||
onSubmit={async (formData) => {
|
||||
await onCreateTemplate({
|
||||
organization: templateQuery.data!.organization_name,
|
||||
organization: (templateQuery.data as Template).organization_name,
|
||||
version: firstVersionFromFile(
|
||||
templateVersionQuery.data!.job.file_id,
|
||||
(templateVersionQuery.data as TemplateVersion).job.file_id,
|
||||
formData.user_variable_values,
|
||||
formData.provisioner_type,
|
||||
formData.tags,
|
||||
|
||||
@@ -8,7 +8,7 @@ import { ErrorAlert } from "components/Alert/ErrorAlert";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
import { useDashboard } from "modules/dashboard/useDashboard";
|
||||
import type { FC } from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import { keepPreviousData, useQuery } from "react-query";
|
||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||
import { CreateTemplateForm } from "./CreateTemplateForm";
|
||||
import type { CreateTemplatePageViewProps } from "./types";
|
||||
@@ -46,7 +46,7 @@ export const ImportStarterTemplateView: FC<CreateTemplatePageViewProps> = ({
|
||||
|
||||
const missedVariables = useQuery({
|
||||
...templateVersionVariables(isJobError ? error.version.id : ""),
|
||||
keepPreviousData: true,
|
||||
placeholderData: keepPreviousData,
|
||||
enabled:
|
||||
isJobError && error.job.error_code === "REQUIRED_TEMPLATE_VARIABLES",
|
||||
});
|
||||
|
||||
@@ -60,7 +60,7 @@ export const UploadTemplateView: FC<CreateTemplatePageViewProps> = ({
|
||||
uploadFileMutation.reset();
|
||||
}
|
||||
},
|
||||
isUploading: uploadFileMutation.isLoading,
|
||||
isUploading: uploadFileMutation.isPending,
|
||||
onRemove: uploadFileMutation.reset,
|
||||
file: uploadFileMutation.variables,
|
||||
}}
|
||||
|
||||
@@ -24,11 +24,11 @@ const CreateTokenPage: FC = () => {
|
||||
|
||||
const {
|
||||
mutate: saveToken,
|
||||
isLoading: isCreating,
|
||||
isPending: isCreating,
|
||||
isError: creationFailed,
|
||||
isSuccess: creationSuccessful,
|
||||
data: newToken,
|
||||
} = useMutation(API.createToken);
|
||||
} = useMutation({ mutationFn: API.createToken });
|
||||
const {
|
||||
data: tokenConfig,
|
||||
isLoading: fetchingTokenConfig,
|
||||
|
||||
@@ -28,7 +28,7 @@ const CreateUserPage: FC = () => {
|
||||
|
||||
<CreateUserForm
|
||||
error={createUserMutation.error}
|
||||
isLoading={createUserMutation.isLoading}
|
||||
isLoading={createUserMutation.isPending}
|
||||
onSubmit={async (user) => {
|
||||
await createUserMutation.mutateAsync({
|
||||
username: user.username,
|
||||
|
||||
@@ -15,44 +15,33 @@ const CreateWorkspaceExperimentRouter: FC = () => {
|
||||
|
||||
const { organization: organizationName = "default", template: templateName } =
|
||||
useParams() as { organization?: string; template: string };
|
||||
const templateQuery = useQuery(
|
||||
dynamicParametersEnabled
|
||||
? templateByName(organizationName, templateName)
|
||||
: { enabled: false },
|
||||
);
|
||||
const templateQuery = useQuery({
|
||||
...templateByName(organizationName, templateName),
|
||||
enabled: dynamicParametersEnabled,
|
||||
});
|
||||
|
||||
const optOutQuery = useQuery(
|
||||
templateQuery.data
|
||||
? {
|
||||
queryKey: [
|
||||
organizationName,
|
||||
"template",
|
||||
templateQuery.data.id,
|
||||
"optOut",
|
||||
],
|
||||
queryFn: () => {
|
||||
const templateId = templateQuery.data.id;
|
||||
const localStorageKey = optOutKey(templateId);
|
||||
const storedOptOutString = localStorage.getItem(localStorageKey);
|
||||
const optOutQuery = useQuery({
|
||||
enabled: !!templateQuery.data,
|
||||
queryKey: [organizationName, "template", templateQuery.data?.id, "optOut"],
|
||||
queryFn: () => {
|
||||
const templateId = templateQuery.data?.id;
|
||||
const localStorageKey = optOutKey(templateId ?? "");
|
||||
const storedOptOutString = localStorage.getItem(localStorageKey);
|
||||
|
||||
let optOutResult: boolean;
|
||||
let optOutResult: boolean;
|
||||
|
||||
if (storedOptOutString !== null) {
|
||||
optOutResult = storedOptOutString === "true";
|
||||
} else {
|
||||
optOutResult = Boolean(
|
||||
templateQuery.data.use_classic_parameter_flow,
|
||||
);
|
||||
}
|
||||
if (storedOptOutString !== null) {
|
||||
optOutResult = storedOptOutString === "true";
|
||||
} else {
|
||||
optOutResult = !!templateQuery.data?.use_classic_parameter_flow;
|
||||
}
|
||||
|
||||
return {
|
||||
templateId: templateId,
|
||||
optedOut: optOutResult,
|
||||
};
|
||||
},
|
||||
}
|
||||
: { enabled: false },
|
||||
);
|
||||
return {
|
||||
templateId: templateId,
|
||||
optedOut: optOutResult,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
if (dynamicParametersEnabled) {
|
||||
if (optOutQuery.isLoading) {
|
||||
@@ -63,7 +52,7 @@ const CreateWorkspaceExperimentRouter: FC = () => {
|
||||
}
|
||||
|
||||
const toggleOptedOut = () => {
|
||||
const key = optOutKey(optOutQuery.data.templateId);
|
||||
const key = optOutKey(optOutQuery.data?.templateId ?? "");
|
||||
const storedValue = localStorage.getItem(key);
|
||||
|
||||
const current = storedValue
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
} from "api/queries/templates";
|
||||
import { autoCreateWorkspace, createWorkspace } from "api/queries/workspaces";
|
||||
import type {
|
||||
Template,
|
||||
TemplateVersionParameter,
|
||||
UserParameter,
|
||||
Workspace,
|
||||
@@ -62,15 +63,14 @@ const CreateWorkspacePage: FC = () => {
|
||||
);
|
||||
const templateVersionPresetsQuery = useQuery({
|
||||
...templateVersionPresets(templateQuery.data?.active_version_id ?? ""),
|
||||
enabled: templateQuery.data !== undefined,
|
||||
enabled: !!templateQuery.data,
|
||||
});
|
||||
const permissionsQuery = useQuery({
|
||||
...checkAuthorization({
|
||||
checks: createWorkspaceChecks(templateQuery.data?.organization_id ?? ""),
|
||||
}),
|
||||
enabled: !!templateQuery.data,
|
||||
});
|
||||
const permissionsQuery = useQuery(
|
||||
templateQuery.data
|
||||
? checkAuthorization({
|
||||
checks: createWorkspaceChecks(templateQuery.data.organization_id),
|
||||
})
|
||||
: { enabled: false },
|
||||
);
|
||||
const realizedVersionId =
|
||||
customVersionId ?? templateQuery.data?.active_version_id;
|
||||
const organizationId = templateQuery.data?.organization_id;
|
||||
@@ -96,7 +96,7 @@ const CreateWorkspacePage: FC = () => {
|
||||
const loadFormDataError =
|
||||
templateQuery.error ?? permissionsQuery.error ?? richParametersQuery.error;
|
||||
|
||||
const title = autoCreateWorkspaceMutation.isLoading
|
||||
const title = autoCreateWorkspaceMutation.isPending
|
||||
? "Creating workspace..."
|
||||
: "Create workspace";
|
||||
|
||||
@@ -111,7 +111,7 @@ const CreateWorkspacePage: FC = () => {
|
||||
const autofillEnabled = experiments.includes("auto-fill-parameters");
|
||||
const userParametersQuery = useQuery({
|
||||
queryKey: ["userParameters"],
|
||||
queryFn: () => API.getUserParameters(templateQuery.data!.id),
|
||||
queryFn: () => API.getUserParameters(templateQuery.data?.id ?? ""),
|
||||
enabled: autofillEnabled && templateQuery.isSuccess,
|
||||
});
|
||||
const autofillParameters = getAutofillParameters(
|
||||
@@ -203,7 +203,7 @@ const CreateWorkspacePage: FC = () => {
|
||||
autoCreateWorkspaceMutation.error
|
||||
}
|
||||
resetMutation={createWorkspaceMutation.reset}
|
||||
template={templateQuery.data!}
|
||||
template={templateQuery.data as Template}
|
||||
versionId={realizedVersionId}
|
||||
externalAuth={externalAuth ?? []}
|
||||
externalAuthPollingState={externalAuthPollingState}
|
||||
@@ -212,7 +212,7 @@ const CreateWorkspacePage: FC = () => {
|
||||
permissions={permissionsQuery.data as CreateWorkspacePermissions}
|
||||
parameters={realizedParameters as TemplateVersionParameter[]}
|
||||
presets={templateVersionPresetsQuery.data ?? []}
|
||||
creatingWorkspace={createWorkspaceMutation.isLoading}
|
||||
creatingWorkspace={createWorkspaceMutation.isPending}
|
||||
onCancel={() => {
|
||||
navigate(-1);
|
||||
}}
|
||||
@@ -245,15 +245,11 @@ const useExternalAuth = (versionId: string | undefined) => {
|
||||
setExternalAuthPollingState("polling");
|
||||
}, []);
|
||||
|
||||
const { data: externalAuth, isLoading: isLoadingExternalAuth } = useQuery(
|
||||
versionId
|
||||
? {
|
||||
...templateVersionExternalAuth(versionId),
|
||||
refetchInterval:
|
||||
externalAuthPollingState === "polling" ? 1000 : false,
|
||||
}
|
||||
: { enabled: false },
|
||||
);
|
||||
const { data: externalAuth, isPending: isLoadingExternalAuth } = useQuery({
|
||||
...templateVersionExternalAuth(versionId ?? ""),
|
||||
enabled: !!versionId,
|
||||
refetchInterval: externalAuthPollingState === "polling" ? 1000 : false,
|
||||
});
|
||||
|
||||
const allSignedIn = externalAuth?.every((it) => it.authenticated);
|
||||
|
||||
|
||||
@@ -73,18 +73,16 @@ const CreateWorkspacePageExperimental: FC = () => {
|
||||
const templateQuery = useQuery(
|
||||
templateByName(organizationName, templateName),
|
||||
);
|
||||
const templateVersionPresetsQuery = useQuery(
|
||||
templateQuery.data
|
||||
? templateVersionPresets(templateQuery.data.active_version_id)
|
||||
: { enabled: false },
|
||||
);
|
||||
const permissionsQuery = useQuery(
|
||||
templateQuery.data
|
||||
? checkAuthorization({
|
||||
checks: createWorkspaceChecks(templateQuery.data.organization_id),
|
||||
})
|
||||
: { enabled: false },
|
||||
);
|
||||
const templateVersionPresetsQuery = useQuery({
|
||||
...templateVersionPresets(templateQuery.data?.active_version_id ?? ""),
|
||||
enabled: !!templateQuery.data,
|
||||
});
|
||||
const permissionsQuery = useQuery({
|
||||
...checkAuthorization({
|
||||
checks: createWorkspaceChecks(templateQuery.data?.organization_id ?? ""),
|
||||
}),
|
||||
enabled: !!templateQuery.data,
|
||||
});
|
||||
const realizedVersionId =
|
||||
customVersionId ?? templateQuery.data?.active_version_id;
|
||||
|
||||
@@ -192,7 +190,7 @@ const CreateWorkspacePageExperimental: FC = () => {
|
||||
permissionsQuery.isLoading;
|
||||
const loadFormDataError = templateQuery.error ?? permissionsQuery.error;
|
||||
|
||||
const title = autoCreateWorkspaceMutation.isLoading
|
||||
const title = autoCreateWorkspaceMutation.isPending
|
||||
? "Creating workspace..."
|
||||
: "Create workspace";
|
||||
|
||||
@@ -308,7 +306,7 @@ const CreateWorkspacePageExperimental: FC = () => {
|
||||
permissions={permissionsQuery.data as CreateWorkspacePermissions}
|
||||
parameters={sortedParams}
|
||||
presets={templateVersionPresetsQuery.data ?? []}
|
||||
creatingWorkspace={createWorkspaceMutation.isLoading}
|
||||
creatingWorkspace={createWorkspaceMutation.isPending}
|
||||
sendMessage={sendMessage}
|
||||
onCancel={() => {
|
||||
navigate(-1);
|
||||
@@ -344,15 +342,11 @@ const useExternalAuth = (versionId: string | undefined) => {
|
||||
setExternalAuthPollingState("polling");
|
||||
}, []);
|
||||
|
||||
const { data: externalAuth, isLoading: isLoadingExternalAuth } = useQuery(
|
||||
versionId
|
||||
? {
|
||||
...templateVersionExternalAuth(versionId),
|
||||
refetchInterval:
|
||||
externalAuthPollingState === "polling" ? 1000 : false,
|
||||
}
|
||||
: { enabled: false },
|
||||
);
|
||||
const { data: externalAuth, isLoading: isLoadingExternalAuth } = useQuery({
|
||||
...templateVersionExternalAuth(versionId ?? ""),
|
||||
enabled: !!versionId,
|
||||
refetchInterval: externalAuthPollingState === "polling" ? 1000 : false,
|
||||
});
|
||||
|
||||
const allSignedIn = externalAuth?.every((it) => it.authenticated);
|
||||
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ const AppearanceSettingsPage: FC = () => {
|
||||
|
||||
try {
|
||||
await updateAppearanceMutation.mutateAsync(newAppearance);
|
||||
await queryClient.invalidateQueries(appearanceConfigKey);
|
||||
await queryClient.invalidateQueries({ queryKey: appearanceConfigKey });
|
||||
displaySuccess("Successfully updated appearance settings!");
|
||||
} catch (error) {
|
||||
displayError(
|
||||
|
||||
@@ -36,9 +36,10 @@ const IdpOrgSyncPage: FC = () => {
|
||||
setField(settingsQuery.data.field);
|
||||
}, [settingsQuery.data]);
|
||||
|
||||
const fieldValuesQuery = useQuery(
|
||||
field ? deploymentIdpSyncFieldValues(field) : { enabled: false },
|
||||
);
|
||||
const fieldValuesQuery = useQuery({
|
||||
...deploymentIdpSyncFieldValues(field),
|
||||
enabled: !!field,
|
||||
});
|
||||
|
||||
const patchOrganizationSyncSettingsMutation = useMutation(
|
||||
patchOrganizationSyncSettings(queryClient),
|
||||
|
||||
@@ -12,9 +12,10 @@ const AddNewLicensePage: FC = () => {
|
||||
|
||||
const {
|
||||
mutate: saveLicenseKeyApi,
|
||||
isLoading: isCreating,
|
||||
isPending: isCreating,
|
||||
error: savingLicenseError,
|
||||
} = useMutation(API.createLicense, {
|
||||
} = useMutation({
|
||||
mutationFn: API.createLicense,
|
||||
onSuccess: () => {
|
||||
displaySuccess("You have successfully added a license");
|
||||
navigate("/deployment/licenses?success=true");
|
||||
|
||||
@@ -37,11 +37,12 @@ const LicensesSettingsPage: FC = () => {
|
||||
}
|
||||
}, [entitlementsQuery.error]);
|
||||
|
||||
const { mutate: removeLicenseApi, isLoading: isRemovingLicense } =
|
||||
useMutation(API.removeLicense, {
|
||||
const { mutate: removeLicenseApi, isPending: isRemovingLicense } =
|
||||
useMutation({
|
||||
mutationFn: API.removeLicense,
|
||||
onSuccess: () => {
|
||||
displaySuccess("Successfully removed license");
|
||||
void queryClient.invalidateQueries(["licenses"]);
|
||||
void queryClient.invalidateQueries({ queryKey: ["licenses"] });
|
||||
},
|
||||
onError: () => {
|
||||
displayError("Failed to remove license");
|
||||
@@ -77,7 +78,7 @@ const LicensesSettingsPage: FC = () => {
|
||||
<LicensesSettingsPageView
|
||||
showConfetti={confettiOn}
|
||||
isLoading={isLoading}
|
||||
isRefreshing={refreshEntitlementsMutation.isLoading}
|
||||
isRefreshing={refreshEntitlementsMutation.isPending}
|
||||
userLimitActual={entitlementsQuery.data?.features.user_limit.actual}
|
||||
userLimitLimit={entitlementsQuery.data?.features.user_limit.limit}
|
||||
licenses={licenses}
|
||||
|
||||
@@ -7,13 +7,11 @@ import type { FC } from "react";
|
||||
import { useMutation } from "react-query";
|
||||
|
||||
export const Troubleshooting: FC = () => {
|
||||
const { mutate: sendTestNotificationApi, isLoading } = useMutation(
|
||||
API.postTestNotification,
|
||||
{
|
||||
onSuccess: () => displaySuccess("Test notification sent"),
|
||||
onError: () => displayError("Failed to send test notification"),
|
||||
},
|
||||
);
|
||||
const { mutate: sendTestNotificationApi, isPending } = useMutation({
|
||||
mutationFn: API.postTestNotification,
|
||||
onSuccess: () => displaySuccess("Test notification sent"),
|
||||
onError: () => displayError("Failed to send test notification"),
|
||||
});
|
||||
|
||||
const theme = useTheme();
|
||||
return (
|
||||
@@ -33,12 +31,12 @@ export const Troubleshooting: FC = () => {
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={isLoading}
|
||||
disabled={isPending}
|
||||
onClick={() => {
|
||||
sendTestNotificationApi();
|
||||
}}
|
||||
>
|
||||
<Spinner loading={isLoading} />
|
||||
<Spinner loading={isPending} />
|
||||
Send notification
|
||||
</Button>
|
||||
</span>
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ const CreateOAuth2AppPage: FC = () => {
|
||||
</Helmet>
|
||||
|
||||
<CreateOAuth2AppPageView
|
||||
isUpdating={postAppMutation.isLoading}
|
||||
isUpdating={postAppMutation.isPending}
|
||||
error={postAppMutation.error}
|
||||
createApp={async (req) => {
|
||||
try {
|
||||
|
||||
@@ -39,10 +39,10 @@ const EditOAuth2AppPage: FC = () => {
|
||||
isLoadingApp={appQuery.isLoading}
|
||||
isLoadingSecrets={secretsQuery.isLoading}
|
||||
mutatingResource={{
|
||||
updateApp: putAppMutation.isLoading,
|
||||
deleteApp: deleteAppMutation.isLoading,
|
||||
createSecret: postSecretMutation.isLoading,
|
||||
deleteSecret: deleteSecretMutation.isLoading,
|
||||
updateApp: putAppMutation.isPending,
|
||||
deleteApp: deleteAppMutation.isPending,
|
||||
createSecret: postSecretMutation.isPending,
|
||||
deleteSecret: deleteSecretMutation.isPending,
|
||||
}}
|
||||
fullNewSecret={fullNewSecret}
|
||||
ackFullNewSecret={() => setFullNewSecret(undefined)}
|
||||
|
||||
@@ -29,7 +29,7 @@ const CreateGroupPage: FC = () => {
|
||||
);
|
||||
}}
|
||||
error={createGroupMutation.error}
|
||||
isLoading={createGroupMutation.isLoading}
|
||||
isLoading={createGroupMutation.isPending}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { userEvent, within } from "@storybook/test";
|
||||
import { spyOn, userEvent, within } from "@storybook/test";
|
||||
import { API } from "api/api";
|
||||
import { getGroupQueryKey, groupPermissionsKey } from "api/queries/groups";
|
||||
import { organizationMembersKey } from "api/queries/organizations";
|
||||
import { reactRouterParameters } from "storybook-addon-remix-react-router";
|
||||
@@ -52,11 +53,9 @@ export const LoadingGroup: Story = {
|
||||
};
|
||||
|
||||
export const GroupError: Story = {
|
||||
parameters: {
|
||||
queries: [
|
||||
{ ...groupQuery(new Error("test group error")), isError: true },
|
||||
permissionsQuery({}),
|
||||
],
|
||||
beforeEach: () => {
|
||||
spyOn(API, "getGroup").mockRejectedValue(new Error("test group error"));
|
||||
spyOn(API, "checkAuthorization").mockResolvedValue({});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -89,16 +88,19 @@ export const EveryoneGroup: Story = {
|
||||
};
|
||||
|
||||
export const MembersError: Story = {
|
||||
parameters: {
|
||||
queries: [
|
||||
groupQuery(MockGroup),
|
||||
permissionsQuery({ canUpdateGroup: true }),
|
||||
{ ...membersQuery(new Error("test members error")), isError: true },
|
||||
],
|
||||
beforeEach() {
|
||||
spyOn(API, "getGroup").mockResolvedValue(MockGroup);
|
||||
spyOn(API, "checkAuthorization").mockResolvedValue({
|
||||
canUpdateGroup: true,
|
||||
});
|
||||
spyOn(API, "getOrganizationPaginatedMembers").mockRejectedValue(
|
||||
new Error("test members error"),
|
||||
);
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await userEvent.click(canvas.getByRole("button", { name: "Open" }));
|
||||
const combobox = await canvas.findByRole("combobox");
|
||||
await userEvent.click(combobox);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -115,7 +117,8 @@ export const NoMembers: Story = {
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await userEvent.click(canvas.getByRole("button", { name: "Open" }));
|
||||
const combobox = await canvas.findByRole("combobox");
|
||||
await userEvent.click(combobox);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -67,9 +67,10 @@ const GroupPage: FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const groupQuery = useQuery(group(organization, groupName));
|
||||
const groupData = groupQuery.data;
|
||||
const { data: permissions } = useQuery(
|
||||
groupData ? groupPermissions(groupData.id) : { enabled: false },
|
||||
);
|
||||
const { data: permissions } = useQuery({
|
||||
...groupPermissions(groupData?.id ?? ""),
|
||||
enabled: !!groupData,
|
||||
});
|
||||
const addMemberMutation = useMutation(addMember(queryClient));
|
||||
const removeMemberMutation = useMutation(removeMember(queryClient));
|
||||
const deleteGroupMutation = useMutation(deleteGroup(queryClient));
|
||||
@@ -145,7 +146,7 @@ const GroupPage: FC = () => {
|
||||
<Stack spacing={1}>
|
||||
{canUpdateGroup && groupData && !isEveryoneGroup(groupData) && (
|
||||
<AddGroupMember
|
||||
isLoading={addMemberMutation.isLoading}
|
||||
isLoading={addMemberMutation.isPending}
|
||||
organizationId={groupData.organization_id}
|
||||
onSubmit={async (member, reset) => {
|
||||
try {
|
||||
@@ -220,7 +221,7 @@ const GroupPage: FC = () => {
|
||||
{groupQuery.data && (
|
||||
<DeleteDialog
|
||||
isOpen={isDeletingGroup}
|
||||
confirmLoading={deleteGroupMutation.isLoading}
|
||||
confirmLoading={deleteGroupMutation.isPending}
|
||||
name={groupQuery.data.name}
|
||||
entity="group"
|
||||
onConfirm={async () => {
|
||||
|
||||
@@ -66,7 +66,7 @@ const GroupSettingsPage: FC = () => {
|
||||
group={groupQuery.data}
|
||||
formErrors={groupQuery.error}
|
||||
isLoading={groupQuery.isLoading}
|
||||
isUpdating={patchGroupMutation.isLoading}
|
||||
isUpdating={patchGroupMutation.isPending}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -25,14 +25,14 @@ import { GroupsPageView } from "./GroupsPageView";
|
||||
const GroupsPage: FC = () => {
|
||||
const { template_rbac: groupsEnabled } = useFeatureVisibility();
|
||||
const { organization, showOrganizations } = useGroupsSettings();
|
||||
const groupsQuery = useQuery(
|
||||
organization ? groupsByOrganization(organization.name) : { enabled: false },
|
||||
);
|
||||
const permissionsQuery = useQuery(
|
||||
organization
|
||||
? organizationsPermissions([organization.id])
|
||||
: { enabled: false },
|
||||
);
|
||||
const groupsQuery = useQuery({
|
||||
...groupsByOrganization(organization?.name ?? ""),
|
||||
enabled: !!organization,
|
||||
});
|
||||
const permissionsQuery = useQuery({
|
||||
...organizationsPermissions([organization?.id ?? ""]),
|
||||
enabled: !!organization,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (groupsQuery.error) {
|
||||
|
||||
@@ -35,7 +35,7 @@ export const DismissWarningButton = (props: { healthcheck: HealthSection }) => {
|
||||
if (isDismissed) {
|
||||
return (
|
||||
<Button
|
||||
disabled={healthSettingsQuery.isLoading || enableMutation.isLoading}
|
||||
disabled={healthSettingsQuery.isLoading || enableMutation.isPending}
|
||||
variant="outline"
|
||||
onClick={async () => {
|
||||
const updatedSettings = dismissed_healthchecks.filter(
|
||||
@@ -48,7 +48,7 @@ export const DismissWarningButton = (props: { healthcheck: HealthSection }) => {
|
||||
displaySuccess("Warnings enabled successfully!");
|
||||
}}
|
||||
>
|
||||
<Spinner loading={enableMutation.isLoading}>
|
||||
<Spinner loading={enableMutation.isPending}>
|
||||
<NotificationsOffOutlined />
|
||||
</Spinner>
|
||||
Enable warnings
|
||||
@@ -58,7 +58,7 @@ export const DismissWarningButton = (props: { healthcheck: HealthSection }) => {
|
||||
|
||||
return (
|
||||
<Button
|
||||
disabled={healthSettingsQuery.isLoading || dismissMutation.isLoading}
|
||||
disabled={healthSettingsQuery.isLoading || dismissMutation.isPending}
|
||||
variant="outline"
|
||||
onClick={async () => {
|
||||
const updatedSettings = [...dismissed_healthchecks, props.healthcheck];
|
||||
@@ -68,7 +68,7 @@ export const DismissWarningButton = (props: { healthcheck: HealthSection }) => {
|
||||
displaySuccess("Warnings dismissed successfully!");
|
||||
}}
|
||||
>
|
||||
<Spinner loading={dismissMutation.isLoading}>
|
||||
<Spinner loading={dismissMutation.isPending}>
|
||||
<NotificationOutlined />
|
||||
</Spinner>
|
||||
Dismiss warnings
|
||||
|
||||
@@ -31,7 +31,7 @@ export const HealthLayout: FC = () => {
|
||||
...health(),
|
||||
refetchInterval: 30_000,
|
||||
});
|
||||
const { mutate: forceRefresh, isLoading: isRefreshing } = useMutation(
|
||||
const { mutate: forceRefresh, isPending: isRefreshing } = useMutation(
|
||||
refreshHealth(queryClient),
|
||||
);
|
||||
const sections = {
|
||||
|
||||
@@ -84,8 +84,8 @@ const CreateEditRolePage: FC = () => {
|
||||
}
|
||||
isLoading={
|
||||
role
|
||||
? updateOrganizationRoleMutation.isLoading
|
||||
: createOrganizationRoleMutation.isLoading
|
||||
? updateOrganizationRoleMutation.isPending
|
||||
: createOrganizationRoleMutation.isPending
|
||||
}
|
||||
organizationName={organizationName}
|
||||
/>
|
||||
|
||||
@@ -96,7 +96,7 @@ const CustomRolesPage: FC = () => {
|
||||
<DeleteDialog
|
||||
key={roleToDelete?.name}
|
||||
isOpen={roleToDelete !== undefined}
|
||||
confirmLoading={deleteRoleMutation.isLoading}
|
||||
confirmLoading={deleteRoleMutation.isPending}
|
||||
name={roleToDelete?.name ?? ""}
|
||||
entity="role"
|
||||
onCancel={() => setRoleToDelete(undefined)}
|
||||
|
||||
@@ -70,11 +70,10 @@ const IdpSyncPage: FC = () => {
|
||||
const tab = searchParams.get("tab") || "groups";
|
||||
const field = tab === "groups" ? groupField : roleField;
|
||||
|
||||
const fieldValuesQuery = useQuery(
|
||||
field
|
||||
? organizationIdpSyncClaimFieldValues(organizationName, field)
|
||||
: { enabled: false },
|
||||
);
|
||||
const fieldValuesQuery = useQuery({
|
||||
...organizationIdpSyncClaimFieldValues(organizationName, field),
|
||||
enabled: !!field,
|
||||
});
|
||||
|
||||
if (!organization) {
|
||||
return <EmptyState message="Organization not found" />;
|
||||
|
||||
@@ -98,8 +98,8 @@ const OrganizationMembersPage: FC = () => {
|
||||
removeMemberMutation.error ??
|
||||
updateMemberRolesMutation.error
|
||||
}
|
||||
isAddingMember={addMemberMutation.isLoading}
|
||||
isUpdatingMemberRoles={updateMemberRolesMutation.isLoading}
|
||||
isAddingMember={addMemberMutation.isPending}
|
||||
isUpdatingMemberRoles={updateMemberRolesMutation.isPending}
|
||||
me={me}
|
||||
members={members}
|
||||
membersQuery={membersQuery}
|
||||
|
||||
@@ -51,7 +51,7 @@ interface OrganizationMembersPageViewProps {
|
||||
me: User;
|
||||
members: Array<OrganizationMemberTableEntry> | undefined;
|
||||
membersQuery: PaginationResultInfo & {
|
||||
isPreviousData: boolean;
|
||||
isPlaceholderData: boolean;
|
||||
};
|
||||
addMember: (user: User) => Promise<void>;
|
||||
removeMember: (member: OrganizationMemberWithUserData) => void;
|
||||
|
||||
+7
-7
@@ -27,12 +27,12 @@ export const CancelJobConfirmationDialog: FC<
|
||||
const cancelMutation = useMutation({
|
||||
mutationFn: cancelProvisionerJob,
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(
|
||||
provisionerJobsQueryKey(job.organization_id),
|
||||
);
|
||||
queryClient.invalidateQueries(
|
||||
getProvisionerDaemonsKey(job.organization_id, job.tags),
|
||||
);
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: provisionerJobsQueryKey(job.organization_id),
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: getProvisionerDaemonsKey(job.organization_id, job.tags),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -44,7 +44,7 @@ export const CancelJobConfirmationDialog: FC<
|
||||
description={`Are you sure you want to cancel the provisioner job "${job.id}"? This operation will result in the associated workspaces not getting created.`}
|
||||
confirmText="Confirm"
|
||||
cancelText="Discard"
|
||||
confirmLoading={cancelMutation.isLoading}
|
||||
confirmLoading={cancelMutation.isPending}
|
||||
onConfirm={async () => {
|
||||
try {
|
||||
await cancelMutation.mutateAsync(job);
|
||||
|
||||
@@ -31,7 +31,7 @@ const RequestOTPPage: FC = () => {
|
||||
) : (
|
||||
<RequestOTP
|
||||
error={requestOTPMutation.error}
|
||||
isRequesting={requestOTPMutation.isLoading}
|
||||
isRequesting={requestOTPMutation.isPending}
|
||||
onRequest={(email) => {
|
||||
requestOTPMutation.mutate({ email });
|
||||
}}
|
||||
|
||||
@@ -56,7 +56,7 @@ export const SetupPage: FC = () => {
|
||||
</Helmet>
|
||||
<SetupPageView
|
||||
authMethods={authMethodsQuery.data}
|
||||
isLoading={isSigningIn || createFirstUserMutation.isLoading}
|
||||
isLoading={isSigningIn || createFirstUserMutation.isPending}
|
||||
error={createFirstUserMutation.error}
|
||||
onSubmit={async (firstUser) => {
|
||||
await createFirstUserMutation.mutateAsync(firstUser);
|
||||
|
||||
@@ -84,20 +84,23 @@ export const TemplateLayout: FC<PropsWithChildren> = ({
|
||||
queryKey: ["template", templateName],
|
||||
queryFn: () => fetchTemplate(organizationName, templateName),
|
||||
});
|
||||
const workspacePermissionsQuery = useQuery(
|
||||
data
|
||||
? checkAuthorization({
|
||||
checks: workspacePermissionChecks(
|
||||
data.template.organization_id,
|
||||
me.id,
|
||||
),
|
||||
})
|
||||
: { enabled: false },
|
||||
);
|
||||
const workspacePermissionsQuery = useQuery({
|
||||
...checkAuthorization({
|
||||
checks: workspacePermissionChecks(
|
||||
data?.template.organization_id ?? "",
|
||||
me.id,
|
||||
),
|
||||
}),
|
||||
enabled: !!data,
|
||||
});
|
||||
|
||||
const location = useLocation();
|
||||
const paths = location.pathname.split("/");
|
||||
const activeTab = paths.at(-1) === templateName ? "summary" : paths.at(-1)!;
|
||||
const templateNamePath = paths.at(-1);
|
||||
const activeTab =
|
||||
templateNamePath === templateName
|
||||
? "summary"
|
||||
: (templateNamePath as string);
|
||||
// Auditors should also be able to view insights, but do not automatically
|
||||
// have permission to update templates. Need both checks.
|
||||
const shouldShowInsights =
|
||||
|
||||
@@ -19,7 +19,7 @@ const TemplateVersionsPage = () => {
|
||||
const [latestActiveVersion, setLatestActiveVersion] = useState(
|
||||
template.active_version_id,
|
||||
);
|
||||
const { mutate: promoteVersion, isLoading: isPromoting } = useMutation({
|
||||
const { mutate: promoteVersion, isPending: isPromoting } = useMutation({
|
||||
mutationFn: (templateVersionId: string) => {
|
||||
return API.updateActiveTemplateVersion(template.id, {
|
||||
id: templateVersionId,
|
||||
@@ -35,7 +35,7 @@ const TemplateVersionsPage = () => {
|
||||
},
|
||||
});
|
||||
|
||||
const { mutate: archiveVersion, isLoading: isArchiving } = useMutation({
|
||||
const { mutate: archiveVersion, isPending: isArchiving } = useMutation({
|
||||
mutationFn: (templateVersionId: string) => {
|
||||
return API.archiveTemplateVersion(templateVersionId);
|
||||
},
|
||||
|
||||
+23
-25
@@ -28,35 +28,33 @@ const TemplateSettingsPage: FC = () => {
|
||||
|
||||
const {
|
||||
mutate: updateTemplate,
|
||||
isLoading: isSubmitting,
|
||||
isPending: isSubmitting,
|
||||
error: submitError,
|
||||
} = useMutation(
|
||||
(data: UpdateTemplateMeta) => {
|
||||
} = useMutation({
|
||||
mutationFn: (data: UpdateTemplateMeta) => {
|
||||
return API.updateTemplateMeta(template.id, data);
|
||||
},
|
||||
{
|
||||
onSuccess: async (data) => {
|
||||
// This update has a chance to return a 304 which means nothing was updated.
|
||||
// In this case, the return payload will be empty and we should use the
|
||||
// original template data.
|
||||
if (!data) {
|
||||
data = template;
|
||||
} else {
|
||||
// Only invalid the query if data is returned, indicating at least one field was updated.
|
||||
//
|
||||
// we use data.name because an admin may have updated templateName to something new
|
||||
await queryClient.invalidateQueries(
|
||||
templateByNameKey(template.organization_name, data.name),
|
||||
);
|
||||
}
|
||||
displaySuccess("Template updated successfully");
|
||||
navigate(getLink(linkToTemplate(data.organization_name, data.name)));
|
||||
},
|
||||
onError: (error) => {
|
||||
displayError(getErrorMessage(error, "Failed to update template"));
|
||||
},
|
||||
onSuccess: async (data) => {
|
||||
// This update has a chance to return a 304 which means nothing was updated.
|
||||
// In this case, the return payload will be empty and we should use the
|
||||
// original template data.
|
||||
if (!data) {
|
||||
data = template;
|
||||
} else {
|
||||
// Only invalid the query if data is returned, indicating at least one field was updated.
|
||||
//
|
||||
// we use data.name because an admin may have updated templateName to something new
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: templateByNameKey(template.organization_name, data.name),
|
||||
});
|
||||
}
|
||||
displaySuccess("Template updated successfully");
|
||||
navigate(getLink(linkToTemplate(data.organization_name, data.name)));
|
||||
},
|
||||
);
|
||||
onError: (error) => {
|
||||
displayError(getErrorMessage(error, "Failed to update template"));
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
+4
-4
@@ -48,7 +48,7 @@ const TemplatePermissionsPage: FC = () => {
|
||||
});
|
||||
reset();
|
||||
}}
|
||||
isAddingUser={addUserMutation.isLoading}
|
||||
isAddingUser={addUserMutation.isPending}
|
||||
onUpdateUser={async (user, role) => {
|
||||
await updateUserMutation.mutateAsync({
|
||||
templateId: template.id,
|
||||
@@ -58,7 +58,7 @@ const TemplatePermissionsPage: FC = () => {
|
||||
displaySuccess("User role updated successfully!");
|
||||
}}
|
||||
updatingUserId={
|
||||
updateUserMutation.isLoading
|
||||
updateUserMutation.isPending
|
||||
? updateUserMutation.variables?.userId
|
||||
: undefined
|
||||
}
|
||||
@@ -78,7 +78,7 @@ const TemplatePermissionsPage: FC = () => {
|
||||
});
|
||||
reset();
|
||||
}}
|
||||
isAddingGroup={addGroupMutation.isLoading}
|
||||
isAddingGroup={addGroupMutation.isPending}
|
||||
onUpdateGroup={async (group, role) => {
|
||||
await updateGroupMutation.mutateAsync({
|
||||
templateId: template.id,
|
||||
@@ -88,7 +88,7 @@ const TemplatePermissionsPage: FC = () => {
|
||||
displaySuccess("Group role updated successfully!");
|
||||
}}
|
||||
updatingGroupId={
|
||||
updateGroupMutation.isLoading
|
||||
updateGroupMutation.isPending
|
||||
? updateGroupMutation.variables?.groupId
|
||||
: undefined
|
||||
}
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@ import type { Group, ReducedUser } from "api/typesGenerated";
|
||||
import { AvatarData } from "components/Avatar/AvatarData";
|
||||
import { useDebouncedFunction } from "hooks/debounce";
|
||||
import { type ChangeEvent, type FC, useState } from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import { keepPreviousData, useQuery } from "react-query";
|
||||
import { prepareQuery } from "utils/filters";
|
||||
import { getGroupSubtitle } from "utils/groups";
|
||||
|
||||
@@ -36,7 +36,7 @@ export const UserOrGroupAutocomplete: FC<UserOrGroupAutocompleteProps> = ({
|
||||
limit: 25,
|
||||
}),
|
||||
enabled: autoComplete.open,
|
||||
keepPreviousData: true,
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
const options = aclAvailableQuery.data
|
||||
? [
|
||||
|
||||
@@ -25,22 +25,21 @@ const TemplateSchedulePage: FC = () => {
|
||||
|
||||
const {
|
||||
mutate: updateTemplate,
|
||||
isLoading: isSubmitting,
|
||||
isPending: isSubmitting,
|
||||
error: submitError,
|
||||
} = useMutation(
|
||||
(data: UpdateTemplateMeta) => API.updateTemplateMeta(template.id, data),
|
||||
{
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(
|
||||
templateByNameKey(organizationName, templateName),
|
||||
);
|
||||
displaySuccess("Template updated successfully");
|
||||
// clear browser storage of workspaces impending deletion
|
||||
localStorage.removeItem("dismissedWorkspaceList"); // workspaces page
|
||||
localStorage.removeItem("dismissedWorkspace"); // workspace page
|
||||
},
|
||||
} = useMutation({
|
||||
mutationFn: (data: UpdateTemplateMeta) =>
|
||||
API.updateTemplateMeta(template.id, data),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: templateByNameKey(organizationName, templateName),
|
||||
});
|
||||
displaySuccess("Template updated successfully");
|
||||
// clear browser storage of workspaces impending deletion
|
||||
localStorage.removeItem("dismissedWorkspaceList"); // workspaces page
|
||||
localStorage.removeItem("dismissedWorkspace"); // workspace page
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: false,
|
||||
cacheTime: 0,
|
||||
gcTime: 0,
|
||||
refetchOnWindowFocus: false,
|
||||
networkMode: "offlineFirst",
|
||||
},
|
||||
|
||||
@@ -46,7 +46,7 @@ export const TemplateSettingsLayout: FC = () => {
|
||||
enabled: templateQuery.isSuccess,
|
||||
});
|
||||
|
||||
if (templateQuery.isLoading || permissionsQuery.isLoading) {
|
||||
if (!(templateQuery.data && permissionsQuery.data)) {
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
|
||||
+13
-5
@@ -15,7 +15,12 @@ import { Loader } from "components/Loader/Loader";
|
||||
import { linkToTemplate, useLinks } from "modules/navigation";
|
||||
import { type FC, useCallback } from "react";
|
||||
import { Helmet } from "react-helmet-async";
|
||||
import { useMutation, useQuery, useQueryClient } from "react-query";
|
||||
import {
|
||||
keepPreviousData,
|
||||
useMutation,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
} from "react-query";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { pageTitle } from "utils/page";
|
||||
import { useTemplateSettings } from "../TemplateSettingsLayout";
|
||||
@@ -36,25 +41,28 @@ const TemplateVariablesPage: FC = () => {
|
||||
data: version,
|
||||
error: versionError,
|
||||
isLoading: isVersionLoading,
|
||||
} = useQuery({ ...templateVersion(versionId), keepPreviousData: true });
|
||||
} = useQuery({
|
||||
...templateVersion(versionId),
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
const {
|
||||
data: variables,
|
||||
error: variablesError,
|
||||
isLoading: isVariablesLoading,
|
||||
} = useQuery({
|
||||
...templateVersionVariables(versionId),
|
||||
keepPreviousData: true,
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
|
||||
const {
|
||||
mutateAsync: sendCreateAndBuildTemplateVersion,
|
||||
error: buildError,
|
||||
isLoading: isBuilding,
|
||||
isPending: isBuilding,
|
||||
} = useMutation(createAndBuildTemplateVersion(organization));
|
||||
const {
|
||||
mutateAsync: sendUpdateActiveTemplateVersion,
|
||||
error: publishError,
|
||||
isLoading: isPublishing,
|
||||
isPending: isPublishing,
|
||||
} = useMutation(updateActiveTemplateVersion(template, queryClient));
|
||||
|
||||
const publishVersion = useCallback(
|
||||
|
||||
@@ -18,7 +18,12 @@ import { linkToTemplate, useLinks } from "modules/navigation";
|
||||
import { useWatchVersionLogs } from "modules/templates/useWatchVersionLogs";
|
||||
import { type FC, useEffect, useState } from "react";
|
||||
import { Helmet } from "react-helmet-async";
|
||||
import { useMutation, useQuery, useQueryClient } from "react-query";
|
||||
import {
|
||||
keepPreviousData,
|
||||
useMutation,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
} from "react-query";
|
||||
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
|
||||
import { type FileTree, existsFile, traverse } from "utils/filetree";
|
||||
import { pageTitle } from "utils/page";
|
||||
@@ -50,9 +55,9 @@ const TemplateVersionEditorPage: FC = () => {
|
||||
);
|
||||
const activeTemplateVersionQuery = useQuery({
|
||||
...templateVersionOptions,
|
||||
keepPreviousData: true,
|
||||
refetchInterval(data) {
|
||||
return data?.job.status === "pending" ? 1_000 : false;
|
||||
placeholderData: keepPreviousData,
|
||||
refetchInterval({ state }) {
|
||||
return state.data?.job.status === "pending" ? 1_000 : false;
|
||||
},
|
||||
});
|
||||
const { data: activeTemplateVersion } = activeTemplateVersionQuery;
|
||||
@@ -79,9 +84,9 @@ const TemplateVersionEditorPage: FC = () => {
|
||||
const publishVersionMutation = useMutation({
|
||||
mutationFn: publishVersion,
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(
|
||||
templateByNameKey(organizationName, templateName),
|
||||
);
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: templateByNameKey(organizationName, templateName),
|
||||
});
|
||||
},
|
||||
});
|
||||
const [lastSuccessfulPublishedVersion, setLastSuccessfulPublishedVersion] =
|
||||
@@ -183,7 +188,7 @@ const TemplateVersionEditorPage: FC = () => {
|
||||
navigateToVersion(publishedVersion);
|
||||
}}
|
||||
isAskingPublishParameters={isPublishingDialogOpen}
|
||||
isPublishing={publishVersionMutation.isLoading}
|
||||
isPublishing={publishVersionMutation.isPending}
|
||||
publishingError={publishVersionMutation.error}
|
||||
publishedVersion={lastSuccessfulPublishedVersion}
|
||||
onCreateWorkspace={() => {
|
||||
@@ -199,8 +204,8 @@ const TemplateVersionEditorPage: FC = () => {
|
||||
);
|
||||
}}
|
||||
isBuilding={
|
||||
createTemplateVersionMutation.isLoading ||
|
||||
uploadFileMutation.isLoading ||
|
||||
createTemplateVersionMutation.isPending ||
|
||||
uploadFileMutation.isPending ||
|
||||
activeTemplateVersion.job.status === "running" ||
|
||||
activeTemplateVersion.job.status === "pending"
|
||||
}
|
||||
@@ -345,9 +350,9 @@ const publishVersion = async (options: {
|
||||
publishActions.push(API.patchTemplateVersion(version.id, data));
|
||||
}
|
||||
|
||||
if (isActiveVersion) {
|
||||
if (version.template_id && isActiveVersion) {
|
||||
publishActions.push(
|
||||
API.updateActiveTemplateVersion(version.template_id!, {
|
||||
API.updateActiveTemplateVersion(version.template_id, {
|
||||
id: version.id,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -29,7 +29,7 @@ const AppearancePage: FC = () => {
|
||||
return (
|
||||
<>
|
||||
<AppearanceForm
|
||||
isUpdating={updateAppearanceSettingsMutation.isLoading}
|
||||
isUpdating={updateAppearanceSettingsMutation.isPending}
|
||||
error={updateAppearanceSettingsMutation.error}
|
||||
initialValues={{
|
||||
theme_preference: appearanceSettingsQuery.data.theme_preference,
|
||||
|
||||
@@ -58,7 +58,7 @@ const ExternalAuthPage: FC = () => {
|
||||
do so on the oauth2 provider's side."
|
||||
label="Name of the application to unlink"
|
||||
isOpen={appToUnlink !== undefined}
|
||||
confirmLoading={unlinkAppMutation.isLoading}
|
||||
confirmLoading={unlinkAppMutation.isPending}
|
||||
name={appToUnlink ?? ""}
|
||||
entity="application"
|
||||
onCancel={() => setAppToUnlink(undefined)}
|
||||
|
||||
@@ -35,7 +35,7 @@ const OAuth2ProviderPage: FC = () => {
|
||||
info={`This will invalidate any tokens created by the OAuth2 application "${appToRevoke.name}".`}
|
||||
label="Name of the application to revoke"
|
||||
isOpen
|
||||
confirmLoading={revokeAppMutation.isLoading}
|
||||
confirmLoading={revokeAppMutation.isPending}
|
||||
name={appToRevoke.name}
|
||||
entity="application"
|
||||
onCancel={() => setAppIdToRevoke(undefined)}
|
||||
|
||||
@@ -43,7 +43,7 @@ const SSHKeysPage: FC = () => {
|
||||
type="delete"
|
||||
hideCancel={false}
|
||||
open={isConfirmingRegeneration}
|
||||
confirmLoading={regenerateSSHKeyMutation.isLoading}
|
||||
confirmLoading={regenerateSSHKeyMutation.isPending}
|
||||
title={Language.regenerateDialogTitle}
|
||||
description={Language.regenerateDialogMessage}
|
||||
confirmText={Language.confirmLabel}
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
updateUserQuietHoursSchedule,
|
||||
userQuietHoursSchedule,
|
||||
} from "api/queries/settings";
|
||||
import type { UserQuietHoursScheduleResponse } from "api/typesGenerated";
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert";
|
||||
import { displaySuccess } from "components/GlobalSnackbar/utils";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
@@ -25,7 +26,7 @@ const SchedulePage: FC = () => {
|
||||
const {
|
||||
mutate: onSubmit,
|
||||
error: submitError,
|
||||
isLoading: mutationLoading,
|
||||
isPending: mutationLoading,
|
||||
} = useMutation(updateUserQuietHoursSchedule(me.id, queryClient));
|
||||
|
||||
if (isLoading) {
|
||||
@@ -44,7 +45,7 @@ const SchedulePage: FC = () => {
|
||||
>
|
||||
<ScheduleForm
|
||||
isLoading={mutationLoading}
|
||||
initialValues={quietHoursSchedule}
|
||||
initialValues={quietHoursSchedule as UserQuietHoursScheduleResponse}
|
||||
submitError={submitError}
|
||||
onSubmit={(values) => {
|
||||
onSubmit(values, {
|
||||
|
||||
@@ -33,7 +33,7 @@ const SecurityPage: FC = () => {
|
||||
form: {
|
||||
disabled: userLoginType.login_type !== "password",
|
||||
error: updatePasswordMutation.error,
|
||||
isLoading: updatePasswordMutation.isLoading,
|
||||
isLoading: updatePasswordMutation.isPending,
|
||||
onSubmit: async (data) => {
|
||||
await updatePasswordMutation.mutateAsync({
|
||||
userId: me.id,
|
||||
|
||||
@@ -25,7 +25,7 @@ const defaultArgs: ComponentProps<typeof SecurityPageView> = {
|
||||
authMethods: MockAuthMethodsPasswordOnly,
|
||||
closeConfirmation: action("closeConfirmation"),
|
||||
confirm: action("confirm"),
|
||||
error: undefined,
|
||||
error: null,
|
||||
isConfirming: false,
|
||||
isUpdating: false,
|
||||
openConfirmation: action("openConfirmation"),
|
||||
|
||||
@@ -52,7 +52,8 @@ export const useSingleSignOnSection = () => {
|
||||
const [loginTypeConfirmation, setLoginTypeConfirmation] =
|
||||
useState<LoginTypeConfirmation>({ open: false, selectedType: undefined });
|
||||
|
||||
const mutation = useMutation(API.convertToOAUTH, {
|
||||
const mutation = useMutation({
|
||||
mutationFn: API.convertToOAUTH,
|
||||
onSuccess: (data) => {
|
||||
const loginTypeMsg =
|
||||
data.to_type === "github" ? "Github" : "OpenID Connect";
|
||||
@@ -93,7 +94,7 @@ export const useSingleSignOnSection = () => {
|
||||
confirm,
|
||||
// We still want to show it loading when it is success so the modal does not
|
||||
// change until the redirect
|
||||
isUpdating: mutation.isLoading || mutation.isSuccess,
|
||||
isUpdating: mutation.isPending || mutation.isSuccess,
|
||||
isConfirming: loginTypeConfirmation.open,
|
||||
error: mutation.error,
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@ const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: false,
|
||||
cacheTime: 0,
|
||||
gcTime: 0,
|
||||
refetchOnWindowFocus: false,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -18,7 +18,7 @@ export const ConfirmDeleteDialog: FC<ConfirmDeleteDialogProps> = ({
|
||||
}) => {
|
||||
const tokenName = token?.token_name;
|
||||
|
||||
const { mutate: deleteToken, isLoading: isDeleting } =
|
||||
const { mutate: deleteToken, isPending: isDeleting } =
|
||||
useDeleteToken(queryKey);
|
||||
|
||||
const onDeleteSuccess = () => {
|
||||
|
||||
@@ -29,7 +29,9 @@ export const useDeleteToken = (queryKey: QueryKey) => {
|
||||
mutationFn: API.deleteToken,
|
||||
onSuccess: () => {
|
||||
// Invalidate and refetch
|
||||
void queryClient.invalidateQueries(queryKey);
|
||||
void queryClient.invalidateQueries({
|
||||
queryKey,
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -143,7 +143,7 @@ const UsersPage: FC<UserPageProps> = ({ defaultNewPassword }) => {
|
||||
);
|
||||
}
|
||||
}}
|
||||
isUpdatingUserRoles={updateRolesMutation.isLoading}
|
||||
isUpdatingUserRoles={updateRolesMutation.isPending}
|
||||
isLoading={isLoading}
|
||||
canEditUsers={canEditUsers}
|
||||
canViewActivity={entitlements.features.audit_log.enabled}
|
||||
@@ -161,7 +161,7 @@ const UsersPage: FC<UserPageProps> = ({ defaultNewPassword }) => {
|
||||
<DeleteDialog
|
||||
key={userToDelete?.username}
|
||||
isOpen={userToDelete !== undefined}
|
||||
confirmLoading={deleteUserMutation.isLoading}
|
||||
confirmLoading={deleteUserMutation.isPending}
|
||||
name={userToDelete?.username ?? ""}
|
||||
entity="user"
|
||||
onCancel={() => setUserToDelete(undefined)}
|
||||
@@ -183,7 +183,7 @@ const UsersPage: FC<UserPageProps> = ({ defaultNewPassword }) => {
|
||||
type="delete"
|
||||
hideCancel={false}
|
||||
open={userToSuspend !== undefined}
|
||||
confirmLoading={suspendUserMutation.isLoading}
|
||||
confirmLoading={suspendUserMutation.isPending}
|
||||
title="Suspend user"
|
||||
confirmText="Suspend"
|
||||
onClose={() => setUserToSuspend(undefined)}
|
||||
@@ -211,7 +211,7 @@ const UsersPage: FC<UserPageProps> = ({ defaultNewPassword }) => {
|
||||
type="success"
|
||||
hideCancel={false}
|
||||
open={userToActivate !== undefined}
|
||||
confirmLoading={activateUserMutation.isLoading}
|
||||
confirmLoading={activateUserMutation.isPending}
|
||||
title="Activate user"
|
||||
confirmText="Activate"
|
||||
onClose={() => setUserToActivate(undefined)}
|
||||
@@ -238,7 +238,7 @@ const UsersPage: FC<UserPageProps> = ({ defaultNewPassword }) => {
|
||||
<ResetPasswordDialog
|
||||
key={confirmResetPassword?.user.username}
|
||||
open={confirmResetPassword !== undefined}
|
||||
loading={updatePasswordMutation.isLoading}
|
||||
loading={updatePasswordMutation.isPending}
|
||||
user={confirmResetPassword?.user}
|
||||
newPassword={confirmResetPassword?.newPassword}
|
||||
onClose={() => {
|
||||
|
||||
@@ -4,7 +4,7 @@ import dayjs from "dayjs";
|
||||
import { useWorkspaceBuildLogs } from "hooks/useWorkspaceBuildLogs";
|
||||
import type { FC } from "react";
|
||||
import { Helmet } from "react-helmet-async";
|
||||
import { useQuery } from "react-query";
|
||||
import { keepPreviousData, useQuery } from "react-query";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { pageTitle } from "utils/page";
|
||||
import { WorkspaceBuildPageView } from "./WorkspaceBuildPageView";
|
||||
@@ -20,7 +20,7 @@ const WorkspaceBuildPage: FC = () => {
|
||||
const username = params.username.replace("@", "");
|
||||
const wsBuildQuery = useQuery({
|
||||
...workspaceBuildByNumber(username, workspaceName, buildNumber),
|
||||
keepPreviousData: true,
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
const build = wsBuildQuery.data;
|
||||
const buildsQuery = useQuery({
|
||||
|
||||
@@ -36,11 +36,10 @@ const WorkspacePage: FC = () => {
|
||||
const workspace = workspaceQuery.data;
|
||||
|
||||
// Template
|
||||
const templateQuery = useQuery(
|
||||
workspace
|
||||
? templateQueryOptions(workspace.template_id)
|
||||
: { enabled: false },
|
||||
);
|
||||
const templateQuery = useQuery({
|
||||
...templateQueryOptions(workspace?.template_id ?? ""),
|
||||
enabled: !!workspace,
|
||||
});
|
||||
const template = templateQuery.data;
|
||||
|
||||
// Permissions
|
||||
@@ -67,9 +66,9 @@ const WorkspacePage: FC = () => {
|
||||
newWorkspaceData.latest_build.status !== workspace.latest_build.status;
|
||||
|
||||
if (hasNewBuild || lastBuildHasChanged) {
|
||||
await queryClient.invalidateQueries(
|
||||
workspaceBuildsKey(newWorkspaceData.id),
|
||||
);
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: workspaceBuildsKey(newWorkspaceData.id),
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -60,7 +60,7 @@ export const WorkspaceReadyPage: FC<WorkspaceReadyPageProps> = ({
|
||||
open: boolean;
|
||||
buildParameters?: TypesGen.WorkspaceBuildParameter[];
|
||||
}>({ open: false });
|
||||
const { mutate: mutateRestartWorkspace, isLoading: isRestarting } =
|
||||
const { mutate: mutateRestartWorkspace, isPending: isRestarting } =
|
||||
useMutation({
|
||||
mutationFn: API.restartWorkspace,
|
||||
});
|
||||
@@ -133,7 +133,8 @@ export const WorkspaceReadyPage: FC<WorkspaceReadyPageProps> = ({
|
||||
// timings. To refetch the timings, I found the best way was to compare the
|
||||
// expected amount of script timings that run on start, with the current
|
||||
// amount of script timings returned in the response.
|
||||
refetchInterval: (data) => {
|
||||
refetchInterval: ({ state }) => {
|
||||
const { data } = state;
|
||||
const expectedScriptTimingsCount = workspace.latest_build.resources
|
||||
.flatMap((r) => r.agents)
|
||||
.flatMap((a) => a?.scripts ?? [])
|
||||
|
||||
+27
-32
@@ -13,41 +13,36 @@ const WorkspaceParametersExperimentRouter: FC = () => {
|
||||
const workspace = useWorkspaceSettings();
|
||||
const dynamicParametersEnabled = experiments.includes("dynamic-parameters");
|
||||
|
||||
const optOutQuery = useQuery(
|
||||
dynamicParametersEnabled
|
||||
? {
|
||||
queryKey: [
|
||||
"workspace",
|
||||
workspace.id,
|
||||
"template_id",
|
||||
workspace.template_id,
|
||||
"optOut",
|
||||
],
|
||||
queryFn: () => {
|
||||
const templateId = workspace.template_id;
|
||||
const workspaceId = workspace.id;
|
||||
const localStorageKey = optOutKey(templateId);
|
||||
const storedOptOutString = localStorage.getItem(localStorageKey);
|
||||
const optOutQuery = useQuery({
|
||||
enabled: dynamicParametersEnabled,
|
||||
queryKey: [
|
||||
"workspace",
|
||||
workspace.id,
|
||||
"template_id",
|
||||
workspace.template_id,
|
||||
"optOut",
|
||||
],
|
||||
queryFn: () => {
|
||||
const templateId = workspace.template_id;
|
||||
const workspaceId = workspace.id;
|
||||
const localStorageKey = optOutKey(templateId);
|
||||
const storedOptOutString = localStorage.getItem(localStorageKey);
|
||||
|
||||
let optOutResult: boolean;
|
||||
let optOutResult: boolean;
|
||||
|
||||
if (storedOptOutString !== null) {
|
||||
optOutResult = storedOptOutString === "true";
|
||||
} else {
|
||||
optOutResult = Boolean(
|
||||
workspace.template_use_classic_parameter_flow,
|
||||
);
|
||||
}
|
||||
if (storedOptOutString !== null) {
|
||||
optOutResult = storedOptOutString === "true";
|
||||
} else {
|
||||
optOutResult = Boolean(workspace.template_use_classic_parameter_flow);
|
||||
}
|
||||
|
||||
return {
|
||||
templateId,
|
||||
workspaceId,
|
||||
optedOut: optOutResult,
|
||||
};
|
||||
},
|
||||
}
|
||||
: { enabled: false },
|
||||
);
|
||||
return {
|
||||
templateId,
|
||||
workspaceId,
|
||||
optedOut: optOutResult,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
if (dynamicParametersEnabled) {
|
||||
if (optOutQuery.isLoading) {
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ const WorkspaceParametersPage: FC = () => {
|
||||
canChangeVersions={canChangeVersions}
|
||||
data={parameters.data}
|
||||
submitError={updateParameters.error}
|
||||
isSubmitting={updateParameters.isLoading}
|
||||
isSubmitting={updateParameters.isPending}
|
||||
onSubmit={(values) => {
|
||||
if (!parameters.data) {
|
||||
return;
|
||||
|
||||
+1
-1
@@ -222,7 +222,7 @@ const WorkspaceParametersPageExperimental: FC = () => {
|
||||
canChangeVersions={canChangeVersions}
|
||||
parameters={sortedParams}
|
||||
diagnostics={latestResponse.diagnostics}
|
||||
isSubmitting={updateParameters.isLoading}
|
||||
isSubmitting={updateParameters.isPending}
|
||||
onSubmit={handleSubmit}
|
||||
onCancel={() =>
|
||||
navigate(`/@${workspace.owner_name}/${workspace.name}`)
|
||||
|
||||
+4
-4
@@ -55,12 +55,12 @@ const WorkspaceSchedulePage: FC = () => {
|
||||
const submitScheduleMutation = useMutation({
|
||||
mutationFn: submitSchedule,
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(
|
||||
workspaceByOwnerAndNameKey(
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: workspaceByOwnerAndNameKey(
|
||||
params.username.replace(/^@/, ""),
|
||||
params.workspace,
|
||||
),
|
||||
);
|
||||
});
|
||||
displaySuccess("Workspace schedule updated");
|
||||
},
|
||||
onError: () => displayError("Failed to update workspace schedule"),
|
||||
@@ -102,7 +102,7 @@ const WorkspaceSchedulePage: FC = () => {
|
||||
...getAutostart(workspace),
|
||||
...getAutostop(workspace),
|
||||
}}
|
||||
isLoading={submitScheduleMutation.isLoading}
|
||||
isLoading={submitScheduleMutation.isPending}
|
||||
defaultTTL={dayjs.duration(template.default_ttl_ms, "ms").asHours()}
|
||||
onCancel={() => {
|
||||
navigate(`/@${username}/${workspaceName}`);
|
||||
|
||||
@@ -53,14 +53,16 @@ export const WorkspaceSettingsLayout: FC = () => {
|
||||
{isError ? (
|
||||
<ErrorAlert error={error} />
|
||||
) : (
|
||||
<WorkspaceSettings.Provider value={workspace}>
|
||||
<Sidebar workspace={workspace} username={username} />
|
||||
<Suspense fallback={<Loader />}>
|
||||
<main css={{ width: "100%" }}>
|
||||
<Outlet />
|
||||
</main>
|
||||
</Suspense>
|
||||
</WorkspaceSettings.Provider>
|
||||
workspace && (
|
||||
<WorkspaceSettings.Provider value={workspace}>
|
||||
<Sidebar workspace={workspace} username={username} />
|
||||
<Suspense fallback={<Loader />}>
|
||||
<main css={{ width: "100%" }}>
|
||||
<Outlet />
|
||||
</main>
|
||||
</Suspense>
|
||||
</WorkspaceSettings.Provider>
|
||||
)
|
||||
)}
|
||||
</Stack>
|
||||
</Margins>
|
||||
|
||||
@@ -84,7 +84,7 @@ export const WorkspacesButton: FC<WorkspacesButtonProps> = ({
|
||||
paddingBottom: "8px",
|
||||
}}
|
||||
>
|
||||
{templatesFetchStatus === "loading" ? (
|
||||
{templatesFetchStatus === "pending" ? (
|
||||
<Loader size="sm" />
|
||||
) : (
|
||||
<>
|
||||
|
||||
@@ -77,8 +77,8 @@ const WorkspacesPage: FC = () => {
|
||||
});
|
||||
const { data, error, refetch } = useQuery({
|
||||
...workspacesQueryOptions,
|
||||
refetchInterval: (_, query) => {
|
||||
return query.state.error ? false : 5_000;
|
||||
refetchInterval: ({ state }) => {
|
||||
return state.error ? false : 5_000;
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -489,9 +489,9 @@ const WorkspaceActionsCell: FC<WorkspaceActionsCellProps> = ({
|
||||
});
|
||||
|
||||
const isRetrying =
|
||||
startWorkspaceMutation.isLoading ||
|
||||
stopWorkspaceMutation.isLoading ||
|
||||
deleteWorkspaceMutation.isLoading;
|
||||
startWorkspaceMutation.isPending ||
|
||||
stopWorkspaceMutation.isPending ||
|
||||
deleteWorkspaceMutation.isPending;
|
||||
|
||||
const retry = () => {
|
||||
switch (workspace.latest_build.transition) {
|
||||
@@ -525,7 +525,7 @@ const WorkspaceActionsCell: FC<WorkspaceActionsCellProps> = ({
|
||||
{abilities.actions.includes("start") && (
|
||||
<PrimaryAction
|
||||
onClick={() => startWorkspaceMutation.mutate({})}
|
||||
isLoading={startWorkspaceMutation.isLoading}
|
||||
isLoading={startWorkspaceMutation.isPending}
|
||||
label="Start workspace"
|
||||
>
|
||||
<PlayIcon />
|
||||
@@ -548,7 +548,7 @@ const WorkspaceActionsCell: FC<WorkspaceActionsCellProps> = ({
|
||||
{abilities.canCancel && (
|
||||
<PrimaryAction
|
||||
onClick={cancelBuildMutation.mutate}
|
||||
isLoading={cancelBuildMutation.isLoading}
|
||||
isLoading={cancelBuildMutation.isPending}
|
||||
label="Cancel build"
|
||||
>
|
||||
<BanIcon />
|
||||
|
||||
@@ -94,10 +94,10 @@ export function useBatchActions(options: UseBatchActionsProps) {
|
||||
deleteAll: deleteAllMutation.mutateAsync,
|
||||
updateAll: updateAllMutation.mutateAsync,
|
||||
isLoading:
|
||||
favoriteAllMutation.isLoading ||
|
||||
unfavoriteAllMutation.isLoading ||
|
||||
startAllMutation.isLoading ||
|
||||
stopAllMutation.isLoading ||
|
||||
deleteAllMutation.isLoading,
|
||||
favoriteAllMutation.isPending ||
|
||||
unfavoriteAllMutation.isPending ||
|
||||
startAllMutation.isPending ||
|
||||
stopAllMutation.isPending ||
|
||||
deleteAllMutation.isPending,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -22,22 +22,14 @@ import {
|
||||
import themes, { DEFAULT_THEME } from "theme";
|
||||
import { MockUserOwner } from "./entities";
|
||||
|
||||
// Creates one query client for each test case, to make sure that tests are
|
||||
// isolated and can't affect each other
|
||||
export function createTestQueryClient() {
|
||||
// Helps create one query client for each test case, to make sure that tests
|
||||
// are isolated and can't affect each other
|
||||
return new QueryClient({
|
||||
logger: {
|
||||
...console,
|
||||
// Some tests are designed to throw errors as part of their functionality.
|
||||
// To avoid unnecessary noise from these expected errors, the code is
|
||||
// structured to suppress them. If this suppression becomes problematic,
|
||||
// the code can be refactored to handle query errors on a per-test basis.
|
||||
error: () => {},
|
||||
},
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: false,
|
||||
cacheTime: 0,
|
||||
gcTime: 0,
|
||||
refetchOnWindowFocus: false,
|
||||
networkMode: "offlineFirst",
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user