diff --git a/src/GitHub.App/SampleData/SampleViewModels.cs b/src/GitHub.App/SampleData/SampleViewModels.cs
index 161a5767e2..c93d26acd2 100644
--- a/src/GitHub.App/SampleData/SampleViewModels.cs
+++ b/src/GitHub.App/SampleData/SampleViewModels.cs
@@ -388,7 +388,7 @@ public long PrivateReposInPlan
}
[ExcludeFromCodeCoverage]
- public class RepositoryModelDesigner : IRepositoryModel
+ public class RepositoryModelDesigner : NotificationAwareObject, IRepositoryModel
{
public RepositoryModelDesigner() : this("repo")
{
@@ -416,6 +416,8 @@ public void SetIcon(bool isPrivate, bool isFork)
public Octicon Icon { get; set; }
public IAccount Owner { get; set; }
+
+ public void Refresh() { }
}
public class RepositoryCloneViewModelDesigner : BaseViewModelDesigner, IRepositoryCloneViewModel
diff --git a/src/GitHub.Exports/Extensions/SimpleRepositoryModelExtensions.cs b/src/GitHub.Exports/Extensions/SimpleRepositoryModelExtensions.cs
index 08ce5bcf7d..918d747218 100644
--- a/src/GitHub.Exports/Extensions/SimpleRepositoryModelExtensions.cs
+++ b/src/GitHub.Exports/Extensions/SimpleRepositoryModelExtensions.cs
@@ -15,9 +15,7 @@ public static ISimpleRepositoryModel ToModel(this IGitRepositoryInfo repo)
{
if (repo == null)
return null;
- var uri = repo.GetUriFromRepository();
- var name = uri?.NameWithOwner;
- return name != null ? new SimpleRepositoryModel(name, uri, repo.RepositoryPath) : null;
+ return SimpleRepositoryModel.Create(repo.RepositoryPath);
}
public static bool HasCommits(this ISimpleRepositoryModel repository)
diff --git a/src/GitHub.Exports/Models/ISimpleRepositoryModel.cs b/src/GitHub.Exports/Models/ISimpleRepositoryModel.cs
index 5b15b3d179..197a09378f 100644
--- a/src/GitHub.Exports/Models/ISimpleRepositoryModel.cs
+++ b/src/GitHub.Exports/Models/ISimpleRepositoryModel.cs
@@ -1,9 +1,10 @@
using GitHub.Primitives;
using GitHub.UI;
+using System.ComponentModel;
namespace GitHub.Models
{
- public interface ISimpleRepositoryModel
+ public interface ISimpleRepositoryModel : INotifyPropertyChanged
{
string Name { get; }
UriString CloneUrl { get; }
@@ -11,5 +12,11 @@ public interface ISimpleRepositoryModel
Octicon Icon { get; }
void SetIcon(bool isPrivate, bool isFork);
+
+
+ ///
+ /// Updates the url information based on the local path
+ ///
+ void Refresh();
}
}
diff --git a/src/GitHub.Exports/Models/SimpleRepositoryModel.cs b/src/GitHub.Exports/Models/SimpleRepositoryModel.cs
index 7ca976a1d1..4ec5ddbe83 100644
--- a/src/GitHub.Exports/Models/SimpleRepositoryModel.cs
+++ b/src/GitHub.Exports/Models/SimpleRepositoryModel.cs
@@ -1,9 +1,12 @@
-using GitHub.Primitives;
+using GitHub.Extensions;
+using GitHub.Primitives;
using GitHub.UI;
+using GitHub.VisualStudio;
using GitHub.VisualStudio.Helpers;
using System;
using System.Diagnostics;
using System.Globalization;
+using System.IO;
namespace GitHub.Models
{
@@ -18,6 +21,32 @@ public SimpleRepositoryModel(string name, UriString cloneUrl, string localPath =
Icon = Octicon.repo;
}
+ public SimpleRepositoryModel(string path)
+ {
+ if (path == null)
+ throw new ArgumentNullException(nameof(path));
+ var dir = new DirectoryInfo(path);
+ if (!dir.Exists)
+ throw new ArgumentException("Path does not exist", nameof(path));
+ var uri = GitHelpers.GetRepoFromPath(path)?.GetUri();
+ var name = uri?.NameWithOwner;
+ if (name == null)
+ name = dir.Name;
+ Name = name;
+ LocalPath = path;
+ CloneUrl = uri;
+ Icon = Octicon.repo;
+ }
+
+ public static ISimpleRepositoryModel Create(string path)
+ {
+ if (path == null)
+ return null;
+ if (!Directory.Exists(path))
+ return null;
+ return new SimpleRepositoryModel(path);
+ }
+
public void SetIcon(bool isPrivate, bool isFork)
{
Icon = isPrivate
@@ -27,15 +56,30 @@ public void SetIcon(bool isPrivate, bool isFork)
: Octicon.repo;
}
+ public void Refresh()
+ {
+ if (LocalPath == null)
+ return;
+ var uri = GitHelpers.GetRepoFromPath(LocalPath)?.GetUri();
+ if (CloneUrl != uri)
+ CloneUrl = uri;
+ }
+
public string Name { get; private set; }
- public UriString CloneUrl { get; private set; }
+ UriString cloneUrl;
+ public UriString CloneUrl { get { return cloneUrl; } set { cloneUrl = value; this.RaisePropertyChange(); } }
public string LocalPath { get; private set; }
Octicon icon;
public Octicon Icon { get { return icon; } set { icon = value; this.RaisePropertyChange(); } }
+ ///
+ /// Note: We don't consider CloneUrl a part of the hash code because it can change during the lifetime
+ /// of a repository. Equals takes care of any hash collisions because of this
+ ///
+ ///
public override int GetHashCode()
{
- return (Name?.GetHashCode() ?? 0) ^ (CloneUrl?.GetHashCode() ?? 0) ^ (LocalPath?.TrimEnd('\\').ToUpperInvariant().GetHashCode() ?? 0);
+ return (Name?.GetHashCode() ?? 0) ^ (LocalPath?.TrimEnd('\\').ToUpperInvariant().GetHashCode() ?? 0);
}
public override bool Equals(object obj)
diff --git a/src/GitHub.Exports/Services/ITeamExplorerServiceHolder.cs b/src/GitHub.Exports/Services/ITeamExplorerServiceHolder.cs
index 7356dc1b7f..eab5345aef 100644
--- a/src/GitHub.Exports/Services/ITeamExplorerServiceHolder.cs
+++ b/src/GitHub.Exports/Services/ITeamExplorerServiceHolder.cs
@@ -1,6 +1,7 @@
using System;
using GitHub.Primitives;
using Microsoft.VisualStudio.TeamFoundation.Git.Extensibility;
+using GitHub.Models;
namespace GitHub.Services
{
@@ -28,13 +29,13 @@ public interface ITeamExplorerServiceHolder
///
/// A IGitRepositoryInfo representing the currently active repository
///
- IGitRepositoryInfo ActiveRepo { get; }
+ ISimpleRepositoryModel ActiveRepo { get; }
///
/// Subscribe to be notified when the active repository is set and Notify is called.
///
/// The instance that is interested in being called (or a unique key/object for that instance)
/// The handler to call when ActiveRepo is set
- void Subscribe(object who, Action handler);
+ void Subscribe(object who, Action handler);
///
/// Unsubscribe from notifications
///
@@ -42,11 +43,16 @@ public interface ITeamExplorerServiceHolder
void Unsubscribe(object who);
IGitAwareItem HomeSection { get; }
+
+ ///
+ /// Refresh the information on the active repo (in case of remote url changes or other such things)
+ ///
+ void Refresh();
}
public interface IGitAwareItem
{
- IGitRepositoryInfo ActiveRepo { get; }
+ ISimpleRepositoryModel ActiveRepo { get; }
///
/// Represents the web URL of the repository on GitHub.com, even if the origin is an SSH address.
diff --git a/src/GitHub.VisualStudio/Base/TeamExplorerGitRepoInfo.cs b/src/GitHub.VisualStudio/Base/TeamExplorerGitRepoInfo.cs
index 9a75cb4efa..2bc47af60c 100644
--- a/src/GitHub.VisualStudio/Base/TeamExplorerGitRepoInfo.cs
+++ b/src/GitHub.VisualStudio/Base/TeamExplorerGitRepoInfo.cs
@@ -1,4 +1,5 @@
-using GitHub.Primitives;
+using GitHub.Models;
+using GitHub.Primitives;
using GitHub.Services;
using Microsoft.VisualStudio.TeamFoundation.Git.Extensibility;
using NullGuard;
@@ -12,9 +13,9 @@ public TeamExplorerGitRepoInfo()
ActiveRepo = null;
}
- IGitRepositoryInfo activeRepo;
+ ISimpleRepositoryModel activeRepo;
[AllowNull]
- public IGitRepositoryInfo ActiveRepo
+ public ISimpleRepositoryModel ActiveRepo
{
[return: AllowNull]
get { return activeRepo; }
diff --git a/src/GitHub.VisualStudio/Base/TeamExplorerItemBase.cs b/src/GitHub.VisualStudio/Base/TeamExplorerItemBase.cs
index 27893aaf6a..b181f9ea0e 100644
--- a/src/GitHub.VisualStudio/Base/TeamExplorerItemBase.cs
+++ b/src/GitHub.VisualStudio/Base/TeamExplorerItemBase.cs
@@ -50,7 +50,7 @@ protected virtual void RepoChanged()
var repo = ActiveRepo;
if (repo != null)
{
- var uri = repo.GetUriFromRepository();
+ var uri = repo.CloneUrl;
if (uri?.RepositoryName != null)
{
ActiveRepoUri = uri;
diff --git a/src/GitHub.VisualStudio/Base/TeamExplorerNavigationItemBase.cs b/src/GitHub.VisualStudio/Base/TeamExplorerNavigationItemBase.cs
index dd3abd0aad..e60fc892f0 100644
--- a/src/GitHub.VisualStudio/Base/TeamExplorerNavigationItemBase.cs
+++ b/src/GitHub.VisualStudio/Base/TeamExplorerNavigationItemBase.cs
@@ -10,6 +10,7 @@
using Microsoft.VisualStudio.PlatformUI;
using Microsoft.VisualStudio.TeamFoundation.Git.Extensibility;
using NullGuard;
+using GitHub.Models;
namespace GitHub.VisualStudio.Base
{
@@ -56,7 +57,7 @@ void OnThemeChanged()
}
}
- void UpdateRepo(IGitRepositoryInfo repo)
+ void UpdateRepo(ISimpleRepositoryModel repo)
{
ActiveRepo = repo;
RepoChanged();
diff --git a/src/GitHub.VisualStudio/Base/TeamExplorerSectionBase.cs b/src/GitHub.VisualStudio/Base/TeamExplorerSectionBase.cs
index 7f6b0833d5..6b234ba36c 100644
--- a/src/GitHub.VisualStudio/Base/TeamExplorerSectionBase.cs
+++ b/src/GitHub.VisualStudio/Base/TeamExplorerSectionBase.cs
@@ -100,7 +100,7 @@ public virtual void SaveContext(object sender, SectionSaveContextEventArgs e)
void SubscribeToRepoChanges()
{
- holder.Subscribe(this, (IGitRepositoryInfo repo) =>
+ holder.Subscribe(this, (ISimpleRepositoryModel repo) =>
{
ActiveRepo = repo;
RepoChanged();
diff --git a/src/GitHub.VisualStudio/Base/TeamExplorerServiceHolder.cs b/src/GitHub.VisualStudio/Base/TeamExplorerServiceHolder.cs
index 931494e2d3..046b0171a7 100644
--- a/src/GitHub.VisualStudio/Base/TeamExplorerServiceHolder.cs
+++ b/src/GitHub.VisualStudio/Base/TeamExplorerServiceHolder.cs
@@ -11,6 +11,7 @@
using System.Linq;
using System.Threading;
using System.Globalization;
+using GitHub.Models;
namespace GitHub.VisualStudio.Base
{
@@ -18,8 +19,8 @@ namespace GitHub.VisualStudio.Base
[PartCreationPolicy(CreationPolicy.Shared)]
public class TeamExplorerServiceHolder : ITeamExplorerServiceHolder
{
- readonly Dictionary