Skip to content

Commit d199c4e

Browse files
authored
Merge pull request #2378 from digma-ai/export-settings
export import settings Closes #2370
2 parents 599084c + b6de16c commit d199c4e

File tree

4 files changed

+284
-99
lines changed

4 files changed

+284
-99
lines changed

ide-common/src/main/java/org/digma/intellij/plugin/settings/ProjectSettings.java

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -93,61 +93,7 @@ public void apply() throws ConfigurationException {
9393
//run all checks and only then update the settings.
9494
//never update the settings before checks are complete because then the settings will have incorrect data
9595

96-
try {
97-
Objects.requireNonNull(mySettingsComponent.getApiUrl(), "Api url can not be null");
98-
Objects.requireNonNull(mySettingsComponent.getRuntimeObservabilityBackendUrl(), "Runtime observability url can not be null");
99-
} catch (Exception e) {
100-
throw new ConfigurationException(e.getMessage());
101-
}
102-
103-
if (mySettingsComponent.getApiUrl().isBlank()) {
104-
throw new ConfigurationException("Api url can not be empty");
105-
}
106-
if (!CommonUtils.isHttpsUrl(mySettingsComponent.getApiUrl())) {
107-
throw new ConfigurationException("Api url schema must be https");
108-
}
109-
try {
110-
URLValidator.create(mySettingsComponent.getApiUrl()).validate();
111-
} catch (MalformedURLException | URISyntaxException | URLValidator.InvalidUrlException | URLValidator.QueryNotAllowedException |
112-
URLValidator.IncorrectSchemaException e) {
113-
throw new ConfigurationException("Api url is not a well formed: " + e.getMessage());
114-
}
115-
116-
if (mySettingsComponent.getRuntimeObservabilityBackendUrl().isBlank()) {
117-
throw new ConfigurationException("Runtime observability url can not be empty");
118-
}
119-
try {
120-
URLValidator.create(mySettingsComponent.getRuntimeObservabilityBackendUrl()).validate();
121-
} catch (MalformedURLException | URISyntaxException | URLValidator.InvalidUrlException | URLValidator.QueryNotAllowedException |
122-
URLValidator.IncorrectSchemaException e) {
123-
throw new ConfigurationException("Backend observability url is not a well formed: " + e.getMessage());
124-
}
125-
126-
127-
if (mySettingsComponent.getJaegerLinkMode() == JaegerLinkMode.Embedded) {
128-
if (mySettingsComponent.getJaegerQueryUrl() == null || mySettingsComponent.getJaegerQueryUrl().trim().isBlank()) {
129-
throw new ConfigurationException("Jaeger query url can not be empty in mode " + mySettingsComponent.getJaegerLinkMode());
130-
}
131-
try {
132-
URLValidator.create(mySettingsComponent.getJaegerQueryUrl()).validate();
133-
} catch (MalformedURLException | URISyntaxException | URLValidator.InvalidUrlException | URLValidator.QueryNotAllowedException |
134-
URLValidator.IncorrectSchemaException e) {
135-
throw new ConfigurationException("Jaeger query url is not a well formed: " + e.getMessage());
136-
}
137-
} else {
138-
if (mySettingsComponent.getJaegerUrl() == null || mySettingsComponent.getJaegerUrl().trim().isBlank()) {
139-
throw new ConfigurationException("Jaeger url can not be empty in mode " + mySettingsComponent.getJaegerLinkMode());
140-
}
141-
try {
142-
if (mySettingsComponent.getJaegerUrl() != null) {
143-
URLValidator.create(mySettingsComponent.getJaegerUrl()).validate();
144-
}
145-
} catch (MalformedURLException | URISyntaxException | URLValidator.InvalidUrlException | URLValidator.QueryNotAllowedException |
146-
URLValidator.IncorrectSchemaException e) {
147-
throw new ConfigurationException("Jaeger url is not a well formed: " + e.getMessage());
148-
}
149-
}
150-
96+
SettingsUtils.validateSettings(mySettingsComponent);
15197

15298
updateSettingsAndFireChange();
15399

ide-common/src/main/java/org/digma/intellij/plugin/settings/SettingsComponent.java

Lines changed: 165 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package org.digma.intellij.plugin.settings;
22

33
import com.intellij.icons.AllIcons;
4+
import com.intellij.openapi.fileChooser.*;
5+
import com.intellij.openapi.options.ConfigurationException;
6+
import com.intellij.openapi.project.Project;
47
import com.intellij.openapi.ui.*;
58
import com.intellij.ui.*;
69
import com.intellij.ui.components.*;
@@ -9,6 +12,7 @@
912
import org.digma.intellij.plugin.analytics.BackendInfoHolder;
1013
import org.digma.intellij.plugin.auth.account.*;
1114
import org.digma.intellij.plugin.common.*;
15+
import org.digma.intellij.plugin.errorreporting.ErrorReporter;
1216
import org.jetbrains.annotations.*;
1317

1418
import javax.swing.*;
@@ -49,6 +53,9 @@ class SettingsComponent {
4953

5054
public SettingsComponent() {
5155

56+
var defaultLabelForeground = JBColor.foreground();
57+
58+
5259
extendedObservabilityTextFiled.setToolTipText("package names in format 'my.pkg1;my.pkg2");
5360
extendedObservabilityExcludeTextField.setToolTipText("class/method names to exclude in format 'MyClass;MyOtherClass.myOtherMethod;*get");
5461
var extendedObservabilityTextBoxPanel = new JBPanel<JBPanel<?>>();
@@ -58,8 +65,6 @@ public SettingsComponent() {
5865
extendedObservabilityExcludeTextBoxPanel.setLayout(new BorderLayout());
5966
extendedObservabilityExcludeTextBoxPanel.add(extendedObservabilityExcludeTextField, BorderLayout.CENTER);
6067

61-
var defaultLabelForeground = JBColor.foreground();
62-
6368

6469
var myUrlLabel = new JBLabel("Digma API URL: ");
6570
myApiUrlTextField.setInputVerifier(new InputVerifier() {
@@ -121,7 +126,6 @@ public boolean verify(JComponent input) {
121126

122127

123128
myRuntimeObservabilityBackendUrlLabel.setToolTipText("Where should observability data be sent from the IDE? This would be the Digma collector URL typically listening to port 5050");
124-
125129
myRuntimeObservabilityBackendUrlTextField.setInputVerifier(new InputVerifier() {
126130
@Override
127131
public boolean verify(JComponent input) {
@@ -141,7 +145,6 @@ public boolean verify(JComponent input) {
141145

142146

143147
myEmbeddedJaegerMessage.setForeground(JBColor.BLUE);
144-
145148
var myJaegerLinkModeLabel = new JBLabel("Jaeger link mode: ");
146149
myJaegerLinkModeLabel.setToolTipText("Internal will open the link as an embedded URL within the IDE. "
147150
+ "External will open the link externally to your default browser. "
@@ -157,45 +160,16 @@ public boolean verify(JComponent input) {
157160
+ "Micrometer will use Micrometer tracing, including the annotation of 'Observed' "
158161
);
159162

160-
var resetButton = new JButton("Reset to defaults");
161-
resetButton.setToolTipText("<html><body>Reset the settings to initial defaults</body>");
162-
resetButton.addActionListener(e -> resetToDefaults());
163163

164+
var resetToDefaultsButton = createResetToDefaultsButton();
164165

165-
var userId = "";
166-
if (DigmaDefaultAccountHolder.getInstance().getAccount() != null &&
167-
!DigmaDefaultAccountHolder.getInstance().getAccount().getUserId().equals(DigmaAccountKt.DEFAULT_LOGIN_ID)) {
168-
userId = DigmaDefaultAccountHolder.getInstance().getAccount().getUserId();
169-
}
170-
var userIdLabel = new JBLabel(userId);
171-
userIdLabel.setCopyable(true);
172-
173-
var backendVersionLabel = new JBLabel("Unknown");
174-
var someProject = ProjectUtilsKt.findActiveProject();
175-
if (someProject != null) {
176-
var about = BackendInfoHolder.getInstance(someProject).getAbout();
177-
if (about != null) {
178-
backendVersionLabel.setText(about.getApplicationVersion());
179-
}
180-
}
166+
var userIdLabel = createUserIdLabel();
181167

168+
var backendVersionLabel = createBackendVersionLabel();
182169

183-
pluginResetWarning.setForeground(JBColor.RED);
184-
pluginResetWarning.setVisible(false);
185-
var resetPluginButton = new JButton("Reset plugin");
186-
resetPluginButton.setToolTipText("<html><body>Reset plugin persistent properties to initial values to simulate fresh start</body>");
187-
resetPluginButton.setVisible("true".equalsIgnoreCase(System.getProperty("org.digma.plugin.resetPlugin.enabled")));
188-
resetPluginButton.addActionListener(e -> {
189-
var confirmation = Messages.showYesNoDialog("Are you sure?\n(Plugin will reset and IDE will restart when the settings window is closed)", "Reset Confirmation", AllIcons.General.WarningDialog);
190-
if (confirmation == 0) {
191-
resetPluginRequested = true;
192-
pluginResetWarning.setVisible(true);
193-
} else {
194-
resetPluginRequested = false;
195-
pluginResetWarning.setVisible(false);
196-
}
197-
});
170+
var importExportPanel = createImportExportPanel();
198171

172+
var resetPluginButton = createResetPluginButton();
199173

200174

201175
myMainPanel = FormBuilder.createFormBuilder()
@@ -209,9 +183,10 @@ public boolean verify(JComponent input) {
209183
.addLabeledComponent(myRuntimeObservabilityBackendUrlLabel, myRuntimeObservabilityBackendUrlTextField, 1, false)
210184
.addLabeledComponent("Extended observability (beta)", extendedObservabilityTextBoxPanel, 1, false)
211185
.addLabeledComponent("Extended observability exclude (beta)", extendedObservabilityExcludeTextBoxPanel, 1, false)
212-
.addComponent(resetButton)
186+
.addComponent(resetToDefaultsButton)
213187
.addLabeledComponent(new JBLabel("User id"), userIdLabel)
214188
.addLabeledComponent(new JBLabel("Backend version"), backendVersionLabel)
189+
.addComponent(importExportPanel)
215190
.addComponent(resetPluginButton)
216191
.addComponent(pluginResetWarning)
217192
.addComponentFillVertically(new JPanel(), 0)
@@ -348,10 +323,12 @@ public void resetResetPluginRequested() {
348323
}
349324

350325

351-
352326
private void resetToDefaults() {
353327
//create a new SettingsState object and use it for default startup values
354-
SettingsState settingsState = new SettingsState();
328+
resetFromSettings(new SettingsState());
329+
}
330+
331+
private void resetFromSettings(SettingsState settingsState) {
355332
resetResetPluginRequested();
356333
hidePluginResetWarning();
357334
this.setApiUrl(settingsState.getApiUrl());
@@ -370,4 +347,151 @@ private void resetToDefaults() {
370347
public void hidePluginResetWarning() {
371348
this.pluginResetWarning.setVisible(false);
372349
}
350+
351+
352+
@NotNull
353+
private JButton createResetToDefaultsButton() {
354+
var resetButton = new JButton("Reset to defaults");
355+
resetButton.setToolTipText("<html><body>Reset the settings to initial defaults</body>");
356+
resetButton.addActionListener(e -> resetToDefaults());
357+
return resetButton;
358+
}
359+
360+
361+
@NotNull
362+
private static JBLabel createUserIdLabel() {
363+
var userId = "";
364+
if (DigmaDefaultAccountHolder.getInstance().getAccount() != null &&
365+
!DigmaDefaultAccountHolder.getInstance().getAccount().getUserId().equals(DigmaAccountKt.DEFAULT_LOGIN_ID)) {
366+
userId = DigmaDefaultAccountHolder.getInstance().getAccount().getUserId();
367+
}
368+
var userIdLabel = new JBLabel(userId);
369+
userIdLabel.setCopyable(true);
370+
return userIdLabel;
371+
}
372+
373+
374+
@NotNull
375+
private static JBLabel createBackendVersionLabel() {
376+
var backendVersionLabel = new JBLabel("Unknown");
377+
var someProject = ProjectUtilsKt.findActiveProject();
378+
if (someProject != null) {
379+
var about = BackendInfoHolder.getInstance(someProject).getAbout();
380+
if (about != null) {
381+
backendVersionLabel.setText(about.getApplicationVersion());
382+
}
383+
}
384+
return backendVersionLabel;
385+
}
386+
387+
388+
private JPanel createImportExportPanel() {
389+
//noinspection ExtractMethodRecommender
390+
var exportSettingsButton = new JButton("Export Settings");
391+
exportSettingsButton.addActionListener(actionEvent -> {
392+
try {
393+
394+
SettingsUtils.validateSettings(this);
395+
396+
var dialog = FileChooserFactory.getInstance().createSaveFileDialog(new FileSaverDescriptor("Export To File", "Export settings to file", "conf"), (Project) null);
397+
var file = dialog.save("digma-setting.conf");
398+
if (file != null) {
399+
var exportResult = SettingsUtils.exportSettingsToFile(file.getFile(), toProperties());
400+
if (!exportResult) {
401+
Messages.showErrorDialog("Could not export settings,Please check the logs.", "Export Error");
402+
}
403+
}
404+
} catch (ConfigurationException configurationException) {
405+
Messages.showErrorDialog(configurationException.getMessage(), "Invalid Settings");
406+
} catch (Throwable e) {
407+
Messages.showErrorDialog(e.getMessage(), "Error");
408+
ErrorReporter.getInstance().reportError("SettingsComponent.exportSettingsButton.ActionListener", e);
409+
}
410+
});
411+
412+
var importSettingsButton = new JButton("Import Settings");
413+
importSettingsButton.addActionListener(actionEvent -> {
414+
try {
415+
var dialog = FileChooserFactory.getInstance().createPathChooser(new FileChooserDescriptor(true, false, false, false, false, false), null, myMainPanel);
416+
dialog.choose(null, virtualFiles -> {
417+
if (virtualFiles.size() == 1) {
418+
var properties = SettingsUtils.importSettingsFromFile(virtualFiles.get(0));
419+
if (properties == null) {
420+
Messages.showErrorDialog("Could not import settings,Please check the logs.", "Import Error");
421+
} else {
422+
fromProperties(properties);
423+
}
424+
}
425+
});
426+
} catch (Throwable e) {
427+
Messages.showErrorDialog(e.getMessage(), "Error");
428+
ErrorReporter.getInstance().reportError("SettingsComponent.importSettingsButton.ActionListener", e);
429+
}
430+
});
431+
432+
var importExportPanel = new JPanel();
433+
importExportPanel.add(exportSettingsButton);
434+
importExportPanel.add(importSettingsButton);
435+
436+
return importExportPanel;
437+
}
438+
439+
440+
@NotNull
441+
private JButton createResetPluginButton() {
442+
pluginResetWarning.setForeground(JBColor.RED);
443+
pluginResetWarning.setVisible(false);
444+
var resetPluginButton = new JButton("Reset plugin");
445+
resetPluginButton.setToolTipText("<html><body>Reset plugin persistent properties to initial values to simulate fresh start</body>");
446+
resetPluginButton.setVisible("true".equalsIgnoreCase(System.getProperty("org.digma.plugin.resetPlugin.enabled")));
447+
resetPluginButton.addActionListener(e -> {
448+
var confirmation = Messages.showYesNoDialog("Are you sure?\n(Plugin will reset and IDE will restart when the settings window is closed)", "Reset Confirmation", AllIcons.General.WarningDialog);
449+
if (confirmation == Messages.YES) {
450+
resetPluginRequested = true;
451+
pluginResetWarning.setVisible(true);
452+
} else {
453+
resetPluginRequested = false;
454+
pluginResetWarning.setVisible(false);
455+
}
456+
});
457+
return resetPluginButton;
458+
}
459+
460+
461+
private Map<String, String> toProperties() {
462+
Map<String, String> properties = new HashMap<>();
463+
properties.put("apiUrl", getApiUrl());
464+
if (getApiToken() != null) {
465+
properties.put("apiToken", getApiToken());
466+
}
467+
if (getJaegerUrl() != null) {
468+
properties.put("jaegerUrl", getJaegerUrl());
469+
}
470+
if (getJaegerQueryUrl() != null) {
471+
properties.put("jaegerQueryUrl", getJaegerQueryUrl());
472+
}
473+
properties.put("jaegerLinkMode", getJaegerLinkMode().name());
474+
properties.put("springBootObservabilityMode", getSpringBootObservabilityMode().name());
475+
properties.put("runtimeObservabilityBackendUrl", getRuntimeObservabilityBackendUrl());
476+
if (getExtendedObservability() != null) {
477+
properties.put("extendedObservability", getExtendedObservability());
478+
}
479+
if (getExtendedObservabilityExclude() != null) {
480+
properties.put("extendedObservabilityExcludes", getExtendedObservabilityExclude());
481+
}
482+
return properties;
483+
}
484+
485+
private void fromProperties(Map<String, String> properties) {
486+
setApiUrl(properties.get("apiUrl"));
487+
setApiToken(properties.get("apiToken"));
488+
setJaegerUrl(properties.get("jaegerUrl"));
489+
setJaegerQueryUrl(properties.get("jaegerQueryUrl"));
490+
setJaegerLinkMode(JaegerLinkMode.valueOf(properties.get("jaegerLinkMode")));
491+
setSpringBootObservabilityMode(SpringBootObservabilityMode.valueOf(properties.get("springBootObservabilityMode")));
492+
setRuntimeObservabilityBackendUrl(properties.get("runtimeObservabilityBackendUrl"));
493+
setExtendedObservability(properties.get("extendedObservability"));
494+
setExtendedObservabilityExclude(properties.get("extendedObservabilityExcludes"));
495+
}
496+
373497
}

ide-common/src/main/java/org/digma/intellij/plugin/settings/SettingsState.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ public class SettingsState implements PersistentStateComponent<SettingsState>, D
3838

3939
@NotNull
4040
private String apiUrl = DEFAULT_API_URL;
41-
4241
@Nullable
4342
private String apiToken = null;
4443
@Nullable
@@ -206,6 +205,5 @@ public String getNormalizedExtendedObservabilityExcludes() {
206205
return normalizeExtendedObservabilityValue(extendedObservabilityExcludes);
207206
}
208207

209-
210208
}
211209

0 commit comments

Comments
 (0)