Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 876fe31

Browse files
committed
Merge branch 'dev' into settings_navigation_app
2 parents cb5ff45 + 0060f16 commit 876fe31

File tree

19 files changed

+354
-306
lines changed

19 files changed

+354
-306
lines changed

‎client/packages/lowcoder/src/comps/hooks/modalComp.tsx

Lines changed: 199 additions & 179 deletions
Large diffs are not rendered by default.

‎client/packages/lowcoder/src/pages/ApplicationV2/index.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import {
3232
UserIcon,
3333
} from "lowcoder-design";
3434
import React, { useCallback, useEffect, useState, useMemo } from "react";
35-
import { fetchAllApplications, fetchHomeData } from "redux/reduxActions/applicationActions";
35+
import { fetchHomeData } from "redux/reduxActions/applicationActions";
3636
import { fetchSubscriptionsAction } from "redux/reduxActions/subscriptionActions";
3737
import { getHomeOrg, normalAppListSelector } from "redux/selectors/applicationSelector";
3838
import { DatasourceHome } from "../datasource";
@@ -125,18 +125,13 @@ export default function ApplicationHome() {
125125
}, [org, orgHomeId]);
126126

127127
useEffect(() => {
128-
if (allAppCount !== 0) {
129-
return;
130-
}
131-
user.currentOrgId && dispatch(fetchAllApplications({}));
132-
}, [dispatch, allAppCount, user.currentOrgId]);
133-
134-
useEffect(() => {
135-
if (allFoldersCount !== 0) {
128+
// Check if we need to fetch data (either no folders or no applications)
129+
if (allFoldersCount !== 0 && allAppCount !== 0) {
136130
return;
137131
}
132+
138133
user.currentOrgId && dispatch(fetchFolderElements({}));
139-
}, [dispatch, allFoldersCount, user.currentOrgId]);
134+
}, [dispatch, allFoldersCount, allAppCount, user.currentOrgId]);
140135

141136
if (fetchingUser || !isPreloadCompleted) {
142137
return <ProductLoading />;

‎client/packages/lowcoder/src/pages/common/WorkspaceSection.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,16 @@ const WorkspaceList = styled.div`
7171
}
7272
`;
7373

74-
const WorkspaceItem = styled.div<{ isActive?: boolean }>`
74+
const WorkspaceItem = styled.div<{ $isActive?: boolean }>`
7575
display: flex;
7676
align-items: center;
7777
padding: 10px 16px;
7878
cursor: pointer;
7979
transition: background-color 0.2s;
80-
background-color: ${props => props.isActive ? '#f0f5ff' : 'transparent'};
80+
background-color: ${props => props.$isActive ? '#f0f5ff' : 'transparent'};
8181
8282
&:hover {
83-
background-color: ${props => props.isActive ? '#f0f5ff' : '#f8f9fa'};
83+
background-color: ${props => props.$isActive ? '#f0f5ff' : '#f8f9fa'};
8484
}
8585
`;
8686

@@ -242,7 +242,7 @@ export default function WorkspaceSectionComponent({
242242
displayWorkspaces.map((org: Org) => (
243243
<WorkspaceItem
244244
key={org.id}
245-
isActive={user.currentOrgId === org.id}
245+
$isActive={user.currentOrgId === org.id}
246246
onClick={() => handleOrgSwitch(org.id)}
247247
>
248248
<WorkspaceName title={org.name}>{org.name}</WorkspaceName>

‎client/packages/lowcoder/src/pages/common/profileDropdown.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ export default function ProfileDropdown(props: DropDownProps) {
192192
<StyledDropdown
193193
open={dropdownVisible}
194194
onOpenChange={setDropdownVisible}
195-
dropdownRender={() => dropdownContent}
195+
popupRender={() => dropdownContent}
196196
trigger={["click"]}
197197
placement="bottomRight"
198198
>

‎client/packages/lowcoder/src/pages/editor/LeftContent.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,14 @@ export const LeftContent = (props: LeftContentProps) => {
446446
</span>
447447
{info?.show && data && (
448448
<Modal
449-
title={data.name}
449+
title={
450+
<div>
451+
<div>{data.name}</div>
452+
<div style={{ fontSize: '12px', color: '#666', fontWeight: 'normal', marginTop: '4px' }}>
453+
<strong>Type:</strong> {data.type}
454+
</div>
455+
</div>
456+
}
450457
open={info.show}
451458
onOk={() => setShowData([])}
452459
cancelButtonProps={{ style: { display: 'none' } }}

‎client/packages/lowcoder/src/redux/sagas/folderSagas.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,19 @@ export function* fetchFolderElementsSaga(action: ReduxAction<FetchFolderElements
118118
type: ReduxActionTypes.FETCH_ALL_FOLDERS_SUCCESS,
119119
payload: response.data.data.filter((m) => m.folder),
120120
});
121+
122+
// filter out applications with NORMAL status
123+
124+
const applications = response.data.data.filter((item): item is ApplicationMeta =>
125+
!item.folder && item.applicationStatus === "NORMAL"
126+
);
127+
128+
yield put({
129+
type: ReduxActionTypes.FETCH_ALL_APPLICATIONS_SUCCESS,
130+
payload: applications,
131+
});
121132
}
133+
122134
yield put({
123135
type: ReduxActionTypes.FETCH_FOLDER_ELEMENTS_SUCCESS,
124136
payload: { parentFolderId: action.payload.folderId, elements: response.data.data },

‎server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/model/Organization.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static java.util.Optional.ofNullable;
2222
import static org.apache.commons.lang3.ObjectUtils.firstNonNull;
2323
import static org.lowcoder.infra.util.AssetUtils.toAssetPath;
24+
import java.time.Instant;
2425

2526

2627
@Getter

‎server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/repository/UserRepository.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package org.lowcoder.domain.user.repository;
22

33
import java.util.Collection;
4+
import java.util.List;
45

56
import org.lowcoder.domain.user.model.User;
7+
import org.springframework.data.domain.Pageable;
68
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
79
import org.springframework.stereotype.Repository;
810

911
import reactor.core.publisher.Flux;
1012
import reactor.core.publisher.Mono;
13+
import org.springframework.data.mongodb.repository.Query;
1114

1215
@Repository
1316
public interface UserRepository extends ReactiveMongoRepository<User, String> {
@@ -23,4 +26,10 @@ public interface UserRepository extends ReactiveMongoRepository<User, String> {
2326

2427
//email1 and email2 should be equal
2528
Flux<User> findByEmailOrConnections_Email(String email1, String email2);
29+
30+
@Query("{ '_id': { $in: ?0 }, 'state': ?1, 'isEnabled': ?2, $or: [ { 'name': { $regex: ?3, $options: 'i' } }, { '_id': { $regex: ?3, $options: 'i' } } ] }")
31+
Flux<User> findUsersByIdsAndSearchNameForPagination(Collection<String> ids, String state, boolean isEnabled, String searchRegex, Pageable pageable);
32+
33+
@Query(value = "{ '_id': { $in: ?0 }, 'state': ?1, 'isEnabled': ?2, $or: [ { 'name': { $regex: ?3, $options: 'i' } }, { '_id': { $regex: ?3, $options: 'i' } } ] }", count = true)
34+
Mono<Long> countUsersByIdsAndSearchName(Collection<String> ids, String state, boolean isEnabled, String searchRegex);
2635
}

‎server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/UserService.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@
33
import java.util.Collection;
44
import java.util.Map;
55

6-
import org.lowcoder.domain.user.model.AuthUser;
7-
import org.lowcoder.domain.user.model.Connection;
8-
import org.lowcoder.domain.user.model.User;
9-
import org.lowcoder.domain.user.model.UserDetail;
6+
import org.lowcoder.domain.user.model.*;
107
import org.lowcoder.infra.annotation.NonEmptyMono;
118
import org.lowcoder.infra.mongo.MongoUpsertHelper.PartialResourceWithId;
9+
import org.springframework.data.domain.Pageable;
1210
import org.springframework.http.codec.multipart.Part;
1311
import org.springframework.web.server.ServerWebExchange;
1412

@@ -68,5 +66,7 @@ public interface UserService {
6866

6967
Flux<User> findBySourceAndIds(String connectionSource, Collection<String> connectionSourceUuids);
7068

71-
}
69+
Flux<User> findUsersByIdsAndSearchNameForPagination(Collection<String> ids, String state, boolean isEnabled, String searchRegex, Pageable pageable);
7270

71+
Mono<Long> countUsersByIdsAndSearchName(Collection<String> ids, String state, boolean isEnabled, String searchRegex);
72+
}

‎server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/UserServiceImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.lowcoder.sdk.util.HashUtils;
3737
import org.lowcoder.sdk.util.LocaleUtils;
3838
import org.springframework.dao.DuplicateKeyException;
39+
import org.springframework.data.domain.Pageable;
3940
import org.springframework.http.codec.multipart.Part;
4041
import org.springframework.stereotype.Service;
4142
import org.springframework.web.server.ServerWebExchange;
@@ -473,4 +474,13 @@ public Flux<User> findBySourceAndIds(String connectionSource, Collection<String>
473474
return repository.findByConnections_SourceAndConnections_RawIdIn(connectionSource, connectionSourceUuids);
474475
}
475476

477+
@Override
478+
public Flux<User> findUsersByIdsAndSearchNameForPagination(Collection<String> ids, String state, boolean isEnabled, String searchRegex, Pageable pageable) {
479+
return repository.findUsersByIdsAndSearchNameForPagination(ids, state, isEnabled, searchRegex, pageable);
480+
}
481+
482+
@Override
483+
public Mono<Long> countUsersByIdsAndSearchName(Collection<String> ids, String state, boolean isEnabled, String searchRegex) {
484+
return repository.countUsersByIdsAndSearchName(ids, state, isEnabled, searchRegex);
485+
}
476486
}

‎server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupApiService.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.lowcoder.api.usermanagement;
22

33
import org.lowcoder.api.usermanagement.view.*;
4+
import org.lowcoder.api.usermanagement.view.OrgMemberListView;
45
import org.lowcoder.domain.group.model.Group;
56
import reactor.core.publisher.Mono;
67

@@ -24,4 +25,6 @@ public interface GroupApiService {
2425
Mono<Boolean> update(String groupId, UpdateGroupRequest updateGroupRequest);
2526

2627
Mono<Boolean> removeUser(String groupId, String userId);
28+
29+
Mono<OrgMemberListView> getPotentialGroupMembers(String groupId, String searchName, Integer pageNum, Integer pageSize);
2730
}

‎server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupApiServiceImpl.java

Lines changed: 66 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,31 @@
99
import static org.lowcoder.sdk.util.StreamUtils.collectList;
1010
import static org.lowcoder.sdk.util.StreamUtils.collectMap;
1111

12-
import java.util.List;
13-
import java.util.Map;
14-
import java.util.Objects;
12+
import java.util.*;
13+
import java.util.regex.Pattern;
1514
import java.util.stream.Collectors;
1615

1716
import com.github.f4b6a3.uuid.UuidCreator;
1817
import lombok.RequiredArgsConstructor;
1918
import org.apache.commons.lang3.tuple.Pair;
2019
import org.lowcoder.api.bizthreshold.AbstractBizThresholdChecker;
2120
import org.lowcoder.api.home.SessionUserService;
22-
import org.lowcoder.api.usermanagement.view.CreateGroupRequest;
23-
import org.lowcoder.api.usermanagement.view.GroupMemberAggregateView;
24-
import org.lowcoder.api.usermanagement.view.GroupMemberView;
25-
import org.lowcoder.api.usermanagement.view.GroupView;
26-
import org.lowcoder.api.usermanagement.view.UpdateGroupRequest;
27-
import org.lowcoder.api.usermanagement.view.UpdateRoleRequest;
21+
import org.lowcoder.api.usermanagement.view.*;
2822
import org.lowcoder.domain.group.model.Group;
2923
import org.lowcoder.domain.group.model.GroupMember;
24+
import org.lowcoder.domain.user.model.UserState;
25+
import org.lowcoder.api.usermanagement.view.OrgMemberListView;
3026
import org.lowcoder.domain.group.service.GroupMemberService;
3127
import org.lowcoder.domain.group.service.GroupService;
3228
import org.lowcoder.domain.organization.model.MemberRole;
3329
import org.lowcoder.domain.organization.model.OrgMember;
3430
import org.lowcoder.domain.organization.service.OrgMemberService;
35-
import org.lowcoder.domain.organization.service.OrganizationService;
3631
import org.lowcoder.domain.user.model.User;
3732
import org.lowcoder.domain.user.service.UserService;
3833
import org.lowcoder.infra.util.TupleUtils;
3934
import org.lowcoder.sdk.exception.BizError;
35+
import org.springframework.data.domain.Pageable;
36+
import org.springframework.data.domain.PageRequest;
4037
import org.springframework.stereotype.Service;
4138

4239
import reactor.core.publisher.Flux;
@@ -53,7 +50,6 @@ public class GroupApiServiceImpl implements GroupApiService {
5350
private final UserService userService;
5451
private final GroupService groupService;
5552
private final AbstractBizThresholdChecker bizThresholdChecker;
56-
private final OrganizationService organizationService;
5753
private final OrgMemberService orgMemberService;
5854

5955
@Override
@@ -311,4 +307,63 @@ public Mono<Boolean> removeUser(String groupId, String userId) {
311307
return groupMemberService.removeMember(groupId, userId);
312308
});
313309
}
310+
311+
@Override
312+
public Mono<OrgMemberListView> getPotentialGroupMembers(String groupId, String searchName, Integer pageNum, Integer pageSize) {
313+
return groupService.getById(groupId)
314+
.flatMap(group -> {
315+
String orgId = group.getOrganizationId();
316+
Mono<List<OrgMember>> orgMemberUserIdsMono = orgMemberService.getOrganizationMembers(orgId).collectList();
317+
Mono<List<GroupMember>> groupMemberUserIdsMono = groupMemberService.getGroupMembers(groupId);
318+
319+
return Mono.zip(orgMemberUserIdsMono, groupMemberUserIdsMono)
320+
.flatMap(tuple -> {
321+
List<OrgMember> orgMembers = tuple.getT1();
322+
List<GroupMember> groupMembers = tuple.getT2();
323+
324+
Set<String> groupMemberUserIds = groupMembers.stream()
325+
.map(GroupMember::getUserId)
326+
.collect(Collectors.toSet());
327+
328+
Collection<String> potentialUserIds = orgMembers.stream()
329+
.map(OrgMember::getUserId)
330+
.filter(uid -> !groupMemberUserIds.contains(uid))
331+
.collect(Collectors.toList());
332+
333+
if (potentialUserIds.isEmpty()) {
334+
return Mono.just(OrgMemberListView.builder()
335+
.members(List.of())
336+
.total(0)
337+
.pageNum(pageNum)
338+
.pageSize(pageSize)
339+
.build());
340+
}
341+
342+
Pageable pageable = PageRequest.of(pageNum - 1, pageSize);
343+
String searchRegex = searchName != null && !searchName.isBlank() ? ".*" + Pattern.quote(searchName) + ".*" : ".*";
344+
345+
return userService.findUsersByIdsAndSearchNameForPagination(
346+
potentialUserIds, String.valueOf(UserState.ACTIVATED), true, searchRegex, pageable)
347+
.collectList()
348+
.zipWith(userService.countUsersByIdsAndSearchName(
349+
potentialUserIds, String.valueOf(UserState.ACTIVATED), true, searchRegex))
350+
.map(tupleUser -> {
351+
List<User> users = tupleUser.getT1();
352+
long total = tupleUser.getT2();
353+
List<OrgMemberListView.OrgMemberView> memberViews = users.stream()
354+
.map(u -> OrgMemberListView.OrgMemberView.builder()
355+
.userId(u.getId())
356+
.name(u.getName())
357+
.build())
358+
.collect(Collectors.toList());
359+
return OrgMemberListView.builder()
360+
.members(memberViews)
361+
.total((int) total)
362+
.pageNum(pageNum)
363+
.pageSize(pageSize)
364+
.build();
365+
});
366+
});
367+
});
368+
}
314369
}

‎server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupController.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@
2020
import org.lowcoder.domain.organization.service.OrgMemberService;
2121
import org.lowcoder.sdk.exception.BizError;
2222
import org.springframework.beans.factory.annotation.Autowired;
23-
import org.springframework.web.bind.annotation.PathVariable;
24-
import org.springframework.web.bind.annotation.RequestBody;
25-
import org.springframework.web.bind.annotation.RequestParam;
26-
import org.springframework.web.bind.annotation.RestController;
23+
import org.springframework.web.bind.annotation.*;
24+
import org.lowcoder.api.usermanagement.view.OrgMemberListView;
2725

2826
import reactor.core.publisher.Mono;
2927
import reactor.util.function.Tuple2;
@@ -180,4 +178,15 @@ public Mono<ResponseView<Boolean>> removeUser(@PathVariable String groupId,
180178
.map(Tuple2::getT2)
181179
.map(ResponseView::success));
182180
}
181+
182+
@Override
183+
public Mono<ResponseView<OrgMemberListView>> searchPotentialGroupMembers(
184+
@PathVariable String groupId,
185+
@RequestParam(required = false) String searchName,
186+
@RequestParam(required = false, defaultValue = "1") Integer pageNum,
187+
@RequestParam(required = false, defaultValue = "1000") Integer pageSize) {
188+
return gidService.convertGroupIdToObjectId(groupId).flatMap(id ->
189+
groupApiService.getPotentialGroupMembers(id, searchName, pageNum, pageSize)
190+
.map(ResponseView::success));
191+
}
183192
}

‎server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupEndpoints.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,19 @@ public Mono<ResponseView<Boolean>> updateRoleForMember(@RequestBody UpdateRoleRe
115115
@DeleteMapping("/{groupId}/remove")
116116
public Mono<ResponseView<Boolean>> removeUser(@PathVariable String groupId,
117117
@RequestParam String userId);
118+
119+
@Operation(
120+
tags = TAG_GROUP_MEMBERS,
121+
operationId = "searchPotentialGroupMembers",
122+
summary = "Search Potential Group Members",
123+
description = "Retrieve a list of users who are not currently members of the specified group within an organization."
124+
)
125+
126+
@GetMapping("/{groupId}/potential-members")
127+
public Mono<ResponseView<OrgMemberListView>> searchPotentialGroupMembers(
128+
@PathVariable String groupId,
129+
@RequestParam(required = false) String searchName,
130+
@RequestParam(required = false, defaultValue = "1") Integer pageNum,
131+
@RequestParam(required = false, defaultValue = "1000") Integer pageSize
132+
);
118133
}

‎server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiService.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,5 @@ public interface OrgApiService {
5353
Mono<ConfigView> getOrganizationConfigs(String orgId);
5454

5555
Mono<Long> getApiUsageCount(String orgId, Boolean lastMonthOnly);
56-
57-
Mono<OrgMemberListView> getOrganizationMembersForSearch(String orgId, String searchMemberName, String searchGroupId, Integer pageNum, Integer pageSize);
5856
}
5957

0 commit comments

Comments
 (0)