mirror of
https://github.com/coder/coder.git
synced 2025-07-09 11:45:56 +00:00
refactor: Extract ssh logic from auth service (#5670)
* refactor: Extract ssh logic from auth service * Update site/src/i18n/en/userSettingsPage.json Co-authored-by: Kira Pilot <kira@coder.com> Co-authored-by: Kira Pilot <kira@coder.com>
This commit is contained in:
@ -1,3 +1,4 @@
|
||||
{
|
||||
"securityUpdateSuccessMessage": "Updated password."
|
||||
"securityUpdateSuccessMessage": "Updated password.",
|
||||
"sshRegenerateSuccessMessage": "SSH Key regenerated successfully."
|
||||
}
|
||||
|
@ -5,9 +5,11 @@ import {
|
||||
MockGitSSHKey,
|
||||
renderWithAuth,
|
||||
} from "../../../testHelpers/renderHelpers"
|
||||
import { Language as authXServiceLanguage } from "../../../xServices/auth/authXService"
|
||||
import { Language as SSHKeysPageLanguage, SSHKeysPage } from "./SSHKeysPage"
|
||||
import { Language as SSHKeysPageViewLanguage } from "./SSHKeysPageView"
|
||||
import { i18n } from "i18n"
|
||||
|
||||
const { t } = i18n
|
||||
|
||||
describe("SSH keys Page", () => {
|
||||
it("shows the SSH key", async () => {
|
||||
@ -52,7 +54,10 @@ describe("SSH keys Page", () => {
|
||||
fireEvent.click(confirmButton)
|
||||
|
||||
// Check if the success message is displayed
|
||||
await screen.findByText(authXServiceLanguage.successRegenerateSSHKey)
|
||||
const successMessage = t("sshRegenerateSuccessMessage", {
|
||||
ns: "userSettingsPage",
|
||||
})
|
||||
await screen.findByText(successMessage)
|
||||
|
||||
// Check if the API was called correctly
|
||||
expect(API.regenerateUserSSHKey).toBeCalledTimes(1)
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { useActor } from "@xstate/react"
|
||||
import { useContext, useEffect, PropsWithChildren, FC } from "react"
|
||||
import { useMachine } from "@xstate/react"
|
||||
import { PropsWithChildren, FC } from "react"
|
||||
import { sshKeyMachine } from "xServices/sshKey/sshKeyXService"
|
||||
import { ConfirmDialog } from "../../../components/Dialogs/ConfirmDialog/ConfirmDialog"
|
||||
import { Section } from "../../../components/SettingsLayout/Section"
|
||||
import { XServiceContext } from "../../../xServices/StateContext"
|
||||
import { SSHKeysPageView } from "./SSHKeysPageView"
|
||||
|
||||
export const Language = {
|
||||
@ -15,19 +15,13 @@ export const Language = {
|
||||
}
|
||||
|
||||
export const SSHKeysPage: FC<PropsWithChildren<unknown>> = () => {
|
||||
const xServices = useContext(XServiceContext)
|
||||
const [authState, authSend] = useActor(xServices.authXService)
|
||||
const { sshKey, getSSHKeyError, regenerateSSHKeyError } = authState.context
|
||||
|
||||
useEffect(() => {
|
||||
authSend({ type: "GET_SSH_KEY" })
|
||||
}, [authSend])
|
||||
|
||||
const isLoading = authState.matches("signedIn.ssh.gettingSSHKey")
|
||||
const hasLoaded = authState.matches("signedIn.ssh.loaded")
|
||||
const [sshState, sshSend] = useMachine(sshKeyMachine)
|
||||
const isLoading = sshState.matches("gettingSSHKey")
|
||||
const hasLoaded = sshState.matches("loaded")
|
||||
const { getSSHKeyError, regenerateSSHKeyError, sshKey } = sshState.context
|
||||
|
||||
const onRegenerateClick = () => {
|
||||
authSend({ type: "REGENERATE_SSH_KEY" })
|
||||
sshSend({ type: "REGENERATE_SSH_KEY" })
|
||||
}
|
||||
|
||||
return (
|
||||
@ -46,17 +40,15 @@ export const SSHKeysPage: FC<PropsWithChildren<unknown>> = () => {
|
||||
<ConfirmDialog
|
||||
type="delete"
|
||||
hideCancel={false}
|
||||
open={authState.matches("signedIn.ssh.loaded.confirmSSHKeyRegenerate")}
|
||||
confirmLoading={authState.matches(
|
||||
"signedIn.ssh.loaded.regeneratingSSHKey",
|
||||
)}
|
||||
open={sshState.matches("confirmSSHKeyRegenerate")}
|
||||
confirmLoading={sshState.matches("regeneratingSSHKey")}
|
||||
title={Language.regenerateDialogTitle}
|
||||
confirmText={Language.confirmLabel}
|
||||
onConfirm={() => {
|
||||
authSend({ type: "CONFIRM_REGENERATE_SSH_KEY" })
|
||||
sshSend({ type: "CONFIRM_REGENERATE_SSH_KEY" })
|
||||
}}
|
||||
onClose={() => {
|
||||
authSend({ type: "CANCEL_REGENERATE_SSH_KEY" })
|
||||
sshSend({ type: "CANCEL_REGENERATE_SSH_KEY" })
|
||||
}}
|
||||
description={<>{Language.regenerateDialogMessage}</>}
|
||||
/>
|
||||
|
@ -5,7 +5,6 @@ import { displaySuccess } from "../../components/GlobalSnackbar/utils"
|
||||
|
||||
export const Language = {
|
||||
successProfileUpdate: "Updated settings.",
|
||||
successRegenerateSSHKey: "SSH Key regenerated successfully",
|
||||
}
|
||||
|
||||
export const checks = {
|
||||
@ -83,20 +82,12 @@ export interface AuthContext {
|
||||
methods?: TypesGen.AuthMethods
|
||||
permissions?: Permissions
|
||||
checkPermissionsError?: Error | unknown
|
||||
// SSH
|
||||
sshKey?: TypesGen.GitSSHKey
|
||||
getSSHKeyError?: Error | unknown
|
||||
regenerateSSHKeyError?: Error | unknown
|
||||
}
|
||||
|
||||
export type AuthEvent =
|
||||
| { type: "SIGN_OUT" }
|
||||
| { type: "SIGN_IN"; email: string; password: string }
|
||||
| { type: "UPDATE_PROFILE"; data: TypesGen.UpdateUserProfileRequest }
|
||||
| { type: "GET_SSH_KEY" }
|
||||
| { type: "REGENERATE_SSH_KEY" }
|
||||
| { type: "CONFIRM_REGENERATE_SSH_KEY" }
|
||||
| { type: "CANCEL_REGENERATE_SSH_KEY" }
|
||||
| { type: "GET_AUTH_METHODS" }
|
||||
|
||||
export const authMachine =
|
||||
@ -128,12 +119,6 @@ export const authMachine =
|
||||
checkPermissions: {
|
||||
data: TypesGen.AuthorizationResponse
|
||||
}
|
||||
getSSHKey: {
|
||||
data: TypesGen.GitSSHKey
|
||||
}
|
||||
regenerateSSHKey: {
|
||||
data: TypesGen.GitSSHKey
|
||||
}
|
||||
hasFirstUser: {
|
||||
data: boolean
|
||||
}
|
||||
@ -279,79 +264,6 @@ export const authMachine =
|
||||
},
|
||||
},
|
||||
},
|
||||
ssh: {
|
||||
initial: "idle",
|
||||
states: {
|
||||
idle: {
|
||||
on: {
|
||||
GET_SSH_KEY: {
|
||||
target: "gettingSSHKey",
|
||||
},
|
||||
},
|
||||
},
|
||||
gettingSSHKey: {
|
||||
entry: "clearGetSSHKeyError",
|
||||
invoke: {
|
||||
src: "getSSHKey",
|
||||
onDone: [
|
||||
{
|
||||
actions: "assignSSHKey",
|
||||
target: "loaded",
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
actions: "assignGetSSHKeyError",
|
||||
target: "idle",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
loaded: {
|
||||
initial: "idle",
|
||||
states: {
|
||||
idle: {
|
||||
on: {
|
||||
REGENERATE_SSH_KEY: {
|
||||
target: "confirmSSHKeyRegenerate",
|
||||
},
|
||||
},
|
||||
},
|
||||
confirmSSHKeyRegenerate: {
|
||||
on: {
|
||||
CANCEL_REGENERATE_SSH_KEY: {
|
||||
target: "idle",
|
||||
},
|
||||
CONFIRM_REGENERATE_SSH_KEY: {
|
||||
target: "regeneratingSSHKey",
|
||||
},
|
||||
},
|
||||
},
|
||||
regeneratingSSHKey: {
|
||||
entry: "clearRegenerateSSHKeyError",
|
||||
invoke: {
|
||||
src: "regenerateSSHKey",
|
||||
onDone: [
|
||||
{
|
||||
actions: [
|
||||
"assignSSHKey",
|
||||
"notifySuccessSSHKeyRegenerated",
|
||||
],
|
||||
target: "idle",
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
actions: "assignRegenerateSSHKeyError",
|
||||
target: "idle",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
initial: "idle",
|
||||
states: {
|
||||
@ -480,9 +392,6 @@ export const authMachine =
|
||||
checks: permissionsToCheck,
|
||||
})
|
||||
},
|
||||
// SSH
|
||||
getSSHKey: () => API.getUserSSHKey(),
|
||||
regenerateSSHKey: () => API.regenerateUserSSHKey(),
|
||||
// First user
|
||||
hasFirstUser: () => API.hasFirstUser(),
|
||||
},
|
||||
@ -538,25 +447,6 @@ export const authMachine =
|
||||
clearGetPermissionsError: assign({
|
||||
checkPermissionsError: (_) => undefined,
|
||||
}),
|
||||
// SSH
|
||||
assignSSHKey: assign({
|
||||
sshKey: (_, event) => event.data,
|
||||
}),
|
||||
assignGetSSHKeyError: assign({
|
||||
getSSHKeyError: (_, event) => event.data,
|
||||
}),
|
||||
clearGetSSHKeyError: assign({
|
||||
getSSHKeyError: (_) => undefined,
|
||||
}),
|
||||
assignRegenerateSSHKeyError: assign({
|
||||
regenerateSSHKeyError: (_, event) => event.data,
|
||||
}),
|
||||
clearRegenerateSSHKeyError: assign({
|
||||
regenerateSSHKeyError: (_) => undefined,
|
||||
}),
|
||||
notifySuccessSSHKeyRegenerated: () => {
|
||||
displaySuccess(Language.successRegenerateSSHKey)
|
||||
},
|
||||
redirect: (_, { data }) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- data can be undefined
|
||||
if (!data) {
|
||||
|
125
site/src/xServices/sshKey/sshKeyXService.ts
Normal file
125
site/src/xServices/sshKey/sshKeyXService.ts
Normal file
@ -0,0 +1,125 @@
|
||||
import { getUserSSHKey, regenerateUserSSHKey } from "api/api"
|
||||
import { GitSSHKey } from "api/typesGenerated"
|
||||
import { displaySuccess } from "components/GlobalSnackbar/utils"
|
||||
import { createMachine, assign } from "xstate"
|
||||
import { i18n } from "i18n"
|
||||
|
||||
const { t } = i18n
|
||||
|
||||
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(
|
||||
t("sshRegenerateSuccessMessage", { ns: "userSettingsPage" }),
|
||||
)
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
Reference in New Issue
Block a user