mirror of
https://github.com/coder/coder.git
synced 2026-09-22 05:05:20 +08:00
chore(site): move ssh keys management to react-query (#9625)
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
import { QueryClient } from "@tanstack/react-query";
|
||||
import * as API from "api/api";
|
||||
import { GitSSHKey } from "api/typesGenerated";
|
||||
|
||||
const getUserSSHKeyQueryKey = (userId: string) => [userId, "sshKey"];
|
||||
|
||||
export const userSSHKey = (userId: string) => {
|
||||
return {
|
||||
queryKey: getUserSSHKeyQueryKey(userId),
|
||||
queryFn: () => API.getUserSSHKey(userId),
|
||||
};
|
||||
};
|
||||
|
||||
export const regenerateUserSSHKey = (
|
||||
userId: string,
|
||||
queryClient: QueryClient,
|
||||
) => {
|
||||
return {
|
||||
mutationFn: () => API.regenerateUserSSHKey(userId),
|
||||
onSuccess: (newKey: GitSSHKey) => {
|
||||
queryClient.setQueryData(getUserSSHKeyQueryKey(userId), newKey);
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,9 +1,10 @@
|
||||
import { useMachine } from "@xstate/react";
|
||||
import { PropsWithChildren, FC } from "react";
|
||||
import { sshKeyMachine } from "xServices/sshKey/sshKeyXService";
|
||||
import { PropsWithChildren, FC, useState } from "react";
|
||||
import { ConfirmDialog } from "../../../components/Dialogs/ConfirmDialog/ConfirmDialog";
|
||||
import { Section } from "../../../components/SettingsLayout/Section";
|
||||
import { SSHKeysPageView } from "./SSHKeysPageView";
|
||||
import { regenerateUserSSHKey, userSSHKey } from "api/queries/sshKeys";
|
||||
import { displaySuccess } from "components/GlobalSnackbar/utils";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
export const Language = {
|
||||
title: "SSH keys",
|
||||
@@ -15,40 +16,47 @@ export const Language = {
|
||||
};
|
||||
|
||||
export const SSHKeysPage: FC<PropsWithChildren<unknown>> = () => {
|
||||
const [sshState, sshSend] = useMachine(sshKeyMachine);
|
||||
const isLoading = sshState.matches("gettingSSHKey");
|
||||
const hasLoaded = sshState.matches("loaded");
|
||||
const { getSSHKeyError, regenerateSSHKeyError, sshKey } = sshState.context;
|
||||
|
||||
const onRegenerateClick = () => {
|
||||
sshSend({ type: "REGENERATE_SSH_KEY" });
|
||||
};
|
||||
const [isConfirmingRegeneration, setIsConfirmingRegeneration] =
|
||||
useState(false);
|
||||
const queryClient = useQueryClient();
|
||||
const userSSHKeyQuery = useQuery(userSSHKey("me"));
|
||||
const regenerateSSHKeyMutationOptions = regenerateUserSSHKey(
|
||||
"me",
|
||||
queryClient,
|
||||
);
|
||||
const regenerateSSHKeyMutation = useMutation({
|
||||
...regenerateSSHKeyMutationOptions,
|
||||
onSuccess: (newKey) => {
|
||||
regenerateSSHKeyMutationOptions.onSuccess(newKey);
|
||||
displaySuccess("SSH Key regenerated successfully.");
|
||||
setIsConfirmingRegeneration(false);
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Section title={Language.title}>
|
||||
<SSHKeysPageView
|
||||
isLoading={isLoading}
|
||||
hasLoaded={hasLoaded}
|
||||
getSSHKeyError={getSSHKeyError}
|
||||
regenerateSSHKeyError={regenerateSSHKeyError}
|
||||
sshKey={sshKey}
|
||||
onRegenerateClick={onRegenerateClick}
|
||||
isLoading={userSSHKeyQuery.isLoading}
|
||||
getSSHKeyError={userSSHKeyQuery.error}
|
||||
regenerateSSHKeyError={regenerateSSHKeyMutation.error}
|
||||
sshKey={userSSHKeyQuery.data}
|
||||
onRegenerateClick={() => {
|
||||
setIsConfirmingRegeneration(true);
|
||||
}}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
<ConfirmDialog
|
||||
type="delete"
|
||||
hideCancel={false}
|
||||
open={sshState.matches("confirmSSHKeyRegenerate")}
|
||||
confirmLoading={sshState.matches("regeneratingSSHKey")}
|
||||
open={isConfirmingRegeneration}
|
||||
confirmLoading={regenerateSSHKeyMutation.isLoading}
|
||||
title={Language.regenerateDialogTitle}
|
||||
confirmText={Language.confirmLabel}
|
||||
onConfirm={() => {
|
||||
sshSend({ type: "CONFIRM_REGENERATE_SSH_KEY" });
|
||||
}}
|
||||
onConfirm={regenerateSSHKeyMutation.mutate}
|
||||
onClose={() => {
|
||||
sshSend({ type: "CANCEL_REGENERATE_SSH_KEY" });
|
||||
setIsConfirmingRegeneration(false);
|
||||
}}
|
||||
description={<>{Language.regenerateDialogMessage}</>}
|
||||
/>
|
||||
|
||||
@@ -7,7 +7,6 @@ const meta: Meta<typeof SSHKeysPageView> = {
|
||||
component: SSHKeysPageView,
|
||||
args: {
|
||||
isLoading: false,
|
||||
hasLoaded: true,
|
||||
sshKey: {
|
||||
user_id: "test-user-id",
|
||||
created_at: "2022-07-28T07:45:50.795918897Z",
|
||||
@@ -30,7 +29,7 @@ export const Loading: Story = {
|
||||
|
||||
export const WithGetSSHKeyError: Story = {
|
||||
args: {
|
||||
hasLoaded: false,
|
||||
sshKey: undefined,
|
||||
getSSHKeyError: mockApiError({
|
||||
message: "Failed to get SSH key",
|
||||
}),
|
||||
|
||||
@@ -14,7 +14,6 @@ export const Language = {
|
||||
|
||||
export interface SSHKeysPageViewProps {
|
||||
isLoading: boolean;
|
||||
hasLoaded: boolean;
|
||||
getSSHKeyError?: unknown;
|
||||
regenerateSSHKeyError?: unknown;
|
||||
sshKey?: GitSSHKey;
|
||||
@@ -25,7 +24,6 @@ export const SSHKeysPageView: FC<
|
||||
React.PropsWithChildren<SSHKeysPageViewProps>
|
||||
> = ({
|
||||
isLoading,
|
||||
hasLoaded,
|
||||
getSSHKeyError,
|
||||
regenerateSSHKeyError,
|
||||
sshKey,
|
||||
@@ -49,7 +47,7 @@ export const SSHKeysPageView: FC<
|
||||
{Boolean(regenerateSSHKeyError) && (
|
||||
<ErrorAlert error={regenerateSSHKeyError} dismissible />
|
||||
)}
|
||||
{hasLoaded && sshKey && (
|
||||
{sshKey && (
|
||||
<>
|
||||
<p className={styles.description}>
|
||||
The following public key is used to authenticate Git in workspaces.
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
import { getUserSSHKey, regenerateUserSSHKey } from "api/api";
|
||||
import { GitSSHKey } from "api/typesGenerated";
|
||||
import { displaySuccess } from "components/GlobalSnackbar/utils";
|
||||
import { createMachine, assign } from "xstate";
|
||||
|
||||
interface Context {
|
||||
sshKey?: GitSSHKey;
|
||||
getSSHKeyError?: unknown;
|
||||
regenerateSSHKeyError?: unknown;
|
||||
}
|
||||
|
||||
type Events =
|
||||
| { type: "REGENERATE_SSH_KEY" }
|
||||
| { type: "CONFIRM_REGENERATE_SSH_KEY" }
|
||||
| { type: "CANCEL_REGENERATE_SSH_KEY" };
|
||||
|
||||
export const sshKeyMachine = createMachine(
|
||||
{
|
||||
id: "sshKeyState",
|
||||
predictableActionArguments: true,
|
||||
schema: {
|
||||
context: {} as Context,
|
||||
events: {} as Events,
|
||||
services: {} as {
|
||||
getSSHKey: {
|
||||
data: GitSSHKey;
|
||||
};
|
||||
regenerateSSHKey: {
|
||||
data: GitSSHKey;
|
||||
};
|
||||
},
|
||||
},
|
||||
tsTypes: {} as import("./sshKeyXService.typegen").Typegen0,
|
||||
initial: "gettingSSHKey",
|
||||
states: {
|
||||
gettingSSHKey: {
|
||||
entry: "clearGetSSHKeyError",
|
||||
invoke: {
|
||||
src: "getSSHKey",
|
||||
onDone: [
|
||||
{
|
||||
actions: "assignSSHKey",
|
||||
target: "loaded",
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
actions: "assignGetSSHKeyError",
|
||||
target: "notLoaded",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
notLoaded: {
|
||||
type: "final",
|
||||
},
|
||||
loaded: {
|
||||
on: {
|
||||
REGENERATE_SSH_KEY: {
|
||||
target: "confirmSSHKeyRegenerate",
|
||||
},
|
||||
},
|
||||
},
|
||||
confirmSSHKeyRegenerate: {
|
||||
on: {
|
||||
CANCEL_REGENERATE_SSH_KEY: {
|
||||
target: "loaded",
|
||||
},
|
||||
CONFIRM_REGENERATE_SSH_KEY: {
|
||||
target: "regeneratingSSHKey",
|
||||
},
|
||||
},
|
||||
},
|
||||
regeneratingSSHKey: {
|
||||
entry: "clearRegenerateSSHKeyError",
|
||||
invoke: {
|
||||
src: "regenerateSSHKey",
|
||||
onDone: [
|
||||
{
|
||||
actions: ["assignSSHKey", "notifySuccessSSHKeyRegenerated"],
|
||||
target: "loaded",
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
actions: "assignRegenerateSSHKeyError",
|
||||
target: "loaded",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
services: {
|
||||
getSSHKey: () => getUserSSHKey(),
|
||||
regenerateSSHKey: () => regenerateUserSSHKey(),
|
||||
},
|
||||
actions: {
|
||||
assignSSHKey: assign({
|
||||
sshKey: (_, { data }) => data,
|
||||
}),
|
||||
assignGetSSHKeyError: assign({
|
||||
getSSHKeyError: (_, { data }) => data,
|
||||
}),
|
||||
clearGetSSHKeyError: assign({
|
||||
getSSHKeyError: (_) => undefined,
|
||||
}),
|
||||
assignRegenerateSSHKeyError: assign({
|
||||
regenerateSSHKeyError: (_, { data }) => data,
|
||||
}),
|
||||
clearRegenerateSSHKeyError: assign({
|
||||
regenerateSSHKeyError: (_) => undefined,
|
||||
}),
|
||||
notifySuccessSSHKeyRegenerated: () => {
|
||||
displaySuccess("SSH Key regenerated successfully.");
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
Reference in New Issue
Block a user