From 63905fa390f45fd2a96f35a028af09821c9ad4ca Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Tue, 12 May 2026 19:11:49 +0200 Subject: [PATCH 1/2] fix(collections): add id workaround for all collections (@fehmer) (#7944) --- frontend/src/ts/collections/presets.ts | 12 +++++++----- .../src/ts/collections/result-filter-presets.ts | 12 +++++++----- frontend/src/ts/collections/results.ts | 10 ++++------ frontend/src/ts/collections/tags.ts | 14 ++++++++------ frontend/src/ts/collections/utils/misc.ts | 9 +++++++++ 5 files changed, 35 insertions(+), 22 deletions(-) diff --git a/frontend/src/ts/collections/presets.ts b/frontend/src/ts/collections/presets.ts index 98a9a0b6725b..051497b34340 100644 --- a/frontend/src/ts/collections/presets.ts +++ b/frontend/src/ts/collections/presets.ts @@ -9,7 +9,7 @@ import Ape from "../ape"; import { queryClient } from "../queries"; import { baseKey } from "../queries/utils/keys"; import { ConfigGroupName } from "@monkeytype/schemas/configs"; -import { tempId } from "./utils/misc"; +import { applyIdWorkaround, tempId } from "./utils/misc"; import { isAuthenticated } from "../states/core"; import { replaceUnderscoresWithSpaces } from "../utils/strings"; @@ -42,10 +42,12 @@ const presetsCollection = createCollection( throw new Error("Error fetching presets:" + response.body.message); } - return response.body.data.map((it) => ({ - ...it, - name: replaceUnderscoresWithSpaces(it.name), - })); + return response.body.data + .map((it) => ({ + ...it, + name: replaceUnderscoresWithSpaces(it.name), + })) + .map(applyIdWorkaround); }, }), ); diff --git a/frontend/src/ts/collections/result-filter-presets.ts b/frontend/src/ts/collections/result-filter-presets.ts index 774771d67930..1ef6fb3c47ad 100644 --- a/frontend/src/ts/collections/result-filter-presets.ts +++ b/frontend/src/ts/collections/result-filter-presets.ts @@ -12,7 +12,7 @@ import { replaceSpacesWithUnderscores, replaceUnderscoresWithSpaces, } from "../utils/strings"; -import { tempId } from "./utils/misc"; +import { applyIdWorkaround, tempId } from "./utils/misc"; import { fetchUserFromApi } from "../ape/user"; const queryKeys = { @@ -31,10 +31,12 @@ const resultFilterPresetsCollection = createCollection( const userData = await fetchUserFromApi(); if (userData === undefined) return []; - return (userData.resultFilterPresets ?? []).map((it) => ({ - ...it, - name: replaceUnderscoresWithSpaces(it.name), - })); + return (userData.resultFilterPresets ?? []) + .map((it) => ({ + ...it, + name: replaceUnderscoresWithSpaces(it.name), + })) + .map(applyIdWorkaround); }, }), ); diff --git a/frontend/src/ts/collections/results.ts b/frontend/src/ts/collections/results.ts index 0b8662f7f78c..53133bb829ea 100644 --- a/frontend/src/ts/collections/results.ts +++ b/frontend/src/ts/collections/results.ts @@ -34,6 +34,7 @@ import { import { isAuthenticated } from "../states/core"; import { createEffectOn } from "../hooks/effects"; import { getLastResult, setLastResult } from "../states/snapshot"; +import { applyIdWorkaround } from "./utils/misc"; export type ResultsQueryState = { difficulty: SnapshotResult["difficulty"][]; @@ -180,9 +181,6 @@ function normalizeResult( resultDate.setHours(0); resultDate.setMilliseconds(0); - // @ts-expect-error without this resorting the datatable causes wrong data e.g. tags to show up - result.id = result._id; - //results strip default values, add them back result.bailedOut ??= false; result.blindMode ??= false; @@ -229,9 +227,9 @@ const resultsCollection = createCollection( throw new Error("Error fetching results:" + response.body.message); } - const results = response.body.data.map((result) => - normalizeResult(result, knownTagIds), - ); + const results = response.body.data + .map((result) => normalizeResult(result, knownTagIds)) + .map(applyIdWorkaround); if (getLastResult() === undefined && results.length > 0) { const lastResult = results.reduce((acc, cur) => diff --git a/frontend/src/ts/collections/tags.ts b/frontend/src/ts/collections/tags.ts index b4f3bf45b174..5142acebbae3 100644 --- a/frontend/src/ts/collections/tags.ts +++ b/frontend/src/ts/collections/tags.ts @@ -20,7 +20,7 @@ import { } from "@monkeytype/schemas/shared"; import { Difficulty } from "@monkeytype/schemas/configs"; import { Language } from "@monkeytype/schemas/languages"; -import { tempId } from "./utils/misc"; +import { applyIdWorkaround, tempId } from "./utils/misc"; import { fetchUserFromApi } from "../ape/user"; export type TagItem = UserTag & { active: boolean }; @@ -40,11 +40,13 @@ const tagsCollection = createCollection( const userData = await fetchUserFromApi(); if (userData === undefined) return []; - return (userData.tags ?? []).map((tag) => ({ - ...tag, - name: tag.name.replace(/_/g, " "), - active: activeIds.includes(tag._id), - })); + return (userData.tags ?? []) + .map((tag) => ({ + ...tag, + name: tag.name.replace(/_/g, " "), + active: activeIds.includes(tag._id), + })) + .map(applyIdWorkaround); }, }), ); diff --git a/frontend/src/ts/collections/utils/misc.ts b/frontend/src/ts/collections/utils/misc.ts index 6324263d72ca..bce53db4547a 100644 --- a/frontend/src/ts/collections/utils/misc.ts +++ b/frontend/src/ts/collections/utils/misc.ts @@ -3,3 +3,12 @@ export function tempId(): string { "temp_" + Math.random().toString(36).slice(2) + Date.now().toString(36) ); } + +/** + * temp. workaround for https://github.com/TanStack/db/issues/1524 + */ +export function applyIdWorkaround(item: T): T { + //@ts-expect-error this is fine + item.id = item._id; + return item; +} From 1171ed5072e43f4e6df679699479bfab47721aef Mon Sep 17 00:00:00 2001 From: ares?? <146799833+AzureNightlock@users.noreply.github.com> Date: Tue, 12 May 2026 23:04:05 +0530 Subject: [PATCH 2/2] feat(command-line): add profile search (@AzureNightlock) (#7867) ### Description This PR: Adds the ability to search for a profile from the command line Changes Made: * Added a search profile command in navigation.ts * Added frontend and backend validation Additional Changes Made: * Added an alias to toggleFullscreen command * Added debounce ### Checks - [x] Make sure the PR title follows the Conventional Commits standard. (https://www.conventionalcommits.org for more info) - [x] Make sure to include your GitHub username prefixed with @ inside parentheses at the end of the PR title. --------- Co-authored-by: Christian Fehmer --- .../src/ts/commandline/lists/navigation.ts | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/frontend/src/ts/commandline/lists/navigation.ts b/frontend/src/ts/commandline/lists/navigation.ts index fc81b9b6ea77..5f61c557a756 100644 --- a/frontend/src/ts/commandline/lists/navigation.ts +++ b/frontend/src/ts/commandline/lists/navigation.ts @@ -1,7 +1,10 @@ import { navigate } from "../../controllers/route-controller"; import { isAuthenticated } from "../../states/core"; import { toggleFullscreen } from "../../utils/misc"; -import { Command } from "../types"; +import { Command, withValidation } from "../types"; +import { remoteValidation } from "../../utils/remote-validation"; +import { UserNameSchema } from "@monkeytype/schemas/users"; +import Ape from "../../ape"; const commands: Command[] = [ { @@ -50,6 +53,27 @@ const commands: Command[] = [ isAuthenticated() ? void navigate("/account") : void navigate("/login"); }, }, + withValidation({ + id: "searchProfile", + display: "Search for a profile", + alias: "profile user search find lookup", + icon: "fa-search", + input: true, + validation: { + schema: UserNameSchema, + debounceDelay: 1000, + isValid: remoteValidation( + async (name) => Ape.users.getProfile({ params: { uidOrName: name } }), + { + on4xx: () => "Unknown user", + }, + ), + }, + exec: ({ input }): void => { + if (input === undefined) return; + void navigate(`/profile/${input}`); + }, + }), { id: "toggleFullscreen", display: "Toggle Fullscreen",