1- using Elsa . Studio . Components ;
1+ using Elsa . Studio . Components ;
22using Microsoft . AspNetCore . Components ;
33using Microsoft . AspNetCore . WebUtilities ;
44using Microsoft . Extensions . Logging ;
55using MudBlazor ;
6- namespace Elsa . Studio . Workflows . Components ;
7-
8- /// <summary>
9- /// Base component that provides common URL query parsing and update logic for
10- /// table components that want to reflect state in the query string.
11- /// Derived components must implement ApplyQueryParameters and BuildQueryFromState.
12- /// </summary>
13- public abstract class QueryTableComponentBase : StudioComponentBase
6+ namespace Elsa . Studio . Workflows . Components
147{
15- protected bool _initializedFromQuery ;
16-
17- [ Inject ] protected NavigationManager NavigationManager { get ; set ; } = default ! ;
18- [ Inject ] protected ILogger < QueryTableComponentBase > ? Logger { get ; set ; }
19-
208 /// <summary>
21- /// Specifies the initial page index used when starting pagination operations.
9+ /// Base component that provides common URL query parsing and update logic for
10+ /// table components that want to reflect state in the query string.
11+ /// Derived components must implement ApplyQueryParameters and BuildQueryFromState.
2212 /// </summary>
2313 public abstract class QueryTableComponentBase : StudioComponentBase
2414 {
@@ -37,8 +27,6 @@ public abstract class QueryTableComponentBase : StudioComponentBase
3727 /// </summary>
3828 protected int InitialPage { get ; set ; } = 0 ;
3929
40- {
41- if ( firstRender )
4230 /// <summary>
4331 /// Specifies the initial number of items to display per page.
4432 /// </summary>
@@ -54,18 +42,15 @@ public abstract class QueryTableComponentBase : StudioComponentBase
5442 /// <inheritdoc/>
5543 protected override async Task OnAfterRenderAsync ( bool firstRender )
5644 {
57- await ParseQueryParameters ( ) ;
58- StateHasChanged ( ) ;
59- }
45+ if ( firstRender )
46+ {
47+ await ParseQueryParameters ( ) ;
48+ StateHasChanged ( ) ;
49+ }
6050
51+ await base . OnAfterRenderAsync ( firstRender ) ;
52+ }
6153
62- /// <summary>
63- /// Parses the current URI's query string and delegates to <see cref="ApplyQueryParameters"/>.
64- /// Only runs once unless you reset <see cref="InitializedFromQuery"/> or call ParseQueryParameters(force: true).
65- /// </summary>
66- private async Task ParseQueryParameters ( bool force = false )
67- {
68- if ( InitializedFromQuery && ! force ) return ;
6954 /// <summary>
7055 /// Parses the current URI's query string and delegates to <see cref="ApplyQueryParameters"/>.
7156 /// Only runs once unless you reset <see cref="InitializedFromQuery"/> or call ParseQueryParameters(force: true).
@@ -74,44 +59,36 @@ private async Task ParseQueryParameters(bool force = false)
7459 {
7560 if ( InitializedFromQuery && ! force ) return ;
7661
77- /// <summary>
78- /// Parses the current URI's query string and delegates to <see cref="ApplyQueryParameters"/>.
79- /// Only runs once unless you clear _initializedFromQuery or call ParseQueryParameters(force: true).
80- /// </summary>
81- protected async Task ParseQueryParameters ( bool force = false )
82- {
83- if ( _initializedFromQuery && ! force ) return ;
62+ try
63+ {
64+ var uri = NavigationManager . ToAbsoluteUri ( NavigationManager . Uri ) ;
65+ var query = QueryHelpers . ParseQuery ( uri . Query ) ;
8466
85- try
86- {
87- var uri = NavigationManager . ToAbsoluteUri ( NavigationManager . Uri ) ;
88- var query = QueryHelpers . ParseQuery ( uri . Query ) ;
67+ // Convert StringValues to single string values
68+ var dict = query . ToDictionary ( k => k . Key , kv => kv . Value . ToString ( ) , StringComparer . OrdinalIgnoreCase ) ;
8969
90- // Convert StringValues to single string values
91- var dict = query . ToDictionary ( k => k . Key , kv => kv . Value . ToString ( ) , StringComparer . OrdinalIgnoreCase ) ;
70+ try
71+ {
72+ await ApplyQueryParameters ( dict ) ;
73+ }
74+ catch ( Exception ex )
75+ {
76+ Logger ? . LogDebug ( ex , "Error while applying query parameters in derived component." ) ;
77+ }
9278
9379 InitializedFromQuery = true ;
9480 }
9581 catch ( Exception ex )
9682 {
97- Logger ? . LogDebug ( ex , "Error while applying query parameters in derived component ." ) ;
83+ Logger ? . LogWarning ( ex , "Failed parsing query parameters." ) ;
9884 }
99-
100- _initializedFromQuery = true ;
101- }
102- catch ( Exception ex )
103- {
104- Logger ? . LogWarning ( ex , "Failed parsing query parameters." ) ;
10585 }
106- }
10786
108- /// <summary>
109- /// Build and navigate to an updated URI that reflects the provided table state.
110- /// Delegates construction of the query dictionary to <see cref="BuildQueryFromState"/>.
111- /// </summary>
112- protected void TryUpdateUrlFromState ( TableState state )
113- {
114- try
87+ /// <summary>
88+ /// Build and navigate to an updated URI that reflects the provided table state.
89+ /// Delegates construction of the query dictionary to <see cref="BuildQueryFromState"/>.
90+ /// </summary>
91+ protected void TryUpdateUrlFromState ( TableState state )
11592 {
11693 try
11794 {
@@ -124,37 +101,38 @@ protected void TryUpdateUrlFromState(TableState state)
124101 var dict = query . Where ( kv => ! string . IsNullOrEmpty ( kv . Value ) ) . ToDictionary ( kv => kv . Key , kv => kv . Value , StringComparer . OrdinalIgnoreCase ) ;
125102 var newUri = QueryHelpers . AddQueryString ( baseUri , dict ) ;
126103
127- if ( ! string . Equals ( NavigationManager . Uri , newUri , StringComparison . Ordinal ) )
128- NavigationManager . NavigateTo ( newUri , replace : true ) ;
129- }
130- catch ( Exception ex )
131- {
132- Logger ? . LogWarning ( ex , "Failed to update URL with table state." ) ;
104+ if ( ! string . Equals ( NavigationManager . Uri , newUri , StringComparison . Ordinal ) )
105+ NavigationManager . NavigateTo ( newUri , replace : true ) ;
106+ }
107+ catch ( Exception ex )
108+ {
109+ Logger ? . LogWarning ( ex , "Failed to update URL with table state." ) ;
110+ }
133111 }
134- }
135112
136- /// <summary>
137- /// Derived components must map parsed key/value pairs (from the query string)
138- /// to their local component state in this method.
139- /// </summary>
140- /// <param name="query">Key -> string value dictionary (single values only).</param>
141- //protected abstract void ApplyQueryParameters(IDictionary<string, string> query);
142- protected abstract Task ApplyQueryParameters ( IDictionary < string , string > query ) ;
113+ /// <summary>
114+ /// Derived components must map parsed key/value pairs (from the query string)
115+ /// to their local component state in this method.
116+ /// </summary>
117+ /// <param name="query">Key -> string value dictionary (single values only).</param>
118+ //protected abstract void ApplyQueryParameters(IDictionary<string, string> query);
119+ protected abstract Task ApplyQueryParameters ( IDictionary < string , string > query ) ;
143120
144- /// <summary>
145- /// Derived components must return the query dictionary to represent the current state
146- /// (keys -> values). Values that are null or empty will be excluded before navigation.
147- /// </summary>
148- protected abstract Dictionary < string , string ? > BuildQueryFromState ( TableState state ) ;
121+ /// <summary>
122+ /// Derived components must return the query dictionary to represent the current state
123+ /// (keys -> values). Values that are null or empty will be excluded before navigation.
124+ /// </summary>
125+ protected abstract Dictionary < string , string ? > BuildQueryFromState ( TableState state ) ;
149126
150- /// <summary>
151- /// Convenience helper used by components that need the timestamp filter encoding.
152- /// </summary>
153- protected static string EncodeTimestampFiltersToBase64Json < T > ( IEnumerable < T > filters )
154- {
155- var opts = new System . Text . Json . JsonSerializerOptions ( System . Text . Json . JsonSerializerDefaults . Web ) { WriteIndented = false } ;
156- var json = System . Text . Json . JsonSerializer . Serialize ( filters , opts ) ;
157- var bytes = System . Text . Encoding . UTF8 . GetBytes ( json ) ;
158- return Convert . ToBase64String ( bytes ) ;
127+ /// <summary>
128+ /// Convenience helper used by components that need the timestamp filter encoding.
129+ /// </summary>
130+ protected static string EncodeTimestampFiltersToBase64Json < T > ( IEnumerable < T > filters )
131+ {
132+ var opts = new System . Text . Json . JsonSerializerOptions ( System . Text . Json . JsonSerializerDefaults . Web ) { WriteIndented = false } ;
133+ var json = System . Text . Json . JsonSerializer . Serialize ( filters , opts ) ;
134+ var bytes = System . Text . Encoding . UTF8 . GetBytes ( json ) ;
135+ return Convert . ToBase64String ( bytes ) ;
136+ }
159137 }
160138}
0 commit comments