-
Notifications
You must be signed in to change notification settings - Fork 23
Bugfix/v16/activecampaign/pagination filtering #284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a1a28d3
b8f07f0
3cb8c08
1798828
584d3c1
1b730ce
6187c87
710ea33
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,7 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Asp.Versioning; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Microsoft.AspNetCore.Http; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Microsoft.AspNetCore.Mvc; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Microsoft.AspNetCore.WebUtilities; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Microsoft.Extensions.Options; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Umbraco.Cms.Api.Common.Builders; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Umbraco.Cms.Integrations.Crm.ActiveCampaign.Configuration; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -21,15 +22,13 @@ public GetFormsByPageController(IOptions<ActiveCampaignSettings> options, IHttpC | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [ProducesResponseType(StatusCodes.Status404NotFound)] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [ProducesResponseType(StatusCodes.Status403Forbidden)] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [ProducesResponseType(StatusCodes.Status500InternalServerError)] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public async Task<IActionResult> GetForms([FromQuery] int? page = 1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public async Task<IActionResult> GetForms([FromQuery] int? page = 1, [FromQuery] string? searchQuery = "") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var client = HttpClientFactory.CreateClient(Constants.FormsHttpClient); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var requestUriString = page == 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? $"{client.BaseAddress}{ApiPath}&limit={Constants.DefaultPageSize}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : $"{client.BaseAddress}{ApiPath}&limit={Constants.DefaultPageSize}&offset={(page - 1) * Constants.DefaultPageSize}"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var requestUriString = BuildRequestUri(client.BaseAddress.ToString(), page ?? 1, searchQuery); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var requestMessage = new HttpRequestMessage | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -48,5 +47,22 @@ public async Task<IActionResult> GetForms([FromQuery] int? page = 1) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .Build()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private string BuildRequestUri(string baseAddress, int page, string searchQuery) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var uri = $"{baseAddress}{ApiPath}?limit={Constants.DefaultPageSize}"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (page > 1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uri = QueryHelpers.AddQueryString(uri, "offset", ((page - 1) * Constants.DefaultPageSize).ToString()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!string.IsNullOrWhiteSpace(searchQuery)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uri = QueryHelpers.AddQueryString(uri, "search", searchQuery); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+53
to
+64
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var uri = $"{baseAddress}{ApiPath}?limit={Constants.DefaultPageSize}"; | |
| if (page > 1) | |
| { | |
| uri = QueryHelpers.AddQueryString(uri, "offset", ((page - 1) * Constants.DefaultPageSize).ToString()); | |
| } | |
| if (!string.IsNullOrWhiteSpace(searchQuery)) | |
| { | |
| uri = QueryHelpers.AddQueryString(uri, "search", searchQuery); | |
| } | |
| var uri = $"{baseAddress}{ApiPath}"; | |
| var queryParams = new Dictionary<string, string> | |
| { | |
| { "limit", Constants.DefaultPageSize.ToString() } | |
| }; | |
| if (page > 1) | |
| { | |
| queryParams["offset"] = ((page - 1) * Constants.DefaultPageSize).ToString(); | |
| } | |
| if (!string.IsNullOrWhiteSpace(searchQuery)) | |
| { | |
| queryParams["search"] = searchQuery; | |
| } | |
| uri = QueryHelpers.AddQueryString(uri, queryParams); |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -29,6 +29,11 @@ export default class ActiveCampaignFormsModalElement | |||||||
| @state() | ||||||||
| _totalPages = 1; | ||||||||
|
|
||||||||
| @state() | ||||||||
| _searchQuery = ""; | ||||||||
|
|
||||||||
| #filterTimeout?: NodeJS.Timeout; | ||||||||
|
|
||||||||
| constructor() { | ||||||||
| super(); | ||||||||
|
|
||||||||
|
|
@@ -47,6 +52,13 @@ export default class ActiveCampaignFormsModalElement | |||||||
| this.#checkApiAccess(); | ||||||||
| } | ||||||||
|
|
||||||||
| disconnectedCallback() { | ||||||||
| super.disconnectedCallback(); | ||||||||
| if (this.#filterTimeout) { | ||||||||
| clearTimeout(this.#filterTimeout); | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| async #checkApiAccess() { | ||||||||
| if (!this.#activecampaignFormsContext || !this.#configurationModel) return; | ||||||||
|
|
||||||||
|
|
@@ -58,10 +70,10 @@ export default class ActiveCampaignFormsModalElement | |||||||
| await this.#loadForms(); | ||||||||
| } | ||||||||
|
|
||||||||
| async #loadForms(page?: number) { | ||||||||
| async #loadForms(page?: number, searchQuery?: string) { | ||||||||
| this._loading = true; | ||||||||
|
|
||||||||
| const { data } = await this.#activecampaignFormsContext.getForms(page); | ||||||||
| const { data } = await this.#activecampaignFormsContext.getForms(page, searchQuery); | ||||||||
| if (!data) { | ||||||||
| this._loading = false; | ||||||||
| return; | ||||||||
|
|
@@ -75,21 +87,26 @@ export default class ActiveCampaignFormsModalElement | |||||||
| this._loading = false; | ||||||||
| } | ||||||||
|
|
||||||||
| #handleFilterInput(event: UUIInputEvent) { | ||||||||
| async #handleFilterInput(event: UUIInputEvent) { | ||||||||
|
||||||||
| async #handleFilterInput(event: UUIInputEvent) { | |
| #handleFilterInput(event: UUIInputEvent) { |
Copilot
AI
Oct 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When filtering is applied, the page number should be reset to 1 to avoid displaying empty results if the current page exceeds the filtered result set. Consider resetting this._currentPageNumber to 1 before calling #loadForms.
| this._currentPageNumber = 1; |
Copilot
AI
Oct 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The timeout is not cleared when the component is destroyed, which could lead to attempted state updates after the element is removed from the DOM. Add cleanup in a disconnectedCallback or similar lifecycle method to clear this.#filterTimeout.
Copilot
AI
Oct 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The 500ms debounce timeout is hardcoded. Consider extracting this to a constant (e.g., SEARCH_DEBOUNCE_MS) to improve maintainability and make it easier to adjust the debounce delay if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The URI construction manually appends '?limit=' without checking if ApiPath already contains query parameters. If ApiPath includes a query string, this will produce malformed URIs. Use QueryHelpers.AddQueryString for the limit parameter as well to handle this correctly.