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:
committed by
Bjarke Berg
parent
026ece2132
commit
439878883a
@@ -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>
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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: "@",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user