feat(server): Enable upcoming integrations endpoint (#40256)
This PR adds a new endpoint to the Plugin API that fetches upcoming integrations from Appsmith's cloud services. This feature enables users to discover and prepare for new integration options that will be available in future releases. ## Changes - Added a new getUpcomingIntegrations endpoint to the PluginController at GET /api/v1/plugins/upcoming-integrations - Implemented the corresponding service method in PluginService to fetch data from cloud services - Added proper error handling for cloud service communication issues - Injected CloudServicesConfig to ensure proper cloud service URLs are used - Added instanceId to all requests to cloud services for tracking and authorization ## Technical Details - Uses WebClientUtils for HTTP requests to external services - Uses ConfigService to retrieve the instance ID for authentication - Handles error responses gracefully, returning empty results instead of errors to clients - Returns properly formatted integration data including names, descriptions, and other metadata This enhancement will help users discover upcoming integration options and provide feedback on planned datasource connectors. /ok-to-test tags="@tag.Sanity" Solves https://github.com/appsmithorg/appsmith/issues/40048 <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/14490650726> > Commit: a9ae87419b119adb08a156bf19dbe9fe7dd16b64 > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=14490650726&attempt=2" target="_blank">Cypress dashboard</a>. > Tags: `@tag.Sanity` > Spec: > <hr>Wed, 16 Apr 2025 11:50:36 UTC <!-- end of auto-generated comment: Cypress test results --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added a new endpoint to fetch upcoming integrations, providing users with information about future external service integrations. - **Bug Fixes** - Improved error handling for external integration data fetches, ensuring a graceful fallback and user-friendly messaging if data cannot be retrieved. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: nilansh <nilansh@appsmith.com>
This commit is contained in:
parent
e07de53491
commit
99e3cb5d65
|
|
@ -1,5 +1,6 @@
|
|||
package com.appsmith.server.controllers;
|
||||
|
||||
import com.appsmith.server.configurations.CloudServicesConfig;
|
||||
import com.appsmith.server.constants.Url;
|
||||
import com.appsmith.server.controllers.ce.PluginControllerCE;
|
||||
import com.appsmith.server.plugins.base.PluginService;
|
||||
|
|
@ -11,7 +12,10 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
@RequestMapping(Url.PLUGIN_URL)
|
||||
public class PluginController extends PluginControllerCE {
|
||||
|
||||
public PluginController(PluginService service, PluginTriggerSolution pluginTriggerSolution) {
|
||||
super(service, pluginTriggerSolution);
|
||||
public PluginController(
|
||||
PluginService service,
|
||||
PluginTriggerSolution pluginTriggerSolution,
|
||||
CloudServicesConfig cloudServicesConfig) {
|
||||
super(service, pluginTriggerSolution, cloudServicesConfig);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@ package com.appsmith.server.controllers.ce;
|
|||
import com.appsmith.external.models.TriggerRequestDTO;
|
||||
import com.appsmith.external.models.TriggerResultDTO;
|
||||
import com.appsmith.external.views.Views;
|
||||
import com.appsmith.server.configurations.CloudServicesConfig;
|
||||
import com.appsmith.server.constants.FieldName;
|
||||
import com.appsmith.server.constants.Url;
|
||||
import com.appsmith.server.domains.Plugin;
|
||||
import com.appsmith.server.dtos.ResponseDTO;
|
||||
import com.appsmith.server.exceptions.AppsmithException;
|
||||
import com.appsmith.server.plugins.base.PluginService;
|
||||
import com.appsmith.server.plugins.solutions.PluginTriggerSolution;
|
||||
import com.fasterxml.jackson.annotation.JsonView;
|
||||
|
|
@ -28,6 +30,7 @@ import reactor.core.publisher.Flux;
|
|||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RequestMapping(Url.PLUGIN_URL)
|
||||
@RequiredArgsConstructor
|
||||
|
|
@ -38,6 +41,8 @@ public class PluginControllerCE {
|
|||
|
||||
private final PluginTriggerSolution pluginTriggerSolution;
|
||||
|
||||
private final CloudServicesConfig cloudServicesConfig;
|
||||
|
||||
@JsonView(Views.Public.class)
|
||||
@GetMapping
|
||||
public Mono<ResponseDTO<List<Plugin>>> getAll(@RequestParam String workspaceId) {
|
||||
|
|
@ -96,4 +101,21 @@ public class PluginControllerCE {
|
|||
serverWebExchange.getRequest().getHeaders())
|
||||
.map(triggerResultDTO -> new ResponseDTO<>(HttpStatus.OK, triggerResultDTO));
|
||||
}
|
||||
|
||||
@JsonView(Views.Public.class)
|
||||
@GetMapping("/upcoming-integrations")
|
||||
public Mono<ResponseDTO<List<Map<String, String>>>> getUpcomingIntegrations() {
|
||||
log.debug("Fetching upcoming integrations from external API");
|
||||
return service.getUpcomingIntegrations()
|
||||
.map(integrations -> new ResponseDTO<>(HttpStatus.OK, integrations))
|
||||
.onErrorResume(error -> {
|
||||
if (error instanceof AppsmithException) {
|
||||
log.warn("Cloud service error: {}", error.getMessage());
|
||||
return Mono.just(new ResponseDTO<>(HttpStatus.OK.value(), List.of(), error.getMessage()));
|
||||
}
|
||||
log.warn("Error retrieving upcoming integrations from external service: {}", error.getMessage());
|
||||
return Mono.just(new ResponseDTO<>(
|
||||
HttpStatus.OK.value(), List.of(), "Unable to fetch upcoming integrations at this time"));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,4 +53,6 @@ public interface PluginServiceCE extends CrudService<Plugin, String> {
|
|||
Mono<Map<String, Plugin>> findAllPluginsInWorkspace(String workspaceId);
|
||||
|
||||
Flux<Plugin> getPluginsByType(PluginType pluginType);
|
||||
|
||||
Mono<List<Map<String, String>>> getUpcomingIntegrations();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.appsmith.server.plugins.base;
|
|||
|
||||
import com.appsmith.external.models.Datasource;
|
||||
import com.appsmith.external.models.PluginType;
|
||||
import com.appsmith.server.configurations.CloudServicesConfig;
|
||||
import com.appsmith.server.constants.FieldName;
|
||||
import com.appsmith.server.domains.Plugin;
|
||||
import com.appsmith.server.domains.Workspace;
|
||||
|
|
@ -15,7 +16,9 @@ import com.appsmith.server.helpers.LoadShifter;
|
|||
import com.appsmith.server.repositories.PluginRepository;
|
||||
import com.appsmith.server.services.AnalyticsService;
|
||||
import com.appsmith.server.services.BaseService;
|
||||
import com.appsmith.server.services.ConfigService;
|
||||
import com.appsmith.server.services.WorkspaceService;
|
||||
import com.appsmith.util.WebClientUtils;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
|
@ -46,6 +49,7 @@ import java.io.InputStream;
|
|||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
|
@ -65,6 +69,7 @@ public class PluginServiceCEImpl extends BaseService<PluginRepository, Plugin, S
|
|||
private final ReactiveRedisTemplate<String, String> reactiveTemplate;
|
||||
private final ChannelTopic topic;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final CloudServicesConfig cloudServicesConfig;
|
||||
|
||||
private final Map<String, Mono<Map<?, ?>>> formCache = new HashMap<>();
|
||||
private final Map<String, Mono<Map<String, String>>> templateCache = new HashMap<>();
|
||||
|
|
@ -86,6 +91,8 @@ public class PluginServiceCEImpl extends BaseService<PluginRepository, Plugin, S
|
|||
public static final String KEY_COMMENT = "_comment";
|
||||
public static final String KEY_FILES = "files";
|
||||
|
||||
private final ConfigService configService;
|
||||
|
||||
@Autowired
|
||||
public PluginServiceCEImpl(
|
||||
Validator validator,
|
||||
|
|
@ -95,13 +102,17 @@ public class PluginServiceCEImpl extends BaseService<PluginRepository, Plugin, S
|
|||
PluginManager pluginManager,
|
||||
ReactiveRedisTemplate<String, String> reactiveTemplate,
|
||||
ChannelTopic topic,
|
||||
ObjectMapper objectMapper) {
|
||||
ObjectMapper objectMapper,
|
||||
CloudServicesConfig cloudServicesConfig,
|
||||
ConfigService configService) {
|
||||
super(validator, repository, analyticsService);
|
||||
this.workspaceService = workspaceService;
|
||||
this.pluginManager = pluginManager;
|
||||
this.reactiveTemplate = reactiveTemplate;
|
||||
this.topic = topic;
|
||||
this.objectMapper = objectMapper;
|
||||
this.cloudServicesConfig = cloudServicesConfig;
|
||||
this.configService = configService;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -660,6 +671,55 @@ public class PluginServiceCEImpl extends BaseService<PluginRepository, Plugin, S
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<List<Map<String, String>>> getUpcomingIntegrations() {
|
||||
log.debug("Fetching upcoming integrations from external API");
|
||||
|
||||
return configService.getInstanceId().flatMap(instanceId -> {
|
||||
String apiUrl = cloudServicesConfig.getBaseUrl()
|
||||
+ "/api/v1/config/external-saas/upcoming-integrations?instanceId=" + instanceId;
|
||||
return WebClientUtils.create()
|
||||
.get()
|
||||
.uri(apiUrl)
|
||||
.retrieve()
|
||||
.bodyToMono(Map.class)
|
||||
.flatMap(response -> {
|
||||
// Extract the integrations list from the response
|
||||
if (response.containsKey("data")) {
|
||||
List<Map<String, String>> integrations = new ArrayList<>();
|
||||
List<?> data = (List<?>) response.get("data");
|
||||
for (Object item : data) {
|
||||
if (item instanceof Map) {
|
||||
integrations.add((Map<String, String>) item);
|
||||
}
|
||||
}
|
||||
return Mono.just(integrations);
|
||||
} else if (response.containsKey("responseMeta")) {
|
||||
Map<String, Object> responseMeta = (Map<String, Object>) response.get("responseMeta");
|
||||
if (responseMeta.containsKey("error")) {
|
||||
Map<String, Object> error = (Map<String, Object>) responseMeta.get("error");
|
||||
if (error.containsKey("message")) {
|
||||
String errorMessage = (String) error.get("message");
|
||||
return Mono.error(new AppsmithException(
|
||||
AppsmithError.INSTANCE_REGISTRATION_FAILURE, errorMessage));
|
||||
}
|
||||
}
|
||||
return Mono.error(new RuntimeException("Unknown error in response metadata"));
|
||||
}
|
||||
return Mono.just(List.<Map<String, String>>of());
|
||||
})
|
||||
.onErrorResume(error -> {
|
||||
if (error instanceof AppsmithException) {
|
||||
return Mono.error(error);
|
||||
}
|
||||
log.warn(
|
||||
"Error retrieving upcoming integrations from external service: {}", error.getMessage());
|
||||
return Mono.error(
|
||||
new RuntimeException("Error retrieving upcoming integrations: " + error.getMessage()));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Data
|
||||
static class PluginTemplatesMeta {
|
||||
List<PluginTemplate> templates;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package com.appsmith.server.plugins.base;
|
||||
|
||||
import com.appsmith.server.configurations.CloudServicesConfig;
|
||||
import com.appsmith.server.repositories.PluginRepository;
|
||||
import com.appsmith.server.services.AnalyticsService;
|
||||
import com.appsmith.server.services.ConfigService;
|
||||
import com.appsmith.server.services.WorkspaceService;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.validation.Validator;
|
||||
|
|
@ -23,7 +25,9 @@ public class PluginServiceImpl extends PluginServiceCEImpl implements PluginServ
|
|||
PluginManager pluginManager,
|
||||
ReactiveRedisTemplate<String, String> reactiveTemplate,
|
||||
ChannelTopic topic,
|
||||
ObjectMapper objectMapper) {
|
||||
ObjectMapper objectMapper,
|
||||
CloudServicesConfig cloudServicesConfig,
|
||||
ConfigService configService) {
|
||||
|
||||
super(
|
||||
validator,
|
||||
|
|
@ -33,6 +37,8 @@ public class PluginServiceImpl extends PluginServiceCEImpl implements PluginServ
|
|||
pluginManager,
|
||||
reactiveTemplate,
|
||||
topic,
|
||||
objectMapper);
|
||||
objectMapper,
|
||||
cloudServicesConfig,
|
||||
configService);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package com.appsmith.server.services.ce;
|
||||
|
||||
import com.appsmith.server.configurations.CloudServicesConfig;
|
||||
import com.appsmith.server.domains.Plugin;
|
||||
import com.appsmith.server.plugins.base.PluginServiceCE;
|
||||
import com.appsmith.server.plugins.base.PluginServiceCEImpl;
|
||||
import com.appsmith.server.repositories.PluginRepository;
|
||||
import com.appsmith.server.services.AnalyticsService;
|
||||
import com.appsmith.server.services.ConfigService;
|
||||
import com.appsmith.server.services.WorkspaceService;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.validation.Validator;
|
||||
|
|
@ -56,6 +58,8 @@ public class PluginServiceCEImplTest {
|
|||
ObjectMapper objectMapper;
|
||||
|
||||
PluginServiceCE pluginService;
|
||||
CloudServicesConfig cloudServicesConfig;
|
||||
ConfigService configService;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
|
|
@ -68,7 +72,9 @@ public class PluginServiceCEImplTest {
|
|||
pluginManager,
|
||||
reactiveTemplate,
|
||||
topic,
|
||||
objectMapper);
|
||||
objectMapper,
|
||||
cloudServicesConfig,
|
||||
configService);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user