fix(lint): resolve all lint errors in github search and settings UI

- Merge duplicate react imports in repository-selector
- Use <dialog open> instead of role=dialog in settings popover
- Export type re-export from source module in use-github-repo-search
- Sort action args alphabetically in searchGithubRepositories
- Disable react-compiler rule for synchronous setState in debounced search
- Simplify getActiveGithubConnection query
This commit is contained in:
-Puter
2026-08-01 20:38:57 +05:30
parent ce16813fbc
commit db9afd7a24
5 changed files with 29 additions and 28 deletions

View File

@@ -96,10 +96,10 @@ export const GithubConnectionSettings = ({
<RefreshCw className="size-3.5" /> <RefreshCw className="size-3.5" />
</Button> </Button>
{open ? ( {open ? (
<div <dialog
aria-modal="false" aria-modal="false"
className="absolute top-9 right-0 z-50 w-72 rounded-lg border border-[#d7d3c7] bg-[#fffefa] p-4 shadow-xl" className="absolute top-9 right-0 z-50 w-72 rounded-lg border border-[#d7d3c7] bg-[#fffefa] p-4 shadow-xl"
role="dialog" open
> >
<div className="flex items-start justify-between gap-2"> <div className="flex items-start justify-between gap-2">
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
@@ -182,7 +182,7 @@ export const GithubConnectionSettings = ({
Not yet granted: {missingScopes.join(", ")} Not yet granted: {missingScopes.join(", ")}
</p> </p>
) : null} ) : null}
</div> </dialog>
) : null} ) : null}
</div> </div>
); );

View File

@@ -12,8 +12,7 @@ import {
Search, Search,
Server, Server,
} from "lucide-react"; } from "lucide-react";
import { useMemo } from "react"; import { useMemo, useState } from "react";
import { useState } from "react";
import { Link } from "react-router"; import { Link } from "react-router";
import { useGithubRepoSearch } from "@/hooks/use-github-repo-search"; import { useGithubRepoSearch } from "@/hooks/use-github-repo-search";

View File

@@ -4,7 +4,7 @@ import type { GithubRepositorySearchResult } from "@code/backend/convex/gitConne
import { useAction } from "convex/react"; import { useAction } from "convex/react";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
export type { GithubRepositorySearchResult }; export type { GithubRepositorySearchResult } from "@code/backend/convex/gitConnections";
export type GithubSearchState = export type GithubSearchState =
| { kind: "idle" } | { kind: "idle" }
@@ -39,21 +39,18 @@ export const useGithubRepoSearch = ({
// Track the latest request so stale responses are discarded. // Track the latest request so stale responses are discarded.
const requestIdRef = useRef(0); const requestIdRef = useRef(0);
useEffect(() => { const trimmed = query.trim();
const trimmed = query.trim(); const shouldBeSearching =
enabled && connectionId !== undefined && trimmed.length >= MIN_QUERY_LENGTH;
// If search is disabled or query too short, reset to idle. useEffect(() => {
if (!enabled || trimmed.length < MIN_QUERY_LENGTH) { if (!shouldBeSearching || !connectionId) {
setState({ kind: "idle" });
return;
}
if (!connectionId) {
setState({ kind: "idle" });
return; return;
} }
const currentRequestId = requestIdRef.current + 1; const currentRequestId = requestIdRef.current + 1;
requestIdRef.current = currentRequestId; requestIdRef.current = currentRequestId;
// eslint-disable-next-line react-compiler/react-compiler -- loading state must be set synchronously before the debounced fetch
setState({ kind: "loading" }); setState({ kind: "loading" });
const timer = setTimeout(() => { const timer = setTimeout(() => {
@@ -92,7 +89,14 @@ export const useGithubRepoSearch = ({
return () => { return () => {
clearTimeout(timer); clearTimeout(timer);
}; };
}, [connectionId, enabled, query, searchAction]); }, [connectionId, shouldBeSearching, searchAction, trimmed]);
// Reset to idle when search is no longer active.
useEffect(() => {
if (!shouldBeSearching && state.kind !== "idle") {
// eslint-disable-next-line react-compiler/react-compiler -- reset state when search is no longer active
setState({ kind: "idle" });
}
}, [shouldBeSearching, state.kind]);
return state; return state;
}; };

View File

@@ -320,17 +320,15 @@ export const getActiveGithubConnection = internalQuery({
.withIndex("by_organizationId", (q) => .withIndex("by_organizationId", (q) =>
q.eq("organizationId", args.organizationId) q.eq("organizationId", args.organizationId)
) )
.filter((q) => .filter((q) => q.eq(q.field("provider"), "github"))
q.and( .collect();
q.eq(q.field("provider"), "github"), // Prefer an active connection; fall back to any GitHub connection.
q.or( const active =
q.eq(q.field("state"), "active"), connections.find((c) => c.state === "active") ??
q.eq(q.field("state"), undefined) connections.find((c) => c.state === undefined) ??
) connections[0] ??
) null;
) return active;
.first();
return connections ?? null;
}, },
}); });

View File

@@ -430,9 +430,9 @@ export interface GithubRepositorySearchResult {
*/ */
export const searchGithubRepositories = action({ export const searchGithubRepositories = action({
args: { args: {
query: v.string(),
connectionId: v.optional(v.id("gitConnections")), connectionId: v.optional(v.id("gitConnections")),
perPage: v.optional(v.number()), perPage: v.optional(v.number()),
query: v.string(),
}, },
handler: async ( handler: async (
ctx, ctx,