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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy