Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a1340a7
Add flag support for pending changes and scheduled publish
lauraneto Feb 23, 2026
a2b925b
Fix HasScheduleFlagProvider test mocks to match refactored per-item l…
lauraneto Feb 23, 2026
3a1c23e
Extract PublishableVariantItemResponseModelBase to deduplicate varian…
lauraneto Feb 23, 2026
e9cbc6e
Merge branch 'v18/dev' into v18/feature/element-flag-support
lauraneto Feb 24, 2026
2e91370
Merge branch 'v18/dev' into v18/feature/element-flag-support
lauraneto Feb 25, 2026
500cccb
Extract shared base class from Document/Element presentation factories
lauraneto Mar 2, 2026
c2030d7
Fix flags fallback to use empty array instead of empty string
lauraneto Mar 3, 2026
8c6cb5e
Merge branch 'v18/dev' into v18/feature/element-flag-support
lauraneto Mar 3, 2026
dc4ef1d
Merge branch 'v18/dev' into v18/feature/element-flag-support
lauraneto Mar 4, 2026
3563320
Merge branch 'v18/dev' into v18/feature/element-flag-support
lauraneto Mar 4, 2026
10e59d7
Acceptance Tests: Fix element tree item locator to match both element…
lauraneto Mar 4, 2026
c435927
Merge branch 'v18/dev' into v18/feature/element-flag-support
lauraneto Mar 6, 2026
76c6f52
Merge branch 'v18/dev' into v18/feature/element-flag-support
AndyButland Mar 6, 2026
5c12f78
Merge branch 'v18/dev' into v18/feature/element-flag-support
nielslyngsoe Mar 10, 2026
54fbbd8
Merge branch 'v18/dev' into v18/feature/element-flag-support
lauraneto Mar 26, 2026
d42f520
Split HasScheduleFlagProvider into document and element providers
lauraneto Mar 26, 2026
38a89cb
Make tree and recycle bin mapping methods async
lauraneto Mar 27, 2026
327b904
Extract Task.WhenAll select expressions into named variables
lauraneto Mar 27, 2026
f449d3a
Add missing XML docs to async methods on IDocumentPresentationFactory
lauraneto Mar 27, 2026
71ffacd
Fix DateTime vs DateTimeOffset comparison in schedule flag provider
lauraneto Mar 30, 2026
9dbafc3
Merge branch 'v18/dev' into v18/feature/element-flag-support
lauraneto Mar 30, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public DocumentItemResponseModel CreateItemResponseModel(IDocumentEntitySlim ent

responseModel.Variants = CreateVariantsItemResponseModels(entity);

PopulateFlagsOnDocuments(responseModel);
PopulateFlags(responseModel);

return responseModel;
}
Expand Down Expand Up @@ -143,7 +143,7 @@ public IEnumerable<DocumentVariantItemResponseModel> CreateVariantsItemResponseM
Culture = null,
};

PopulateFlagsOnVariants(model);
PopulateFlags(model);
yield return model;
yield break;
}
Expand All @@ -157,7 +157,7 @@ public IEnumerable<DocumentVariantItemResponseModel> CreateVariantsItemResponseM
State = DocumentVariantStateHelper.GetState(entity, cultureNamePair.Key)
};

PopulateFlagsOnVariants(model);
PopulateFlags(model);
yield return model;
}
}
Expand Down Expand Up @@ -212,19 +212,12 @@ public Attempt<List<CulturePublishScheduleModel>, ContentPublishingOperationStat
return Attempt.SucceedWithStatus(ContentPublishingOperationStatus.Success, model);
}

private void PopulateFlagsOnDocuments(DocumentItemResponseModel model)
private void PopulateFlags<TItem>(TItem model)
where TItem : IHasFlags
{
foreach (IFlagProvider signProvider in _flagProviderCollection.Where(x => x.CanProvideFlags<DocumentItemResponseModel>()))
foreach (IFlagProvider flagProvider in _flagProviderCollection.Where(x => x.CanProvideFlags<TItem>()))
{
signProvider.PopulateFlagsAsync([model]).GetAwaiter().GetResult();
}
}

private void PopulateFlagsOnVariants(DocumentVariantItemResponseModel model)
{
foreach (IFlagProvider signProvider in _flagProviderCollection.Where(x => x.CanProvideFlags<DocumentVariantItemResponseModel>()))
{
signProvider.PopulateFlagsAsync([model]).GetAwaiter().GetResult();
flagProvider.PopulateFlagsAsync([model]).GetAwaiter().GetResult();
Comment thread
lauraneto marked this conversation as resolved.
Outdated
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
using Umbraco.Cms.Api.Management.Mapping.Content;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Api.Management.Mapping.Content;
using Umbraco.Cms.Api.Management.Services.Flags;
using Umbraco.Cms.Api.Management.ViewModels;
using Umbraco.Cms.Api.Management.ViewModels.DocumentType;
using Umbraco.Cms.Api.Management.ViewModels.Element;
using Umbraco.Cms.Api.Management.ViewModels.Element.Item;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Entities;
Expand All @@ -17,11 +20,13 @@ public class ElementPresentationFactory : IElementPresentationFactory
{
private readonly IUmbracoMapper _umbracoMapper;
private readonly IIdKeyMap _idKeyMap;
private readonly FlagProviderCollection _flagProviderCollection;

public ElementPresentationFactory(IUmbracoMapper umbracoMapper, IIdKeyMap idKeyMap)
public ElementPresentationFactory(IUmbracoMapper umbracoMapper, IIdKeyMap idKeyMap, FlagProviderCollection flagProviderCollection)
{
_umbracoMapper = umbracoMapper;
_idKeyMap = idKeyMap;
_flagProviderCollection = flagProviderCollection;
}

public ElementResponseModel CreateResponseModel(IElement element, ContentScheduleCollection schedule)
Expand All @@ -47,6 +52,8 @@ public ElementItemResponseModel CreateItemResponseModel(IElementEntitySlim entit

responseModel.Variants = CreateVariantsItemResponseModels(entity);

PopulateFlags(responseModel);

return responseModel;
}

Expand All @@ -61,6 +68,7 @@ public IEnumerable<ElementVariantItemResponseModel> CreateVariantsItemResponseMo
Culture = null,
};

PopulateFlags(model);
yield return model;
yield break;
}
Expand All @@ -74,10 +82,20 @@ public IEnumerable<ElementVariantItemResponseModel> CreateVariantsItemResponseMo
State = DocumentVariantStateHelper.GetState(entity, cultureNamePair.Key)
};

PopulateFlags(model);
yield return model;
}
}

public DocumentTypeReferenceResponseModel CreateDocumentTypeReferenceResponseModel(IElementEntitySlim entity)
=> _umbracoMapper.Map<DocumentTypeReferenceResponseModel>(entity)!;

private void PopulateFlags<TItem>(TItem model)
where TItem : IHasFlags
{
foreach (IFlagProvider flagProvider in _flagProviderCollection.Where(x => x.CanProvideFlags<TItem>()))
{
flagProvider.PopulateFlagsAsync([model]).GetAwaiter().GetResult();
Comment thread
lauraneto marked this conversation as resolved.
Outdated
}
}
}
64 changes: 49 additions & 15 deletions src/Umbraco.Cms.Api.Management/OpenApi.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using Umbraco.Cms.Api.Management.ViewModels;
using Umbraco.Cms.Api.Management.ViewModels;
using Umbraco.Cms.Api.Management.ViewModels.Document;
using Umbraco.Cms.Api.Management.ViewModels.Element;
using Umbraco.Cms.Core;

namespace Umbraco.Cms.Api.Management.Services.Flags;

/// <summary>
/// Implements a <see cref="IFlagProvider"/> that provides flags for documents that have pending changes.
/// Implements a <see cref="IFlagProvider"/> that provides flags for documents and elements that have pending changes.
/// </summary>
public class HasPendingChangesFlagProvider : IFlagProvider
{
Expand All @@ -15,31 +16,31 @@ public class HasPendingChangesFlagProvider : IFlagProvider
public bool CanProvideFlags<TItem>()
where TItem : IHasFlags =>
typeof(TItem) == typeof(DocumentVariantItemResponseModel) ||
typeof(TItem) == typeof(DocumentVariantResponseModel);

typeof(TItem) == typeof(DocumentVariantResponseModel) ||
typeof(TItem) == typeof(ElementVariantItemResponseModel) ||
typeof(TItem) == typeof(ElementVariantResponseModel);

/// <inheritdoc/>
public Task PopulateFlagsAsync<TItem>(IEnumerable<TItem> items)
where TItem : IHasFlags
{
foreach (TItem item in items)
{
if (HasPendingChanges(item))
DocumentVariantState? state = item switch
{
DocumentVariantItemResponseModel variant => variant.State,
DocumentVariantResponseModel variant => variant.State,
ElementVariantItemResponseModel variant => variant.State,
ElementVariantResponseModel variant => variant.State,
_ => null,
};

if (state == DocumentVariantState.PublishedPendingChanges)
{
item.AddFlag(Alias);
}
}

return Task.CompletedTask;
}

/// <summary>
/// Determines if the given item has any variant that has pending changes.
/// </summary>
private static bool HasPendingChanges(object item) => item switch
{
DocumentVariantItemResponseModel variant => variant.State == DocumentVariantState.PublishedPendingChanges,
DocumentVariantResponseModel variant => variant.State == DocumentVariantState.PublishedPendingChanges,
_ => false,
};
}
Loading
Loading