Skip to content

Commit fef2195

Browse files
Don't refresh all the page
1 parent 6dbdba0 commit fef2195

18 files changed

Lines changed: 130 additions & 44 deletions

src/IdServer/SimpleIdServer.IdServer.Website/Infrastructures/RealmRouter.cs

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,49 +7,119 @@
77
using Microsoft.Extensions.Options;
88
using SimpleIdServer.IdServer.Domains;
99
using System.Reflection;
10+
using System.Runtime.ExceptionServices;
1011
using System.Text.RegularExpressions;
1112

1213
namespace SimpleIdServer.IdServer.Website.Infrastructures;
1314

1415
public class RealmRouter : IComponent, IHandleAfterRender, IDisposable
1516
{
17+
string _baseUri;
18+
string _locationAbsolute;
19+
bool _navigationInterceptionEnabled;
1620
private RenderHandle _renderHandle;
1721
private Dictionary<Type, Dictionary<string, string>> _routeableComponents;
1822
internal static IServiceProvider _serviceProvider;
23+
private CancellationTokenSource _onNavigateCts;
24+
private Task _previousOnNavigateTask = Task.CompletedTask;
25+
private IRoutingStateProvider? RoutingStateProvider { get; set; }
26+
1927
[Inject] private NavigationManager NavigationManager { get; set; }
28+
[Inject] IServiceProvider ServiceProvider { get; set; }
29+
[Inject] private IScrollToLocationHash ScrollToLocationHash { get; set; }
30+
[Inject] private INavigationInterception NavigationInterception { get; set; }
2031
[Parameter] public Assembly AppAssembly { get; set; }
2132
[Parameter] public RenderFragment<RouteData> Found { get; set; }
2233
[Parameter] public RenderFragment NotFound { get; set; }
34+
[Parameter] public RenderFragment? Navigating { get; set; }
35+
[Parameter] public EventCallback<CustomNavigationContext> OnNavigateAsync { get; set; }
36+
private bool _onNavigateCalled;
2337

2438
public void Attach(RenderHandle renderHandle)
2539
{
2640
_renderHandle = renderHandle;
27-
NavigationManager.LocationChanged += OnLocationChanged;
2841
_routeableComponents = GetRouteableComponents();
42+
_baseUri = NavigationManager.BaseUri;
43+
_locationAbsolute = NavigationManager.Uri;
44+
NavigationManager.LocationChanged += OnLocationChanged;
45+
RoutingStateProvider = ServiceProvider.GetService<IRoutingStateProvider>();
2946
}
3047

3148
public async Task SetParametersAsync(ParameterView parameters)
3249
{
3350
parameters.SetParameterProperties(this);
3451
var locationPath = NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
35-
await Navigate(locationPath);
52+
if (!_onNavigateCalled)
53+
{
54+
_onNavigateCalled = true;
55+
await RunOnNavigateAsync(locationPath, false);
56+
}
57+
else
58+
{
59+
await Refresh(locationPath, false);
60+
}
3661
}
3762

3863
public void Dispose()
3964
{
4065
NavigationManager.LocationChanged -= OnLocationChanged;
4166
}
4267

43-
public Task OnAfterRenderAsync()
68+
public async Task OnAfterRenderAsync()
69+
{
70+
if (!_navigationInterceptionEnabled)
71+
{
72+
_navigationInterceptionEnabled = true;
73+
await NavigationInterception.EnableNavigationInterceptionAsync();
74+
}
75+
}
76+
77+
private async Task RunOnNavigateAsync(string locationPath, bool isNavigationIntercepted)
4478
{
45-
return Task.CompletedTask;
79+
_onNavigateCts?.Cancel();
80+
await _previousOnNavigateTask;
81+
var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
82+
_previousOnNavigateTask = tcs.Task;
83+
if (!OnNavigateAsync.HasDelegate)
84+
{
85+
await Refresh(locationPath, isNavigationIntercepted);
86+
}
87+
88+
_onNavigateCts = new CancellationTokenSource();
89+
var navigateContext = new CustomNavigationContext(locationPath, _onNavigateCts.Token);
90+
var cancellationTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
91+
navigateContext.CancellationToken.Register(state =>
92+
((TaskCompletionSource)state).SetResult(), cancellationTcs);
93+
94+
try
95+
{
96+
var task = await Task.WhenAny(OnNavigateAsync.InvokeAsync(navigateContext), cancellationTcs.Task);
97+
await task;
98+
tcs.SetResult();
99+
await Refresh(locationPath, isNavigationIntercepted);
100+
}
101+
catch (Exception e)
102+
{
103+
_renderHandle.Render(builder => ExceptionDispatchInfo.Throw(e));
104+
}
46105
}
47106

48-
private async Task Navigate(string locationPath)
107+
private async Task Refresh(string locationPath, bool isNavigationIntercepted)
49108
{
109+
if (_previousOnNavigateTask.Status != TaskStatus.RanToCompletion)
110+
{
111+
if (Navigating != null)
112+
{
113+
_renderHandle.Render(Navigating);
114+
}
115+
return;
116+
}
117+
118+
50119
var options = _serviceProvider.GetRequiredService<IOptions<IdServerWebsiteOptions>>();
51120
var routeParameters = new Dictionary<string, object>();
52121
Type handlerContext = null;
122+
var relativePath = NavigationManager.ToBaseRelativePath(_locationAbsolute);
53123
if (!options.Value.IsReamEnabled)
54124
{
55125
if (!locationPath.StartsWith("/"))
@@ -61,7 +131,7 @@ private async Task Navigate(string locationPath)
61131
}
62132

63133
var routeData = new RouteData(handlerContext, routeParameters);
64-
_renderHandle.Render(Found(routeData));
134+
_renderHandle.Render(Found(routeData));
65135
return;
66136
}
67137
else
@@ -85,7 +155,7 @@ private async void OnLocationChanged(object sender, LocationChangedEventArgs arg
85155
if(_renderHandle.IsInitialized && _routeableComponents != null)
86156
{
87157
var locationPath = NavigationManager.ToBaseRelativePath(args.Location);
88-
_ = Navigate(locationPath);
158+
_ = RunOnNavigateAsync((locationPath), args.IsNavigationIntercepted);
89159
}
90160
}
91161

@@ -144,3 +214,23 @@ private Dictionary<Type, Dictionary<string, string>> GetRouteableComponents()
144214
return dic;
145215
}
146216
}
217+
218+
public class CustomNavigationContext
219+
{
220+
public CustomNavigationContext(string path, CancellationToken cancellationToken)
221+
{
222+
Path = path;
223+
CancellationToken = cancellationToken;
224+
}
225+
226+
/// <summary>
227+
/// The target path for the navigation.
228+
/// </summary>
229+
public string Path { get; }
230+
231+
/// <summary>
232+
/// The <see cref="CancellationToken"/> to use to cancel navigation.
233+
/// </summary>
234+
public CancellationToken CancellationToken { get; }
235+
236+
}

src/IdServer/SimpleIdServer.IdServer.Website/Pages/Acrs.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@
127127
StateHasChanged();
128128
});
129129
if (!acrsState.Value.IsLoading && acrsGrid != null)
130-
acrsGrid.Reload();
130+
acrsGrid?.Reload();
131131
}
132132
}
133133

src/IdServer/SimpleIdServer.IdServer.Website/Pages/Auditing.razor

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
if(firstRender)
6666
{
6767
if (!searchAuditingRecordsState.Value.IsLoading)
68-
auditEvtsGrid.Reload();
68+
auditEvtsGrid?.Reload();
6969
}
7070
}
7171

@@ -92,6 +92,6 @@
9292
void DisplayErrors(bool a)
9393
{
9494
displayErrors = a;
95-
auditEvtsGrid.Reload();
95+
auditEvtsGrid?.Reload();
9696
}
9797
}

src/IdServer/SimpleIdServer.IdServer.Website/Pages/CertificateAuthorities.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@
108108
await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
109109
});
110110
if (!searchCertificateAuthoritiesState.Value.IsLoading)
111-
caGrid.Reload();
111+
caGrid?.Reload();
112112
}
113113
}
114114

src/IdServer/SimpleIdServer.IdServer.Website/Pages/Clients.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@
9898
StateHasChanged();
9999
});
100100
if (!clientState.Value.IsLoading)
101-
clientsGrid.Reload();
101+
clientsGrid?.Reload();
102102
}
103103
}
104104

src/IdServer/SimpleIdServer.IdServer.Website/Pages/Groups.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@
9898
dialogService.Close();
9999
});
100100
if (!searchGroupsState.Value.IsLoading)
101-
groupsGrid.Reload();
101+
groupsGrid?.Reload();
102102
}
103103
}
104104

src/IdServer/SimpleIdServer.IdServer.Website/Pages/IdProviders.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
StateHasChanged();
7777
});
7878
if (!searchIdProvidersState.Value.IsLoading)
79-
idProvidersGrid.Reload();
79+
idProvidersGrid?.Reload();
8080
}
8181
}
8282

src/IdServer/SimpleIdServer.IdServer.Website/Pages/IdentityProvisioningLst.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
if(firstRender)
6868
{
6969
if (!searchIdentityProvisioningState.Value.IsLoading)
70-
identityProvisioningGrid.Reload();
70+
identityProvisioningGrid?.Reload();
7171
}
7272
}
7373

src/IdServer/SimpleIdServer.IdServer.Website/Pages/RealmRoles.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
if(firstRender)
5353
{
5454
if (realmScopesState.Value.IsLoading && scopesGrid != null)
55-
scopesGrid.Reload();
55+
scopesGrid?.Reload();
5656
}
5757
}
5858

src/IdServer/SimpleIdServer.IdServer.Website/Pages/RegistrationWorkflows.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@
114114
StateHasChanged();
115115
});
116116
if (!registrationWorkflowsState.Value.IsLoading && registrationWorkflowsGrid != null)
117-
registrationWorkflowsGrid.Reload();
117+
registrationWorkflowsGrid?.Reload();
118118
}
119119
}
120120

0 commit comments

Comments
 (0)