MCPcopy Index your code
hub / github.com/bytebase/bytebase / ProjectSelect

Function ProjectSelect

frontend/src/react/components/ProjectSelect.tsx:29–137  ·  view source on GitHub ↗
({
  value,
  onChange,
  placeholder,
  disabled,
  className,
  excludeDefault = true,
  emptyContent,
  portal,
}: ProjectSelectProps)

Source from the content-addressed store, hash-verified

27}
28
29export function ProjectSelect({
30 value,
31 onChange,
32 placeholder,
33 disabled,
34 className,
35 excludeDefault = true,
36 emptyContent,
37 portal,
38}: ProjectSelectProps) {
39 const { t } = useTranslation();
40 const [projects, setProjects] = useState<Project[]>([]);
41 // Projects referenced by `value` that aren't in the paged fetch.
42 // Mirrors Vue's `additionalOptions` so deep-linked URLs (e.g.
43 // `/sql-editor/projects/foo/...`) show the correct project label
44 // when the user lands on the page before the matching page-1 fetch
45 // returns it.
46 const [additionalProjects, setAdditionalProjects] = useState<Project[]>([]);
47
48 // Read `excludeDefault` from a ref inside the callback so the
49 // callback identity stays stable across re-renders. Without this, any
50 // parent re-render that re-evaluates the `excludeDefault` prop
51 // expression (e.g. the SQL Editor's `AsidePanel` re-rendering on
52 // tab.connection mutations) recreates the callback, which causes the
53 // mount-`useEffect` below to re-fire and hit `ListProjects` on every
54 // re-render. The boolean value itself is read live each call, so
55 // updates still take effect — just without re-running the effect.
56 const excludeDefaultRef = useRef(excludeDefault);
57 excludeDefaultRef.current = excludeDefault;
58
59 const fetchProjects = useCallback((query: string) => {
60 useAppStore
61 .getState()
62 .fetchProjectList({
63 filter: { query, excludeDefault: excludeDefaultRef.current },
64 pageSize: getDefaultPagination(),
65 })
66 .then(({ projects: result }) => setProjects(result));
67 }, []);
68
69 // Fetch the first page on mount, and re-fetch only when
70 // `excludeDefault` actually flips (rare — typically once after
71 // permissions hydrate). `fetchProjects` is stable so this effect
72 // never re-fires from parent re-renders alone.
73 useEffect(() => {
74 fetchProjects("");
75 }, [excludeDefault, fetchProjects]);
76
77 // Hydrate the selected project so the trigger always renders its
78 // label, even before the paged list loads or when the project is
79 // outside the first page window.
80 useEffect(() => {
81 if (!isValidProjectName(value)) return;
82 let cancelled = false;
83 void useAppStore
84 .getState()
85 .getOrFetchProjectByName(value)
86 .then((p) => {

Callers

nothing calls this directly

Calls 5

getDefaultPaginationFunction · 0.90
isValidProjectNameFunction · 0.90
addMethod · 0.80
tFunction · 0.50

Tested by

no test coverage detected