From 3800c849484f547547b1e0d832a9de93a500fa56 Mon Sep 17 00:00:00 2001 From: bot-hermes Date: Fri, 14 Aug 2026 13:12:50 +0000 Subject: [PATCH] =?UTF-8?q?feat(ui):=20forge=20user=20lookup=20=E2=80=94?= =?UTF-8?q?=20assignee=20combobox,=20@-mentions,=20repo-scoped=20user=20se?= =?UTF-8?q?arch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Repo-scoped assignable-user search for GitHub, GitLab, and Gitea, surfaced as an assignee combobox in the metadata editor and @-mention autocomplete in forge comment/reply/review surfaces. - server: GET /api/{provider}/users/search (assignees / project members), query + directory/override repo resolution, 429 -> 503, connected:false degradation; GitLab assignee writes resolve login -> ID server-side - wire: searchUsers (+ searchLabels/milestones/branches/tags) on the three API clients with tests - facade: userSearch capability (all three), searchUsers adapters, mapGithubAssignee/mapGitlabMember/mapGiteaAssignee -> ForgeUser - ui: ForgeLookupCombobox (keyboard nav, debounced 30s-TTL cache, connected-only caching), ForgeMentionTextarea (@ token parsing, caret restore), free-text fallback when lookup is unavailable; i18n in 12 locales - extras sharing the same infrastructure: GitLab create-issue dialog and label/milestone/branch/tag lookups in the metadata editor --- .../forge/actions/ForgeCommentComposer.tsx | 10 +- .../forge/actions/ForgeCreateIssueDialog.tsx | 124 ++++++ .../forge/actions/ForgeLookupCombobox.tsx | 190 +++++++++ .../forge/actions/ForgeMentionTextarea.tsx | 206 ++++++++++ .../forge/actions/ForgeMetadataEditor.tsx | 51 ++- .../forge/actions/ForgeReviewActions.tsx | 10 +- .../views/forge/actions/ForgeThreadReply.tsx | 10 +- .../components/views/forge/actions/index.ts | 1 + .../views/forge/actions/useForgeLookup.ts | 206 ++++++++++ .../views/git/GitHubIssuesSection.tsx | 32 +- .../views/git/GitLabIssuesSection.tsx | 28 +- .../views/git/GiteaIssuesSection.tsx | 28 +- packages/ui/src/lib/api/types.ts | 174 +++++++++ packages/ui/src/lib/forge/adapters.ts | 310 ++++++++++++++- packages/ui/src/lib/forge/forge.test.ts | 360 +++++++++++++++++- packages/ui/src/lib/forge/index.ts | 8 + packages/ui/src/lib/forge/normalize.ts | 30 ++ packages/ui/src/lib/forge/provider.ts | 110 ++++++ packages/ui/src/lib/forge/types.ts | 10 + packages/ui/src/lib/i18n/messages/de.ts | 9 + packages/ui/src/lib/i18n/messages/en.ts | 9 + packages/ui/src/lib/i18n/messages/es.ts | 9 + packages/ui/src/lib/i18n/messages/fr.ts | 9 + packages/ui/src/lib/i18n/messages/ja.ts | 9 + packages/ui/src/lib/i18n/messages/ko.ts | 9 + packages/ui/src/lib/i18n/messages/pl.ts | 9 + packages/ui/src/lib/i18n/messages/pt-BR.ts | 9 + packages/ui/src/lib/i18n/messages/uk.ts | 9 + packages/ui/src/lib/i18n/messages/zh-CN.ts | 9 + packages/ui/src/lib/i18n/messages/zh-TW.ts | 9 + .../web/server/lib/gitea/DOCUMENTATION.md | 1 + packages/web/server/lib/gitea/client.js | 8 + packages/web/server/lib/gitea/routes.js | 267 +++++++++++++ packages/web/server/lib/gitea/routes.test.js | 168 ++++++++ .../web/server/lib/github/DOCUMENTATION.md | 1 + packages/web/server/lib/github/routes.js | 319 ++++++++++++++++ packages/web/server/lib/github/routes.test.js | 244 ++++++++++++ .../web/server/lib/gitlab/DOCUMENTATION.md | 1 + packages/web/server/lib/gitlab/client.js | 11 + packages/web/server/lib/gitlab/routes.js | 305 +++++++++++++++ packages/web/server/lib/gitlab/routes.test.js | 228 +++++++++++ packages/web/src/api/gitea.test.ts | 94 +++++ packages/web/src/api/gitea.ts | 80 ++++ packages/web/src/api/github.test.ts | 99 +++++ packages/web/src/api/github.ts | 90 +++++ packages/web/src/api/gitlab.test.ts | 94 +++++ packages/web/src/api/gitlab.ts | 80 ++++ 47 files changed, 4052 insertions(+), 35 deletions(-) create mode 100644 packages/ui/src/components/views/forge/actions/ForgeCreateIssueDialog.tsx create mode 100644 packages/ui/src/components/views/forge/actions/ForgeLookupCombobox.tsx create mode 100644 packages/ui/src/components/views/forge/actions/ForgeMentionTextarea.tsx create mode 100644 packages/ui/src/components/views/forge/actions/useForgeLookup.ts create mode 100644 packages/web/src/api/github.test.ts diff --git a/packages/ui/src/components/views/forge/actions/ForgeCommentComposer.tsx b/packages/ui/src/components/views/forge/actions/ForgeCommentComposer.tsx index 4a86ddee..10661f7b 100644 --- a/packages/ui/src/components/views/forge/actions/ForgeCommentComposer.tsx +++ b/packages/ui/src/components/views/forge/actions/ForgeCommentComposer.tsx @@ -1,11 +1,11 @@ import React, { useState } from 'react'; import { Icon } from '@/components/icon/Icon'; import { Button } from '@/components/ui/button'; -import { Textarea } from '@/components/ui/textarea'; import { toast } from '@/components/ui/toast'; import { useI18n } from '@/lib/i18n'; import type { ForgeEntityRef, ForgeProvider } from '@/lib/forge/provider'; import type { ForgeComment } from '@/lib/forge/types'; +import { ForgeMentionTextarea } from './ForgeMentionTextarea'; interface ForgeCommentComposerProps { provider: ForgeProvider; @@ -47,12 +47,14 @@ export const ForgeCommentComposer: React.FC = ({ prov return (
-