[vcs] Allow loading repository url suggestions separately

Some hosting service integrations (like github) can provide loaders that will load urls in several steps.
It is better to allow displaying partial results.
This commit is contained in:
Ivan Semenov
2018-06-13 19:50:15 +03:00
parent c8d2f5d619
commit 2d2b14e494
2 changed files with 45 additions and 8 deletions
@@ -4,14 +4,19 @@
package com.intellij.dvcs.hosting;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.CalledInBackground;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
/**
* Allows to query remote service for a list of available VCS repositories with the current IDEA settings.
* Can be used to suggest the list of repositories that can be checked out.
* <p>
* Implement either {@link #getAvailableRepositories(ProgressIndicator)} to load everything in a single request
* or {@link #getAvailableRepositoriesFromMultipleSources(ProgressIndicator)} to load in several requests
*/
public interface RepositoryListLoader {
/**
@@ -24,7 +29,26 @@ public interface RepositoryListLoader {
*/
boolean enable();
/**
* Load repository urls in a single requests
*/
@CalledInBackground
@NotNull
List<String> getAvailableRepositories(@NotNull ProgressIndicator progressIndicator) throws RepositoryListLoadingException;
default List<String> getAvailableRepositories(@NotNull ProgressIndicator progressIndicator) throws RepositoryListLoadingException {
return Collections.emptyList();
}
/**
* Load repository urls in multiple requests with ability to show partial result
*/
@CalledInBackground
@NotNull
default Pair<List<String>, List<RepositoryListLoadingException>> getAvailableRepositoriesFromMultipleSources(@NotNull ProgressIndicator progressIndicator) {
try {
return Pair.create(getAvailableRepositories(progressIndicator), Collections.emptyList());
}
catch (RepositoryListLoadingException e) {
return Pair.create(Collections.emptyList(), Collections.singletonList(e));
}
}
}
@@ -20,6 +20,7 @@ import com.intellij.dvcs.DvcsRememberedInputs;
import com.intellij.dvcs.DvcsUtil;
import com.intellij.dvcs.hosting.RepositoryHostingService;
import com.intellij.dvcs.hosting.RepositoryListLoader;
import com.intellij.dvcs.hosting.RepositoryListLoadingException;
import com.intellij.ide.impl.ProjectUtil;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionManager;
@@ -41,6 +42,7 @@ import com.intellij.openapi.ui.ValidationInfo;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
@@ -109,6 +111,7 @@ public abstract class CloneDvcsDialog extends DialogWrapper {
@NotNull private final List<String> myLoadedRepositoryHostingServicesNames;
@Nullable private Alarm myRepositoryUrlAutoCompletionTooltipAlarm;
@NotNull private final Set<String> myUniqueAvailableRepositories;
@NotNull private List<ValidationInfo> myRepositoryListLoadingErrors = new ArrayList<>();
public CloneDvcsDialog(@NotNull Project project, @NotNull String displayName, @NotNull String vcsDirectoryName) {
this(project, displayName, vcsDirectoryName, null);
@@ -261,7 +264,7 @@ public abstract class CloneDvcsDialog extends DialogWrapper {
List<Action> loginActions = new ArrayList<>();
Map<String, RepositoryListLoader> enabledLoaders = new HashMap<>();
for (RepositoryHostingService service : repositoryHostingServices) {
for (RepositoryHostingService service: repositoryHostingServices) {
String serviceDisplayName = service.getServiceDisplayName();
RepositoryListLoader loader = service.getRepositoryListLoader(myProject);
if (loader == null) continue;
@@ -304,14 +307,18 @@ public abstract class CloneDvcsDialog extends DialogWrapper {
private void schedule(@NotNull String serviceDisplayName, @NotNull RepositoryListLoader loader) {
mySpinnerProgressManager.run(new Task.Backgroundable(myProject, "Not Visible") {
private final List<String> myNewRepositories = new ArrayList<>();
private final List<RepositoryListLoadingException> myErrors = new ArrayList<>();
@Override
public void run(@NotNull ProgressIndicator indicator) {
for (String repository : loader.getAvailableRepositories(indicator)) {
Pair<List<String>, List<RepositoryListLoadingException>> loadingResult =
loader.getAvailableRepositoriesFromMultipleSources(indicator);
for (String repository: loadingResult.first) {
if (myUniqueAvailableRepositories.add(repository)) {
myNewRepositories.add(repository);
}
}
myErrors.addAll(loadingResult.second);
}
@Override
@@ -324,11 +331,16 @@ public abstract class CloneDvcsDialog extends DialogWrapper {
}
myLoadedRepositoryHostingServicesNames.add(serviceDisplayName);
showRepositoryUrlAutoCompletionTooltip();
}
@Override
public void onThrowable(@NotNull Throwable error) {
//TODO: show warning
if (!myErrors.isEmpty()) {
for (RepositoryListLoadingException error: myErrors) {
StringBuilder errorMessageBuilder = new StringBuilder();
errorMessageBuilder.append(error.getMessage());
Throwable cause = error.getCause();
if (cause != null) errorMessageBuilder.append(": ").append(cause.getMessage());
myRepositoryListLoadingErrors.add(new ValidationInfo(errorMessageBuilder.toString(), false));
}
startTrackingValidation();
}
}
});
}
@@ -416,6 +428,7 @@ public abstract class CloneDvcsDialog extends DialogWrapper {
ContainerUtil.addIfNotNull(infoList, myCreateDirectoryValidationInfo);
ContainerUtil.addIfNotNull(infoList, urlValidation);
ContainerUtil.addIfNotNull(infoList, directoryValidation);
infoList.addAll(myRepositoryListLoadingErrors);
return infoList;
}