0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-06-22 01:27:16 +02:00

Tighten search-box types, expand test prefix, drop stale CSS comment

- chooseFromApi is now generic over the response shape; each caller
  declares a typed *SearchResponse, removing four `any` annotations
- e2e test prefix: rc- → repo-collab- for legibility in the test DB
- web_src/css/modules/search.css: drop the stale leading comment

Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
This commit is contained in:
silverwind 2026-04-26 21:15:54 +02:00
parent 4fd1adee5f
commit 26cdb902c9
No known key found for this signature in database
GPG Key ID: 2E62B41C93869443
5 changed files with 10 additions and 6 deletions

View File

@ -1,5 +1,3 @@
/* Styles for the first-party search-box autocomplete (web_src/js/modules/fomantic/search.ts) */
.ui.search {
position: relative;
}

View File

@ -2,6 +2,8 @@ import {chooseFromApi} from '../../modules/search.ts';
const {appSubUrl} = window.config;
type RepoSearchResponse = {data: Array<{repository: {full_name: string}}>};
export async function initCompSearchRepoBox(el: HTMLElement) {
const uid = el.getAttribute('data-uid');
const exclusive = el.getAttribute('data-exclusive');
@ -10,7 +12,7 @@ export async function initCompSearchRepoBox(el: HTMLElement) {
const input = el.querySelector<HTMLInputElement>('input.prompt')!;
while (el.isConnected) {
const pick = await chooseFromApi(el, url, (response: any) => response.data.map((item: any) => ({
const pick = await chooseFromApi<RepoSearchResponse>(el, url, (response) => response.data.map((item) => ({
title: item.repository.full_name.split('/')[1],
description: item.repository.full_name,
})));

View File

@ -3,6 +3,8 @@ import {chooseFromApi, type SearchResult} from '../../modules/search.ts';
const {appSubUrl} = window.config;
const looksLikeEmailAddressCheck = /^\S+@\S+$/;
type UserSearchResponse = {data: Array<{login: string; avatar_url: string; full_name: string}>};
export async function initCompSearchUserBox() {
const box = document.querySelector<HTMLElement>('#search-user-box');
if (!box) return;
@ -14,7 +16,7 @@ export async function initCompSearchUserBox() {
const input = box.querySelector<HTMLInputElement>('input.prompt')!;
while (box.isConnected) {
const pick = await chooseFromApi(box, url, (response: any, query: string) => {
const pick = await chooseFromApi<UserSearchResponse>(box, url, (response, query) => {
const items: SearchResult[] = [];
const queryUpper = query.toUpperCase();
for (const item of response.data) {

View File

@ -46,6 +46,8 @@ function initRepoSettingsCollaboration() {
}
}
type TeamSearchResponse = {data: Array<{name: string; permission: string}>};
async function initRepoSettingsSearchTeamBox() {
const box = document.querySelector<HTMLElement>('#search-team-box');
if (!box) return;
@ -53,7 +55,7 @@ async function initRepoSettingsSearchTeamBox() {
const url = `${appSubUrl}/org/${box.getAttribute('data-org-name')}/teams/-/search?q={query}`;
const input = box.querySelector<HTMLInputElement>('input.prompt')!;
while (box.isConnected) {
const pick = await chooseFromApi(box, url, (response: any) => response.data.map((item: any) => ({
const pick = await chooseFromApi<TeamSearchResponse>(box, url, (response) => response.data.map((item) => ({
title: item.name,
description: `${item.permission} access`, // TODO: translate this string
})));

View File

@ -17,7 +17,7 @@ function buildResultHTML(result: SearchResult): string {
// Awaits one user selection from an autocomplete attached to `container`. Resolves with
// the chosen item; the caller writes it to whatever input/state it owns. Wrap in a loop
// to keep the search box live across selections.
export function chooseFromApi(container: HTMLElement, url: string, parse: (raw: any, query: string) => SearchResult[], {minCharacters = 2}: {minCharacters?: number} = {}): Promise<SearchResult> {
export function chooseFromApi<T = unknown>(container: HTMLElement, url: string, parse: (raw: T, query: string) => SearchResult[], {minCharacters = 2}: {minCharacters?: number} = {}): Promise<SearchResult> {
return new Promise((resolve) => {
const input = container.querySelector<HTMLInputElement>('input.prompt') ?? container.querySelector<HTMLInputElement>('input')!;