Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ public enum FeatureFlagEnum {
release_git_autocommit_eligibility_enabled,
release_dynamodb_connection_time_to_live_enabled,
release_reactive_actions_enabled,
/**
* Feature flag to enable alphabetical ordering for workspaces and applications
*/
release_alphabetical_ordering_enabled,

// Add EE flags below this line, to avoid conflicts.
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ public interface ApplicationServiceCE extends CrudService<Application, String> {

Flux<Application> findByWorkspaceIdAndBaseApplicationsInRecentlyUsedOrder(String workspaceId);

Flux<Application> findByWorkspaceIdAndBaseApplicationsInAlphabeticalOrder(String workspaceId);

Flux<Application> findByWorkspaceIdAndBaseApplicationsForHome(String workspaceId);

Mono<Application> save(Artifact application);

Mono<Application> updateApplicationWithPresets(String branchedApplicationId, Application application);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.appsmith.server.applications.base;

import com.appsmith.external.enums.FeatureFlagEnum;
import com.appsmith.external.models.ActionDTO;
import com.appsmith.external.models.Policy;
import com.appsmith.server.acl.AclPermission;
Expand Down Expand Up @@ -36,6 +37,7 @@
import com.appsmith.server.services.AnalyticsService;
import com.appsmith.server.services.AssetService;
import com.appsmith.server.services.BaseService;
import com.appsmith.server.services.FeatureFlagService;
import com.appsmith.server.services.PermissionGroupService;
import com.appsmith.server.services.SessionUserService;
import com.appsmith.server.services.UserDataService;
Expand All @@ -59,6 +61,7 @@

import java.time.Instant;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -90,6 +93,7 @@ public class ApplicationServiceCEImpl extends BaseService<ApplicationRepository,
private final WorkspaceService workspaceService;
private final WorkspacePermission workspacePermission;
private final ObservationRegistry observationRegistry;
private final FeatureFlagService featureFlagService;

private static final Integer MAX_RETRIES = 5;

Expand All @@ -108,7 +112,8 @@ public ApplicationServiceCEImpl(
UserDataService userDataService,
WorkspaceService workspaceService,
WorkspacePermission workspacePermission,
ObservationRegistry observationRegistry) {
ObservationRegistry observationRegistry,
FeatureFlagService featureFlagService) {

super(validator, repository, analyticsService);
this.policySolution = policySolution;
Expand All @@ -122,6 +127,7 @@ public ApplicationServiceCEImpl(
this.workspaceService = workspaceService;
this.workspacePermission = workspacePermission;
this.observationRegistry = observationRegistry;
this.featureFlagService = featureFlagService;
}

@Override
Expand Down Expand Up @@ -214,6 +220,63 @@ public Flux<Application> findByWorkspaceIdAndBaseApplicationsInRecentlyUsedOrder
})));
}

/**
* This method is used to fetch all the applications for a given workspaceId. It sorts the applications in
* alphabetical order by name.
* For git connected applications only default branched application is returned.
*
* @param workspaceId workspaceId for which applications are to be fetched
* @return Flux of applications sorted alphabetically
*/
@Override
public Flux<Application> findByWorkspaceIdAndBaseApplicationsInAlphabeticalOrder(String workspaceId) {

if (!StringUtils.hasLength(workspaceId)) {
return Flux.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.WORKSPACE_ID));
}

// Read the workspace
Mono<Workspace> workspaceMono = workspaceService
.findById(workspaceId, workspacePermission.getReadPermission())
.switchIfEmpty(Mono.error(
new AppsmithException(AppsmithError.ACL_NO_RESOURCE_FOUND, FieldName.WORKSPACE, workspaceId)));

return workspaceMono.thenMany(this.findByWorkspaceId(workspaceId, applicationPermission.getReadPermission())
.sort(Comparator.comparing(application -> application.getName().toLowerCase()))
.filter(application -> {
/*
* Filter applications based on the following criteria:
* - Applications that are not connected to Git.
* - Applications that, when connected, revert with default branch only.
*/
return !GitUtils.isArtifactConnectedToGit(application.getGitArtifactMetadata())
|| GitUtils.isDefaultBranchedArtifact(application.getGitArtifactMetadata());
}));
}

/**
* This method is used to fetch all the applications for a given workspaceId. It sorts the applications based
* on feature flag - either alphabetically or by recently used order.
* For git connected applications only default branched application is returned.
*
* @param workspaceId workspaceId for which applications are to be fetched
* @return Flux of applications sorted based on feature flag
*/
@Override
public Flux<Application> findByWorkspaceIdAndBaseApplicationsForHome(String workspaceId) {
Mono<Boolean> isAlphabeticalOrderingEnabled =
featureFlagService.check(FeatureFlagEnum.release_alphabetical_ordering_enabled);
return isAlphabeticalOrderingEnabled.flatMapMany(isEnabled -> {
if (isEnabled) {
// If alphabetical ordering is enabled, then we need to sort the applications in alphabetical order
return findByWorkspaceIdAndBaseApplicationsInAlphabeticalOrder(workspaceId);
} else {
// If alphabetical ordering is disabled, then we need to sort the applications in recently used order
return findByWorkspaceIdAndBaseApplicationsInRecentlyUsedOrder(workspaceId);
}
});
}

@Override
public Mono<Application> save(Artifact artifact) {
Application application = (Application) artifact;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.appsmith.server.repositories.NewActionRepository;
import com.appsmith.server.services.AnalyticsService;
import com.appsmith.server.services.AssetService;
import com.appsmith.server.services.FeatureFlagService;
import com.appsmith.server.services.PermissionGroupService;
import com.appsmith.server.services.SessionUserService;
import com.appsmith.server.services.UserDataService;
Expand Down Expand Up @@ -39,7 +40,8 @@ public ApplicationServiceImpl(
UserDataService userDataService,
WorkspaceService workspaceService,
WorkspacePermission workspacePermission,
ObservationRegistry observationRegistry) {
ObservationRegistry observationRegistry,
FeatureFlagService featureFlagService) {
super(
validator,
repository,
Expand All @@ -54,6 +56,7 @@ public ApplicationServiceImpl(
userDataService,
workspaceService,
workspacePermission,
observationRegistry);
observationRegistry,
featureFlagService);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public Mono<ResponseDTO<Application>> delete(@PathVariable String branchedApplic
public Mono<ResponseDTO<List<Application>>> findByWorkspaceIdAndRecentlyUsedOrder(
@RequestParam(required = false) String workspaceId) {
log.debug("Going to get all applications by workspace id {}", workspaceId);
return service.findByWorkspaceIdAndBaseApplicationsInRecentlyUsedOrder(workspaceId)
return service.findByWorkspaceIdAndBaseApplicationsForHome(workspaceId)
.collectList()
.map(applications -> new ResponseDTO<>(HttpStatus.OK, applications));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public Mono<ResponseDTO<Workspace>> deleteLogo(@PathVariable String workspaceId)
@GetMapping("/home")
public Mono<ResponseDTO<List<Workspace>>> workspacesForHome() {
return userWorkspaceService
.getUserWorkspacesByRecentlyUsedOrder()
.getUserWorkspacesForHome()
.map(workspaces -> new ResponseDTO<>(HttpStatus.OK, workspaces));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public UserWorkspaceServiceImpl(
PermissionGroupService permissionGroupService,
OrganizationService organizationService,
WorkspacePermission workspacePermission,
PermissionGroupPermission permissionGroupPermission) {
PermissionGroupPermission permissionGroupPermission,
FeatureFlagService featureFlagService) {

super(
sessionUserService,
Expand All @@ -29,6 +30,7 @@ public UserWorkspaceServiceImpl(
permissionGroupService,
organizationService,
workspacePermission,
permissionGroupPermission);
permissionGroupPermission,
featureFlagService);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,8 @@ Mono<MemberInfoDTO> updatePermissionGroupForMember(
Mono<Boolean> isLastAdminRoleEntity(PermissionGroup permissionGroup);

Mono<List<Workspace>> getUserWorkspacesByRecentlyUsedOrder();

Mono<List<Workspace>> getUserWorkspacesInAlphabeticalOrder();

Mono<List<Workspace>> getUserWorkspacesForHome();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.appsmith.server.services.ce;

import com.appsmith.external.enums.FeatureFlagEnum;
import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.PermissionGroup;
import com.appsmith.server.domains.User;
Expand All @@ -13,6 +14,7 @@
import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.helpers.AppsmithComparators;
import com.appsmith.server.repositories.UserRepository;
import com.appsmith.server.services.FeatureFlagService;
import com.appsmith.server.services.OrganizationService;
import com.appsmith.server.services.PermissionGroupService;
import com.appsmith.server.services.SessionUserService;
Expand All @@ -32,6 +34,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
Expand All @@ -54,6 +57,7 @@ public class UserWorkspaceServiceCEImpl implements UserWorkspaceServiceCE {
private final OrganizationService organizationService;
private final WorkspacePermission workspacePermission;
private final PermissionGroupPermission permissionGroupPermission;
private final FeatureFlagService featureFlagService;

@Autowired
public UserWorkspaceServiceCEImpl(
Expand All @@ -64,7 +68,8 @@ public UserWorkspaceServiceCEImpl(
PermissionGroupService permissionGroupService,
OrganizationService organizationService,
WorkspacePermission workspacePermission,
PermissionGroupPermission permissionGroupPermission) {
PermissionGroupPermission permissionGroupPermission,
FeatureFlagService featureFlagService) {
this.sessionUserService = sessionUserService;
this.workspaceService = workspaceService;
this.userRepository = userRepository;
Expand All @@ -73,6 +78,7 @@ public UserWorkspaceServiceCEImpl(
this.organizationService = organizationService;
this.workspacePermission = workspacePermission;
this.permissionGroupPermission = permissionGroupPermission;
this.featureFlagService = featureFlagService;
}

@Override
Expand Down Expand Up @@ -419,4 +425,39 @@ public Mono<List<Workspace>> getUserWorkspacesByRecentlyUsedOrder() {
// collect to list to keep the order of the workspaces
.collectList());
}

/*
* Returns a list of workspaces for the current user, sorted in alphabetical order.
*
* @return Mono containing the list of workspaces
*/
@Override
public Mono<List<Workspace>> getUserWorkspacesInAlphabeticalOrder() {
return workspaceService
.getAll(workspacePermission.getReadPermission())
.sort(Comparator.comparing(workspace -> workspace.getName().toLowerCase()))
.collectList();
}

/**
* Returns a list of workspaces for the current user, sorted based on feature flag.
* If alphabetical ordering is enabled, returns workspaces in alphabetical order.
* Otherwise, returns workspaces in recently used order.
*
* @return Mono containing the list of workspaces
*/
@Override
public Mono<List<Workspace>> getUserWorkspacesForHome() {
Mono<Boolean> isAlphabeticalOrderingEnabled =
featureFlagService.check(FeatureFlagEnum.release_alphabetical_ordering_enabled);
return isAlphabeticalOrderingEnabled.flatMap(isEnabled -> {
if (isEnabled) {
// If alphabetical ordering is enabled, then we need to sort the workspaces in alphabetical order
return getUserWorkspacesInAlphabeticalOrder();
} else {
// If alphabetical ordering is disabled, then we need to sort the workspaces in recently used order
return getUserWorkspacesByRecentlyUsedOrder();
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.appsmith.server.repositories.NewActionRepository;
import com.appsmith.server.services.AnalyticsService;
import com.appsmith.server.services.AssetService;
import com.appsmith.server.services.FeatureFlagService;
import com.appsmith.server.services.PermissionGroupService;
import com.appsmith.server.services.SessionUserService;
import com.appsmith.server.services.UserDataService;
Expand Down Expand Up @@ -34,7 +35,8 @@ public ApplicationServiceCECompatibleImpl(
UserDataService userDataService,
WorkspaceService workspaceService,
WorkspacePermission workspacePermission,
ObservationRegistry observationRegistry) {
ObservationRegistry observationRegistry,
FeatureFlagService featureFlagService) {
super(
validator,
repository,
Expand All @@ -49,6 +51,7 @@ public ApplicationServiceCECompatibleImpl(
userDataService,
workspaceService,
workspacePermission,
observationRegistry);
observationRegistry,
featureFlagService);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -377,4 +377,40 @@ public void invalid_removeAnotherDeveloperAsDeveloperInWorkspace() {
.cleanPermissionGroupCacheForUsers(List.of(api_user.getId(), test_user.getId()))
.block();
}

@Test
@WithUserDetails(value = "api_user")
public void getUserWorkspacesInAlphabeticalOrder_WhenUserHasWorkspaces_ReturnsWorkspacesSortedAlphabetically() {

List<String> existingWorkspaceNames =
workspaceService.getAll().map(Workspace::getName).collectList().block();

// Arrange: Create multiple workspaces with different names
List<String> workspaceNames =
new java.util.ArrayList<>(List.of("Zebra Workspace", "Alpha Workspace", "Beta Workspace"));
assert existingWorkspaceNames != null;
for (String name : workspaceNames) {
Workspace workspace = new Workspace();
workspace.setName(name);
// Ensures default permission groups & current user access are created
workspaceService.create(workspace).block();
}

// Act: Call the method to get the user's workspaces in alphabetical order
Mono<List<Workspace>> workspacesMono = userWorkspaceService.getUserWorkspacesInAlphabeticalOrder();

// Assert: Verify the workspaces are returned in alphabetical order
StepVerifier.create(workspacesMono)
.assertNext(workspaces -> {
assertThat(workspaces).isNotNull();
assertThat(workspaces).hasSize(3 + existingWorkspaceNames.size());
List<String> workspaceNamesList =
workspaces.stream().map(Workspace::getName).collect(Collectors.toList());
workspaceNames.addAll(existingWorkspaceNames);
List<String> sortedExistingWorkspaceNames =
workspaceNames.stream().sorted().toList();
assertThat(workspaceNamesList).containsExactly(sortedExistingWorkspaceNames.toArray(new String[0]));
})
.verifyComplete();
}
}