Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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,8 @@ public interface ApplicationServiceCE extends CrudService<Application, String> {

Flux<Application> findByWorkspaceIdAndBaseApplicationsInRecentlyUsedOrder(String workspaceId);

Flux<Application> findByWorkspaceIdAndBaseApplicationsInAlphabeticalOrder(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
Expand Up @@ -59,6 +59,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 @@ -214,6 +215,41 @@ 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());
}));
}

@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 @@ -11,6 +11,7 @@
import com.appsmith.server.imports.internal.partial.PartialImportService;
import com.appsmith.server.services.ApplicationPageService;
import com.appsmith.server.services.ApplicationSnapshotService;
import com.appsmith.server.services.FeatureFlagService;
import com.appsmith.server.solutions.UserReleaseNotes;
import com.appsmith.server.themes.base.ThemeService;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -33,7 +34,8 @@ public ApplicationController(
PartialExportService partialExportService,
PartialImportService partialImportService,
ImportService importService,
ExportService exportService) {
ExportService exportService,
FeatureFlagService featureFlagService) {
super(
artifactService,
service,
Expand All @@ -45,6 +47,7 @@ public ApplicationController(
partialExportService,
partialImportService,
importService,
exportService);
exportService,
featureFlagService);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.appsmith.server.constants.Url;
import com.appsmith.server.controllers.ce.WorkspaceControllerCE;
import com.appsmith.server.services.FeatureFlagService;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

LGTM: FeatureFlagService added and propagated to CE.

Signature and super(...) call align with the feature‑flag pattern used elsewhere. Please verify the CE constructor includes the flag service and remains singular.

Quick verification script:

Also applies to: 15-15, 17-17


🏁 Script executed:

#!/bin/bash
set -euo pipefail

ce_file="$(fd -a 'WorkspaceControllerCE.java' | head -n1)"
[[ -n "${ce_file:-}" ]] || { echo "WorkspaceControllerCE.java not found"; exit 1; }

echo "== CE constructor context =="
rg -nP -C2 'public\s+WorkspaceControllerCE\s*\(' "$ce_file"

echo "== Ensure FeatureFlagService is a constructor param =="
rg -nP 'WorkspaceControllerCE\s*\([^)]*FeatureFlagService' "$ce_file" >/dev/null || {
  echo "FeatureFlagService missing in CE constructor"; exit 2; }

echo "== Ensure only one CE constructor (expected 1) =="
ctor_count="$(rg -nP 'WorkspaceControllerCE\s*\(' "$ce_file" | wc -l | tr -d ' ')"
echo "Constructor count: $ctor_count"

sub_file='app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/WorkspaceController.java'
echo "== Subclass super(...) call context =="
rg -n 'super\s*\(' "$sub_file" -C1

echo "== Ensure FeatureFlagService is passed to super(...) =="
rg -nP 'super\s*\([^)]*FeatureFlagService' "$sub_file" >/dev/null || {
  echo "FeatureFlagService not passed to super"; exit 3; }

Length of output: 28


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find CE file
ce_file="$(rg --hidden --files -g '**/WorkspaceControllerCE.java' | head -n1 || true)"
if [[ -z "${ce_file:-}" ]]; then
  echo "WorkspaceControllerCE.java not found"
  exit 1
fi
echo "CE file: $ce_file"
echo "== CE class declaration =="
rg -nP -C2 'class\s+WorkspaceControllerCE\b' "$ce_file" || true

echo "== CE constructor matches =="
rg -nP -n '(^|\s)WorkspaceControllerCE\s*\(' "$ce_file" -n -C2 || true

if rg -nP 'public\s+WorkspaceControllerCE\s*\([^)]*FeatureFlagService' "$ce_file" >/dev/null 2>&1; then
  echo "FeatureFlagService present in CE constructor signature"
else
  echo "FeatureFlagService missing in CE constructor signature"
fi

ctor_count="$(rg -nP '(^|\s)WorkspaceControllerCE\s*\(' "$ce_file" | wc -l | tr -d ' ' || true)"
echo "Constructor count: ${ctor_count:-0}"

# Find subclass file
sub_file="$(rg --hidden --files -g '**/WorkspaceController.java' | head -n1 || true)"
if [[ -z "${sub_file:-}" ]]; then
  echo "WorkspaceController.java not found"
  exit 1
fi
echo "Sub file: $sub_file"
echo "== subclass class declaration =="
rg -nP -C2 'class\s+WorkspaceController\b' "$sub_file" || true

echo "== super(...) call context =="
rg -n -C1 'super\s*\(' "$sub_file" || true

if rg -nP 'super\s*\([^)]*FeatureFlagService' "$sub_file" >/dev/null 2>&1; then
  echo "FeatureFlagService passed to super(...)"
else
  echo "FeatureFlagService NOT passed to super(...)"
fi

exit 0

Length of output: 1048


CE constructor missing FeatureFlagService — fix required

WorkspaceControllerCE (app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ce/WorkspaceControllerCE.java) is annotated with @requiredargsconstructor and only has final WorkspaceService and UserWorkspaceService; it does NOT accept FeatureFlagService. WorkspaceController (app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/WorkspaceController.java) calls super(..., featureFlagService) (line 17) — constructor mismatch / compile error.

  • Add private final FeatureFlagService featureFlagService; to WorkspaceControllerCE (or provide an explicit CE constructor) so the parent constructor matches the super(...) call; ensure only one CE constructor exists.
🤖 Prompt for AI Agents
In
app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/WorkspaceController.java
around line 5, the subclass calls super(..., featureFlagService) but the parent
WorkspaceControllerCE constructor does not accept FeatureFlagService, causing a
constructor mismatch; to fix, add a private final FeatureFlagService
featureFlagService field to WorkspaceControllerCE (or create a single explicit
CE constructor that includes FeatureFlagService) so the generated/explicit
constructor signature matches the super(...) call, and ensure there is only one
CE constructor to avoid duplicates.

import com.appsmith.server.services.UserWorkspaceService;
import com.appsmith.server.services.WorkspaceService;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -11,8 +12,8 @@
@RequestMapping(Url.WORKSPACE_URL)
public class WorkspaceController extends WorkspaceControllerCE {

public WorkspaceController(WorkspaceService workspaceService, UserWorkspaceService userWorkspaceService) {
public WorkspaceController(WorkspaceService workspaceService, UserWorkspaceService userWorkspaceService, FeatureFlagService featureFlagService) {

super(workspaceService, userWorkspaceService);
super(workspaceService, userWorkspaceService, featureFlagService);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@
import com.appsmith.server.projections.ApplicationSnapshotResponseDTO;
import com.appsmith.server.services.ApplicationPageService;
import com.appsmith.server.services.ApplicationSnapshotService;
import com.appsmith.server.services.FeatureFlagService;
import com.appsmith.server.solutions.UserReleaseNotes;
import com.appsmith.server.themes.base.ThemeService;
import com.appsmith.external.enums.FeatureFlagEnum;
import com.fasterxml.jackson.annotation.JsonView;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -75,6 +77,7 @@ public class ApplicationControllerCE {
private final PartialImportService partialImportService;
private final ImportService importService;
private final ExportService exportService;
private final FeatureFlagService featureFlagService;

@JsonView(Views.Public.class)
@PostMapping
Expand Down Expand Up @@ -130,9 +133,21 @@ 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)
.collectList()
.map(applications -> new ResponseDTO<>(HttpStatus.OK, applications));

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 applications in alphabetical order
return service.findByWorkspaceIdAndBaseApplicationsInAlphabeticalOrder(workspaceId)
.collectList()
.map(applications -> new ResponseDTO<>(HttpStatus.OK, applications));
} else {
// If alphabetical ordering is disabled, then we need to sort the applications in recently used order
return service.findByWorkspaceIdAndBaseApplicationsInRecentlyUsedOrder(workspaceId)
.collectList()
.map(applications -> new ResponseDTO<>(HttpStatus.OK, applications));
}
});
Comment thread
tomjose92 marked this conversation as resolved.
Outdated
}

@JsonView(Views.Public.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
import com.appsmith.server.dtos.PermissionGroupInfoDTO;
import com.appsmith.server.dtos.ResponseDTO;
import com.appsmith.server.dtos.UpdatePermissionGroupDTO;
import com.appsmith.server.services.FeatureFlagService;
import com.appsmith.server.services.UserWorkspaceService;
import com.appsmith.server.services.WorkspaceService;
import com.appsmith.external.enums.FeatureFlagEnum;
import com.fasterxml.jackson.annotation.JsonView;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
Expand All @@ -33,6 +35,7 @@
public class WorkspaceControllerCE {
private final WorkspaceService service;
private final UserWorkspaceService userWorkspaceService;
private final FeatureFlagService featureFlagService;

@JsonView(Views.Public.class)
@GetMapping("/{id}")
Expand Down Expand Up @@ -106,8 +109,19 @@ public Mono<ResponseDTO<Workspace>> deleteLogo(@PathVariable String workspaceId)
@JsonView(Views.Public.class)
@GetMapping("/home")
public Mono<ResponseDTO<List<Workspace>>> workspacesForHome() {
return userWorkspaceService
.getUserWorkspacesByRecentlyUsedOrder()
.map(workspaces -> new ResponseDTO<>(HttpStatus.OK, workspaces));
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 userWorkspaceService
.getUserWorkspacesInAlphabeticalOrder()
.map(workspaces -> new ResponseDTO<>(HttpStatus.OK, workspaces));
} else {
// If alphabetical ordering is disabled, then we need to sort the workspaces in recently used order
return userWorkspaceService
.getUserWorkspacesByRecentlyUsedOrder()
.map(workspaces -> new ResponseDTO<>(HttpStatus.OK, workspaces));
}
});
Comment thread
tomjose92 marked this conversation as resolved.
Outdated
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ Mono<MemberInfoDTO> updatePermissionGroupForMember(
Mono<Boolean> isLastAdminRoleEntity(PermissionGroup permissionGroup);

Mono<List<Workspace>> getUserWorkspacesByRecentlyUsedOrder();

Mono<List<Workspace>> getUserWorkspacesInAlphabeticalOrder();
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,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 Down Expand Up @@ -419,4 +420,17 @@ 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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -377,4 +377,31 @@ public void invalid_removeAnotherDeveloperAsDeveloperInWorkspace() {
.cleanPermissionGroupCacheForUsers(List.of(api_user.getId(), test_user.getId()))
.block();
}

@Test
@WithUserDetails(value = "api_user")
public void getUserWorkspaceInAlphabeticalOrder_WhenUserHasWorkspaces_ReturnsWorkspacesSortedAlphabetically() {
// Arrange: Create multiple workspaces with different names
String[] workspaceNames = {"Zebra Workspace", "Alpha Workspace", "Beta Workspace"};

for (String name : workspaceNames) {
Workspace workspace = new Workspace();
workspace.setName(name);
workspaceRepository.save(workspace).block();
}

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

// Assert: Verify the workspaces are returned in alphabetical order
StepVerifier.create(workspacesMono)
.assertNext(workspaces -> {
assertThat(workspaces).isNotNull();
assertThat(workspaces).hasSize(3);
assertThat(workspaces.get(0).getName()).isEqualTo("Alpha Workspace");
assertThat(workspaces.get(1).getName()).isEqualTo("Beta Workspace");
assertThat(workspaces.get(2).getName()).isEqualTo("Zebra Workspace");
})
.verifyComplete();
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
Loading