V10/bugfix/variant permissions segments (#12890)

* Remove null check from MapperContext.SetCulture and .SetSegment

We need to be able to set these to null, since null = invariant / default segment

* show segment label on property

* Add ContentVariation to ContentPropertyDisplay

* Add ContentVariation to DocumentTypeDisplay

* Change variations to be on ContentTypeBasic.cs

* don't cache value

* show correct label and unlock text for culture and segment variations

* make lock overlay take up less space

Co-authored-by: nikolajlauridsen <nikolajlauridsen@protonmail.ch>
Co-authored-by: Zeegaan <nge@umbraco.dk>
This commit is contained in:
Mads Rasmussen
2022-08-24 16:17:56 +02:00
committed by GitHub
parent 38f144fa08
commit 2431a21de1
15 changed files with 89 additions and 35 deletions

View File

@@ -1967,7 +1967,11 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
</key>
<key alias="fallbackLanguage">Fall back language</key>
<key alias="none">none</key>
<key alias="invariantPropertyUnlockHelp"><![CDATA[<strong>%0%</strong> is shared across all languages.]]></key>
<key alias="invariantPropertyUnlockHelp"><![CDATA[<strong>%0%</strong> is shared across languages and segments.]]></key>
<key alias="invariantCulturePropertyUnlockHelp"><![CDATA[<strong>%0%</strong> is shared across all languages.]]></key>
<key alias="invariantSegmentPropertyUnlockHelp"><![CDATA[<strong>%0%</strong> is shared across all segments.]]></key>
<key alias="invariantLanguageProperty">Shared: Languages</key>
<key alias="invariantSegmentProperty">Shared: Segments</key>
</area>
<area alias="macro">
<key alias="addParameter">Add parameter</key>

View File

@@ -15,6 +15,9 @@ public class ContentPropertyDisplay : ContentPropertyBasic
Validation = new PropertyTypeValidation();
}
[DataMember(Name = "variations")]
public ContentVariation Variations { get; set; }
[DataMember(Name = "label", IsRequired = true)]
[Required]
public string? Label { get; set; }

View File

@@ -42,6 +42,9 @@ public class ContentTypeBasic : EntityBasic
[DataMember(Name = "thumbnail")]
public string? Thumbnail { get; set; }
[DataMember(Name = "variations")]
public ContentVariation Variations { get; set; }
/// <summary>
/// Returns true if the icon represents a CSS class instead of a file path
/// </summary>

View File

@@ -16,6 +16,9 @@ public class DocumentTypeDisplay : ContentTypeCompositionDisplay<PropertyTypeDis
[DataMember(Name = "allowedTemplates")]
public IEnumerable<EntityBasic> AllowedTemplates { get; set; }
[DataMember(Name = "variations")]
public ContentVariation Variations { get; set; }
[DataMember(Name = "defaultTemplate")]
public EntityBasic? DefaultTemplate { get; set; }

View File

@@ -56,6 +56,9 @@ internal class ContentPropertyDisplayMapper : ContentPropertyBasicMapper<Content
dest.HideLabel = valEditor?.HideLabel ?? false;
dest.LabelOnTop = originalProp.PropertyType?.LabelOnTop;
// Set variation, the frontend needs this to determine if the content varies by segment
dest.Variations = originalProp.PropertyType?.Variations ?? ContentVariation.Nothing;
// add the validation information
dest.Validation.Mandatory = originalProp.PropertyType?.Mandatory ?? false;
dest.Validation.MandatoryMessage = originalProp.PropertyType?.MandatoryMessage;

View File

@@ -323,6 +323,7 @@ public class ContentTypeMapDefinition : IMapDefinition
target.AllowCultureVariant = source.VariesByCulture();
target.AllowSegmentVariant = source.VariesBySegment();
target.ContentApps = _commonMapper.GetContentAppsForEntity(source);
target.Variations = source.Variations;
// sync templates
if (source.AllowedTemplates is not null)
@@ -419,6 +420,7 @@ public class ContentTypeMapDefinition : IMapDefinition
? string.Empty
: _hostingEnvironment.ToAbsolute("~/umbraco/images/thumbnails/" + source.Thumbnail);
target.UpdateDate = source.UpdateDate;
target.Variations = source.Variations;
}
// no MapAll - uses the IContentTypeBase map method, which has MapAll
@@ -751,6 +753,7 @@ public class ContentTypeMapDefinition : IMapDefinition
target.AllowedContentTypes = source.AllowedContentTypes?.OrderBy(c => c.SortOrder).Select(x => x.Id.Value);
target.CompositeContentTypes = source.ContentTypeComposition.Select(x => x.Alias);
target.LockedCompositeContentTypes = MapLockedCompositions(source);
target.Variations = source.Variations;
}
// no MapAll - relies on the non-generic method
@@ -794,6 +797,7 @@ public class ContentTypeMapDefinition : IMapDefinition
: _hostingEnvironment.ToAbsolute("~/umbraco/images/thumbnails/" + source.Thumbnail);
target.Trashed = source.Trashed;
target.Udi = source.Udi;
target.Variations = source.Variations;
}
// no MapAll - relies on the non-generic method

View File

@@ -26,24 +26,12 @@ public static class MapperContextExtensions
/// <summary>
/// Sets a context culture.
/// </summary>
public static void SetCulture(this MapperContext context, string? culture)
{
if (culture is not null)
{
context.Items[CultureKey] = culture;
}
}
public static void SetCulture(this MapperContext context, string? culture) => context.Items[CultureKey] = culture;
/// <summary>
/// Sets a context segment.
/// </summary>
public static void SetSegment(this MapperContext context, string? segment)
{
if (segment is not null)
{
context.Items[SegmentKey] = segment;
}
}
public static void SetSegment(this MapperContext context, string? segment) => context.Items[SegmentKey] = segment;
/// <summary>
/// Get included properties.

View File

@@ -189,10 +189,6 @@
return false;
}
if (property.$propertyEditorDisabledCache) {
return property.$propertyEditorDisabledCache;
}
var contentLanguage = $scope.content.language;
var otherCreatedVariants = $scope.contentNodeModel.variants.filter(x => x.compositeId !== $scope.content.compositeId && (x.state !== "NotCreated" || x.name !== null)).length === 0;
@@ -205,7 +201,7 @@
var canEditSegment = property.segment === $scope.content.segment;
return property.$propertyEditorDisabledCache = !canEditCulture || !canEditSegment;
return !canEditCulture || !canEditSegment;
}
}

View File

@@ -19,6 +19,7 @@
},
bindings: {
property: "=",
node: "<",
elementKey: "@",
// optional, if set this will be used for the property alias validation path (hack required because NC changes the actual property.alias :/)
propertyAlias: "@",

View File

@@ -11,6 +11,7 @@ function umbPropEditor(umbPropEditorHelper, localizationService) {
return {
scope: {
model: "=",
node: "<",
isPreValue: "@",
preview: "<",
allowUnlock: "<?",
@@ -43,6 +44,16 @@ function umbPropEditor(umbPropEditorHelper, localizationService) {
scope.labels.invariantPropertyUnlockHelp = value;
});
localizationService.localize('languages_invariantCulturePropertyUnlockHelp', [scope.model.label])
.then(function(value) {
scope.labels.invariantCulturePropertyUnlockHelp = value;
});
localizationService.localize('languages_invariantSegmentPropertyUnlockHelp', [scope.model.label])
.then(function(value) {
scope.labels.invariantSegmentPropertyUnlockHelp = value;
});
var unbindWatcher = scope.$watch("model.view",
function() {
scope.propertyEditorView = umbPropEditorHelper.getViewPath(scope.model.view, scope.isPreValue);

View File

@@ -46,7 +46,7 @@
transform: translate(-50%, 0);
max-width: 800px;
min-width: 300px;
padding: 12px 20px;
padding: 9px 15px;
background: rgba(242,246,255,.8);
border: 1px solid @blueMid;
color: @blueMid;

View File

@@ -1,18 +1,26 @@
.umb-property:focus-within .umb-property-culture-label,
.umb-property:hover .umb-property-culture-label {
.umb-property:focus-within .umb-property-variant-label-container,
.umb-property:hover .umb-property-variant-label-container {
opacity: 1;
}
.umb-property:hover .umb-property:not(:hover) .umb-property-culture-label {
.umb-property:hover .umb-property:not(:hover) .umb-property-variant-label-container {
opacity: 0;
}
.umb-property-culture-label {
.umb-property-variant-label-container {
float: left;
clear: both;
opacity: 0;
}
.umb-property-variant-label {
font-size: 11px;
padding: 0 7px;
background: @gray-10;
border-radius: 3px;
float: left;
clear: both;
opacity: 0;
display: inline-block;
}
.umb-property-variant-label + .umb-property-variant-label {
margin-right: 3px;
}

View File

@@ -11,7 +11,7 @@
data-element="property-{{property.alias}}"
ng-repeat="property in tab.properties track by property.alias"
property="property"
show-inherit="contentNodeModel.variants.length > 1 && !property.culture"
show-inherit="contentNodeModel.variants.length > 1 && property.variation !== 'CultureAndSegment'"
inherits-from="defaultVariant.displayName">
<umb-property-editor
@@ -43,11 +43,13 @@
data-element="property-{{property.alias}}"
ng-repeat="property in group.properties track by property.alias"
property="property"
show-inherit="contentNodeModel.variants.length > 1 && !property.culture"
node="contentNodeModel"
show-inherit="contentNodeModel.variants.length > 1 && property.variation !== 'CultureAndSegment'"
inherits-from="defaultVariant.displayName">
<umb-property-editor
model="property"
node="contentNodeModel"
preview="(propertyEditorDisabled(property) && allowUpdate) || (!allowUpdate && !property.supportsReadOnly)"
allow-unlock="allowUpdate && allowEditInvariantFromNonDefault"
on-unlock="unlockInvariantValue(property)"

View File

@@ -1,8 +1,15 @@
<div class="umb-property-editor db">
<div ng-if="preview && allowUnlock" class="umb-property-editor__lock-overlay-container">
<div class="umb-property-editor__lock-overlay">
<span ng-bind-html="labels.invariantPropertyUnlockHelp"></span>
<span ng-if="model.variations === 'Nothing' && node.documentType.variations === 'Culture'" ng-bind-html="labels.invariantCulturePropertyUnlockHelp"></span>
<span ng-if="model.variations === 'Nothing' && node.documentType.variations === 'Segment'" ng-bind-html="labels.invariantSegmentPropertyUnlockHelp"></span>
<span ng-if="model.variations === 'Nothing' && node.documentType.variations === 'CultureAndSegment'" ng-bind-html="labels.invariantPropertyUnlockHelp"></span>
<span ng-if="model.variations === 'Culture' && node.documentType.variations === 'CultureAndSegment'" ng-bind-html="labels.invariantSegmentPropertyUnlockHelp"></span>
<span ng-if="model.variations === 'Segment' && node.documentType.variations === 'CultureAndSegment'" ng-bind-html="labels.invariantCulturePropertyUnlockHelp"></span>
<umb-button button-style="success" type="button" action="unlock()" label-key="general_edit" size="xxs"></umb-button>
</div>
</div>

View File

@@ -28,10 +28,31 @@
</div>
<div ng-if="vm.showInherit || vm.property.culture" class="umb-property-culture-label">
<span ng-if="vm.showInherit"><localize key="general_shared"></localize></span>
<span ng-if="!vm.showInherit">{{ vm.property.culture }}</span>
<div class="umb-property-variant-label-container" ng-if="vm.showInherit && vm.property && vm.node">
<span ng-if="vm.property.variations === 'Nothing'" class="umb-property-variant-label">
<localize key="general_shared"></localize>
</span>
<span ng-if="vm.property.variations === 'Segment' && vm.node.documentType.variations === 'CultureAndSegment'" class="umb-property-variant-label">
<localize key="languages_invariantLanguageProperty"></localize>
</span>
<span ng-if="vm.property.variations === 'Culture' || vm.property.variations === 'CultureAndSegment'" class="umb-property-variant-label">
{{ vm.property.culture }}
</span>
<span ng-if="vm.property.variations === 'Culture' && vm.node.documentType.variations === 'CultureAndSegment'" class="umb-property-variant-label">
<localize key="languages_invariantSegmentProperty"></localize>
</span>
<span ng-if="vm.property.variations === 'Segment' || vm.property.variations === 'CultureAndSegment'" class="umb-property-variant-label">
<span>{{ vm.property.segment }}</span>
<span ng-if="!vm.property.segment">Default</span>
</span>
</div>
</div>
<div class="controls" ng-transclude>