Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
29edc58
Adding description to user groups
LanThuyNguyen Dec 4, 2025
edc9287
Add description to dto and test and umbraco plan
LanThuyNguyen Dec 4, 2025
971e747
update unit test for user group
LanThuyNguyen Dec 5, 2025
d0e1647
remove change from link picker
LanThuyNguyen Dec 5, 2025
9368725
edit icon ui for user group
LanThuyNguyen Dec 5, 2025
abc4aa9
Fixed table exists check in migration.
AndyButland Dec 5, 2025
7a8bb7d
Merge branch 'main' into v17/add-description-to-user-group
andr317c Dec 5, 2025
f7e59f9
Merge branch 'main' of https://github.com/umbraco/Umbraco-CMS into v1…
LanThuyNguyen Dec 8, 2025
81c3091
update description in table user groups
LanThuyNguyen Dec 9, 2025
dabd7e7
Merge branch 'main' of https://github.com/umbraco/Umbraco-CMS into v1…
LanThuyNguyen Dec 9, 2025
7759309
update user group editor css
LanThuyNguyen Dec 9, 2025
3867349
Merge branch 'main' of https://github.com/umbraco/Umbraco-CMS into v1…
LanThuyNguyen Dec 16, 2025
0b982fa
update description default
LanThuyNguyen Dec 16, 2025
d655015
remove description column element
LanThuyNguyen Dec 17, 2025
76667f5
fix conflict
LanThuyNguyen Dec 17, 2025
7367e96
add ignore large method
LanThuyNguyen Dec 17, 2025
f561b66
remove codesence
LanThuyNguyen Dec 17, 2025
da2c09f
update user group descriptions default
LanThuyNguyen Dec 17, 2025
c707c8c
Merge branch 'main' into v17/add-description-to-user-group
AndyButland Jan 7, 2026
cc39b1d
Added description to constructor of ReadOnlyUserGroup.
AndyButland Jan 7, 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 @@ -54,6 +54,7 @@ public async Task<UserGroupResponseModel> CreateAsync(IUserGroup userGroup)
{
Id = userGroup.Key,
Name = userGroup.Name ?? string.Empty,
Description = userGroup.Description ?? string.Empty,
Alias = userGroup.Alias,
DocumentStartNode = ReferenceByIdModel.ReferenceOrNull(contentStartNodeKey),
DocumentRootAccess = contentRootAccess,
Expand Down Expand Up @@ -87,6 +88,7 @@ public async Task<UserGroupResponseModel> CreateAsync(IReadOnlyUserGroup userGro
{
Id = userGroup.Key,
Name = userGroup.Name ?? string.Empty,
Description = userGroup.Description ?? string.Empty,
Alias = userGroup.Alias,
DocumentStartNode = ReferenceByIdModel.ReferenceOrNull(contentStartNodeKey),
MediaStartNode = ReferenceByIdModel.ReferenceOrNull(mediaStartNodeKey),
Expand Down Expand Up @@ -132,6 +134,7 @@ public async Task<Attempt<IUserGroup, UserGroupOperationStatus>> CreateAsync(Cre
{
Name = CleanUserGroupNameOrAliasForXss(requestModel.Name),
Alias = CleanUserGroupNameOrAliasForXss(requestModel.Alias),
Description = requestModel.Description,
Icon = requestModel.Icon,
HasAccessToAllLanguages = requestModel.HasAccessToAllLanguages,
Permissions = requestModel.FallbackPermissions,
Expand Down Expand Up @@ -197,9 +200,10 @@ public async Task<Attempt<IUserGroup, UserGroupOperationStatus>> UpdateAsync(IUs

current.Name = CleanUserGroupNameOrAliasForXss(request.Name);
current.Alias = CleanUserGroupNameOrAliasForXss(request.Alias);
current.Description = request.Description;
current.Icon = request.Icon;
current.HasAccessToAllLanguages = request.HasAccessToAllLanguages;

current.Permissions = request.FallbackPermissions;
current.GranularPermissions = await _permissionPresentationFactory.CreatePermissionSetsAsync(request.Permissions);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Umbraco.Cms.Api.Management.ViewModels.UserGroup.Permissions;
using Umbraco.Cms.Api.Management.ViewModels.UserGroup.Permissions;

namespace Umbraco.Cms.Api.Management.ViewModels.UserGroup;

Expand All @@ -22,6 +22,11 @@ public class UserGroupBase
/// </summary>
public required string Alias { get; init; }

/// <summary>
/// The description of the user group
/// </summary>
public string? Description { get; set; }

/// <summary>
/// The Icon for the user group
/// </summary>
Expand Down
9 changes: 4 additions & 5 deletions src/Umbraco.Core/Models/Membership/IReadOnlyUserGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ public interface IReadOnlyUserGroup
{
string? Name { get; }

string Alias { get; }

string? Description { get { return null; } }

string? Icon { get; }

int Id { get; }
Expand All @@ -19,11 +23,6 @@ public interface IReadOnlyUserGroup

int? StartMediaId { get; }

/// <summary>
/// The alias
/// </summary>
string Alias { get; }

// This is set to return true as default to avoid breaking changes.
bool HasAccessToAllLanguages => true;

Expand Down
8 changes: 8 additions & 0 deletions src/Umbraco.Core/Models/Membership/IUserGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ public interface IUserGroup : IEntity, IRememberBeingDirty
/// </summary>
string? Name { get; set; }

/// <summary>
/// The description
/// </summary>
string? Description {
get => null;
set { }
}

/// <summary>
/// If this property is true it will give the group access to all languages
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions src/Umbraco.Core/Models/Membership/ReadOnlyUserGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ public bool Equals(ReadOnlyUserGroup? other)

public string Name { get; }

public string? Description { get; }

public string? Icon { get; }

public int? StartContentId { get; }
Expand Down
8 changes: 8 additions & 0 deletions src/Umbraco.Core/Models/Membership/UserGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class UserGroup : EntityBase, IUserGroup, IReadOnlyUserGroup
private string _alias;
private string? _icon;
private string _name;
private string? _description;
private bool _hasAccessToAllLanguages;
private ISet<string> _permissions;
private ISet<IGranularPermission> _granularPermissions;
Expand Down Expand Up @@ -111,6 +112,13 @@ public string? Name
set => SetPropertyValueAndDetectChanges(value, ref _name!, nameof(Name));
}

[DataMember]
public string? Description
{
get => _description;
set => SetPropertyValueAndDetectChanges(value, ref _description!, nameof(Description));
}

[DataMember]
public bool HasAccessToAllLanguages
{
Expand Down
3 changes: 3 additions & 0 deletions src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@
// To 17.0.1
To<V_17_0_1.EnsureUmbracoPropertyDataColumnCasing>("{BE5CA411-E12D-4455-A59E-F12A669E5363}");

// To 17.1.0
To<V_17_1_0.AddDescriptionToUserGroup>("{F1A2B3C4-D5E6-4789-ABCD-1234567890AB}");

Check warning on line 149 in src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

❌ New issue: Large Method

UmbracoPlan has 70 lines, threshold = 70. Large functions with many lines of code are generally harder to understand and lower the code health. Avoid adding more lines to this function.
// To 18.0.0
// TODO (V18): Enable on 18 branch
//// To<V_18_0_0.MigrateSingleBlockList>("{74332C49-B279-4945-8943-F8F00B1F5949}");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Umbraco.Cms.Core;
using Umbraco.Cms.Infrastructure.Persistence.Dtos;

namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_17_1_0
{
/// <summary>
/// Migration to add a description column to the user group table.
/// </summary>
public class AddDescriptionToUserGroup : AsyncMigrationBase
{
/// <summary>
/// Initializes a new instance of the <see cref="AddDescriptionToUserGroup"/> class.
/// </summary>
/// <param name="context">The migration context.</param>
public AddDescriptionToUserGroup(
IMigrationContext context)
: base(context)
{
}

/// <inheritdoc/>
protected override async Task MigrateAsync()
{
if (TableExists(Constants.DatabaseSchema.Tables.UserGroup) is false)
{
return;
}

const string ColumnName = "description";
var hasColumn = Context.SqlContext.SqlSyntax.GetColumnsInSchema(Context.Database)
.Any(c =>
c.TableName == Constants.DatabaseSchema.Tables.UserGroup &&
c.ColumnName == ColumnName);

if (hasColumn)
{
return;
}

AddColumn<UserGroupDto>(Constants.DatabaseSchema.Tables.UserGroup, ColumnName);
}
}
}
5 changes: 5 additions & 0 deletions src/Umbraco.Infrastructure/Persistence/Dtos/UserGroupDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public UserGroupDto()
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoUserGroup_userGroupName")]
public string? Name { get; set; }

[Column(Name = "description")]
[SpecialDbType(SpecialDbTypes.NVARCHARMAX)]
[NullSetting(NullSetting = NullSettings.Null)]
public string? Description { get; set; }

[Column("userGroupDefaultPermissions")]
[Length(50)]
[NullSetting(NullSetting = NullSettings.Null)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public static IUserGroup BuildEntity(IShortStringHelper shortStringHelper, UserG
userGroup.StartMediaId = dto.StartMediaId;
userGroup.Permissions = dto.UserGroup2PermissionDtos.Select(x => x.Permission).ToHashSet();
userGroup.HasAccessToAllLanguages = dto.HasAccessToAllLanguages;
userGroup.Description = dto.Description;
if (dto.UserGroup2AppDtos != null)
{
foreach (UserGroup2AppDto app in dto.UserGroup2AppDtos)
Expand Down Expand Up @@ -84,6 +85,7 @@ public static UserGroupDto BuildDto(IUserGroup entity)
Key = entity.Key,
Alias = entity.Alias,
Name = entity.Name,
Description = entity.Description,
UserGroup2AppDtos = new List<UserGroup2AppDto>(),
CreateDate = entity.CreateDate,
UpdateDate = entity.UpdateDate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ protected override void DefineMaps()
DefineMap<UserGroup, UserGroupDto>(nameof(UserGroup.Icon), nameof(UserGroupDto.Icon));
DefineMap<UserGroup, UserGroupDto>(nameof(UserGroup.StartContentId), nameof(UserGroupDto.StartContentId));
DefineMap<UserGroup, UserGroupDto>(nameof(UserGroup.StartMediaId), nameof(UserGroupDto.StartMediaId));
DefineMap<UserGroup, UserGroupDto>(nameof(UserGroup.Description), nameof(UserGroupDto.Description));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@ private static void AppendGroupBy(Sql<ISqlContext> sql) =>
x => x.UpdateDate,
x => x.Alias,
x => x.Name,
x => x.Description,
x => x.HasAccessToAllLanguages,
x => x.Key,
x => x.DefaultPermissions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ export type CreateUserGroupRequestModel = {
fallbackPermissions: Array<string>;
permissions: Array<DocumentPermissionPresentationModel | DocumentPropertyValuePermissionPresentationModel | UnknownTypePermissionPresentationModel>;
id?: string | null;
description?: string | null;
};

export type CreateUserRequestModel = {
Expand Down Expand Up @@ -2810,6 +2811,7 @@ export type UpdateUserDataRequestModel = {

export type UpdateUserGroupRequestModel = {
name: string;
description?: string | null;
alias: string;
icon?: string | null;
sections: Array<string>;
Expand Down Expand Up @@ -2925,6 +2927,7 @@ export type UserGroupResponseModel = {
id: string;
isDeletable: boolean;
aliasCanBeChanged: boolean;
description?: string | null;
};

export type UserInstallRequestModel = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export class UmbUserGroupCollectionServerDataSource implements UmbCollectionData
mediaRootAccess: item.mediaRootAccess,
mediaStartNode: item.mediaStartNode ? { unique: item.mediaStartNode.id } : null,
name: item.name,
description: item.description || null,
permissions: item.permissions,
sections: item.sections,
unique: item.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
this.#observeMediaStartNode(value);
}

@property({ type: String })
description: string | null = null;

@property({ type: Array })
public get sections(): Array<string> {
return [];
Expand Down Expand Up @@ -150,18 +153,20 @@
`;
}

#renderDetails() {

Check notice on line 156 in src/Umbraco.Web.UI.Client/src/packages/user/user-group/components/user-group-ref/user-group-ref.element.ts

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

✅ No longer an issue: Complex Conditional

UmbUserGroupRefElement.renderDetails no longer has a complex conditional
const hasSections = this._sectionLabels.length;
const hasDocument = !!this._documentLabel || this.documentRootAccess;
const hasMedia = !!this._mediaLabel || this.mediaRootAccess;
const hasUserPermissions = this._userPermissionLabels.length;

if (!hasSections && !hasDocument && !hasMedia && !hasUserPermissions) return;

return html`
<div id="details">
${this.#renderSections()} ${this.#renderDocumentStartNode()} ${this.#renderMediaStartNode()}
${this.#renderUserPermissions()}
${this.#renderDescription()} ${this.#renderSections()} ${this.#renderDocumentStartNode()}
${this.#renderMediaStartNode()} ${this.#renderUserPermissions()}
</div>
`;
}

#renderDescription() {
if (!this.description) return;
return html`
<div>
<small>${this.description}</small>
</div>
`;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ export class UmbUserGroupPickerModalElement extends UmbModalBaseElement<
?mediaRootAccess=${userGroup.mediaRootAccess}
.mediaStartNode=${!userGroup.mediaRootAccess ? userGroup.mediaStartNode?.unique : null}
.sections=${userGroup.sections}
.description=${userGroup.description}
@selected=${(event: UUIMenuItemEvent) => this.#onSelected(event, userGroup)}
@deselected=${(event: UUIMenuItemEvent) => this.#onDeselected(event, userGroup)}>
${when(userGroup.icon, () => html`<umb-icon name=${userGroup.icon!} slot="icon"></umb-icon>`)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export class UmbUserGroupServerDataSource
permissions: [],
sections: [],
unique: UmbId.new(),
description: '',
};

return { data };
Expand Down Expand Up @@ -98,6 +99,7 @@ export class UmbUserGroupServerDataSource
permissions,
sections: data.sections,
unique: data.id,
description: data.description ?? null,
};

return { data: userGroup };
Expand Down Expand Up @@ -136,6 +138,7 @@ export class UmbUserGroupServerDataSource
name: model.name,
permissions,
sections: model.sections,
description: model.description,
};

const { data, error } = await tryExecute(
Expand Down Expand Up @@ -186,6 +189,7 @@ export class UmbUserGroupServerDataSource
name: model.name,
permissions,
sections: model.sections,
description: model.description,
};

const { error } = await tryExecute(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ export interface UmbUserGroupDetailModel {
permissions: Array<any>;
sections: Array<string>;
unique: string;
description: string | null;
}
Loading
Loading