Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a1a28d3
Update pagination and filtering actions
acoumb Oct 22, 2025
b8f07f0
Update ActiveCampaign backoffice version
acoumb Oct 22, 2025
3cb8c08
Add debouncing feature
acoumb Oct 23, 2025
1798828
Modify timeout delay
acoumb Oct 23, 2025
584d3c1
Use QueryHelpers and clear timeout on disconnected callback.
acoumb Oct 23, 2025
1b730ce
Remove unused declarations
acoumb Oct 23, 2025
6187c87
Add timeout check on disconnected
acoumb Oct 23, 2025
710ea33
PR updates
acoumb Oct 23, 2025
c72deb1
Merge pull request #284 from umbraco/bugfix/v16/activecampaign/pagina…
acoumb Oct 23, 2025
ea00697
Update V16 with changes for load balancing environments and media con…
acoumb Nov 13, 2025
13fb582
Add missing handler
acoumb Nov 13, 2025
dd3dae0
Merge pull request #287 from umbraco/bugfix/v16/algolia-load-balancing
acoumb Nov 13, 2025
8732608
Update azure-pipeline - Crm.ActiveCampaign.yml for Azure Pipelines
acoumb Nov 14, 2025
8345a12
Update azure-pipeline - Crm.Dynamics.yml for Azure Pipelines
acoumb Nov 14, 2025
96d9cb5
Update azure-pipeline - Search.Algolia.yml for Azure Pipelines
acoumb Nov 14, 2025
cbdc86b
Update azure-pipelines - Automation.Zapier.yml for Azure Pipelines
acoumb Nov 14, 2025
40193a6
Update azure-pipelines - Commerce.Shopify.yml for Azure Pipelines
acoumb Nov 14, 2025
01e807c
Update azure-pipeline - Crm.Hubspot.yml for Azure Pipelines
acoumb Nov 14, 2025
c2eee47
Update azure-pipeline - SEO.SemrushTools.yml for Azure Pipelines
acoumb Nov 14, 2025
97f08d0
Merge branch 'v17/dev' into feature/v17/hubspot
acoumb Nov 18, 2025
a7c6cdb
Update HubSpot integration for V17
acoumb Nov 18, 2025
9cb603e
Update pipeline SDK
acoumb Nov 18, 2025
85f8d97
Update static assets path
acoumb Nov 18, 2025
e1efed2
Update PackageProjectUrl to point to v17
acoumb Nov 18, 2025
a0f963e
Update HubSpot to latest RC and fix breaking changes.
acoumb Nov 24, 2025
2b153d3
Upgrade to Umbraco 17.0.0
rickbutterfield Nov 25, 2025
bffeb06
Update build pipeline
rickbutterfield Nov 25, 2025
f48c168
Update build pipeline
rickbutterfield Nov 25, 2025
fbf4e2b
Update .gitignore and remove appsettings.Local.json
rickbutterfield Nov 25, 2025
33a937a
Update build pipelines
rickbutterfield Nov 25, 2025
33868dd
Merge branch 'v17/dev' into feature/v17/hubspot
acoumb Nov 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 37 additions & 10 deletions azure-pipeline - Crm.Hubspot.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
trigger:
branches:
include:
- main-v16
- v16/dev
- main-v17
- v17/dev
paths:
include:
- src/Umbraco.Cms.Integrations.Crm.Hubspot/**
Expand All @@ -16,24 +16,28 @@ variables:
project: 'src/$(projectName)/$(projectName).csproj'
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
productGroup: 'DXP'
productVersion: 'v17'
DT_API_KEY: $(dtApiKey)
DT_BASE_URL: $(dtBaseUrl)

steps:
- task: UseDotNet@2
displayName: 'Use SDK version 10.0.100'
inputs:
packageType: 'sdk'
version: '10.0.100'

- task: NuGetToolInstaller@1
displayName: 'Install NuGet'

- task: DotNetCoreCLI@2
displayName: 'NuGet Restore'
inputs:
command: 'restore'
feedsToUse: 'select'
feedsToUse: 'config'
projects: '$(project)'
includeNuGetOrg: true

- task: UseDotNet@2
displayName: 'Use SDK version 9.0.203'
inputs:
packageType: 'sdk'
version: '9.0.203'
nugetConfigPath: 'NuGet.config'

- task: VSBuild@1
displayName: 'Build Project'
Expand All @@ -57,3 +61,26 @@ steps:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'drop'
publishLocation: 'Container'

# Generate/upload SBOM with cdxgen
- script: |
cd $(Build.SourcesDirectory)
npm install --global @cyclonedx/cdxgen
displayName: 'Install cdxgen'

- script: |
mkdir -p $(Build.ArtifactStagingDirectory)/bom
cd $(Build.SourcesDirectory)

cdxgen --recurse --output $(Build.ArtifactStagingDirectory)\bom\bom.json --json-pretty --project-group "$(productGroup)" --project-name "$(projectName)" --project-version "$(productVersion)" --server-url "$(DT_BASE_URL)" --api-key "$(DT_API_KEY)" --deep
displayName: 'Generate & Upload SBOM with cdxgen'
env:
DT_API_KEY: $(DT_API_KEY)
DT_BASE_URL: $(DT_BASE_URL)

# Publish SBOM artifact
- task: PublishPipelineArtifact@1
displayName: 'Publish SBOM Artifact'
inputs:
targetPath: $(Build.ArtifactStagingDirectory)/bom
artifactName: SBOM
47 changes: 38 additions & 9 deletions azure-pipeline - Search.Algolia.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
trigger:
branches:
include:
- main-v16
- v16/dev
- main-v17
- v17/dev
paths:
include:
- src/Umbraco.Cms.Integrations.Search.Algolia/**
Expand All @@ -16,23 +16,29 @@ variables:
project: 'src/$(projectName)/$(projectName).csproj'
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
productGroup: 'DXP'
productVersion: 'v17'
DT_API_KEY: $(dtApiKey)
DT_BASE_URL: $(dtBaseUrl)

steps:
- task: UseDotNet@2
displayName: 'Use SDK version 10.0.100'
inputs:
packageType: 'sdk'
version: '10.0.100'

- task: NuGetToolInstaller@1
displayName: 'Install NuGet'

- task: DotNetCoreCLI@2
displayName: 'NuGet Restore'
inputs:
command: 'restore'
feedsToUse: 'select'
feedsToUse: 'config'
projects: '$(project)'
includeNuGetOrg: true
- task: UseDotNet@2
displayName: 'Use SDK version 9.0.203'
inputs:
packageType: 'sdk'
version: '9.0.203'
nugetConfigPath: 'NuGet.config'

- task: VSBuild@1
displayName: 'Build Project'
inputs:
Expand All @@ -55,3 +61,26 @@ steps:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'drop'
publishLocation: 'Container'

# Generate/upload SBOM with cdxgen
- script: |
cd $(Build.SourcesDirectory)
npm install --global @cyclonedx/cdxgen
displayName: 'Install cdxgen'

- script: |
mkdir -p $(Build.ArtifactStagingDirectory)/bom
cd $(Build.SourcesDirectory)

cdxgen --recurse --output $(Build.ArtifactStagingDirectory)\bom\bom.json --json-pretty --project-group "$(productGroup)" --project-name "$(projectName)" --project-version "$(productVersion)" --server-url "$(DT_BASE_URL)" --api-key "$(DT_API_KEY)" --deep
displayName: 'Generate & Upload SBOM with cdxgen'
env:
DT_API_KEY: $(DT_API_KEY)
DT_BASE_URL: $(DT_BASE_URL)

# Publish SBOM artifact
- task: PublishPipelineArtifact@1
displayName: 'Publish SBOM Artifact'
inputs:
targetPath: $(Build.ArtifactStagingDirectory)/bom
artifactName: SBOM
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

<ItemGroup>
<PackageReference Include="Umbraco.Cms" Version="17.0.0" />
<ProjectReference Include="..\..\src\Umbraco.Cms.Integrations.Crm.Hubspot\Umbraco.Cms.Integrations.Crm.Hubspot.csproj" />
<ProjectReference Include="..\..\src\Umbraco.Cms.Integrations.SEO.Semrush\Umbraco.Cms.Integrations.SEO.Semrush.csproj" />
<ProjectReference Include="..\..\src\Umbraco.Cms.Integrations.Automation.Zapier\Umbraco.Cms.Integrations.Automation.Zapier.csproj" />
<ProjectReference Include="..\..\src\Umbraco.Cms.Integrations.Crm.Dynamics\Umbraco.Cms.Integrations.Crm.Dynamics.csproj" />
Expand Down
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;
Expand All @@ -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
{
Expand All @@ -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);
}

return uri;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export type GetFormsData = {
path?: never;
query?: {
page?: number;
searchQuery?: string;
};
url: '/umbraco/activecampaign-forms/management/api/v1/forms';
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ export class ActiveCampaignFormsContext extends UmbControllerBase {
this.#configurationModel.setValue(data);
}

async getForms(page?: number) {
return await this.#repository.getForms(page);
async getForms(page?: number, searchQuery?: string) {
return await this.#repository.getForms(page, searchQuery);
}

async getForm(id: string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ export default class ActiveCampaignFormsModalElement
@state()
_totalPages = 1;

@state()
_searchQuery = "";

#filterTimeout?: NodeJS.Timeout;

constructor() {
super();

Expand All @@ -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;

Expand All @@ -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;
Expand All @@ -75,21 +87,26 @@ export default class ActiveCampaignFormsModalElement
this._loading = false;
}

#handleFilterInput(event: UUIInputEvent) {
async #handleFilterInput(event: UUIInputEvent) {
let query = (event.target.value as string) || '';
query = query.toLowerCase();
this._searchQuery = query;

const result = !query
? this._forms
: this._forms.filter((form) => form.name.toLowerCase().includes(query));
// Clear existing timeout
if (this.#filterTimeout) {
clearTimeout(this.#filterTimeout);
}

this._filteredForms = result;
this.#filterTimeout = setTimeout(async () => {
this._currentPageNumber = 1;
await this.#loadForms(this._currentPageNumber, this._searchQuery);
}, 500);
}

async #onPageChange(event: UUIPaginationEvent) {
this._currentPageNumber = event.target?.current;

await this.#loadForms(this._currentPageNumber);
await this.#loadForms(this._currentPageNumber, this._searchQuery);
}

#renderPagination() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ export default class ActiveCampaignFormPickerElement extends UmbElementMixin(Lit

@property({ type: String })
public value = "";


@state()
private _form: FormDtoModel = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ export class ActiveCampaignFormsRepository extends UmbControllerBase {
return { data };
}

async getForms(page?: number) {
const { data, error } = await tryExecute(this, ActiveCampaignForms.getForms({ query: { page } }));
async getForms(page?: number, searchQuery?: string) {
const { data, error } = await tryExecute(this, ActiveCampaignFormsService.getForms({ query: { page, searchQuery } }));

if (error || !data) {
return { error };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ public class GetAccessTokenController : HubspotFormsControllerBase

public GetAccessTokenController(
IOptions<HubspotSettings> settingsOptions,
AuthorizationImplementationFactory authorizationImplementationFactory)
IHubspotAuthorizationServiceFactory authorizationServiceFactory)
: base(settingsOptions)
=> _authorizationService = authorizationImplementationFactory(Settings.UseUmbracoAuthorization);
=> _authorizationService = authorizationServiceFactory.GetAuthorizationService(Settings.UseUmbracoAuthorization);

[HttpPost("access-token", Name = Constants.OperationIdentifiers.GetAccessToken)]
[ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ public class GetAuthorizationUrlController : HubspotFormsControllerBase

public GetAuthorizationUrlController(
IOptions<HubspotSettings> settingsOptions,
AuthorizationImplementationFactory authorizationImplementationFactory)
: base(settingsOptions) => _authorizationService = authorizationImplementationFactory(Settings.UseUmbracoAuthorization);
IHubspotAuthorizationServiceFactory authorizationServiceFactory)
: base(settingsOptions) => _authorizationService = authorizationServiceFactory.GetAuthorizationService(Settings.UseUmbracoAuthorization);

[HttpGet("authorization-url", Name = Constants.OperationIdentifiers.GetAuthorizationUrl)]
[ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using Microsoft.Extensions.Options;
using Umbraco.Cms.Integrations.Crm.Hubspot.Configuration;
using Umbraco.Cms.Integrations.Crm.Hubspot.Services;
using static Umbraco.Cms.Integrations.Crm.Hubspot.HubspotComposer;

namespace Umbraco.Cms.Integrations.Crm.Hubspot.Api.Management.Controllers
{
Expand All @@ -15,8 +14,8 @@ public class RefreshAccessTokenController : HubspotFormsControllerBase

public RefreshAccessTokenController(
IOptions<HubspotSettings> settingsOptions,
AuthorizationImplementationFactory authorizationImplementationFactory)
: base(settingsOptions) => _authorizationService = authorizationImplementationFactory(Settings.UseUmbracoAuthorization);
IHubspotAuthorizationServiceFactory authorizationServiceFactory)
: base(settingsOptions) => _authorizationService = authorizationServiceFactory.GetAuthorizationService(Settings.UseUmbracoAuthorization);

[HttpPost("refresh", Name = Constants.OperationIdentifiers.RefreshAccessToken)]
[ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ public ValidateAccessTokenController(
IOptions<HubspotSettings> settingsOptions,
IHttpClientFactory httpClientFactory,
ITokenService tokenService,
IHubspotAuthorizationService authorizationService)
IHubspotAuthorizationServiceFactory authorizationServiceFactory)
: base(settingsOptions)
{
_httpClientFactory = httpClientFactory;
_tokenService = tokenService;
_authorizationService = authorizationService;
_authorizationService = authorizationServiceFactory.GetAuthorizationService(settingsOptions.Value.UseUmbracoAuthorization);
}

[HttpGet("validate", Name = Constants.OperationIdentifiers.ValidateAccessToken)]
Expand Down
1 change: 1 addition & 0 deletions src/Umbraco.Cms.Integrations.Crm.Hubspot/Client/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@umbraco-cms:registry=https://www.myget.org/F/umbracoprereleases/npm/
Loading
Loading