From 7fdbd65d96a32ea75f8ef5912e46dac0eda0d091 Mon Sep 17 00:00:00 2001 From: Jamie Cansdale Date: Wed, 9 Aug 2017 15:08:02 +0100 Subject: [PATCH] Add command to show the current PR --- .../Models/PullRequestDetailArgument.cs | 5 ++- .../PullRequestDetailViewModelDesigner.cs | 4 +- .../ViewModels/PullRequestDetailViewModel.cs | 22 +++++----- .../ViewModels/PullRequestListViewModel.cs | 2 +- .../ViewModels/IPullRequestDetailViewModel.cs | 4 +- src/GitHub.Exports/Settings/PkgCmdID.cs | 1 + .../GitHub.VisualStudio.csproj | 1 + .../GitHub.VisualStudio.vsct | 21 +++++++--- src/GitHub.VisualStudio/Menus/MenuProvider.cs | 3 +- .../Menus/ShowCurrentPullRequest.cs | 40 +++++++++++++++++++ .../UI/Views/PullRequestDetailView.xaml.cs | 11 ++++- 11 files changed, 88 insertions(+), 26 deletions(-) create mode 100644 src/GitHub.VisualStudio/Menus/ShowCurrentPullRequest.cs diff --git a/src/GitHub.App/Models/PullRequestDetailArgument.cs b/src/GitHub.App/Models/PullRequestDetailArgument.cs index 4fa31ad910..3710e75a68 100644 --- a/src/GitHub.App/Models/PullRequestDetailArgument.cs +++ b/src/GitHub.App/Models/PullRequestDetailArgument.cs @@ -1,5 +1,6 @@ using System; using GitHub.ViewModels; +using GitHub.Primitives; namespace GitHub.Models { @@ -9,9 +10,9 @@ namespace GitHub.Models public class PullRequestDetailArgument { /// - /// Gets or sets the repository containing the pull request. + /// Gets or sets the owner of the repository containing the pull request. /// - public IRemoteRepositoryModel Repository { get; set; } + public string RepositoryOwner { get; set; } /// /// Gets or sets the number of the pull request. diff --git a/src/GitHub.App/SampleData/PullRequestDetailViewModelDesigner.cs b/src/GitHub.App/SampleData/PullRequestDetailViewModelDesigner.cs index 2df82a50f4..718844b047 100644 --- a/src/GitHub.App/SampleData/PullRequestDetailViewModelDesigner.cs +++ b/src/GitHub.App/SampleData/PullRequestDetailViewModelDesigner.cs @@ -36,7 +36,7 @@ public PullRequestDetailViewModelDesigner() { var repoPath = @"C:\Repo"; - Model = new PullRequestModel(419, + Model = new PullRequestModel(419, "Error handling/bubbling from viewmodels to views to viewhosts", new AccountDesigner { Login = "shana", IsUser = true }, DateTime.Now.Subtract(TimeSpan.FromDays(3))) @@ -75,7 +75,7 @@ public PullRequestDetailViewModelDesigner() public IPullRequestModel Model { get; } public IPullRequestSession Session { get; } public ILocalRepositoryModel LocalRepository { get; } - public IRemoteRepositoryModel RemoteRepository { get; } + public string RemoteRepositoryOwner { get; } public string SourceBranchDisplayName { get; set; } public string TargetBranchDisplayName { get; set; } public int CommentCount { get; set; } diff --git a/src/GitHub.App/ViewModels/PullRequestDetailViewModel.cs b/src/GitHub.App/ViewModels/PullRequestDetailViewModel.cs index 791f9eeb48..732fab50b1 100644 --- a/src/GitHub.App/ViewModels/PullRequestDetailViewModel.cs +++ b/src/GitHub.App/ViewModels/PullRequestDetailViewModel.cs @@ -93,7 +93,7 @@ public PullRequestDetailViewModel( Checkout = ReactiveCommand.CreateAsyncObservable( this.WhenAnyValue(x => x.CheckoutState) .Cast() - .Select(x => x != null && x.IsEnabled), + .Select(x => x != null && x.IsEnabled), DoCheckout); Checkout.IsExecuting.Subscribe(x => isInCheckout = x); SubscribeOperationError(Checkout); @@ -145,13 +145,13 @@ private set public ILocalRepositoryModel LocalRepository { get; } /// - /// Gets the remote repository that contains the pull request. + /// Gets the owner of the remote repository that contains the pull request. /// /// /// The remote repository may be different from the local repository if the local /// repository is a fork and the user is viewing pull requests from the parent repository. /// - public IRemoteRepositoryModel RemoteRepository { get; private set; } + public string RemoteRepositoryOwner { get; private set; } /// /// Gets the session for the pull request. @@ -323,13 +323,13 @@ public IReadOnlyList ChangedFilesTree public override void Initialize(ViewWithData data) { int number; - var repo = RemoteRepository; + var repoOwner = RemoteRepositoryOwner; if (data != null) { var arg = (PullRequestDetailArgument)data.Data; number = arg.Number; - repo = arg.Repository; + repoOwner = arg.RepositoryOwner; } else { @@ -346,7 +346,7 @@ public override void Initialize(ViewWithData data) } ErrorMessage = OperationError = null; - modelService.GetPullRequest(repo, number) + modelService.GetPullRequest(repoOwner, LocalRepository.Name, number) .TakeLast(1) .ObserveOn(RxApp.MainThreadScheduler) .Catch(ex => @@ -355,23 +355,23 @@ public override void Initialize(ViewWithData data) IsLoading = IsBusy = false; return Observable.Empty(); }) - .Subscribe(x => Load(repo, x).Forget()); + .Subscribe(x => Load(repoOwner, x).Forget()); } /// /// Loads the view model from octokit models. /// - /// The remote repository. + /// The owner of the remote repository. /// The pull request model. - public async Task Load(IRemoteRepositoryModel remoteRepository, IPullRequestModel pullRequest) + public async Task Load(string remoteRepositoryOwner, IPullRequestModel pullRequest) { - Guard.ArgumentNotNull(remoteRepository, nameof(remoteRepository)); + Guard.ArgumentNotNull(remoteRepositoryOwner, nameof(remoteRepositoryOwner)); try { var firstLoad = (Model == null); Model = pullRequest; - RemoteRepository = remoteRepository; + RemoteRepositoryOwner = remoteRepositoryOwner; Session = await sessionManager.GetSession(pullRequest); Title = Resources.PullRequestNavigationItemText + " #" + pullRequest.Number; diff --git a/src/GitHub.App/ViewModels/PullRequestListViewModel.cs b/src/GitHub.App/ViewModels/PullRequestListViewModel.cs index bfeba84293..a9df06f266 100644 --- a/src/GitHub.App/ViewModels/PullRequestListViewModel.cs +++ b/src/GitHub.App/ViewModels/PullRequestListViewModel.cs @@ -321,7 +321,7 @@ void DoOpenPullRequest(object pullRequest) { Data = new PullRequestDetailArgument { - Repository = SelectedRepository, + RepositoryOwner = SelectedRepository.Owner, Number = (int)pullRequest, } }; diff --git a/src/GitHub.Exports.Reactive/ViewModels/IPullRequestDetailViewModel.cs b/src/GitHub.Exports.Reactive/ViewModels/IPullRequestDetailViewModel.cs index 2ff276e945..675be9ae3f 100644 --- a/src/GitHub.Exports.Reactive/ViewModels/IPullRequestDetailViewModel.cs +++ b/src/GitHub.Exports.Reactive/ViewModels/IPullRequestDetailViewModel.cs @@ -83,13 +83,13 @@ public interface IPullRequestDetailViewModel : IViewModel, IHasLoading, IHasBusy ILocalRepositoryModel LocalRepository { get; } /// - /// Gets the remote repository that contains the pull request. + /// Gets the owner of the remote repository that contains the pull request. /// /// /// The remote repository may be different from the local repository if the local /// repository is a fork and the user is viewing pull requests from the parent repository. /// - IRemoteRepositoryModel RemoteRepository { get; } + string RemoteRepositoryOwner { get; } /// /// Gets a string describing how to display the pull request's source branch. diff --git a/src/GitHub.Exports/Settings/PkgCmdID.cs b/src/GitHub.Exports/Settings/PkgCmdID.cs index b41e29fdfe..1c8ba5d56e 100644 --- a/src/GitHub.Exports/Settings/PkgCmdID.cs +++ b/src/GitHub.Exports/Settings/PkgCmdID.cs @@ -9,6 +9,7 @@ public static class PkgCmdIDList public const int idGitHubToolbar = 0x1120; public const int showGitHubPaneCommand = 0x200; public const int openPullRequestsCommand = 0x201; + public const int showCurrentPullRequestCommand = 0x202; public const int backCommand = 0x300; public const int forwardCommand = 0x301; public const int refreshCommand = 0x302; diff --git a/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj b/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj index dc244324c8..7866ebe453 100644 --- a/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj +++ b/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj @@ -294,6 +294,7 @@ + diff --git a/src/GitHub.VisualStudio/GitHub.VisualStudio.vsct b/src/GitHub.VisualStudio/GitHub.VisualStudio.vsct index 24fd2ab45c..8dc212ef03 100644 --- a/src/GitHub.VisualStudio/GitHub.VisualStudio.vsct +++ b/src/GitHub.VisualStudio/GitHub.VisualStudio.vsct @@ -88,6 +88,16 @@ + + - + - + @@ -260,7 +270,7 @@ - + @@ -271,13 +281,14 @@ + - + @@ -313,7 +324,7 @@ - + diff --git a/src/GitHub.VisualStudio/Menus/MenuProvider.cs b/src/GitHub.VisualStudio/Menus/MenuProvider.cs index e1d2db07b9..0edf16514e 100644 --- a/src/GitHub.VisualStudio/Menus/MenuProvider.cs +++ b/src/GitHub.VisualStudio/Menus/MenuProvider.cs @@ -44,7 +44,8 @@ public MenuProvider(IGitHubServiceProvider serviceProvider) { new AddConnection(serviceProvider), new OpenPullRequests(serviceProvider), - new ShowGitHubPane(serviceProvider) + new ShowGitHubPane(serviceProvider), + new ShowCurrentPullRequest(serviceProvider) }; DynamicMenus = new List diff --git a/src/GitHub.VisualStudio/Menus/ShowCurrentPullRequest.cs b/src/GitHub.VisualStudio/Menus/ShowCurrentPullRequest.cs new file mode 100644 index 0000000000..058fc75c47 --- /dev/null +++ b/src/GitHub.VisualStudio/Menus/ShowCurrentPullRequest.cs @@ -0,0 +1,40 @@ +using System; +using GitHub.Exports; +using GitHub.UI; +using GitHub.Services; +using GitHub.Extensions; +using GitHub.Models; + +namespace GitHub.VisualStudio.Menus +{ + [ExportMenu(MenuType = MenuType.OpenPullRequests)] + public class ShowCurrentPullRequest : MenuBase, IMenuHandler + { + public ShowCurrentPullRequest(IGitHubServiceProvider serviceProvider) + : base(serviceProvider) + { + Guard.ArgumentNotNull(serviceProvider, nameof(serviceProvider)); + } + + public Guid Guid => Guids.guidGitHubCmdSet; + public int CmdId => PkgCmdIDList.showCurrentPullRequestCommand; + + public void Activate(object data = null) + { + var pullRequestSessionManager = ServiceProvider.ExportProvider.GetExportedValueOrDefault(); + var session = pullRequestSessionManager?.CurrentSession; + if (session == null) + { + return; // No active PR session. + } + + var pullRequest = session.PullRequest; + var arg = new PullRequestDetailArgument { RepositoryOwner = session.RepositoryOwner, Number = pullRequest.Number }; + var viewWithData = new ViewWithData(UIControllerFlow.PullRequestDetail) { Data = arg }; + + var manager = ServiceProvider.TryGetService(); + var host = manager.ShowHomePane(); + host?.ShowView(viewWithData); + } + } +} diff --git a/src/GitHub.VisualStudio/UI/Views/PullRequestDetailView.xaml.cs b/src/GitHub.VisualStudio/UI/Views/PullRequestDetailView.xaml.cs index 54eacf51e0..9afd8e775d 100644 --- a/src/GitHub.VisualStudio/UI/Views/PullRequestDetailView.xaml.cs +++ b/src/GitHub.VisualStudio/UI/Views/PullRequestDetailView.xaml.cs @@ -26,6 +26,7 @@ using Task = System.Threading.Tasks.Task; using Microsoft.VisualStudio.TextManager.Interop; using System.Text; +using System.Globalization; namespace GitHub.VisualStudio.UI.Views { @@ -71,12 +72,18 @@ protected override void OnVisualParentChanged(DependencyObject oldParent) void DoOpenOnGitHub() { - var repo = ViewModel.RemoteRepository; var browser = VisualStudioBrowser; - var url = repo.CloneUrl.ToRepositoryUrl().Append("pull/" + ViewModel.Model.Number); + var cloneUrl = ViewModel.LocalRepository.CloneUrl; + var url = ToPullRequestUrl(cloneUrl.Host, ViewModel.RemoteRepositoryOwner, ViewModel.LocalRepository.Name, ViewModel.Model.Number); browser.OpenUrl(url); } + static Uri ToPullRequestUrl(string host, string owner, string repositoryName, int number) + { + var url = string.Format(CultureInfo.InvariantCulture, "https://{0}/{1}/{2}/pull/{3}", host, owner, repositoryName, number); + return new Uri(url); + } + async Task DoOpenFile(IPullRequestFileNode file, bool workingDirectory) { try