Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit e7dc313

Browse files
authored
Merge branch 'master' into refactor/pr-list-0.6-update
2 parents fc3c14b + 55d5ca0 commit e7dc313

File tree

7 files changed

+250
-47
lines changed

7 files changed

+250
-47
lines changed

src/GitHub.App/Collections/SequentialListSource.cs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,18 @@ async Task<Page<TModel>> EnsureLoaded(int pageNumber)
146146
}
147147
}
148148

149-
await Task.WhenAny(loading, pageLoaded).ConfigureAwait(false);
149+
var completed = await Task.WhenAny(loading, pageLoaded).ConfigureAwait(false);
150+
151+
if (completed.IsFaulted)
152+
{
153+
throw completed.Exception;
154+
}
150155

151156
if (pageLoaded.IsCompleted)
152157
{
153-
return pages[pageNumber];
158+
// A previous waiting task may have already returned the page. If so, return null.
159+
pages.TryGetValue(pageNumber, out var result);
160+
return result;
154161
}
155162
}
156163

@@ -177,13 +184,18 @@ async Task Load()
177184
{
178185
OnBeginLoading();
179186

180-
while (nextPage <= loadTo && !disposed)
187+
try
188+
{
189+
while (nextPage <= loadTo && !disposed)
190+
{
191+
await LoadNextPage().ConfigureAwait(false);
192+
PageLoaded?.Invoke(this, EventArgs.Empty);
193+
}
194+
}
195+
finally
181196
{
182-
await LoadNextPage().ConfigureAwait(false);
183-
PageLoaded?.Invoke(this, EventArgs.Empty);
197+
OnEndLoading();
184198
}
185-
186-
OnEndLoading();
187199
}
188200

189201
async Task LoadNextPage()

src/GitHub.App/Collections/VirtualizingList.cs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
using System.Collections.Generic;
44
using System.Collections.Specialized;
55
using System.ComponentModel;
6+
using System.IO;
67
using System.Linq;
8+
using System.Reflection;
79
using System.Threading.Tasks;
810
using System.Windows;
911
using System.Windows.Threading;
@@ -139,6 +141,7 @@ object IList.this[int index]
139141

140142
public event NotifyCollectionChangedEventHandler CollectionChanged;
141143
public event PropertyChangedEventHandler PropertyChanged;
144+
public event EventHandler<ErrorEventArgs> InitializationError;
142145

143146
public IEnumerator<T> GetEnumerator()
144147
{
@@ -176,14 +179,22 @@ void LoadCount()
176179
{
177180
countTask.ContinueWith(x =>
178181
{
179-
count = x.Result;
180-
SendReset();
181-
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count)));
182+
if (x.IsFaulted)
183+
{
184+
RaiseInitializationError(x.Exception);
185+
}
186+
else if (!x.IsCanceled)
187+
{
188+
count = x.Result;
189+
SendReset();
190+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count)));
191+
}
182192
}, TaskScheduler.FromCurrentSynchronizationContext());
183193
}
184194
}
185195
catch (Exception ex)
186196
{
197+
RaiseInitializationError(ex);
187198
log.Error(ex, "Error loading virtualizing list count");
188199
}
189200
}
@@ -206,6 +217,25 @@ async void LoadPage(int number)
206217
catch (Exception ex)
207218
{
208219
log.Error(ex, "Error loading virtualizing list page {Number}", number);
220+
pages.Remove(number);
221+
}
222+
}
223+
224+
void RaiseInitializationError(Exception e)
225+
{
226+
if (InitializationError != null)
227+
{
228+
if (e is AggregateException ae)
229+
{
230+
e = ae = ae.Flatten();
231+
232+
if (ae.InnerExceptions.Count == 1)
233+
{
234+
e = ae.InnerException;
235+
}
236+
}
237+
238+
InitializationError(this, new ErrorEventArgs(e));
209239
}
210240
}
211241

src/GitHub.App/ViewModels/GitHubPane/IssueListViewModelBase.cs

Lines changed: 55 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.ComponentModel;
4+
using System.IO;
45
using System.Linq;
56
using System.Reactive;
67
using System.Reactive.Disposables;
@@ -9,10 +10,12 @@
910
using GitHub.Collections;
1011
using GitHub.Extensions;
1112
using GitHub.Extensions.Reactive;
13+
using GitHub.Logging;
1214
using GitHub.Models;
1315
using GitHub.Primitives;
1416
using GitHub.Services;
1517
using ReactiveUI;
18+
using Serilog;
1619

1720
namespace GitHub.ViewModels.GitHubPane
1821
{
@@ -21,6 +24,7 @@ namespace GitHub.ViewModels.GitHubPane
2124
/// </summary>
2225
public abstract class IssueListViewModelBase : PanePageViewModelBase, IIssueListViewModelBase
2326
{
27+
static readonly ILogger log = LogManager.ForContext<GitHubPaneViewModel>();
2428
readonly IRepositoryService repositoryService;
2529
IReadOnlyList<IIssueListItemViewModelBase> items;
2630
ICollectionView itemsView;
@@ -123,44 +127,53 @@ public string SelectedState
123127
/// <inheritdoc/>
124128
public async Task InitializeAsync(ILocalRepositoryModel repository, IConnection connection)
125129
{
126-
LocalRepository = repository;
127-
SelectedState = States.FirstOrDefault();
128-
AuthorFilter = new UserFilterViewModel(LoadAuthors);
129-
130-
var parent = await repositoryService.FindParent(
131-
HostAddress.Create(repository.CloneUrl),
132-
repository.Owner,
133-
repository.Name);
134-
135-
if (parent == null)
136-
{
137-
RemoteRepository = repository;
138-
}
139-
else
130+
try
140131
{
141-
// TODO: Handle forks with different names.
142-
RemoteRepository = new RepositoryModel(
143-
repository.Name,
144-
UriString.ToUriString(repository.CloneUrl.ToRepositoryUrl(parent.Value.owner)));
132+
LocalRepository = repository;
133+
SelectedState = States.FirstOrDefault();
134+
AuthorFilter = new UserFilterViewModel(LoadAuthors);
135+
IsLoading = true;
145136

146-
Forks = new IRepositoryModel[]
137+
var parent = await repositoryService.FindParent(
138+
HostAddress.Create(repository.CloneUrl),
139+
repository.Owner,
140+
repository.Name);
141+
142+
if (parent == null)
143+
{
144+
RemoteRepository = repository;
145+
}
146+
else
147147
{
148+
// TODO: Handle forks with different names.
149+
RemoteRepository = new RepositoryModel(
150+
repository.Name,
151+
UriString.ToUriString(repository.CloneUrl.ToRepositoryUrl(parent.Value.owner)));
152+
153+
Forks = new IRepositoryModel[]
154+
{
148155
RemoteRepository,
149156
repository,
150-
};
151-
}
157+
};
158+
}
152159

153-
this.WhenAnyValue(x => x.SelectedState, x => x.RemoteRepository)
154-
.Skip(1)
155-
.Subscribe(_ => Refresh().Forget());
160+
this.WhenAnyValue(x => x.SelectedState, x => x.RemoteRepository)
161+
.Skip(1)
162+
.Subscribe(_ => Refresh().Forget());
156163

157-
Observable.Merge(
158-
this.WhenAnyValue(x => x.SearchQuery).Skip(1).SelectUnit(),
159-
AuthorFilter.WhenAnyValue(x => x.Selected).Skip(1).SelectUnit())
160-
.Subscribe(_ => FilterChanged());
164+
Observable.Merge(
165+
this.WhenAnyValue(x => x.SearchQuery).Skip(1).SelectUnit(),
166+
AuthorFilter.WhenAnyValue(x => x.Selected).Skip(1).SelectUnit())
167+
.Subscribe(_ => FilterChanged());
161168

162-
IsLoading = true;
163-
await Refresh();
169+
await Refresh();
170+
}
171+
catch (Exception ex)
172+
{
173+
Error = ex;
174+
IsLoading = false;
175+
log.Error(ex, "Error initializing IssueListViewModelBase");
176+
}
164177
}
165178

166179
/// <summary>
@@ -169,6 +182,12 @@ public async Task InitializeAsync(ILocalRepositoryModel repository, IConnection
169182
/// <returns>A task tracking the operation.</returns>
170183
public override Task Refresh()
171184
{
185+
if (RemoteRepository == null)
186+
{
187+
// If an exception occurred reading the parent repository, do nothing.
188+
return Task.CompletedTask;
189+
}
190+
172191
subscription?.Dispose();
173192

174193
var dispose = new CompositeDisposable();
@@ -179,6 +198,7 @@ public override Task Refresh()
179198
view.Filter = FilterItem;
180199
Items = items;
181200
ItemsView = view;
201+
Error = null;
182202

183203
dispose.Add(itemSource);
184204
dispose.Add(
@@ -190,6 +210,11 @@ public override Task Refresh()
190210
this.WhenAnyValue(x => x.AuthorFilter.Selected),
191211
(loading, count, _, __, ___) => Tuple.Create(loading, count))
192212
.Subscribe(x => UpdateState(x.Item1, x.Item2)));
213+
dispose.Add(
214+
Observable.FromEventPattern<ErrorEventArgs>(
215+
x => items.InitializationError += x,
216+
x => items.InitializationError -= x)
217+
.Subscribe(x => Error = x.EventArgs.GetException()));
193218
subscription = dispose;
194219

195220
return Task.CompletedTask;

src/GitHub.App/ViewModels/GitHubPane/PullRequestListViewModel.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ protected override IIssueListItemViewModelBase CreateViewModel(PullRequestListIt
122122
return result;
123123
}
124124

125-
protected override Task<Page<PullRequestListItemModel>> LoadPage(string after)
125+
protected override async Task<Page<PullRequestListItemModel>> LoadPage(string after)
126126
{
127127
PullRequestStateEnum[] states;
128128

@@ -139,15 +139,12 @@ protected override Task<Page<PullRequestListItemModel>> LoadPage(string after)
139139
break;
140140
}
141141

142-
var sw = Stopwatch.StartNew();
143-
var result = owner.service.ReadPullRequests(
142+
var result = await owner.service.ReadPullRequests(
144143
HostAddress.Create(owner.RemoteRepository.CloneUrl),
145144
owner.RemoteRepository.Owner,
146145
owner.RemoteRepository.Name,
147146
after,
148-
states);
149-
sw.Stop();
150-
System.Diagnostics.Debug.WriteLine("Read PR page in " + sw.Elapsed);
147+
states).ConfigureAwait(false);
151148
return result;
152149
}
153150
}

src/GitHub.App/ViewModels/UserFilterViewModel.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,13 @@ async Task Load()
120120
while (true)
121121
{
122122
var page = await load(after);
123-
users.AddRange(page.Items.Select(x => new ActorViewModel(x)));
123+
124+
foreach (var item in page.Items)
125+
{
126+
var vm = new ActorViewModel(item);
127+
users.Add(vm);
128+
}
129+
124130
after = page.EndCursor;
125131
if (!page.HasNextPage) break;
126132
}

0 commit comments

Comments
 (0)