-
Notifications
You must be signed in to change notification settings - Fork 6
Introduce region expansion feature #424
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 18 commits
607ffb4
8cc4e24
30d0c88
81d81a1
6c9754d
361258f
99781cb
f993305
829609a
398b3c9
f621afa
ca945a4
f964453
6c92606
1eee603
e289726
a4df970
db49167
935bf3d
d42d6e6
4bf1628
54a98a8
656d0a4
45ba81e
1083257
9a00b6d
9e419ee
d0f6984
f57d7bd
93dbc9c
b9a9914
63f665b
c692094
7a57c81
8513620
5ad6ad1
ece2caf
8561bb4
2a64e97
40ba462
350bca4
8b21be2
dabf6eb
d0dfc29
26f461e
e54f63b
05490a8
3b3a6f6
5da1e55
d4b48fa
e0662b7
2ddb91f
5f16e20
5f0cd95
72499a1
e87a173
daf42bd
7800b04
8232542
8809c0f
35150d2
6e79177
be93054
02cbfed
5dca42c
9ff6363
30b3d10
f90d716
dd31a5f
dc9f378
45697d5
a4be9bf
cbfef8b
cac4d2f
9e39e48
8a87cc7
f776d71
90abe10
53aabe0
076b185
ebfb109
e9cdbdc
2d8645a
3abf6a3
b89e815
82e4ebb
a422fe2
3c92ea8
07e6cb0
f3e4031
5311b51
1012ebc
1cd12ae
f276e87
406cf61
1a91099
9b34a95
1c9f68a
544ca08
a9d952e
54e423d
0bc136b
4f43a60
8a6ef18
245cf7a
9fea548
f08ec6a
fd14d45
c3c54bf
1237457
78ea56c
d245b5b
34a07af
7effa50
6541d4e
db38ffe
8537776
c39f4e5
7c9adae
479e4a4
b8cd737
4d6cc3c
dfad058
4d39576
97ea08c
35a27c8
1822995
be2a48a
267db7e
05de84c
99b0920
f700976
c096b28
a3c264f
eb349e4
646e4fd
0de46d7
0636955
f003b03
e219b2b
861415d
18045c4
ed5c0b2
4486398
99d6a90
e5ec756
a17814a
718ad57
9134c76
8458312
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
activeProfiles= | ||
eclipse.preferences.version=1 | ||
resolveWorkspaceProjects=true | ||
version=1 | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package software.aws.toolkits.eclipse.amazonq.broker.events; | ||
|
||
public enum QDeveloperProfileState { | ||
NOT_APPLICABLE, SELECTED, AVAILABLE | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,243 @@ | ||
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package software.aws.toolkits.eclipse.amazonq.configuration.profiles; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.concurrent.CompletableFuture; | ||
import java.util.concurrent.ExecutionException; | ||
import java.util.stream.Collectors; | ||
|
||
import org.eclipse.mylyn.commons.ui.dialogs.AbstractNotificationPopup; | ||
import org.eclipse.swt.widgets.Display; | ||
|
||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
|
||
import software.amazon.awssdk.utils.StringUtils; | ||
import software.aws.toolkits.eclipse.amazonq.broker.events.QDeveloperProfileState; | ||
import software.aws.toolkits.eclipse.amazonq.exception.AmazonQPluginException; | ||
import software.aws.toolkits.eclipse.amazonq.lsp.model.GetConfigurationFromServerParams; | ||
import software.aws.toolkits.eclipse.amazonq.lsp.model.GetConfigurationFromServerParams.ExpectedResponseType; | ||
import software.aws.toolkits.eclipse.amazonq.lsp.model.LspServerConfigurations; | ||
import software.aws.toolkits.eclipse.amazonq.plugin.Activator; | ||
import software.aws.toolkits.eclipse.amazonq.util.Constants; | ||
import software.aws.toolkits.eclipse.amazonq.util.ObjectMapperFactory; | ||
import software.aws.toolkits.eclipse.amazonq.util.ToolkitNotification; | ||
import software.aws.toolkits.eclipse.amazonq.views.ViewConstants; | ||
import software.aws.toolkits.eclipse.amazonq.views.model.QDeveloperProfile; | ||
import software.aws.toolkits.eclipse.amazonq.views.model.UpdateConfigurationParams; | ||
|
||
public final class QDeveloperProfileUtil { | ||
|
||
private static final QDeveloperProfileUtil INSTANCE; | ||
private List<QDeveloperProfile> profiles; | ||
private QDeveloperProfile savedDeveloperProfile; | ||
private QDeveloperProfile selectedDeveloperProfile; | ||
private CompletableFuture<Void> profileSelectionTask; | ||
private static final ObjectMapper OBJECT_MAPPER = ObjectMapperFactory.getInstance(); | ||
|
||
static { | ||
INSTANCE = new QDeveloperProfileUtil(); | ||
} | ||
|
||
public static QDeveloperProfileUtil getInstance() { | ||
return INSTANCE; | ||
} | ||
|
||
private QDeveloperProfileUtil() { // prevent initialization | ||
try { | ||
savedDeveloperProfile = Optional | ||
.ofNullable(Activator.getPluginStore().get(ViewConstants.Q_DEVELOPER_PROFILE_SELECTION_KEY)) | ||
.map(json -> { | ||
try { | ||
return deserializeProfile(json); | ||
} catch (final JsonProcessingException e) { | ||
Activator.getLogger().error("Failed to process cached profile", e); | ||
return null; | ||
} | ||
}).orElse(null); | ||
|
||
} catch (Exception e) { | ||
Activator.getLogger().error("Failed to deserialize developer profile", e); | ||
} | ||
profileSelectionTask = new CompletableFuture<>(); | ||
profiles = new ArrayList<QDeveloperProfile>(); | ||
} | ||
|
||
private QDeveloperProfile deserializeProfile(final String json) throws JsonProcessingException { | ||
return OBJECT_MAPPER.readValue(json, QDeveloperProfile.class); | ||
} | ||
|
||
private String serializeProfile(final QDeveloperProfile developerProfile) throws JsonProcessingException { | ||
return OBJECT_MAPPER.writeValueAsString(developerProfile); | ||
} | ||
|
||
public void initialize() { | ||
if (savedDeveloperProfile != null) { | ||
setDeveloperProfile(savedDeveloperProfile); | ||
} | ||
} | ||
|
||
public synchronized List<QDeveloperProfile> queryForDeveloperProfiles(final boolean tryApplyCachedProfile) { | ||
CompletableFuture<List<QDeveloperProfile>> profilesFuture = Activator.getLspProvider().getAmazonQServer() | ||
.thenCompose(server -> { | ||
GetConfigurationFromServerParams params = new GetConfigurationFromServerParams( | ||
ExpectedResponseType.Q_DEVELOPER_PROFILE); | ||
CompletableFuture<LspServerConfigurations<QDeveloperProfile>> response = server | ||
.getConfigurationFromServer(params); | ||
return response; | ||
}).thenApply(this::processConfigurations).exceptionally(throwable -> { | ||
Activator.getLogger().error("Error occurred while fetching the list of Q Developer Profile: ", | ||
throwable); | ||
throw new AmazonQPluginException(throwable); | ||
}).thenApply(result -> { | ||
return handleSelectedProfile(result, tryApplyCachedProfile); | ||
}); | ||
try { | ||
profiles = profilesFuture.get(); | ||
} catch (InterruptedException | ExecutionException e) { | ||
Activator.getLogger().error("Failed to fetch developer profiles: ", e); | ||
} | ||
|
||
return profiles; | ||
} | ||
|
||
public synchronized CompletableFuture<Void> getProfileSelectionTaskFuture() { | ||
if (profileSelectionTask != null && !profileSelectionTask.isDone()) { | ||
return profileSelectionTask; | ||
} | ||
profileSelectionTask = new CompletableFuture<Void>(); | ||
return profileSelectionTask; | ||
} | ||
|
||
private boolean isValidProfile(final QDeveloperProfile profile) { | ||
return profile != null && StringUtils.isNotBlank(profile.getName()); | ||
} | ||
|
||
private List<QDeveloperProfile> handleSelectedProfile(final List<QDeveloperProfile> profiles, | ||
final boolean tryApplyCachedProfile) { | ||
boolean isProfileSet = false; | ||
if (profiles.size() <= 1) { | ||
isProfileSet = handleSingleOrNoProfile(profiles, tryApplyCachedProfile); | ||
} else { | ||
isProfileSet = handleMultipleProfiles(profiles, tryApplyCachedProfile); | ||
} | ||
|
||
if (!isProfileSet) { | ||
Activator.getEventBroker().post(QDeveloperProfileState.class, QDeveloperProfileState.AVAILABLE); | ||
} | ||
return profiles; | ||
} | ||
|
||
private boolean handleSingleOrNoProfile(final List<QDeveloperProfile> profiles, | ||
final boolean tryApplyCachedProfile) { | ||
if (!profiles.isEmpty() && tryApplyCachedProfile) { | ||
setDeveloperProfile(profiles.get(0)); | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
private boolean handleMultipleProfiles(final List<QDeveloperProfile> profiles, | ||
final boolean tryApplyCachedProfile) { | ||
boolean isProfileSelected = false; | ||
if (selectedDeveloperProfile != null) { | ||
isProfileSelected = profiles.stream() | ||
.anyMatch(profile -> profile.getArn().equals(selectedDeveloperProfile.getArn())); | ||
|
||
if (isProfileSelected && tryApplyCachedProfile) { | ||
setDeveloperProfile(selectedDeveloperProfile); | ||
} | ||
} | ||
return isProfileSelected; | ||
} | ||
|
||
private List<QDeveloperProfile> processConfigurations( | ||
final LspServerConfigurations<QDeveloperProfile> configurations) { | ||
return Optional.ofNullable(configurations).map( | ||
config -> config.getConfigurations().stream().filter(this::isValidProfile).collect(Collectors.toList())) | ||
.orElse(Collections.emptyList()); | ||
} | ||
|
||
public List<QDeveloperProfile> getDeveloperProfiles(final boolean tryApplyCachedProfile) { | ||
if (profiles != null && !profiles.isEmpty()) { | ||
return profiles; | ||
} | ||
return queryForDeveloperProfiles(tryApplyCachedProfile); | ||
} | ||
|
||
public void setDeveloperProfile(final QDeveloperProfile developerProfile) { | ||
if (developerProfile == null || (selectedDeveloperProfile != null | ||
&& selectedDeveloperProfile.getArn().equals(developerProfile.getArn()))) { | ||
return; | ||
} | ||
|
||
selectedDeveloperProfile = developerProfile; | ||
saveSelectedProfile(); | ||
|
||
String section = "aws.q"; | ||
Map<String, Object> settings = Map.of("profileArn", selectedDeveloperProfile.getArn()); | ||
Activator.getLspProvider().getAmazonQServer() | ||
.thenCompose(server -> server.updateConfiguration(new UpdateConfigurationParams(section, settings))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ideally this and other configuration update logic should live in a specific component. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ahh I see, I'll look into this. |
||
.thenRun(() -> { | ||
showNotification(selectedDeveloperProfile.getName()); | ||
Activator.getEventBroker().post(QDeveloperProfileState.class, QDeveloperProfileState.SELECTED); | ||
if (profileSelectionTask != null) { | ||
profileSelectionTask.complete(null); | ||
} | ||
profiles = null; | ||
}) | ||
.exceptionally(throwable -> { | ||
Activator.getLogger().error("Error occurred while setting Q Developer Profile: ", throwable); | ||
throw new AmazonQPluginException(throwable); | ||
}); | ||
} | ||
|
||
private void showNotification(final String developerProfileName) { | ||
Display.getDefault().asyncExec(() -> { | ||
AbstractNotificationPopup notification = new ToolkitNotification(Display.getCurrent(), | ||
Constants.IDE_DEVELOPER_PROFILES_NOTIFICATION_TITLE, | ||
String.format(Constants.IDE_DEVELOPER_PROFILES_NOTIFICATION_BODY_TEMPLATE, developerProfileName)); | ||
notification.open(); | ||
}); | ||
} | ||
|
||
public void clearSelectedProfile() { | ||
Activator.getPluginStore().remove(ViewConstants.Q_DEVELOPER_PROFILE_SELECTION_KEY); | ||
selectedDeveloperProfile = null; | ||
} | ||
|
||
private void saveSelectedProfile() { | ||
try { | ||
String serializedSelectedProfile = serializeProfile(selectedDeveloperProfile); | ||
|
||
if (serializedSelectedProfile != null) { | ||
Activator.getPluginStore().put(ViewConstants.Q_DEVELOPER_PROFILE_SELECTION_KEY, | ||
serializedSelectedProfile); | ||
} | ||
} catch (final JsonProcessingException e) { | ||
Activator.getLogger().error("Failed to cache Q developer profile"); | ||
} | ||
} | ||
|
||
public boolean isProfileSelectionRequired() { | ||
if (profiles == null || profiles.isEmpty()) { | ||
queryForDeveloperProfiles(false); | ||
|
||
if (profiles.size() == 1) { | ||
handleSingleOrNoProfile(profiles, true); | ||
} | ||
} | ||
return profiles.size() > 1; | ||
} | ||
|
||
public QDeveloperProfile getSelectedProfile() { | ||
return selectedDeveloperProfile; | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the impact of checking this in?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a maven file. Wasn't sure if this was necessitated by other updates. I'll remove this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll update the
.gitignore
as well.