Content-Length: 13176 | pFad | http://github.com/lowcoder-org/lowcoder/pull/1817.diff

thub.com diff --git a/client/packages/lowcoder/src/api/applicationApi.ts b/client/packages/lowcoder/src/api/applicationApi.ts index 2411b50d80..8ed818b371 100644 --- a/client/packages/lowcoder/src/api/applicationApi.ts +++ b/client/packages/lowcoder/src/api/applicationApi.ts @@ -99,6 +99,7 @@ class ApplicationApi extends Api { static publicToMarketplaceURL = (applicationId: string) => `/applications/${applicationId}/public-to-marketplace`; static getMarketplaceAppURL = (applicationId: string) => `/applications/${applicationId}/view_marketplace`; static setAppEditingStateURL = (applicationId: string) => `/applications/editState/${applicationId}`; + static getAvailableGroupsMembersURL = (applicationId: string) => `/applications/${applicationId}/groups-members/available`; static serverSettingsURL = () => `/serverSettings`; static fetchHomeData(request: HomeDataPayload): AxiosPromise { @@ -217,6 +218,10 @@ class ApplicationApi extends Api { }); } + static getAvailableGroupsMembers(applicationId: string, search: string): AxiosPromise { + return Api.get(ApplicationApi.getAvailableGroupsMembersURL(applicationId), {search}) + } + /** * set app as public */ diff --git a/client/packages/lowcoder/src/components/PermissionDialog/Permission.tsx b/client/packages/lowcoder/src/components/PermissionDialog/Permission.tsx index 82ea45beb9..6425d3afc6 100644 --- a/client/packages/lowcoder/src/components/PermissionDialog/Permission.tsx +++ b/client/packages/lowcoder/src/components/PermissionDialog/Permission.tsx @@ -3,16 +3,15 @@ import { CloseIcon, CommonTextLabel, CustomSelect, + Search, TacoButton, } from "lowcoder-design"; -import { useEffect, useRef, useState } from "react"; +import { useEffect, useRef, useState, useCallback } from "react"; import styled from "styled-components"; +import { debounce } from "lodash"; import ProfileImage from "pages/common/profileImage"; -import { useDispatch, useSelector } from "react-redux"; -import { fetchGroupsAction, fetchOrgUsersAction } from "redux/reduxActions/orgActions"; -import { getOrgGroups, getOrgUsers } from "redux/selectors/orgSelectors"; -import { OrgGroup, OrgUser } from "constants/orgConstants"; -import { ApplicationPermissionType, ApplicationRoleType } from "constants/applicationConstants"; +import { useSelector } from "react-redux"; +import { ApplicationPermissionType, ApplicationRoleType, GroupsMembersPermission } from "constants/applicationConstants"; import { PermissionItemName, RoleSelectOption, @@ -27,6 +26,8 @@ import { getUser } from "redux/selectors/usersSelectors"; import { EmptyContent } from "pages/common/styledComponent"; import { trans } from "i18n"; import { PermissionItem } from "./PermissionList"; +import { currentApplication } from "@lowcoder-ee/redux/selectors/applicationSelector"; +import { fetchAvailableGroupsMembers } from "@lowcoder-ee/util/pagination/axios"; const AddAppUserContent = styled.div` display: flex; @@ -86,8 +87,7 @@ const PermissionSelectWrapper = styled.div` padding: 4px 8px; margin-top: 8px; background: #fdfdfd; - outline: 1px solid #d7d9e0; - border-radius: 4px; + outline: 1px dashed #d7d9e0; .ant-select { font-size: 13px; @@ -95,11 +95,11 @@ const PermissionSelectWrapper = styled.div` } &:hover { - outline: 1px solid #8b8fa3; + outline: 1px dashed #8b8fa3; } &:focus-within { - outline: 1px solid #315efb; + outline: 1px dashed rgb(203, 212, 245); border-radius: 4px; box-shadow: 0 0 0 3px rgb(24 144 255 / 20%); } @@ -199,48 +199,34 @@ type PermissionAddEntity = { key: string; }; -/** - * compose users and groups's permissions, filter the data - * - * @param orgGroups groups - * @param orgUsers users - * @param currentUser currentUser - * @param filterItems filterItems - */ +function isGroup(data: GroupsMembersPermission) { + return data?.type === "Group" +} + function getPermissionOptionView( - orgGroups: OrgGroup[], - orgUsers: OrgUser[], - currentUser: User, + groupsMembers: GroupsMembersPermission[], filterItems: PermissionItem[] ): AddAppOptionView[] { - let permissionViews: AddAppOptionView[] = orgGroups.map((group) => { + + let permissionsViews = groupsMembers?.map((user) => { return { - type: "GROUP", - id: group.groupId, - name: group.groupName, - }; - }); - permissionViews = permissionViews.concat( - orgUsers.map((user) => { - return { - type: "USER", - id: user.userId, - name: user.name, - avatarUrl: user.avatarUrl, - }; - }) - ); - permissionViews = permissionViews.filter( - (v) => - !filterItems.find((i) => i.id === v.id && i.type === v.type) && - !(v.type === "USER" && v.id === currentUser.id) + type: user.type as ApplicationPermissionType, + id: isGroup(user) ? user.data.groupId : user.data.userId, + name: isGroup(user) ? user.data.groupName : user.data.name, + ...(isGroup(user) ? {} : { avatarUrl: user.data.avatarUrl }) + } + }) + + permissionsViews = permissionsViews.filter((v) => + !filterItems.find((i) => i.id === v.id && i.type === v.type) ); - return permissionViews; + + return permissionsViews.filter((v) => v.id && v.name) as AddAppOptionView[]; } function PermissionSelectorOption(props: { optionView: AddAppOptionView }) { const { optionView } = props; - const groupIcon = optionView.type === "GROUP" && ( + const groupIcon = optionView.type === "Group" && ( ); return ( @@ -258,7 +244,7 @@ function PermissionSelectorOption(props: { optionView: AddAppOptionView }) { function PermissionSelectorLabel(props: { view: AddAppOptionView }) { const { view } = props; - const groupIcon = view.type === "GROUP" && ( + const groupIcon = view.type === "Group" && ( ); return ( @@ -309,12 +295,52 @@ const PermissionSelector = (props: { filterItems: PermissionItem[]; supportRoles: { label: string; value: PermissionRole }[]; }) => { - const orgGroups = useSelector(getOrgGroups); - const orgUsers = useSelector(getOrgUsers); const { selectedItems, setSelectRole, setSelectedItems, user } = props; - const optionViews = getPermissionOptionView(orgGroups, orgUsers, user, props.filterItems); const [roleSelectVisible, setRoleSelectVisible] = useState(false); const selectRef = useRef(null); + const [optionViews, setOptionViews] = useState() + const [searchValue, setSearchValue] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const application = useSelector(currentApplication) + + const debouncedUserSearch = useCallback( + debounce((searchTerm: string) => { + if (!application) return; + + setIsLoading(true); + fetchAvailableGroupsMembers(application.applicationId, searchTerm).then(res => { + if(res.success) { + setOptionViews(getPermissionOptionView(res.data, props.filterItems)) + } + setIsLoading(false); + }).catch(() => { + setIsLoading(false); + }); + }, 500), + [application, props.filterItems] + ); + + useEffect(() => { + debouncedUserSearch(searchValue); + + return () => { + debouncedUserSearch.cancel(); + }; + }, [searchValue, debouncedUserSearch]); + + useEffect(() => { + if (!application) return; + + setIsLoading(true); + fetchAvailableGroupsMembers(application.applicationId, "").then(res => { + if(res.success) { + setOptionViews(getPermissionOptionView(res.data, props.filterItems)) + } + setIsLoading(false); + }).catch(() => { + setIsLoading(false); + }); + }, [application, props.filterItems]); useEffect(() => { setRoleSelectVisible(selectedItems.length > 0); @@ -325,12 +351,18 @@ const PermissionSelector = (props: { return ( <> + setSearchValue(e.target.value)} + /> document.getElementById("add-app-user-permission-dropdown")!} optionLabelProp="label" tagRender={PermissionTagRender} @@ -350,7 +382,7 @@ const PermissionSelector = (props: { setSelectedItems(selectedItems.filter((item) => item.key !== option.key)); }} > - {optionViews.map((view) => { + {optionViews?.map((view) => { return ( void; }) => { const { onCancel } = props; - const dispatch = useDispatch(); const user = useSelector(getUser); const [selectRole, setSelectRole] = useState("viewer"); const [selectedItems, setSelectedItems] = useState([]); - useEffect(() => { - dispatch(fetchOrgUsersAction(user.currentOrgId)); - dispatch(fetchGroupsAction(user.currentOrgId)); - }, []); - return ( @@ -426,10 +452,10 @@ export const Permission = (props: { buttonType="primary" onClick={() => { const uids = selectedItems - .filter((item) => item.type === "USER") + .filter((item) => item.type === "User") .map((item) => item.id); const gids = selectedItems - .filter((item) => item.type === "GROUP") + .filter((item) => item.type === "Group") .map((item) => item.id); if (uids.length === 0 && gids.length === 0) { onCancel(); diff --git a/client/packages/lowcoder/src/constants/applicationConstants.ts b/client/packages/lowcoder/src/constants/applicationConstants.ts index f29dce24b6..f685eeb8e6 100644 --- a/client/packages/lowcoder/src/constants/applicationConstants.ts +++ b/client/packages/lowcoder/src/constants/applicationConstants.ts @@ -62,7 +62,7 @@ export const AppUILayoutType: Record = { export type ApplicationDSLType = "editing" | "published" | "view_marketplace"; export type ApplicationRoleType = "viewer" | "editor" | "owner"; -export type ApplicationPermissionType = "USER" | "GROUP" | "ORG_ADMIN"; +export type ApplicationPermissionType = "User" | "Group" | "ORG_ADMIN" | "USER" | "GROUP"; export interface ApplicationExtra { moduleHeight?: number; @@ -70,6 +70,18 @@ export interface ApplicationExtra { layers?: boolean; } +export type GroupsMembersPermission = { + type: string + data: { + groupGid?: string + groupId?: string + userId?: string + groupName?: string + name?: string + avatarUrl?: string + } +} + export interface ApplicationMeta { name: string; applicationType: AppTypeEnum; diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 44f5f4b1dd..470e8ec178 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -4010,6 +4010,7 @@ export const en = { "orgName": "{orgName} admins", "addMember": "Add members", "addPermissionPlaceholder": "Please enter a name to search members", + "selectedUsersAndGroups":"Selected Users and Groups", "searchMemberOrGroup": "Search for members or groups: ", "addPermissionErrorMessage": "Failed to add permission, {message}", "copyModalTitle": 'Clone "{name}"', diff --git a/client/packages/lowcoder/src/util/pagination/axios.ts b/client/packages/lowcoder/src/util/pagination/axios.ts index d03bf1800c..e59ccbfec1 100644 --- a/client/packages/lowcoder/src/util/pagination/axios.ts +++ b/client/packages/lowcoder/src/util/pagination/axios.ts @@ -102,6 +102,22 @@ export const fetchGroupUsrPagination = async (request: fetchGroupUserRequestType } } +export const fetchAvailableGroupsMembers = async (applicationId: string, search: string) => { + try{ + const response = await ApplicationApi.getAvailableGroupsMembers(applicationId, search) + return { + success: true, + data: response.data.data + } + } catch (error: any) { + console.error('Failed to fetch data: ', error) + return { + success: false, + error: error + } + } +} + export const fetchOrgUsrPagination = async (request: fetchOrgUserRequestType)=> { try { const response = await OrgApi.fetchOrgUsersPagination(request);








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/lowcoder-org/lowcoder/pull/1817.diff

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy