mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'rvasiliev/error-reporting'
This commit is contained in:
@@ -20,6 +20,8 @@ public abstract class AbstractMessage {
|
||||
private SubmittedReportInfo mySubmissionInfo;
|
||||
private String myAdditionalInfo;
|
||||
private Integer myAssigneeId;
|
||||
private boolean myAssigneeVisible;
|
||||
private Long myDevelopersTimestamp;
|
||||
|
||||
public abstract @NotNull Throwable getThrowable();
|
||||
public abstract @NotNull String getThrowableText();
|
||||
@@ -96,6 +98,22 @@ public abstract class AbstractMessage {
|
||||
myAssigneeId = assigneeId;
|
||||
}
|
||||
|
||||
boolean isAssigneeVisible() {
|
||||
return myAssigneeVisible;
|
||||
}
|
||||
|
||||
void setAssigneeVisible(boolean assigneeVisible) {
|
||||
myAssigneeVisible = assigneeVisible;
|
||||
}
|
||||
|
||||
public @Nullable Long getDevelopersTimestamp() {
|
||||
return myDevelopersTimestamp;
|
||||
}
|
||||
|
||||
public void setDevelopersTimestamp(@Nullable Long developersTimestamp) {
|
||||
myDevelopersTimestamp = developersTimestamp;
|
||||
}
|
||||
|
||||
/** @deprecated use {@link #getIncludedAttachments()} instead (to be removed in IDEA 2020) */
|
||||
@Deprecated
|
||||
public List<Attachment> getAttachments() {
|
||||
|
||||
@@ -1,14 +1,25 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.diagnostic;
|
||||
|
||||
import com.intellij.util.xmlb.annotations.Attribute;
|
||||
import com.intellij.util.xmlb.annotations.Tag;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@Tag("developer")
|
||||
public class Developer {
|
||||
public static final Developer NULL = new Developer(-1, "<none>");
|
||||
|
||||
@Attribute("id")
|
||||
private final int myId;
|
||||
|
||||
@Attribute("name")
|
||||
private final String myName;
|
||||
|
||||
@SuppressWarnings("unused") // need for xml serialization
|
||||
private Developer() {
|
||||
this(0, "");
|
||||
}
|
||||
|
||||
public Developer(int id, String name) {
|
||||
myId = id;
|
||||
myName = name;
|
||||
|
||||
@@ -5,33 +5,69 @@ import com.intellij.credentialStore.CredentialAttributes
|
||||
import com.intellij.credentialStore.Credentials
|
||||
import com.intellij.credentialStore.SERVICE_NAME_PREFIX
|
||||
import com.intellij.ide.passwordSafe.PasswordSafe
|
||||
import com.intellij.openapi.components.PersistentStateComponent
|
||||
import com.intellij.openapi.components.RoamingType
|
||||
import com.intellij.openapi.components.State
|
||||
import com.intellij.openapi.components.Storage
|
||||
import com.intellij.openapi.components.*
|
||||
import com.intellij.util.io.decodeBase64
|
||||
import com.intellij.util.xmlb.XmlSerializer
|
||||
import org.jdom.Element
|
||||
|
||||
@State(name = "ErrorReportConfigurable", storages = [(Storage(value = "other.xml", deprecated = true, roamingType = RoamingType.DISABLED))])
|
||||
internal class ErrorReportConfigurable : PersistentStateComponent<OldState> {
|
||||
@State(name = "ErrorReportConfigurable", storages = [Storage(value = "other.xml", deprecated = true, roamingType = RoamingType.DISABLED), Storage(value = "errorReporting.xml")])
|
||||
internal class ErrorReportConfigurable : PersistentStateComponent<Element> {
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
val SERVICE_NAME = "$SERVICE_NAME_PREFIX — JetBrains Account"
|
||||
|
||||
@JvmStatic
|
||||
val instance: ErrorReportConfigurable
|
||||
get() = ServiceManager.getService(ErrorReportConfigurable::class.java)
|
||||
|
||||
@JvmStatic
|
||||
fun getCredentials() = PasswordSafe.instance.get(CredentialAttributes(SERVICE_NAME))
|
||||
}
|
||||
|
||||
override fun getState() = OldState()
|
||||
private var myState: State? = null
|
||||
|
||||
var developer: Developers?
|
||||
get() = myState?.let { Developers(it.developers.toList(), it.timestamp) }
|
||||
set(value) {
|
||||
myState = value?.let { State(it.developers.toList(), it.timestamp) }
|
||||
}
|
||||
|
||||
override fun getState(): Element? {
|
||||
return myState?.let { XmlSerializer.serialize(it) }
|
||||
}
|
||||
|
||||
override fun loadState(element: Element) {
|
||||
loadOldState(element)
|
||||
myState = XmlSerializer.deserialize(element, State::class.java)
|
||||
}
|
||||
|
||||
private fun loadOldState(element: Element) {
|
||||
val state = XmlSerializer.deserialize(element, OldState::class.java)
|
||||
|
||||
override fun loadState(state: OldState) {
|
||||
if (!state.ITN_LOGIN.isNullOrEmpty() || !state.ITN_PASSWORD_CRYPT.isNullOrEmpty()) {
|
||||
PasswordSafe.instance.set(CredentialAttributes(SERVICE_NAME, state.ITN_LOGIN), Credentials(state.ITN_LOGIN, state.ITN_PASSWORD_CRYPT!!.decodeBase64()))
|
||||
}
|
||||
}
|
||||
|
||||
private data class State(var developers: List<Developer>, var timestamp: Long) {
|
||||
@Suppress("unused")
|
||||
private constructor(): this(emptyList(), 0) // need for xml serialization
|
||||
}
|
||||
|
||||
@Suppress("PropertyName")
|
||||
private class OldState {
|
||||
var ITN_LOGIN: String? = null
|
||||
var ITN_PASSWORD_CRYPT: String? = null
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("PropertyName")
|
||||
internal class OldState {
|
||||
var ITN_LOGIN: String? = null
|
||||
var ITN_PASSWORD_CRYPT: String? = null
|
||||
internal data class Developers(val developers: List<Developer>, val timestamp: Long) {
|
||||
companion object {
|
||||
private const val UPDATE_INTERVAL = 24L * 60 * 60 * 1000 // 24 hours
|
||||
}
|
||||
|
||||
fun isUpToDateAt(timestamp: Long): Boolean {
|
||||
return (timestamp - this.timestamp < UPDATE_INTERVAL) && developers.isNotEmpty()
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,7 @@ class ITNProxy {
|
||||
private static final NotNullLazyValue<Map<String, String>> TEMPLATE = AtomicNotNullLazyValue.createValue(() -> {
|
||||
Map<String, String> template = new LinkedHashMap<>();
|
||||
|
||||
template.put("protocol.version", "1");
|
||||
template.put("protocol.version", "1.1");
|
||||
template.put("os.name", SystemInfo.OS_NAME);
|
||||
template.put("java.version", SystemInfo.JAVA_VERSION);
|
||||
template.put("java.vm.vendor", SystemInfo.JAVA_VENDOR);
|
||||
@@ -254,6 +254,10 @@ class ITNProxy {
|
||||
if (messageObj.getAssigneeId() != null) {
|
||||
append(builder, "assignee.id", Integer.toString(messageObj.getAssigneeId()));
|
||||
}
|
||||
append(builder, "assignee.list.visible", Boolean.toString(messageObj.isAssigneeVisible()));
|
||||
if (messageObj.getDevelopersTimestamp() != null) {
|
||||
append(builder, "assignee.list.timestamp", Long.toString(messageObj.getDevelopersTimestamp()));
|
||||
}
|
||||
}
|
||||
|
||||
return builder.toString().getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
@@ -30,7 +30,6 @@ import com.intellij.openapi.ui.ComboBox;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -74,15 +73,15 @@ public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListene
|
||||
private static final String ACCEPTED_NOTICES_KEY = "exception.accepted.notices";
|
||||
private static final String ACCEPTED_NOTICES_SEPARATOR = ":";
|
||||
private static final String DISABLE_PLUGIN_URL = "#disable";
|
||||
|
||||
private static List<Developer> ourDevelopersList = Collections.emptyList();
|
||||
private static final String EA_PLUGIN_ID = "com.intellij.sisyphus";
|
||||
|
||||
private final MessagePool myMessagePool;
|
||||
private final Project myProject;
|
||||
private final boolean myInternalMode;
|
||||
private final boolean myAssigneeVisible;
|
||||
private final Set<String> myAcceptedNotices;
|
||||
private final List<MessageCluster> myMessageClusters = new ArrayList<>(); // exceptions with the same stacktrace
|
||||
private int myIndex, myLastIndex = -1;
|
||||
private Long myDevelopersTimestamp;
|
||||
|
||||
private JLabel myCountLabel;
|
||||
private JTextComponent myInfoLabel;
|
||||
@@ -101,14 +100,14 @@ public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListene
|
||||
super(project, true);
|
||||
myMessagePool = messagePool;
|
||||
myProject = project;
|
||||
myInternalMode = ApplicationManager.getApplication().isInternal();
|
||||
myAssigneeVisible = ApplicationManager.getApplication().isInternal() || PluginManager.isPluginInstalled(PluginId.getId(EA_PLUGIN_ID));
|
||||
|
||||
setTitle(DiagnosticBundle.message("error.list.title"));
|
||||
setModal(false);
|
||||
init();
|
||||
setCancelButtonText(CommonBundle.message("close.action.name"));
|
||||
|
||||
if (myInternalMode) {
|
||||
if (myAssigneeVisible) {
|
||||
loadDevelopersList();
|
||||
}
|
||||
|
||||
@@ -123,30 +122,45 @@ public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListene
|
||||
}
|
||||
|
||||
private void loadDevelopersList() {
|
||||
if (!ourDevelopersList.isEmpty()) {
|
||||
myAssigneeCombo.setModel(new CollectionComboBoxModel<>(ourDevelopersList));
|
||||
ErrorReportConfigurable configurable = ErrorReportConfigurable.getInstance();
|
||||
Developers developers = configurable.getDeveloper();
|
||||
if (developers != null && developers.isUpToDateAt(System.currentTimeMillis())) {
|
||||
setDevelopers(developers);
|
||||
}
|
||||
else {
|
||||
new Task.Backgroundable(null, "Loading Developers List", true) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
try {
|
||||
List<Developer> developers = ITNProxy.fetchDevelopers(indicator);
|
||||
//noinspection AssignmentToStaticFieldFromInstanceMethod
|
||||
ourDevelopersList = developers;
|
||||
Developers updatedDevelopers = new Developers(ITNProxy.fetchDevelopers(indicator), System.currentTimeMillis());
|
||||
UIUtil.invokeLaterIfNeeded(() -> {
|
||||
configurable.setDeveloper(updatedDevelopers);
|
||||
if (isShowing()) {
|
||||
myAssigneeCombo.setModel(new CollectionComboBoxModel<>(developers));
|
||||
setDevelopers(updatedDevelopers);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (UnknownHostException e) {
|
||||
LOG.debug(e);
|
||||
UIUtil.invokeLaterIfNeeded(() -> {
|
||||
if (isShowing()) {
|
||||
setDevelopers(developers);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (UnknownHostException e) { LOG.debug(e); }
|
||||
catch (IOException e) { LOG.warn(e); }
|
||||
}
|
||||
}.queue();
|
||||
}
|
||||
}
|
||||
|
||||
private void setDevelopers(@Nullable Developers developers) {
|
||||
if (developers != null) {
|
||||
myAssigneeCombo.setModel(new CollectionComboBoxModel<>(developers.getDevelopers()));
|
||||
myDevelopersTimestamp = developers.getTimestamp();
|
||||
}
|
||||
}
|
||||
|
||||
private int selectMessage(@Nullable LogMessage defaultMessage) {
|
||||
if (defaultMessage != null) {
|
||||
for (int i = 0; i < myMessageClusters.size(); i++) {
|
||||
@@ -255,7 +269,7 @@ public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListene
|
||||
}
|
||||
});
|
||||
|
||||
if (myInternalMode) {
|
||||
if (myAssigneeVisible) {
|
||||
myAssigneeCombo = new ComboBox<>();
|
||||
myAssigneeCombo.setRenderer(new ListCellRendererWrapper<Developer>() {
|
||||
@Override
|
||||
@@ -312,7 +326,7 @@ public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListene
|
||||
attachmentsPanel.add(scrollPane(myAttachmentArea, 500, 350), BorderLayout.CENTER);
|
||||
|
||||
JPanel accountRow = new JPanel(new BorderLayout());
|
||||
if (myInternalMode) accountRow.add(myAssigneePanel, BorderLayout.WEST);
|
||||
if (myAssigneeVisible) accountRow.add(myAssigneePanel, BorderLayout.WEST);
|
||||
accountRow.add(myCredentialsLabel, BorderLayout.EAST);
|
||||
myNoticePanel = new JPanel(new GridBagLayout());
|
||||
myNoticePanel.add(new JBLabel(UIUtil.getBalloonWarningIcon()), new GridBagConstraints(0, 0, 1, 1, 0, 0, NORTH, NONE, JBUI.insets(7, 0, 0, 5), 0, 0));
|
||||
@@ -341,7 +355,7 @@ public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListene
|
||||
@Override
|
||||
protected Action[] createActions() {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
if (myInternalMode && myProject != null && !myProject.isDefault()) {
|
||||
if (myAssigneeVisible && myProject != null && !myProject.isDefault()) {
|
||||
AnAction action = ActionManager.getInstance().getAction("Unscramble");
|
||||
if (action != null) {
|
||||
actions.add(new AnalyzeAction(action));
|
||||
@@ -411,7 +425,7 @@ public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListene
|
||||
|
||||
updateLabels(cluster);
|
||||
updateDetails(cluster);
|
||||
if (myInternalMode) {
|
||||
if (myAssigneeVisible) {
|
||||
updateAssigneePanel(cluster);
|
||||
}
|
||||
updateCredentialsPanel(submitter);
|
||||
@@ -541,8 +555,13 @@ public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListene
|
||||
myAssigneeCombo.setSelectedIndex(-1);
|
||||
}
|
||||
else {
|
||||
Condition<Developer> lookup = d -> Objects.equals(assignee, d.getId());
|
||||
myAssigneeCombo.setSelectedIndex(ContainerUtil.indexOf(ourDevelopersList, lookup));
|
||||
int assigneeIndex = getAssigneeIndex(assignee);
|
||||
if (assigneeIndex != -1) {
|
||||
myAssigneeCombo.setSelectedIndex(assigneeIndex);
|
||||
}
|
||||
else {
|
||||
cluster.first.setAssigneeId(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -550,6 +569,16 @@ public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListene
|
||||
}
|
||||
}
|
||||
|
||||
private int getAssigneeIndex(Integer assigneeId) {
|
||||
for (int index = 0; index < myAssigneeCombo.getItemCount(); index++) {
|
||||
if (Objects.equals(assigneeId, myAssigneeCombo.getItemAt(index).getId())) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void updateCredentialsPanel(ErrorReportSubmitter submitter) {
|
||||
if (submitter instanceof ITNReporter) {
|
||||
myCredentialsLabel.setVisible(true);
|
||||
@@ -571,6 +600,8 @@ public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListene
|
||||
if (submitter == null) return false;
|
||||
AbstractMessage message = cluster.first;
|
||||
|
||||
message.setAssigneeVisible(myAssigneeVisible);
|
||||
message.setDevelopersTimestamp(myDevelopersTimestamp);
|
||||
message.setSubmitting(true);
|
||||
|
||||
String notice = submitter.getPrivacyNoticeText();
|
||||
|
||||
Reference in New Issue
Block a user