diff --git a/plugin/src/software/aws/toolkits/eclipse/amazonq/configuration/DeprecationAcknowledgmentStore.java b/plugin/src/software/aws/toolkits/eclipse/amazonq/configuration/DeprecationAcknowledgmentStore.java new file mode 100644 index 000000000..8d403a207 --- /dev/null +++ b/plugin/src/software/aws/toolkits/eclipse/amazonq/configuration/DeprecationAcknowledgmentStore.java @@ -0,0 +1,107 @@ +// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package software.aws.toolkits.eclipse.amazonq.configuration; + +import org.eclipse.core.runtime.preferences.ConfigurationScope; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.osgi.service.prefs.BackingStoreException; + +import software.aws.toolkits.eclipse.amazonq.plugin.Activator; +import software.aws.toolkits.eclipse.amazonq.util.LoggingService; + +/** + * Persists deprecation acknowledgements at the Eclipse installation level when possible. + * + *
Some Eclipse installations do not allow writes to the configuration scope. In those
+ * environments, acknowledgements fall back to the existing workspace-scoped plugin store.
+ */
+public final class DeprecationAcknowledgmentStore {
+
+ private static final String STORAGE_PROBE_KEY = "deprecationAcknowledgmentStorageProbe";
+
+ private final IEclipsePreferences installationPreferences;
+ private final PluginStore workspaceFallback;
+ private final LoggingService logger;
+
+ private boolean storageChecked;
+ private boolean useWorkspaceFallback;
+
+ public DeprecationAcknowledgmentStore(final IEclipsePreferences installationPreferences,
+ final PluginStore workspaceFallback, final LoggingService logger) {
+ this.installationPreferences = installationPreferences;
+ this.workspaceFallback = workspaceFallback;
+ this.logger = logger;
+ }
+
+ public static DeprecationAcknowledgmentStore getInstance() {
+ return InstanceHolder.INSTANCE;
+ }
+
+ public synchronized boolean isAcknowledged(final String key) {
+ ensureStorageAvailable();
+ if (useWorkspaceFallback) {
+ return "true".equals(workspaceFallback.get(key));
+ }
+ try {
+ return "true".equals(installationPreferences.get(key, null));
+ } catch (RuntimeException e) {
+ switchToWorkspaceFallback("reading", key, e);
+ return "true".equals(workspaceFallback.get(key));
+ }
+ }
+
+ public synchronized void acknowledge(final String key) {
+ ensureStorageAvailable();
+ if (useWorkspaceFallback) {
+ workspaceFallback.put(key, "true");
+ return;
+ }
+ try {
+ installationPreferences.put(key, "true");
+ installationPreferences.flush();
+ } catch (BackingStoreException | RuntimeException e) {
+ switchToWorkspaceFallback("saving", key, e);
+ workspaceFallback.put(key, "true");
+ }
+ }
+
+ private void ensureStorageAvailable() {
+ if (storageChecked) {
+ return;
+ }
+ storageChecked = true;
+ try {
+ installationPreferences.put(STORAGE_PROBE_KEY, "true");
+ installationPreferences.flush();
+ installationPreferences.remove(STORAGE_PROBE_KEY);
+ installationPreferences.flush();
+ } catch (BackingStoreException | RuntimeException e) {
+ try {
+ installationPreferences.remove(STORAGE_PROBE_KEY);
+ } catch (RuntimeException ignored) {
+ // The installation scope is already known to be unavailable.
+ }
+ switchToWorkspaceFallback("validating", STORAGE_PROBE_KEY, e);
+ }
+ }
+
+ private void switchToWorkspaceFallback(final String operation, final String key, final Exception exception) {
+ useWorkspaceFallback = true;
+ if (logger != null) {
+ logger.warn(String.format(
+ "Unable to use installation-level preferences while %s deprecation acknowledgement '%s'; using workspace preferences",
+ operation, key), exception);
+ }
+ }
+
+ private static final class InstanceHolder {
+ private static final DeprecationAcknowledgmentStore INSTANCE = new DeprecationAcknowledgmentStore(
+ ConfigurationScope.INSTANCE.getNode(Activator.PLUGIN_ID),
+ Activator.getPluginStore(),
+ Activator.getLogger());
+
+ private InstanceHolder() {
+ }
+ }
+}
diff --git a/plugin/src/software/aws/toolkits/eclipse/amazonq/configuration/PluginStoreKeys.java b/plugin/src/software/aws/toolkits/eclipse/amazonq/configuration/PluginStoreKeys.java
index 5787ad11c..8cf91c69a 100644
--- a/plugin/src/software/aws/toolkits/eclipse/amazonq/configuration/PluginStoreKeys.java
+++ b/plugin/src/software/aws/toolkits/eclipse/amazonq/configuration/PluginStoreKeys.java
@@ -11,5 +11,6 @@ private PluginStoreKeys() {
public static final String CHAT_DISCLAIMER_ACKNOWLEDGED = "qchatDisclaimerAcknowledged";
public static final String PAIR_PROGRAMMING_ACKNOWLEDGED = "qchatPairProgrammingAcknowledged";
+ public static final String CHAT_DEPRECATION_NOTICE_ACKNOWLEDGED = "qchatDeprecationNoticeAcknowledged";
}
diff --git a/plugin/src/software/aws/toolkits/eclipse/amazonq/providers/assets/ChatClientConfiguration.java b/plugin/src/software/aws/toolkits/eclipse/amazonq/providers/assets/ChatClientConfiguration.java
new file mode 100644
index 000000000..681eb469a
--- /dev/null
+++ b/plugin/src/software/aws/toolkits/eclipse/amazonq/providers/assets/ChatClientConfiguration.java
@@ -0,0 +1,39 @@
+// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package software.aws.toolkits.eclipse.amazonq.providers.assets;
+
+import software.aws.toolkits.eclipse.amazonq.configuration.DeprecationAcknowledgmentStore;
+import software.aws.toolkits.eclipse.amazonq.configuration.PluginStore;
+import software.aws.toolkits.eclipse.amazonq.configuration.PluginStoreKeys;
+
+final class ChatClientConfiguration {
+
+ private final boolean disclaimerAcknowledged;
+ private final boolean pairProgrammingAcknowledged;
+ private final boolean deprecationNoticeAcknowledged;
+
+ private ChatClientConfiguration(final boolean disclaimerAcknowledged,
+ final boolean pairProgrammingAcknowledged, final boolean deprecationNoticeAcknowledged) {
+ this.disclaimerAcknowledged = disclaimerAcknowledged;
+ this.pairProgrammingAcknowledged = pairProgrammingAcknowledged;
+ this.deprecationNoticeAcknowledged = deprecationNoticeAcknowledged;
+ }
+
+ static ChatClientConfiguration load(final PluginStore pluginStore,
+ final DeprecationAcknowledgmentStore deprecationAcknowledgmentStore) {
+ return new ChatClientConfiguration(
+ "true".equals(pluginStore.get(PluginStoreKeys.CHAT_DISCLAIMER_ACKNOWLEDGED)),
+ "true".equals(pluginStore.get(PluginStoreKeys.PAIR_PROGRAMMING_ACKNOWLEDGED)),
+ deprecationAcknowledgmentStore.isAcknowledged(
+ PluginStoreKeys.CHAT_DEPRECATION_NOTICE_ACKNOWLEDGED));
+ }
+
+ String toJavaScript() {
+ return String.format("""
+ disclaimerAcknowledged: %b,
+ pairProgrammingAcknowledged: %b,
+ deprecationNoticeAcknowledged: %b,
+ """, disclaimerAcknowledged, pairProgrammingAcknowledged, deprecationNoticeAcknowledged);
+ }
+}
diff --git a/plugin/src/software/aws/toolkits/eclipse/amazonq/providers/assets/ChatWebViewAssetProvider.java b/plugin/src/software/aws/toolkits/eclipse/amazonq/providers/assets/ChatWebViewAssetProvider.java
index 3b7f2905e..b142a3e23 100644
--- a/plugin/src/software/aws/toolkits/eclipse/amazonq/providers/assets/ChatWebViewAssetProvider.java
+++ b/plugin/src/software/aws/toolkits/eclipse/amazonq/providers/assets/ChatWebViewAssetProvider.java
@@ -16,7 +16,7 @@
import software.aws.toolkits.eclipse.amazonq.broker.events.ChatWebViewAssetState;
import software.aws.toolkits.eclipse.amazonq.chat.ChatCommunicationManager;
import software.aws.toolkits.eclipse.amazonq.chat.ChatTheme;
-import software.aws.toolkits.eclipse.amazonq.configuration.PluginStoreKeys;
+import software.aws.toolkits.eclipse.amazonq.configuration.DeprecationAcknowledgmentStore;
import software.aws.toolkits.eclipse.amazonq.plugin.Activator;
import software.aws.toolkits.eclipse.amazonq.providers.lsp.LspManagerProvider;
import software.aws.toolkits.eclipse.amazonq.util.PluginPlatform;
@@ -187,8 +187,8 @@ private String getEclipseWebkitScript() {
}
private String generateJS(final String jsEntrypoint) {
- var disclaimerAcknowledged = Activator.getPluginStore().get(PluginStoreKeys.CHAT_DISCLAIMER_ACKNOWLEDGED);
- var pairProgrammingAcknowledged = Activator.getPluginStore().get(PluginStoreKeys.PAIR_PROGRAMMING_ACKNOWLEDGED);
+ var clientConfiguration = ChatClientConfiguration.load(
+ Activator.getPluginStore(), DeprecationAcknowledgmentStore.getInstance());
return String.format("""
- """, jsEntrypoint, getWaitFunction(), "true".equals(disclaimerAcknowledged), "true".equals(pairProgrammingAcknowledged),
- getInputFunctions());
+ """, jsEntrypoint, getWaitFunction(), clientConfiguration.toJavaScript(), getInputFunctions());
}
@SuppressWarnings("MethodLength")
diff --git a/plugin/src/software/aws/toolkits/eclipse/amazonq/views/AmazonQChatViewActionHandler.java b/plugin/src/software/aws/toolkits/eclipse/amazonq/views/AmazonQChatViewActionHandler.java
index 7e383652b..d494072c5 100644
--- a/plugin/src/software/aws/toolkits/eclipse/amazonq/views/AmazonQChatViewActionHandler.java
+++ b/plugin/src/software/aws/toolkits/eclipse/amazonq/views/AmazonQChatViewActionHandler.java
@@ -23,6 +23,7 @@
import software.aws.toolkits.eclipse.amazonq.chat.ChatCommunicationManager;
import software.aws.toolkits.eclipse.amazonq.chat.ChatMessage;
import software.aws.toolkits.eclipse.amazonq.chat.models.CursorState;
+import software.aws.toolkits.eclipse.amazonq.configuration.DeprecationAcknowledgmentStore;
import software.aws.toolkits.eclipse.amazonq.configuration.PluginStoreKeys;
import software.aws.toolkits.eclipse.amazonq.exception.AmazonQPluginException;
import software.aws.toolkits.eclipse.amazonq.lsp.auth.model.AuthFollowUpType;
@@ -36,9 +37,17 @@
public class AmazonQChatViewActionHandler implements ViewActionHandler {
private ChatCommunicationManager chatCommunicationManager;
+ private final ChatPromptAcknowledgmentHandler promptAcknowledgmentHandler;
public AmazonQChatViewActionHandler(final ChatCommunicationManager chatCommunicationManager) {
+ this(chatCommunicationManager, new ChatPromptAcknowledgmentHandler(
+ Activator.getPluginStore(), DeprecationAcknowledgmentStore.getInstance()));
+ }
+
+ AmazonQChatViewActionHandler(final ChatCommunicationManager chatCommunicationManager,
+ final ChatPromptAcknowledgmentHandler promptAcknowledgmentHandler) {
this.chatCommunicationManager = chatCommunicationManager;
+ this.promptAcknowledgmentHandler = promptAcknowledgmentHandler;
}
/*
@@ -120,10 +129,7 @@ public final void handleCommand(final ParsedCommand parsedCommand, final Browser
@SuppressWarnings("unchecked")
Map