MCPcopy Create free account
hub / github.com/bytebase/bytebase / MemberTable

Function MemberTable

frontend/src/react/pages/settings/MembersPage.tsx:148–604  ·  view source on GitHub ↗
({
  bindings,
  allowEdit,
  selectedBindings,
  onSelectionChange,
  onUpdateBinding,
  onRevokeBinding,
  scope,
}: {
  bindings: MemberBinding[];
  allowEdit: boolean;
  selectedBindings: string[];
  onSelectionChange: (selected: string[]) => void;
  onUpdateBinding: (binding: MemberBinding) => void;
  onRevokeBinding: (binding: MemberBinding) => void;
  scope: "workspace" | "project";
})

Source from the content-addressed store, hash-verified

146// ============================================================
147
148function MemberTable({
149 bindings,
150 allowEdit,
151 selectedBindings,
152 onSelectionChange,
153 onUpdateBinding,
154 onRevokeBinding,
155 scope,
156}: {
157 bindings: MemberBinding[];
158 allowEdit: boolean;
159 selectedBindings: string[];
160 onSelectionChange: (selected: string[]) => void;
161 onUpdateBinding: (binding: MemberBinding) => void;
162 onRevokeBinding: (binding: MemberBinding) => void;
163 scope: "workspace" | "project";
164}) {
165 const { t } = useTranslation();
166 const currentUser = useCurrentUser();
167 const isSaaSMode = useAppStore((s) => s.isSaaSMode());
168 const batchGetOrFetchUsers = useAppStore(
169 (state) => state.batchGetOrFetchUsers
170 );
171 const roleList = useAppStore((state) => state.roleList);
172 const navigate = useNavigate();
173 const canGetGroups = hasWorkspacePermissionV2("bb.groups.get");
174 const canGetUsers = hasWorkspacePermissionV2("bb.users.get");
175
176 // Group expand state. Cache is keyed by group name and invalidated
177 // when the group-binding *content* changes — not on `bindings`
178 // reference change, because the parent rebuilds `memberBindings` via
179 // `useMemo(() => getMemberBindings(...))` and gets a new array identity
180 // whenever its deps change. We can't use the `prevBindingsRef.current
181 // !== bindings` shortcut that `GroupsPage` uses (its `groups` comes
182 // from a reducer-backed `usePagedData` with stable identity).
183 // Comparing a content-derived signature instead lets the cache only
184 // reset on real membership changes — same effect, different trigger.
185 const [expandedGroups, setExpandedGroups] = useState<Set<string>>(new Set());
186 const [memberCache, setMemberCache] = useState<Map<string, User[]>>(
187 new Map()
188 );
189 const memberCacheRef = useRef(memberCache);
190 memberCacheRef.current = memberCache;
191 const loadingRef = useRef<Set<string>>(new Set());
192
193 const fetchGroupMembers = useCallback(
194 (group: GroupBinding) => {
195 if (loadingRef.current.has(group.name)) return;
196 loadingRef.current.add(group.name);
197 const memberNames = group.members.map((m) => m.member);
198 batchGetOrFetchUsers(memberNames)
199 .then((users: (User | undefined)[]) => {
200 setMemberCache((prev) => {
201 const next = new Map(prev);
202 next.set(
203 group.name,
204 users.filter((u): u is User => !!u)
205 );

Callers

nothing calls this directly

Calls 15

useCurrentUserFunction · 0.90
useNavigateFunction · 0.90
hasWorkspacePermissionV2Function · 0.90
getAccountTypeByEmailFunction · 0.90
sortRolesFunction · 0.90
displayRoleTitleFromListFunction · 0.90
isSelectDisabledFunction · 0.85
toggleOneFunction · 0.85
renderProjectRoleSummaryFunction · 0.85
canEditFunction · 0.85
addMethod · 0.80
useAppStoreFunction · 0.70

Tested by

no test coverage detected