Skip to content

Commit 4c6c45a

Browse files
User Preferences page cleanup (#16694)
* add query for user maySetTimeout * updates to use query for timeout, and forms
1 parent 073b313 commit 4c6c45a

File tree

2 files changed

+76
-43
lines changed

2 files changed

+76
-43
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Copyright (c) 2023 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License.AGPL.txt in the project root for license information.
5+
*/
6+
7+
import { useQuery } from "@tanstack/react-query";
8+
import { getGitpodService } from "../../service/service";
9+
import { useCurrentUser } from "../../user-context";
10+
11+
export const useUserMaySetTimeout = () => {
12+
const user = useCurrentUser();
13+
14+
return useQuery<boolean>({
15+
queryKey: getUserMaySetTimeoutQueryKey(user?.id ?? ""),
16+
queryFn: async () => {
17+
if (!user) {
18+
throw new Error("No current user");
19+
}
20+
21+
return !!(await getGitpodService().server.maySetTimeout());
22+
},
23+
enabled: !!user,
24+
});
25+
};
26+
27+
export const getUserMaySetTimeoutQueryKey = (userId: string) => ["may-set-timeout", { userId }];

components/dashboard/src/user-settings/Preferences.tsx

Lines changed: 49 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* See License.AGPL.txt in the project root for license information.
55
*/
66

7-
import { useCallback, useContext, useEffect, useState } from "react";
7+
import { useCallback, useContext, useState } from "react";
88
import { getGitpodService } from "../service/service";
99
import { UserContext } from "../user-context";
1010
import { trackEvent } from "../Analytics";
@@ -14,39 +14,50 @@ import { ThemeSelector } from "../components/ThemeSelector";
1414
import Alert from "../components/Alert";
1515
import { Link } from "react-router-dom";
1616
import { Heading2, Subheading } from "../components/typography/headings";
17+
import { useUserMaySetTimeout } from "../data/current-user/may-set-timeout-query";
18+
import { Button } from "../components/Button";
1719

1820
export default function Preferences() {
19-
const { user } = useContext(UserContext);
21+
const { user, setUser } = useContext(UserContext);
22+
const maySetTimeout = useUserMaySetTimeout();
2023

2124
const [dotfileRepo, setDotfileRepo] = useState<string>(user?.additionalData?.dotfileRepo || "");
22-
const actuallySetDotfileRepo = async (value: string) => {
23-
const additionalData = user?.additionalData || {};
24-
const prevDotfileRepo = additionalData.dotfileRepo || "";
25-
additionalData.dotfileRepo = value;
26-
await getGitpodService().server.updateLoggedInUser({ additionalData });
27-
if (value !== prevDotfileRepo) {
28-
trackEvent("dotfile_repo_changed", {
29-
previous: prevDotfileRepo,
30-
current: value,
31-
});
32-
}
33-
};
34-
3525
const [workspaceTimeout, setWorkspaceTimeout] = useState<string>(user?.additionalData?.workspaceTimeout ?? "");
36-
const actuallySetWorkspaceTimeout = useCallback(async (value: string) => {
37-
try {
38-
await getGitpodService().server.updateWorkspaceTimeoutSetting({ workspaceTimeout: value });
39-
} catch (e) {
40-
alert("Cannot set custom workspace timeout: " + e.message);
41-
}
42-
}, []);
4326

44-
const [allowConfigureWorkspaceTimeout, setAllowConfigureWorkspaceTimeout] = useState<boolean>(false);
45-
useEffect(() => {
46-
getGitpodService()
47-
.server.maySetTimeout()
48-
.then((r) => setAllowConfigureWorkspaceTimeout(r));
49-
}, []);
27+
const saveDotfileRepo = useCallback(
28+
async (e) => {
29+
e.preventDefault();
30+
31+
const prevDotfileRepo = user?.additionalData?.dotfileRepo || "";
32+
const additionalData = {
33+
...(user?.additionalData || {}),
34+
dotfileRepo,
35+
};
36+
const updatedUser = await getGitpodService().server.updateLoggedInUser({ additionalData });
37+
setUser(updatedUser);
38+
39+
if (dotfileRepo !== prevDotfileRepo) {
40+
trackEvent("dotfile_repo_changed", {
41+
previous: prevDotfileRepo,
42+
current: dotfileRepo,
43+
});
44+
}
45+
},
46+
[dotfileRepo, setUser, user?.additionalData],
47+
);
48+
49+
const saveWorkspaceTimeout = useCallback(
50+
async (e) => {
51+
e.preventDefault();
52+
53+
try {
54+
await getGitpodService().server.updateWorkspaceTimeoutSetting({ workspaceTimeout: workspaceTimeout });
55+
} catch (e) {
56+
alert("Cannot set custom workspace timeout: " + e.message);
57+
}
58+
},
59+
[workspaceTimeout],
60+
);
5061

5162
return (
5263
<div>
@@ -69,7 +80,7 @@ export default function Preferences() {
6980

7081
<Heading2 className="mt-12">Dotfiles</Heading2>
7182
<Subheading>Customize workspaces using dotfiles.</Subheading>
72-
<div className="mt-4 max-w-xl">
83+
<form className="mt-4 max-w-xl" onSubmit={saveDotfileRepo}>
7384
<h4>Repository URL</h4>
7485
<span className="flex">
7586
<input
@@ -79,9 +90,9 @@ export default function Preferences() {
7990
placeholder="e.g. https://github.com/username/dotfiles"
8091
onChange={(e) => setDotfileRepo(e.target.value)}
8192
/>
82-
<button className="secondary ml-2" onClick={() => actuallySetDotfileRepo(dotfileRepo)}>
93+
<Button type="secondary" className="ml-2">
8394
Save Changes
84-
</button>
95+
</Button>
8596
</span>
8697
<div className="mt-1">
8798
<p className="text-gray-500 dark:text-gray-400">
@@ -90,14 +101,14 @@ export default function Preferences() {
90101
clone and install your dotfiles for every new workspace.
91102
</p>
92103
</div>
93-
</div>
104+
</form>
94105

95106
<Heading2 className="mt-12">Timeouts</Heading2>
96107
<Subheading>Workspaces will stop after a period of inactivity without any user input.</Subheading>
97108
<div className="mt-4 max-w-xl">
98109
<h4>Default Workspace Timeout</h4>
99110

100-
{!allowConfigureWorkspaceTimeout && (
111+
{!maySetTimeout.isLoading && maySetTimeout.data === false && (
101112
<Alert type="message">
102113
Upgrade organization{" "}
103114
<Link to="/billing" className="gp-link">
@@ -107,32 +118,27 @@ export default function Preferences() {
107118
</Alert>
108119
)}
109120

110-
{allowConfigureWorkspaceTimeout && (
111-
<>
121+
{maySetTimeout.data === true && (
122+
<form onSubmit={saveWorkspaceTimeout}>
112123
<span className="flex">
113124
<input
114125
type="text"
115126
className="w-96 h-9"
116127
value={workspaceTimeout}
117-
disabled={!allowConfigureWorkspaceTimeout}
118128
placeholder="e.g. 30m"
119129
onChange={(e) => setWorkspaceTimeout(e.target.value)}
120130
/>
121-
<button
122-
className="secondary ml-2"
123-
disabled={!allowConfigureWorkspaceTimeout}
124-
onClick={() => actuallySetWorkspaceTimeout(workspaceTimeout)}
125-
>
131+
<Button type="secondary" className="ml-2">
126132
Save Changes
127-
</button>
133+
</Button>
128134
</span>
129135
<div className="mt-1">
130136
<p className="text-gray-500 dark:text-gray-400">
131137
Use minutes or hours, like <span className="font-semibold">30m</span> or{" "}
132138
<span className="font-semibold">2h</span>.
133139
</p>
134140
</div>
135-
</>
141+
</form>
136142
)}
137143
</div>
138144
</PageWithSettingsSubMenu>

0 commit comments

Comments
 (0)