@@ -3,16 +3,15 @@ import {
33CloseIcon ,
44CommonTextLabel ,
55CustomSelect ,
6+ Search ,
67TacoButton ,
78} from "lowcoder-design" ;
8- import { useEffect , useRef , useState } from "react" ;
9+ import { useEffect , useRef , useState , useCallback } from "react" ;
910import styled from "styled-components" ;
11+ import { debounce } from "lodash" ;
1012import ProfileImage from "pages/common/profileImage" ;
11- import { useDispatch , useSelector } from "react-redux" ;
12- import { fetchGroupsAction , fetchOrgUsersAction } from "redux/reduxActions/orgActions" ;
13- import { getOrgGroups , getOrgUsers } from "redux/selectors/orgSelectors" ;
14- import { OrgGroup , OrgUser } from "constants/orgConstants" ;
15- import { ApplicationPermissionType , ApplicationRoleType } from "constants/applicationConstants" ;
13+ import { useSelector } from "react-redux" ;
14+ import { ApplicationPermissionType , ApplicationRoleType , GroupsMembersPermission } from "constants/applicationConstants" ;
1615import {
1716PermissionItemName ,
1817RoleSelectOption ,
@@ -27,6 +26,8 @@ import { getUser } from "redux/selectors/usersSelectors";
2726import { EmptyContent } from "pages/common/styledComponent" ;
2827import { trans } from "i18n" ;
2928import { PermissionItem } from "./PermissionList" ;
29+ import { currentApplication } from "@lowcoder-ee/redux/selectors/applicationSelector" ;
30+ import { fetchAvailableGroupsMembers } from "@lowcoder-ee/util/pagination/axios" ;
3031
3132const AddAppUserContent = styled . div `
3233 display: flex;
@@ -86,20 +87,19 @@ const PermissionSelectWrapper = styled.div`
8687 padding: 4px 8px;
8788 margin-top: 8px;
8889 background: #fdfdfd;
89- outline: 1px solid #d7d9e0;
90- border-radius: 4px;
90+ outline: 1px dashed #d7d9e0;
9191
9292 .ant-select {
9393 font-size: 13px;
9494 line-height: 13px;
9595 }
9696
9797 &:hover {
98- outline: 1pxsolid #8b8fa3;
98+ outline: 1pxdashed #8b8fa3;
9999 }
100100
101101 &:focus-within {
102- outline: 1pxsolid #315efb ;
102+ outline: 1pxdashed rgb(203, 212, 245) ;
103103 border-radius: 4px;
104104 box-shadow: 0 0 0 3px rgb(24 144 255 / 20%);
105105 }
@@ -199,48 +199,34 @@ type PermissionAddEntity = {
199199key :string ;
200200} ;
201201
202- /**
203- * compose users and groups's permissions, filter the data
204- *
205- *@param orgGroups groups
206- *@param orgUsers users
207- *@param currentUser currentUser
208- *@param filterItems filterItems
209- */
202+ function isGroup ( data :GroupsMembersPermission ) {
203+ return data ?. type === "Group"
204+ }
205+
210206function getPermissionOptionView (
211- orgGroups :OrgGroup [ ] ,
212- orgUsers :OrgUser [ ] ,
213- currentUser :User ,
207+ groupsMembers :GroupsMembersPermission [ ] ,
214208filterItems :PermissionItem [ ]
215209) :AddAppOptionView [ ] {
216- let permissionViews :AddAppOptionView [ ] = orgGroups . map ( ( group ) => {
210+
211+ let permissionsViews = groupsMembers ?. map ( ( user ) => {
217212return {
218- type :"GROUP" ,
219- id :group . groupId ,
220- name :group . groupName ,
221- } ;
222- } ) ;
223- permissionViews = permissionViews . concat (
224- orgUsers . map ( ( user ) => {
225- return {
226- type :"USER" ,
227- id :user . userId ,
228- name :user . name ,
229- avatarUrl :user . avatarUrl ,
230- } ;
231- } )
232- ) ;
233- permissionViews = permissionViews . filter (
234- ( v ) =>
235- ! filterItems . find ( ( i ) => i . id === v . id && i . type === v . type ) &&
236- ! ( v . type === "USER" && v . id === currentUser . id )
213+ type :user . type as ApplicationPermissionType ,
214+ id :isGroup ( user ) ?user . data . groupId :user . data . userId ,
215+ name :isGroup ( user ) ?user . data . groupName :user . data . name ,
216+ ...( isGroup ( user ) ?{ } :{ avatarUrl :user . data . avatarUrl } )
217+ }
218+ } )
219+
220+ permissionsViews = permissionsViews . filter ( ( v ) =>
221+ ! filterItems . find ( ( i ) => i . id === v . id && i . type === v . type )
237222) ;
238- return permissionViews ;
223+
224+ return permissionsViews . filter ( ( v ) => v . id && v . name ) as AddAppOptionView [ ] ;
239225}
240226
241227function PermissionSelectorOption ( props :{ optionView :AddAppOptionView } ) {
242228const { optionView} = props ;
243- const groupIcon = optionView . type === "GROUP " && (
229+ const groupIcon = optionView . type === "Group " && (
244230< StyledGroupIcon $color = { getInitialsAndColorCode ( optionView . name ) [ 1 ] } />
245231) ;
246232return (
@@ -258,7 +244,7 @@ function PermissionSelectorOption(props: { optionView: AddAppOptionView }) {
258244
259245function PermissionSelectorLabel ( props :{ view :AddAppOptionView } ) {
260246const { view} = props ;
261- const groupIcon = view . type === "GROUP " && (
247+ const groupIcon = view . type === "Group " && (
262248< StyledGroupIcon $color = { getInitialsAndColorCode ( view . name ) [ 1 ] } $side = { 9 } />
263249) ;
264250return (
@@ -288,7 +274,7 @@ function PermissionTagRender(props: CustomTagProps) {
288274color = { value }
289275closable = { closable }
290276onClose = { onClose }
291- style = { { marginRight :3 } }
277+ style = { { marginRight :3 , display : "flex" , alignItems : "center" } }
292278>
293279{ label }
294280</ StyledTag >
@@ -309,12 +295,52 @@ const PermissionSelector = (props: {
309295filterItems :PermissionItem [ ] ;
310296supportRoles :{ label :string ; value :PermissionRole } [ ] ;
311297} ) => {
312- const orgGroups = useSelector ( getOrgGroups ) ;
313- const orgUsers = useSelector ( getOrgUsers ) ;
314298const { selectedItems, setSelectRole, setSelectedItems, user} = props ;
315- const optionViews = getPermissionOptionView ( orgGroups , orgUsers , user , props . filterItems ) ;
316299const [ roleSelectVisible , setRoleSelectVisible ] = useState ( false ) ;
317300const selectRef = useRef < HTMLDivElement > ( null ) ;
301+ const [ optionViews , setOptionViews ] = useState < AddAppOptionView [ ] > ( )
302+ const [ searchValue , setSearchValue ] = useState ( "" ) ;
303+ const [ isLoading , setIsLoading ] = useState ( false ) ;
304+ const application = useSelector ( currentApplication )
305+
306+ const debouncedUserSearch = useCallback (
307+ debounce ( ( searchTerm :string ) => {
308+ if ( ! application ) return ;
309+
310+ setIsLoading ( true ) ;
311+ fetchAvailableGroupsMembers ( application . applicationId , searchTerm ) . then ( res => {
312+ if ( res . success ) {
313+ setOptionViews ( getPermissionOptionView ( res . data , props . filterItems ) )
314+ }
315+ setIsLoading ( false ) ;
316+ } ) . catch ( ( ) => {
317+ setIsLoading ( false ) ;
318+ } ) ;
319+ } , 500 ) ,
320+ [ application , props . filterItems ]
321+ ) ;
322+
323+ useEffect ( ( ) => {
324+ debouncedUserSearch ( searchValue ) ;
325+
326+ return ( ) => {
327+ debouncedUserSearch . cancel ( ) ;
328+ } ;
329+ } , [ searchValue , debouncedUserSearch ] ) ;
330+
331+ useEffect ( ( ) => {
332+ if ( ! application ) return ;
333+
334+ setIsLoading ( true ) ;
335+ fetchAvailableGroupsMembers ( application . applicationId , "" ) . then ( res => {
336+ if ( res . success ) {
337+ setOptionViews ( getPermissionOptionView ( res . data , props . filterItems ) )
338+ }
339+ setIsLoading ( false ) ;
340+ } ) . catch ( ( ) => {
341+ setIsLoading ( false ) ;
342+ } ) ;
343+ } , [ application , props . filterItems ] ) ;
318344
319345useEffect ( ( ) => {
320346setRoleSelectVisible ( selectedItems . length > 0 ) ;
@@ -325,12 +351,18 @@ const PermissionSelector = (props: {
325351
326352return (
327353< >
354+ < Search
355+ placeholder = { trans ( "home.addPermissionPlaceholder" ) }
356+ value = { searchValue }
357+ onChange = { ( e ) => setSearchValue ( e . target . value ) }
358+ />
328359< PermissionSelectWrapper >
329360< AddPermissionsSelect
330361open
331362ref = { selectRef }
332- placeholder = { trans ( "home.addPermissionPlaceholder " ) }
363+ placeholder = { trans ( "home.selectedUsersAndGroups " ) }
333364mode = "multiple"
365+ showSearch = { false }
334366getPopupContainer = { ( ) => document . getElementById ( "add-app-user-permission-dropdown" ) ! }
335367optionLabelProp = "label"
336368tagRender = { PermissionTagRender }
@@ -350,7 +382,7 @@ const PermissionSelector = (props: {
350382setSelectedItems ( selectedItems . filter ( ( item ) => item . key !== option . key ) ) ;
351383} }
352384>
353- { optionViews . map ( ( view ) => {
385+ { optionViews ? .map ( ( view ) => {
354386return (
355387< CustomSelect . Option
356388key = { `${ view . type } -${ view . id } ` }
@@ -395,16 +427,10 @@ export const Permission = (props: {
395427addPermission :( userIds :string [ ] , groupIds :string [ ] , role :string ) => void ;
396428} ) => {
397429const { onCancel} = props ;
398- const dispatch = useDispatch ( ) ;
399430const user = useSelector ( getUser ) ;
400431const [ selectRole , setSelectRole ] = useState < ApplicationRoleType > ( "viewer" ) ;
401432const [ selectedItems , setSelectedItems ] = useState < PermissionAddEntity [ ] > ( [ ] ) ;
402433
403- useEffect ( ( ) => {
404- dispatch ( fetchOrgUsersAction ( user . currentOrgId ) ) ;
405- dispatch ( fetchGroupsAction ( user . currentOrgId ) ) ;
406- } , [ ] ) ;
407-
408434return (
409435< AddAppUserContent >
410436< CommonTextLabel style = { { marginTop :"16px" } } >
@@ -426,10 +452,10 @@ export const Permission = (props: {
426452buttonType = "primary"
427453onClick = { ( ) => {
428454const uids = selectedItems
429- . filter ( ( item ) => item . type === "USER " )
455+ . filter ( ( item ) => item . type === "User " )
430456. map ( ( item ) => item . id ) ;
431457const gids = selectedItems
432- . filter ( ( item ) => item . type === "GROUP " )
458+ . filter ( ( item ) => item . type === "Group " )
433459. map ( ( item ) => item . id ) ;
434460if ( uids . length === 0 && gids . length === 0 ) {
435461onCancel ( ) ;