diff --git a/client/packages/lowcoder/src/api/orgApi.ts b/client/packages/lowcoder/src/api/orgApi.ts index 588a20df5..379234b32 100644 --- a/client/packages/lowcoder/src/api/orgApi.ts +++ b/client/packages/lowcoder/src/api/orgApi.ts @@ -62,6 +62,7 @@ export class OrgApi extends Api { static updateOrgURL = (orgId: string) => `/organizations/${orgId}/update`; static fetchUsage = (orgId: string) => `/organizations/${orgId}/api-usage`; static fetchOrgsByEmailURL = (email: string) => `organizations/byuser/${email}`; + static fetchGroupPotentialMembersURL = (groupId: string) => `/groups/${groupId}/potential-members`; static createGroup(request: { name: string }): AxiosPromise> { return Api.post(OrgApi.createGroupURL, request); @@ -110,6 +111,10 @@ export class OrgApi extends Api { return Api.get(OrgApi.fetchGroupUsersURL(groupId)); } + static fetchGroupPotentialMembers(searchName: string, groupId: string): AxiosPromise { + return Api.get(OrgApi.fetchGroupPotentialMembersURL(groupId), {searchName}) + } + static fetchGroupUsersPagination(request: fetchGroupUserRequestType): AxiosPromise { const {groupId, ...res} = request; return Api.get(OrgApi.fetchGroupUsersURL(groupId), {...res}); diff --git a/client/packages/lowcoder/src/constants/reduxActionConstants.ts b/client/packages/lowcoder/src/constants/reduxActionConstants.ts index f14f40c73..821470ac5 100644 --- a/client/packages/lowcoder/src/constants/reduxActionConstants.ts +++ b/client/packages/lowcoder/src/constants/reduxActionConstants.ts @@ -86,6 +86,7 @@ export const ReduxActionTypes = { UPDATE_USER_ORG_ROLE: "UPDATE_USER_ORG_ROLE", UPDATE_USER_GROUP_ROLE: "UPDATE_USER_GROUP_ROLE", FETCH_ORG_ALL_USERS: "FETCH_ORG_ALL_USERS", + FETCH_GROUP_POTENTIAL_MEMBERS: "FETCH_ORG_ALL_GROUP_MEMBERS", FETCH_ORG_ALL_USERS_SUCCESS: "FETCH_ORG_ALL_USERS_SUCCESS", FETCH_GROUP_USERS: "FETCH_GROUP_USERS", FETCH_GROUP_USERS_SUCCESS: "FETCH_GROUP_USERS_SUCCESS", diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index fee16d103..48774170c 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -3008,6 +3008,7 @@ export const en = { "deleteModalTitle": "Delete This Group", "deleteModalContent": "The Deleted Group Cannot Be Restored. Are You Sure to Delete the Group?", "addMember": "Add Members", + "searchMember": "Search Members", "nameColumn": "User Name", "joinTimeColumn": "Joining Time", "actionColumn": "Operation", diff --git a/client/packages/lowcoder/src/pages/setting/permission/addGroupUserDialog.tsx b/client/packages/lowcoder/src/pages/setting/permission/addGroupUserDialog.tsx index 8af0e3cec..46cad16b6 100644 --- a/client/packages/lowcoder/src/pages/setting/permission/addGroupUserDialog.tsx +++ b/client/packages/lowcoder/src/pages/setting/permission/addGroupUserDialog.tsx @@ -1,11 +1,14 @@ import Column from "antd/es/table/Column"; import OrgApi from "api/orgApi"; import { GroupUser, MEMBER_ROLE, OrgUser } from "constants/orgConstants"; -import { CheckBox, CustomModal } from "lowcoder-design"; -import { CSSProperties, ReactNode, useEffect, useRef, useState } from "react"; +import { CheckBox, CustomModal, Search } from "lowcoder-design"; +import { CSSProperties, ReactNode, useEffect, useRef, useState, useCallback } from "react"; import { connect, useDispatch } from "react-redux"; import { AppState } from "redux/reducers"; -import { fetchGroupUsersAction, fetchOrgUsersAction } from "redux/reduxActions/orgActions"; +import { fetchGroupUsersAction, + fetchOrgUsersAction, + fetchGroupPotentialMembersAction +} from "redux/reduxActions/orgActions"; import styled from "styled-components"; import { StyledTable, UserTableCellWrapper } from "./styledComponents"; import { formatTimestamp } from "util/dateTimeUtils"; @@ -14,6 +17,7 @@ import { isGroupAdmin } from "util/permissionUtils"; import { SuperUserIcon } from "lowcoder-design"; import { EmptyContent } from "pages/common/styledComponent"; import { trans } from "i18n"; +import { debounce } from "lodash"; const TableWrapper = styled.div` margin-right: -16px; @@ -40,7 +44,25 @@ function AddGroupUserDialog(props: { const addableUsers = orgUsers.filter((user) => !groupUserIdMap.has(user.userId)); const toAddUserIdRecord = useRef>({}); const [confirmLoading, setConfirmLoading] = useState(false); + const [searchValue, setSearchValue] = useState("") const dispatch = useDispatch(); + + const debouncedFetchPotentialMembers = useCallback( + debounce((searchVal: string) => { + dispatch(fetchGroupPotentialMembersAction(searchVal, groupId)); + }, 500), + [dispatch, groupId] + ); + + useEffect(() => { + if (searchValue.length > 2 || searchValue === "") { + debouncedFetchPotentialMembers(searchValue); + } + return () => { + debouncedFetchPotentialMembers.cancel(); + }; + }, [searchValue, debouncedFetchPotentialMembers]); + useEffect(() => { if (dialogVisible) { dispatch(fetchOrgUsersAction(orgId)); @@ -92,7 +114,18 @@ function AddGroupUserDialog(props: { setDialogVisible(false); }} > - {!addableUsers || addableUsers.length === 0 ? ( + setSearchValue(e.target.value)} + style={{ + width: "100%", + height: "32px", + paddingRight: "20px", + marginBottom: "10px" + }} + /> + {(!addableUsers || addableUsers.length === 0) ? ( ) : ( @@ -106,7 +139,7 @@ function AddGroupUserDialog(props: { scroll={{ y: 309 }} > ({ payload: payload, }); +export const fetchGroupPotentialMembersAction = (searchName: string, groupId: string) => ({ + type: ReduxActionTypes.FETCH_GROUP_POTENTIAL_MEMBERS, + payload: { + searchName, + groupId + }, +}); + export type AddGroupUserPayload = { role: string; groupId: string; diff --git a/client/packages/lowcoder/src/redux/sagas/orgSagas.ts b/client/packages/lowcoder/src/redux/sagas/orgSagas.ts index b259f12a0..a2339dca9 100644 --- a/client/packages/lowcoder/src/redux/sagas/orgSagas.ts +++ b/client/packages/lowcoder/src/redux/sagas/orgSagas.ts @@ -107,11 +107,30 @@ export function* updateUserGroupRoleSaga(action: ReduxAction) { + try { + const response: AxiosResponse = yield call( + OrgApi.fetchGroupPotentialMembers, + action.payload.searchName, + action.payload.groupId + ); + const isValidResponse: boolean = validateResponse(response); + if (isValidResponse) { + yield put({ + type: ReduxActionTypes.FETCH_ORG_ALL_USERS_SUCCESS, + payload: response.data.data, + }); + } + } catch (error) { + log.error(error); + } +} + export function* fetchOrgUsersSaga(action: ReduxAction<{ orgId: string }>) { try { const response: AxiosResponse = yield call( OrgApi.fetchOrgUsers, - action.payload.orgId + action.payload.orgId, ); const isValidResponse: boolean = validateResponse(response); if (isValidResponse) { @@ -377,6 +396,7 @@ export default function* orgSagas() { takeLatest(ReduxActionTypes.UPDATE_USER_ORG_ROLE, updateUserOrgRoleSaga), takeLatest(ReduxActionTypes.UPDATE_USER_GROUP_ROLE, updateUserGroupRoleSaga), takeLatest(ReduxActionTypes.FETCH_ORG_ALL_USERS, fetchOrgUsersSaga), + takeLatest(ReduxActionTypes.FETCH_GROUP_POTENTIAL_MEMBERS, fetchGroupPotentialMembersSaga), takeLatest(ReduxActionTypes.DELETE_ORG_USER, deleteOrgUserSaga), takeLatest(ReduxActionTypes.QUIT_GROUP, quitGroupSaga), takeLatest(ReduxActionTypes.QUIT_ORG, quitOrgSaga),