This commit is contained in:
Steven Kirk 2017-12-11 15:57:27 +01:00
Родитель ba29d80269
Коммит 1ea080147d
35 изменённых файлов: 810 добавлений и 8 удалений

Просмотреть файл

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
# Visual Studio 15
VisualStudioVersion = 15.0.27130.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitHub.VisualStudio", "src\GitHub.VisualStudio\GitHub.VisualStudio.csproj", "{11569514-5AE5-4B5B-92A2-F10B0967DE5F}"
ProjectSection(ProjectDependencies) = postProject
@ -213,8 +213,8 @@ Global
{E4ED0537-D1D9-44B6-9212-3096D7C3F7A1}.Release|Any CPU.Build.0 = Release|Any CPU
{E4ED0537-D1D9-44B6-9212-3096D7C3F7A1}.ReleaseWithoutVsix|Any CPU.ActiveCfg = Release|Any CPU
{E4ED0537-D1D9-44B6-9212-3096D7C3F7A1}.ReleaseWithoutVsix|Any CPU.Build.0 = Release|Any CPU
{08DD4305-7787-4823-A53F-4D0F725A07F3}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{08DD4305-7787-4823-A53F-4D0F725A07F3}.Debug|Any CPU.Build.0 = Release|Any CPU
{08DD4305-7787-4823-A53F-4D0F725A07F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{08DD4305-7787-4823-A53F-4D0F725A07F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{08DD4305-7787-4823-A53F-4D0F725A07F3}.DebugCodeAnalysis|Any CPU.ActiveCfg = Release|Any CPU
{08DD4305-7787-4823-A53F-4D0F725A07F3}.DebugCodeAnalysis|Any CPU.Build.0 = Release|Any CPU
{08DD4305-7787-4823-A53F-4D0F725A07F3}.DebugWithoutVsix|Any CPU.ActiveCfg = Release|Any CPU
@ -427,4 +427,7 @@ Global
{110B206F-8554-4B51-BF86-94DAA32F5E26} = {8A7DA2E7-262B-4581-807A-1C45CE79CDFD}
{17EB676B-BB91-48B5-AA59-C67695C647C2} = {8A7DA2E7-262B-4581-807A-1C45CE79CDFD}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {556014CF-5B35-4CE5-B3EF-6AB0007001AC}
EndGlobalSection
EndGlobal

2
script

@ -1 +1 @@
Subproject commit 02618c8047b0dcfd2d83c9a7e5a9c89ce9c97c98
Subproject commit 5ed9b3d7bceee50d27a4a5838d4c0265bd35cc8e

Просмотреть файл

@ -96,6 +96,11 @@ namespace GitHub.Api
return gitHubClient.Gist.Create(newGist);
}
public IObservable<Repository> GetForks(string owner, string name)
{
return gitHubClient.Repository.Forks.GetAll(owner, name);
}
public IObservable<User> GetUser()
{
return gitHubClient.User.Current();

Просмотреть файл

@ -137,7 +137,12 @@
<Compile Include="Models\IssueCommentModel.cs" />
<Compile Include="Models\PullRequestReviewCommentModel.cs" />
<Compile Include="Models\PullRequestDetailArgument.cs" />
<Compile Include="SampleData\ForkRepositoryExecuteViewModelDesigner.cs" />
<Compile Include="SampleData\ForkRepositorySelectViewModelDesigner.cs" />
<Compile Include="Services\GlobalConnection.cs" />
<Compile Include="ViewModels\Dialog\ForkRepositoryExecuteViewModel.cs" />
<Compile Include="ViewModels\Dialog\ForkRepositoryViewModel.cs" />
<Compile Include="ViewModels\Dialog\ForkRepositorySelectViewModel.cs" />
<Compile Include="ViewModels\Dialog\GistCreationViewModel.cs" />
<Compile Include="ViewModels\Dialog\GitHubDialogWindowViewModel.cs" />
<Compile Include="ViewModels\Dialog\LoginCredentialsViewModel.cs" />

9
src/GitHub.App/Resources.Designer.cs сгенерированный
Просмотреть файл

@ -168,6 +168,15 @@ namespace GitHub.App {
}
}
/// <summary>
/// Looks up a localized string similar to Fork Repository.
/// </summary>
internal static string ForkRepositoryTitle {
get {
return ResourceManager.GetString("ForkRepositoryTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to [invalid].
/// </summary>

Просмотреть файл

@ -285,4 +285,7 @@
<data name="WorkingDirectoryHasUncommittedCHanges" xml:space="preserve">
<value>Cannot checkout as your working directory has uncommitted changes.</value>
</data>
<data name="ForkRepositoryTitle" xml:space="preserve">
<value>Fork Repository</value>
</data>
</root>

Просмотреть файл

@ -0,0 +1,48 @@
using System;
using System.Threading.Tasks;
using GitHub.Models;
using GitHub.ViewModels;
using GitHub.ViewModels.Dialog;
using ReactiveUI;
namespace GitHub.SampleData
{
public class ForkRepositoryExecuteViewModelDesigner : ViewModelBase, IForkRepositoryExecuteViewModel
{
public ForkRepositoryExecuteViewModelDesigner()
{
SourceRepository = new RemoteRepositoryModelDesigner
{
Owner = "github",
Name = "VisualStudio",
CloneUrl = "https://github.com/github/VisualStudio",
};
DestinationRepository = new RemoteRepositoryModelDesigner
{
Owner = "user",
Name = "VisualStudio",
CloneUrl = "https://github.com/user/VisualStudio",
};
}
public IObservable<object> Done => null;
public string Title => null;
public IRepositoryModel SourceRepository { get; set; }
public IRepositoryModel DestinationRepository { get; set; }
public ReactiveCommand<object> Start => null;
public Task InitializeAsync(ILocalRepositoryModel repository, IConnection connection)
{
return Task.CompletedTask;
}
public Task InitializeAsync(ILocalRepositoryModel repository, IConnection connection, IAccount account)
{
throw new NotImplementedException();
}
}
}

Просмотреть файл

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using GitHub.Models;
using GitHub.ViewModels;
using GitHub.ViewModels.Dialog;
using ReactiveUI;
namespace GitHub.SampleData
{
public class ForkRepositorySelectViewModelDesigner : ViewModelBase, IForkRepositorySelectViewModel
{
public ForkRepositorySelectViewModelDesigner()
{
Accounts = new[]
{
new AccountDesigner { Login = "Myself" },
new AccountDesigner { Login = "MyOrg1" },
new AccountDesigner { Login = "MyOrg2" },
new AccountDesigner { Login = "MyOrg3" },
new AccountDesigner { Login = "a-long-org-name" },
};
ExistingForks = new[]
{
new RemoteRepositoryModelDesigner { Owner = "MyOrg5", Name = "MyRepo" },
new RemoteRepositoryModelDesigner { Owner = "MyOrg6", Name = "MyRepo" },
};
}
public IReadOnlyList<IAccount> Accounts { get; set; }
public IObservable<object> Done => null;
public IReadOnlyList<IRemoteRepositoryModel> ExistingForks { get; set; }
public bool IsLoading { get; set; }
public string Title => null;
public ReactiveCommand<object> Selected => null;
public Task InitializeAsync(ILocalRepositoryModel repository, IConnection connection)
{
return Task.CompletedTask;
}
}
}

Просмотреть файл

@ -71,5 +71,15 @@ namespace GitHub.Services
var viewModel = factory.CreateViewModel<ILoginViewModel>();
return (IConnection)await showDialog.Show(viewModel);
}
public async Task ShowForkDialog(ILocalRepositoryModel repository, IConnection connection)
{
Guard.ArgumentNotNull(repository, nameof(repository));
Guard.ArgumentNotNull(connection, nameof(connection));
var viewModel = factory.CreateViewModel<IForkRepositoryViewModel>();
await viewModel.InitializeAsync(repository, connection);
await showDialog.Show(viewModel);
}
}
}

Просмотреть файл

@ -94,6 +94,12 @@ namespace GitHub.Services
.ToReadOnlyList(Create);
}
public IObservable<IRemoteRepositoryModel> GetForks(IRepositoryModel repository)
{
return ApiClient.GetForks(repository.Owner, repository.Name)
.Select(x => new RemoteRepositoryModel(x));
}
IObservable<LicenseCacheItem> GetLicensesFromApi()
{
return ApiClient.GetLicenses()

Просмотреть файл

@ -0,0 +1,59 @@
using System;
using System.ComponentModel.Composition;
using System.Threading.Tasks;
using GitHub.App;
using GitHub.Logging;
using GitHub.Models;
using GitHub.Primitives;
using ReactiveUI;
using Serilog;
namespace GitHub.ViewModels.Dialog
{
[Export(typeof(IForkRepositoryExecuteViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class ForkRepositoryExecuteViewModel : ViewModelBase, IForkRepositoryExecuteViewModel
{
static readonly ILogger log = LogManager.ForContext<ForkRepositoryViewModel>();
public ForkRepositoryExecuteViewModel()
{
Start = ReactiveCommand.Create();
}
public IRepositoryModel SourceRepository { get; private set; }
public IRepositoryModel DestinationRepository { get; private set; }
public ReactiveCommand<object> Start { get; }
public string Title => Resources.ForkRepositoryTitle;
public IObservable<object> Done => Start;
public Task InitializeAsync(ILocalRepositoryModel repository, IConnection connection, IAccount account)
{
SourceRepository = repository;
DestinationRepository = new RemoteRepositoryModel(
0,
repository.Name,
CreateForkUri(repository.CloneUrl, account.Login),
false,
true,
account,
null);
return Task.CompletedTask;
}
UriString CreateForkUri(UriString url, string login)
{
var original = url.ToRepositoryUrl();
return new UriString(
string.Format("{0}://{1}/{2}/{3}",
original.Scheme,
original.Authority,
login,
url.RepositoryName));
}
}
}

Просмотреть файл

@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
using GitHub.App;
using GitHub.Factories;
using GitHub.Logging;
using GitHub.Models;
using ReactiveUI;
using Serilog;
namespace GitHub.ViewModels.Dialog
{
[Export(typeof(IForkRepositorySelectViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class ForkRepositorySelectViewModel : ViewModelBase, IForkRepositorySelectViewModel
{
static readonly ILogger log = LogManager.ForContext<ForkRepositoryViewModel>();
readonly IModelServiceFactory modelServiceFactory;
IReadOnlyList<IAccount> accounts;
IReadOnlyList<IRemoteRepositoryModel> existingForks;
bool isLoading;
[ImportingConstructor]
public ForkRepositorySelectViewModel(IModelServiceFactory modelServiceFactory)
{
this.modelServiceFactory = modelServiceFactory;
Selected = ReactiveCommand.Create();
}
public string Title => Resources.ForkRepositoryTitle;
public IReadOnlyList<IAccount> Accounts
{
get { return accounts; }
private set { this.RaiseAndSetIfChanged(ref accounts, value); }
}
public IReadOnlyList<IRemoteRepositoryModel> ExistingForks
{
get { return existingForks; }
private set { this.RaiseAndSetIfChanged(ref existingForks, value); }
}
public bool IsLoading
{
get { return isLoading; }
private set { this.RaiseAndSetIfChanged(ref isLoading, value); }
}
public ReactiveCommand<object> Selected { get; }
public IObservable<object> Done => Selected;
public async Task InitializeAsync(ILocalRepositoryModel repository, IConnection connection)
{
IsLoading = true;
try
{
var modelService = await modelServiceFactory.CreateAsync(connection);
Observable.CombineLatest(
modelService.GetAccounts(),
modelService.GetForks(repository).ToList(),
(a, f) => new { Accounts = a, Forks = f })
.Finally(() => IsLoading = false)
.Subscribe(x =>
{
Accounts = BuildAccounts(x.Accounts, x.Forks);
ExistingForks = BuildExistingForks(x.Accounts, x.Forks);
});
}
catch (Exception ex)
{
log.Error(ex, "Error initializing ForkRepositoryViewModel");
IsLoading = false;
}
}
IReadOnlyList<IAccount> BuildAccounts(IReadOnlyList<IAccount> accounts, IList<IRemoteRepositoryModel> forks)
{
var forksByOwner = forks.ToDictionary(x => x.Owner, x => x);
return accounts.Where(x => !forksByOwner.ContainsKey(x.Login)).ToList();
}
IReadOnlyList<IRemoteRepositoryModel> BuildExistingForks(IReadOnlyList<IAccount> accounts, IList<IRemoteRepositoryModel> forks)
{
var accountsByLogin = accounts.ToDictionary(x => x.Login, x => x);
return forks.Where(x => accountsByLogin.ContainsKey(x.Owner)).ToList();
}
}
}

Просмотреть файл

@ -0,0 +1,44 @@
using System;
using System.ComponentModel.Composition;
using System.Threading.Tasks;
using GitHub.Extensions;
using GitHub.Models;
namespace GitHub.ViewModels.Dialog
{
[Export(typeof(IForkRepositoryViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class ForkRepositoryViewModel : PagedDialogViewModelBase, IForkRepositoryViewModel
{
readonly IForkRepositorySelectViewModel selectPage;
readonly IForkRepositoryExecuteViewModel executePage;
ILocalRepositoryModel repository;
IConnection connection;
[ImportingConstructor]
public ForkRepositoryViewModel(
IForkRepositorySelectViewModel selectPage,
IForkRepositoryExecuteViewModel executePage)
{
this.selectPage = selectPage;
this.executePage = executePage;
selectPage.Done.Subscribe(x => ShowExecutePage((IAccount)x).Forget());
}
public override IObservable<object> Done => null;
public async Task InitializeAsync(ILocalRepositoryModel repository, IConnection connection)
{
this.repository = repository;
this.connection = connection;
await selectPage.InitializeAsync(repository, connection);
Content = selectPage;
}
async Task ShowExecutePage(IAccount account)
{
await executePage.InitializeAsync(repository, connection, account);
Content = executePage;
}
}
}

Просмотреть файл

@ -55,7 +55,7 @@ namespace GitHub.ViewModels.Dialog
{
subscription?.Dispose();
Content = viewModel;
subscription = viewModel.Done.Subscribe(done);
subscription = viewModel.Done?.Subscribe(done);
}
/// <inheritdoc/>

Просмотреть файл

@ -33,6 +33,7 @@ namespace GitHub.Api
bool useOldScopes = false,
bool useFingerprint = true);
IObservable<Repository> GetForks(string owner, string name);
IObservable<string> GetGitIgnoreTemplates();
IObservable<LicenseMetadata> GetLicenses();
IObservable<Unit> DeleteApplicationAuthorization(int id, string twoFactorAuthorizationCode);

Просмотреть файл

@ -122,6 +122,9 @@
<Compile Include="Services\LocalRepositoriesExtensions.cs" />
<Compile Include="Services\ModelServiceExtensions.cs" />
<Compile Include="ViewModels\Dialog\IDialogContentViewModel.cs" />
<Compile Include="ViewModels\Dialog\IForkRepositoryExecuteViewModel.cs" />
<Compile Include="ViewModels\Dialog\IForkRepositoryViewModel.cs" />
<Compile Include="ViewModels\Dialog\IForkRepositorySelectViewModel.cs" />
<Compile Include="ViewModels\Dialog\IGitHubDialogWindowViewModel.cs" />
<Compile Include="ViewModels\Dialog\IGistCreationViewModel.cs" />
<Compile Include="ViewModels\Dialog\ILogin2FaViewModel.cs" />

Просмотреть файл

@ -21,6 +21,7 @@ namespace GitHub.Services
IObservable<IReadOnlyList<IAccount>> GetAccounts();
IObservable<IRemoteRepositoryModel> GetRepository(string owner, string repo);
ITrackingCollection<IRemoteRepositoryModel> GetRepositories(ITrackingCollection<IRemoteRepositoryModel> collection);
IObservable<IRemoteRepositoryModel> GetForks(IRepositoryModel repository);
IObservable<LicenseItem> GetLicenses();
IObservable<GitIgnoreItem> GetGitIgnoreTemplates();
IObservable<IPullRequestModel> GetPullRequest(string owner, string name, int number);

Просмотреть файл

@ -0,0 +1,33 @@
using System;
using System.Threading.Tasks;
using GitHub.Models;
using ReactiveUI;
namespace GitHub.ViewModels.Dialog
{
/// <summary>
/// View model for selecting the account to fork a repository to.
/// </summary>
public interface IForkRepositoryExecuteViewModel : IDialogContentViewModel
{
IRepositoryModel SourceRepository { get; }
IRepositoryModel DestinationRepository { get; }
/// <summary>
/// Gets a command that is executed when the user clicks the "Fork" button.
/// </summary>
ReactiveCommand<object> Start { get; }
/// <summary>
/// Initializes the view model.
/// </summary>
/// <param name="repository">The repository to fork.</param>
/// <param name="connection">The connection to use.</param>
/// <param name="account">The account to fork to.</param>
Task InitializeAsync(
ILocalRepositoryModel repository,
IConnection connection,
IAccount account);
}
}

Просмотреть файл

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using GitHub.Models;
using ReactiveUI;
namespace GitHub.ViewModels.Dialog
{
/// <summary>
/// View model for selecting the account to fork a repository to.
/// </summary>
public interface IForkRepositorySelectViewModel : IDialogContentViewModel
{
/// <summary>
/// Gets a list of accounts that the repository can be forked to.
/// </summary>
IReadOnlyList<IAccount> Accounts { get; }
/// <summary>
/// Gets a list of existing forks for accounts that the owner has access to.
/// </summary>
IReadOnlyList<IRemoteRepositoryModel> ExistingForks { get; }
/// <summary>
/// Gets a value indicating whether the view model is loading.
/// </summary>
bool IsLoading { get; }
/// <summary>
/// Gets a command that is executed when the user selects an item in <see cref="Accounts"/>.
/// </summary>
ReactiveCommand<object> Selected { get; }
/// <summary>
/// Initializes the view model.
/// </summary>
/// <param name="repository">The repository to fork.</param>
/// <param name="connection">The connection to use.</param>
Task InitializeAsync(ILocalRepositoryModel repository, IConnection connection);
}
}

Просмотреть файл

@ -0,0 +1,24 @@
using System;
using System.Threading.Tasks;
using GitHub.Models;
namespace GitHub.ViewModels.Dialog
{
/// <summary>
/// View model for forking a repository.
/// </summary>
public interface IForkRepositoryViewModel : IDialogContentViewModel
{
/// <summary>
/// Gets the currently displayed page.
/// </summary>
IDialogContentViewModel Content { get; }
/// <summary>
/// Initializes the view model.
/// </summary>
/// <param name="repository">The repository to fork.</param>
/// <param name="connection">The connection to use.</param>
Task InitializeAsync(ILocalRepositoryModel repository, IConnection connection);
}
}

Просмотреть файл

@ -57,5 +57,12 @@ namespace GitHub.Services
/// unsuccessful.
/// </returns>
Task<IConnection> ShowLoginDialog();
/// <summary>
/// Shows the Fork Repository dialog.
/// </summary>
/// <param name="repository">The repository to fork.</param>
/// <param name="connection">The connection to use. May not be null.</param>
Task ShowForkDialog(ILocalRepositoryModel repository, IConnection connection);
}
}

Просмотреть файл

@ -38,5 +38,14 @@ namespace GitHub.Extensions
: base(collection)
{
}
/// <summary>
/// Adds the elements of the specified collection to the end of the list.
/// </summary>
/// <param name="items">The items to add.</param>
public void AddRange(IEnumerable<T> items)
{
foreach (var item in items) Add(item);
}
}
}

Просмотреть файл

@ -132,6 +132,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Services\VSGitExt.cs" />
<Compile Include="Home\ForkNavigationItem.cs" />
<Compile Include="RegistryHelper.cs" />
<Compile Include="Services\VSGitServices.cs" />
<Compile Include="Settings.cs" />

Просмотреть файл

@ -0,0 +1,100 @@
using System;
using System.ComponentModel.Composition;
using System.Reactive.Linq;
using GitHub.Api;
using GitHub.Services;
using GitHub.VisualStudio.Base;
using GitHub.VisualStudio.Helpers;
using Microsoft.TeamFoundation.Controls;
using GitHub.UI;
using GitHub.VisualStudio.UI;
using GitHub.Models;
using GitHub.Primitives;
using GitHub.Extensions;
using GitHub.Logging;
using Serilog;
using System.Collections.Specialized;
namespace GitHub.VisualStudio.TeamExplorer.Home
{
[TeamExplorerNavigationItem(ForkNavigationItemId, NavigationItemPriority.Fork)]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class ForkNavigationItem : TeamExplorerNavigationItemBase
{
static readonly ILogger log = LogManager.ForContext<ForkNavigationItem>();
public const string ForkNavigationItemId = "5245767A-B657-4F8E-BFEE-F04159F1DDA6";
readonly IDialogService dialogService;
IConnectionManager connectionManager;
[ImportingConstructor]
public ForkNavigationItem(IGitHubServiceProvider serviceProvider,
ISimpleApiClientFactory apiFactory,
ITeamExplorerServiceHolder holder,
IDialogService dialogService)
: base(serviceProvider, apiFactory, holder, Octicon.repo_forked)
{
this.dialogService = dialogService;
Text = Resources.ForkNavigationItemText;
ArgbColor = Colors.PurpleNavigationItem.ToInt32();
ConnectionManager.Connections.CollectionChanged += ConnectionsChanged;
}
IConnectionManager ConnectionManager
{
get
{
// We can't receive IConnectionManager in the constructor because Invalidate()
// is called from the base constructor and so we don't have chance to save it
// to a field.
if (connectionManager == null)
{
connectionManager = ServiceProvider.GetService<IConnectionManager>();
}
return connectionManager;
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
ConnectionManager.Connections.CollectionChanged -= ConnectionsChanged;
}
public override async void Execute()
{
var connection = await connectionManager.GetConnection(ActiveRepo);
if (connection?.IsLoggedIn == true)
{
await dialogService.ShowForkDialog(ActiveRepo, connection);
}
}
public override async void Invalidate()
{
try
{
IsVisible = false;
if (await IsAGitHubRepo())
{
var connection = await ConnectionManager.GetConnection(ActiveRepo);
IsVisible = connection?.IsLoggedIn ?? false;
}
}
catch (Exception ex)
{
log.Error(ex, "Error updating ForkNavigationItem visibility");
}
}
private void ConnectionsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Invalidate();
}
}
}

Просмотреть файл

@ -14,7 +14,7 @@ namespace GitHub.VisualStudio.TeamExplorer.Home
[PartCreationPolicy(CreationPolicy.NonShared)]
public class PulseNavigationItem : TeamExplorerNavigationItemBase
{
public const string PulseNavigationItemId = "5245767A-B657-4F8E-BFEE-F04159F1DDA2";
public const string PulseNavigationItemId = "5245767A-B657-4F8E-BFEE-F04159F1DDA5";
readonly Lazy<IVisualStudioBrowser> browser;

Просмотреть файл

@ -9,7 +9,8 @@ namespace GitHub.VisualStudio
static class NavigationItemPriority
{
public const int PullRequests = TeamExplorerNavigationItemPriority.GitCommits - 1;
public const int Wiki = TeamExplorerNavigationItemPriority.Settings - 1;
public const int Wiki = TeamExplorerNavigationItemPriority.Settings - 2;
public const int Fork = TeamExplorerNavigationItemPriority.Settings - 1;
public const int Pulse = Wiki - 3;
public const int Graphs = Wiki - 2;
public const int Issues = Wiki - 1;

Просмотреть файл

@ -167,6 +167,9 @@
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\GitHub.TeamFoundation.14\Home\ForkNavigationItem.cs">
<Link>Home\ForkNavigationItem.cs</Link>
</Compile>
<Compile Include="..\GitHub.TeamFoundation.14\Services\VSGitExt.cs">
<Link>Services\VSGitExt.cs</Link>
</Compile>

9
src/GitHub.VisualStudio.UI/Resources.Designer.cs сгенерированный
Просмотреть файл

@ -294,6 +294,15 @@ namespace GitHub.VisualStudio.UI {
}
}
/// <summary>
/// Looks up a localized string similar to Fork.
/// </summary>
public static string ForkNavigationItemText {
get {
return ResourceManager.GetString("ForkNavigationItemText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Get Started.
/// </summary>

Просмотреть файл

@ -398,4 +398,7 @@
<data name="OpenFileInSolution" xml:space="preserve">
<value>Open File in Solution</value>
</data>
<data name="ForkNavigationItemText" xml:space="preserve">
<value>Fork</value>
</data>
</root>

Просмотреть файл

@ -349,6 +349,12 @@
<DependentUpon>OptionsControl.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ContentView.cs" />
<Compile Include="Views\Dialog\ForkRepositoryExecuteView.xaml.cs">
<DependentUpon>ForkRepositoryExecuteView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Dialog\ForkRepositorySelectView.xaml.cs">
<DependentUpon>ForkRepositorySelectView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Dialog\GistCreationView.xaml.cs">
<DependentUpon>GistCreationView.xaml</DependentUpon>
</Compile>
@ -492,6 +498,14 @@
<Generator>MSBuild:Compile</Generator>
<CustomToolNamespace>GitHub.VisualStudio.UI</CustomToolNamespace>
</Page>
<Page Include="Views\Dialog\ForkRepositoryExecuteView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Dialog\ForkRepositorySelectView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Dialog\GistCreationView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>

Просмотреть файл

@ -17,6 +17,7 @@ namespace GitHub.VisualStudio.Views
/// simply add an `[ExportViewFor]` attribute to this class with the type of the view model
/// interface.
/// </remarks>
[ExportViewFor(typeof(IForkRepositoryViewModel))]
[ExportViewFor(typeof(ILoginViewModel))]
[ExportViewFor(typeof(INavigationViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]

Просмотреть файл

@ -0,0 +1,76 @@
<UserControl x:Class="GitHub.VisualStudio.Views.Dialog.ForkRepositoryExecuteView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:markdig="clr-namespace:Markdig.Wpf;assembly=Markdig.Wpf"
xmlns:sampleData="clr-namespace:GitHub.SampleData;assembly=GitHub.App"
Margin="8"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<d:DesignProperties.DataContext>
<sampleData:ForkRepositoryExecuteViewModelDesigner/>
</d:DesignProperties.DataContext>
<StackPanel>
<TextBlock TextWrapping="Wrap">
You're about to fork the
<Hyperlink>
<Run Text="{Binding SourceRepository.Owner, Mode=OneWay}"/>/<Run Text="{Binding SourceRepository.Name, Mode=OneWay}"/>
</Hyperlink>
repository to
<Hyperlink>
<Run Text="{Binding DestinationRepository.Owner, Mode=OneWay}"/>/<Run Text="{Binding DestinationRepository.Name, Mode=OneWay}"/>
</Hyperlink>. This operation will:
</TextBlock>
<ItemsControl Margin="8,16,8,8">
<ItemsControl.Resources>
<Style x:Key="ItemBorder" TargetType="Border">
<Setter Property="Background" Value="#10000000"/>
<Setter Property="CornerRadius" Value="3"/>
<Setter Property="Margin" Value="4"/>
<Setter Property="Padding" Value="4,8"/>
</Style>
<Style TargetType="CheckBox">
<Setter Property="Margin" Value="0,1,6,0"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
</ItemsControl.Resources>
<Border Style="{StaticResource ItemBorder}">
<DockPanel>
<CheckBox IsChecked="True" IsEnabled="False"/>
<TextBlock>Fork the repository</TextBlock>
</DockPanel>
</Border>
<Border Style="{StaticResource ItemBorder}">
<DockPanel>
<CheckBox IsChecked="True"/>
<TextBlock TextWrapping="Wrap">
Update your local repository's <Run Style="{DynamicResource {x:Static markdig:Styles.CodeStyleKey}}">origin</Run> to point to
<Hyperlink><Run Text="{Binding DestinationRepository.CloneUrl, Mode=OneWay}"/></Hyperlink>
</TextBlock>
</DockPanel>
</Border>
<Border Style="{StaticResource ItemBorder}">
<DockPanel>
<CheckBox IsChecked="True"/>
<TextBlock TextWrapping="Wrap">
Add an <Run Style="{DynamicResource {x:Static markdig:Styles.CodeStyleKey}}">upstream</Run> remote pointing to
<Hyperlink><Run Text="{Binding SourceRepository.CloneUrl, Mode=OneWay}"/></Hyperlink>
</TextBlock>
</DockPanel>
</Border>
<Border Style="{StaticResource ItemBorder}">
<DockPanel>
<CheckBox IsChecked="True"/>
<TextBlock TextWrapping="Wrap">
Reset the <Run Style="{DynamicResource {x:Static markdig:Styles.CodeStyleKey}}">master</Run> branch to
<Run Style="{DynamicResource {x:Static markdig:Styles.CodeStyleKey}}">upstream/master</Run>
</TextBlock>
</DockPanel>
</Border>
</ItemsControl>
</StackPanel>
</UserControl>

Просмотреть файл

@ -0,0 +1,17 @@
using System.ComponentModel.Composition;
using System.Windows.Controls;
using GitHub.Exports;
using GitHub.ViewModels.Dialog;
namespace GitHub.VisualStudio.Views.Dialog
{
[ExportViewFor(typeof(IForkRepositoryExecuteViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class ForkRepositoryExecuteView : UserControl
{
public ForkRepositoryExecuteView()
{
InitializeComponent();
}
}
}

Просмотреть файл

@ -0,0 +1,90 @@
<UserControl x:Class="GitHub.VisualStudio.Views.Dialog.ForkRepositorySelectView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cache="clr-namespace:GitHub.UI.Helpers;assembly=GitHub.UI"
xmlns:ui="clr-namespace:GitHub.UI;assembly=GitHub.UI"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:GitHub.VisualStudio.Views.Dialog"
xmlns:sampleData="clr-namespace:GitHub.SampleData;assembly=GitHub.App"
Margin="8"
mc:Ignorable="d"
d:DesignHeight="414" d:DesignWidth="440">
<Control.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<cache:SharedDictionaryManager Source="pack://application:,,,/GitHub.UI;component/SharedDictionary.xaml" />
<cache:SharedDictionaryManager Source="pack://application:,,,/GitHub.UI.Reactive;component/SharedDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Control.Resources>
<d:DesignProperties.DataContext>
<sampleData:ForkRepositorySelectViewModelDesigner IsLoading="True"/>
</d:DesignProperties.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0">
<TextBlock DockPanel.Dock="Top" FontSize="16" Margin="0 8">
Where should we fork this repository?
</TextBlock>
<ui:GitHubProgressBar DockPanel.Dock="Top"
Foreground="{DynamicResource GitHubAccentBrush}"
IsIndeterminate="True"
Style="{DynamicResource GitHubProgressBar}"
Visibility="{Binding IsLoading, Converter={ui:BooleanToHiddenVisibilityConverter}}"/>
<ListBox Name="accountsListBox"
ItemsSource="{Binding Accounts}"
Padding="8"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
SelectionChanged="accountsListBox_SelectionChanged">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<DockPanel Width="100">
<TextBlock DockPanel.Dock="Bottom"
Text="{Binding Login, StringFormat=@{0}}"
TextAlignment="Center"
TextTrimming="CharacterEllipsis"/>
<Image Margin="0,4"
Source="{Binding Avatar}"
Width="32"/>
</DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
<DockPanel Grid.Row="1" Visibility="{Binding ExistingForks, Converter={ui:HasItemsVisibilityConverter}}">
<TextBlock DockPanel.Dock="Top" Margin="0 8">
<Run FontSize="16">Can't find what you're looking for?</Run>
<LineBreak/>
<Run>You have existing forks of this repository:</Run>
</TextBlock>
<ListBox DockPanel.Dock="Bottom" ItemsSource="{Binding ExistingForks}" MaxHeight="120">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ui:OcticonImage Icon="repo_forked" Margin="0,0,2,-2"/>
<TextBlock Text="{Binding Owner, Mode=OneWay}"/>
<TextBlock Text="/"/>
<TextBlock Text="{Binding Name, Mode=OneWay}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</Grid>
</UserControl>

Просмотреть файл

@ -0,0 +1,31 @@
using System;
using System.ComponentModel.Composition;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using GitHub.Exports;
using GitHub.Models;
using GitHub.ViewModels.Dialog;
namespace GitHub.VisualStudio.Views.Dialog
{
[ExportViewFor(typeof(IForkRepositorySelectViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class ForkRepositorySelectView : UserControl
{
public ForkRepositorySelectView()
{
InitializeComponent();
}
private void accountsListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var account = e.AddedItems.OfType<IAccount>().FirstOrDefault();
if (account != null)
{
((IForkRepositorySelectViewModel)DataContext).Selected.Execute(account);
}
}
}
}