From 55d42d86cf947c038f798671403a6779a576dbfe Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Fri, 12 Jun 2026 13:23:15 +0200 Subject: [PATCH 01/30] refactor: solid account settings (@fehmer) --- frontend/src/index.html | 3 +- frontend/src/ts/components/mount.tsx | 3 +- .../account-settings/AccountSettingsPage.tsx | 55 +++++++++++++++++++ frontend/src/ts/states/account-settings.ts | 14 +++++ 4 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 frontend/src/ts/components/pages/account-settings/AccountSettingsPage.tsx diff --git a/frontend/src/index.html b/frontend/src/index.html index da677825157e..9fbf5ba6ab05 100644 --- a/frontend/src/index.html +++ b/frontend/src/index.html @@ -33,7 +33,8 @@ - - - - diff --git a/frontend/src/index.html b/frontend/src/index.html index 17deb81ec402..e462f01e88d2 100644 --- a/frontend/src/index.html +++ b/frontend/src/index.html @@ -33,8 +33,7 @@ - - - + diff --git a/frontend/src/ts/components/pages/account-settings/AuthenticationTab.tsx b/frontend/src/ts/components/pages/account-settings/AuthenticationTab.tsx index eec61f231aff..104c0fc0e1f9 100644 --- a/frontend/src/ts/components/pages/account-settings/AuthenticationTab.tsx +++ b/frontend/src/ts/components/pages/account-settings/AuthenticationTab.tsx @@ -55,7 +55,7 @@ function PasswordAuthentication() { text="update password" onClick={() => showUpdatePasswordModal()} />{" "} - hasAdditionalAuthMethodsReactive("password")}> + - - ${key.name} - ${format(new Date(key.createdOn), "dd MMM yyyy HH:mm")} - ${format(new Date(key.modifiedOn), "dd MMM yyyy HH:mm")} - ${ - key.lastUsedOn === -1 - ? "-" - : format(new Date(key.lastUsedOn), "dd MMM yyyy HH:mm") - } - -
- - -
- - - `); - }); - for (const tr of table?.qsa("tr") ?? []) { - const keyid = tr.getAttribute("keyid") as string; - tr.qs("button.toggleActive")?.on("click", (e) => { - void toggleActiveKey(keyid); - }); - tr.qs("button.deleteButton")?.on("click", (e) => { - showSimpleModal({ - title: "Delete Ape key", - text: "Are you sure?", - buttonText: "delete", - execFn: async (_thisPopup) => { - const response = await Ape.apeKeys.delete({ - params: { apeKeyId: keyid }, - }); - if (response.status !== 200) { - return { - status: "error", - message: "Failed to delete key", - notificationOptions: { response }, - }; - } - - onApeKeyChange?.(); - - return { - status: "success", - message: "Key deleted", - }; - }, - }); - }); - tr.qs("button.editButton")?.on("click", (e) => { - showSimpleModal({ - title: "Edit Ape key", - buttonText: "edit", - schema: z.object({ name: ApeKeyNameSchema }), - inputs: { - name: { - type: "text", - placeholder: "name", - }, - }, - - execFn: async ({ name }) => { - const response = await Ape.apeKeys.save({ - params: { apeKeyId: keyid }, - body: { name }, - }); - if (response.status !== 200) { - return { - status: "error", - message: "Failed to update key", - notificationOptions: { response }, - }; - } - return { - status: "success", - message: "Key updated", - }; - }, - }); - }); - } -} - -async function toggleActiveKey(keyId: string): Promise { - const key = apeKeys?.[keyId]; - if (!key || apeKeys === undefined) return; - showLoaderBar(); - const response = await Ape.apeKeys.save({ - params: { apeKeyId: keyId }, - body: { enabled: !key.enabled }, - }); - hideLoaderBar(); - if (response.status !== 200) { - showErrorNotification("Failed to update key", { response }); - return; - } - key.enabled = !key.enabled; - refreshList(); - if (key.enabled) { - showSuccessNotification("Key active"); - } else { - showSuccessNotification("Key inactive"); - } -} - -let onApeKeyChange: (() => void) | undefined = undefined; - -let lostAccess = false; - -export async function update(onApeKeyChangee?: () => void): Promise { - if (lostAccess) { - qs(".pageAccountSettings .tab[data-tab='apeKeys'] table")?.remove(); - qs(".pageAccountSettings .section.apeKeys .buttons")?.remove(); - qs(".pageAccountSettings .section.apeKeys .lostAccess")?.removeClass( - "hidden", - ); - return; - } - onApeKeyChange = onApeKeyChangee; - await getData(); - refreshList(); -} - -qs(".pageAccountSettings")?.onChild("click", "#generateNewApeKey", () => { - showSimpleModal({ - title: "Generate new Ape key", - buttonText: "generate", - schema: z.object({ name: ApeKeyNameSchema }), - inputs: { - name: { - type: "text", - placeholder: "Name", - }, - }, - - execFn: async ({ name }) => { - const response = await Ape.apeKeys.add({ - body: { name, enabled: false }, - }); - if (response.status !== 200) { - return { - status: "error", - message: "Failed to generate key", - notificationOptions: { response }, - }; - } - - const data = response.body.data; - - onApeKeyChange?.(); - - return { - status: "success", - message: "Key generated", - afterHide: (): void => { - setLastGeneratedApeKey(data.apeKey); - showModal("ViewApeKey"); - }, - }; - }, - }); -}); From 1b2b6ceece4a873e691848fb12ee4ed55b166662 Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Fri, 19 Jun 2026 12:23:38 +0200 Subject: [PATCH 25/30] friends leftover --- frontend/src/styles/media-queries-yellow.scss | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/frontend/src/styles/media-queries-yellow.scss b/frontend/src/styles/media-queries-yellow.scss index 95a343b7a1ae..bdc5cde176a8 100644 --- a/frontend/src/styles/media-queries-yellow.scss +++ b/frontend/src/styles/media-queries-yellow.scss @@ -29,15 +29,4 @@ display: none; } } - - .pageFriends { - .content .friends table, - .content .pendingRequests table { - font-size: 0.9rem; - - .badge .text { - display: none; - } - } - } } From 73c15afb2d4a894e1388ffcec0bb28b6acc8db83 Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Fri, 19 Jun 2026 22:52:07 +0200 Subject: [PATCH 26/30] fix UpdateNameModal --- .../ts/components/modals/account-settings/UpdateNameModal.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/ts/components/modals/account-settings/UpdateNameModal.tsx b/frontend/src/ts/components/modals/account-settings/UpdateNameModal.tsx index 48c664ad22ae..0dbf627f9a60 100644 --- a/frontend/src/ts/components/modals/account-settings/UpdateNameModal.tsx +++ b/frontend/src/ts/components/modals/account-settings/UpdateNameModal.tsx @@ -7,10 +7,9 @@ import { isUsingPasswordAuthentication, reauthenticate, } from "../../../auth"; -import { setSnapshot } from "../../../db"; +import { setSnapshot, getSnapshot } from "../../../db"; import { isAuthenticated } from "../../../states/core"; import { showSimpleModal } from "../../../states/simple-modal"; -import { getSnapshot } from "../../../states/snapshot"; import { remoteValidation } from "../../../utils/remote-validation"; export function showUpdateNameModal(): void { From ce21e2a4b1976215eb7d7f67762bfede4c6e4596 Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Fri, 19 Jun 2026 23:02:38 +0200 Subject: [PATCH 27/30] error handling in ApeKeysTab, review comments --- .../pages/account-settings/ApeKeysTab.tsx | 22 ++++++++++++++++--- .../account-settings/AuthenticationTab.tsx | 2 +- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/frontend/src/ts/components/pages/account-settings/ApeKeysTab.tsx b/frontend/src/ts/components/pages/account-settings/ApeKeysTab.tsx index ad981bb7bb8b..a62f02bcd258 100644 --- a/frontend/src/ts/components/pages/account-settings/ApeKeysTab.tsx +++ b/frontend/src/ts/components/pages/account-settings/ApeKeysTab.tsx @@ -1,4 +1,5 @@ import { ApeKeyNameSchema } from "@monkeytype/schemas/ape-keys"; +import { tryCatch } from "@monkeytype/util/trycatch"; import { createColumnHelper } from "@tanstack/solid-table"; import { format as dateFormat } from "date-fns"; import { createMemo, Show } from "solid-js"; @@ -128,7 +129,12 @@ function getColumns(): DataTableColumnDef[] { text: "Are you sure?", buttonText: "delete", execFn: async () => { - await removeApeKey({ apeKeyId: info.getValue() }); + const { error } = await tryCatch( + removeApeKey({ apeKeyId: info.getValue() }), + ); + if (error !== null) { + return { status: "error", message: error.message }; + } return { status: "success", message: "Key deleted" }; }, }); @@ -157,7 +163,12 @@ function addNewKey(): void { }, execFn: async ({ name }) => { - await insertApeKey({ name }); + const { error } = await tryCatch(insertApeKey({ name })); + + if (error !== null) { + return { status: "error", message: error.message }; + } + return { status: "success", message: "Key generated", @@ -183,7 +194,12 @@ function showRenameModal(apeKeyId: string): void { }, execFn: async ({ name }) => { - await renameApeKey({ apeKeyId, name }); + const { error } = await tryCatch(renameApeKey({ apeKeyId, name })); + + if (error !== null) { + return { status: "error", message: error.message }; + } + return { status: "success", message: "Key updated", diff --git a/frontend/src/ts/components/pages/account-settings/AuthenticationTab.tsx b/frontend/src/ts/components/pages/account-settings/AuthenticationTab.tsx index 104c0fc0e1f9..97d3a062de33 100644 --- a/frontend/src/ts/components/pages/account-settings/AuthenticationTab.tsx +++ b/frontend/src/ts/components/pages/account-settings/AuthenticationTab.tsx @@ -54,7 +54,7 @@ function PasswordAuthentication() { class="w-full" text="update password" onClick={() => showUpdatePasswordModal()} - />{" "} + />