diff --git a/.gitignore b/.gitignore index b5b2517e..4da838ae 100644 --- a/.gitignore +++ b/.gitignore @@ -270,4 +270,5 @@ Temp/ **/Assets/setup.* **/Assets/*.js deps/*.dll -zero.Commerce/ \ No newline at end of file +zero.Commerce/ +Hofbauer.To.Zero/ \ No newline at end of file diff --git a/zero.Core/Api/TranslationsApi.cs b/zero.Core/Api/TranslationsApi.cs index 32ca9ad3..1cf72a01 100644 --- a/zero.Core/Api/TranslationsApi.cs +++ b/zero.Core/Api/TranslationsApi.cs @@ -40,7 +40,7 @@ namespace zero.Core.Api public class TranslationsApi : AppAwareBackofficeApi, ITranslationsApi where T : ITranslation { - IValidator Validator; + //IValidator Validator; public TranslationsApi(IBackofficeStore store) : base(store) @@ -91,7 +91,7 @@ namespace zero.Core.Api /// public async Task> Save(T model) { - return await SaveModel(model, Validator); + return await SaveModel(model, null); } diff --git a/zero.Core/Entities/Gender.cs b/zero.Core/Entities/Gender.cs new file mode 100644 index 00000000..7cd0b9b1 --- /dev/null +++ b/zero.Core/Entities/Gender.cs @@ -0,0 +1,10 @@ +namespace zero.Core.Entities +{ + public enum Gender + { + Undisclosed = 0, + Male = 1, + Female = 2, + NonBinary = 3 + } +} diff --git a/zero.Core/Entities/ListResult.cs b/zero.Core/Entities/ListResult.cs index b75c6071..1711a96c 100644 --- a/zero.Core/Entities/ListResult.cs +++ b/zero.Core/Entities/ListResult.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; namespace zero.Core.Entities { @@ -29,6 +30,14 @@ namespace zero.Core.Entities Items = items; } + public ListResult MapTo(Func convertItem) + { + return new ListResult(Items.Select(x => convertItem(x)).ToList(), TotalItems, Page, PageSize) + { + Statistics = Statistics + }; + } + public long Page { get; private set; } public long PageSize { get; private set; } diff --git a/zero.Core/Extensions/RavenQueryableExtensions.cs b/zero.Core/Extensions/RavenQueryableExtensions.cs index 9cb60e4a..1b491b2c 100644 --- a/zero.Core/Extensions/RavenQueryableExtensions.cs +++ b/zero.Core/Extensions/RavenQueryableExtensions.cs @@ -12,9 +12,11 @@ namespace zero.Core.Extensions { public static class RavenQueryableExtensions { - public static IRavenQueryable Scope(this IRavenQueryable source, string appId, bool includeShared = true) where T : IZeroIdEntity + static Type _appAwareEntity = typeof(IAppAwareEntity); + + public static IRavenQueryable Scope(this IRavenQueryable source, string appId, bool includeShared = true) { - if (appId.IsNullOrEmpty() || source.ElementType.Is()) + if (appId.IsNullOrEmpty() || !_appAwareEntity.IsAssignableFrom(source.ElementType)) { return source; } @@ -31,14 +33,14 @@ namespace zero.Core.Extensions } - public static IRavenQueryable Scope(this IRavenQueryable source, ApiScope scope) where T : IZeroIdEntity + public static IRavenQueryable Scope(this IRavenQueryable source, ApiScope scope) { if (scope == null || scope.Global) { return source; } - if (scope.AppId.IsNullOrEmpty() || source.ElementType.Is()) + if (scope.AppId.IsNullOrEmpty() || !_appAwareEntity.IsAssignableFrom(source.ElementType)) { return source; } diff --git a/zero.Core/Renderer/AbstractRenderer2.cs b/zero.Core/Renderer/AbstractRenderer2.cs new file mode 100644 index 00000000..15bccbf3 --- /dev/null +++ b/zero.Core/Renderer/AbstractRenderer2.cs @@ -0,0 +1,132 @@ +using Lambda2Js; +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using zero.Core.Extensions; + +namespace zero.Core.Renderer +{ + public abstract class AbstractRenderer2 + { + const string METHOD_FIELD = "field"; + + const string METHOD_TAB = "tab"; + + const string METHOD_BOX = "box"; + + protected List Properties { get; set; } = new List(); + + RenderProperty ParentProperty = null; + + int CurrentDepth = 0; + + + + /// + /// Create a field + /// + protected virtual IRendererFieldBuilder Field(Expression> mapExpression, bool required = false) + { + RendererFieldBuilder builder = new RendererFieldBuilder(); + + Add(new RenderProperty() + { + Method = METHOD_FIELD, + Compile = property => + { + string field = mapExpression.CompileToJavascript().ToCamelCaseId(); + + RendererFieldBuilder.Data fieldData = builder.Build(); + + property.NestedRenderer = fieldData.Renderer; + property.Params = new + { + Field = field, + View = fieldData.View, + ComponentPath = fieldData.ComponentPath, + Options = fieldData.Options ?? new List() { }, + //Label = FindLabelName?.Invoke(field), + //Description = FindLabelDescriptionName?.Invoke(field), + Required = required + }; + } + }); + + return builder; + } + + + /// + /// Creates a tab + /// + protected virtual void Tab(string name, Action contentBuilder) + { + Add(new RenderProperty() + { + Method = METHOD_TAB, + Builder = contentBuilder, + Params = new + { + Name = name + } + }); + } + + + /// + /// Creates a visual box + /// + protected virtual void Box(string name, string description, Action contentBuilder) + { + Add(new RenderProperty() + { + Method = METHOD_BOX, + Builder = contentBuilder, + Params = new + { + Name = name, + Description = description + } + }); + } + + + /// + /// Adds a property to the list + /// + void Add(RenderProperty property) + { + if (property.Method == METHOD_TAB && CurrentDepth > 0) + { + throw new Exception("Tabs have to be defined on the root level of the renderer"); + } + if (property.Method == METHOD_BOX && (CurrentDepth > 1 || (CurrentDepth == 1 && ParentProperty?.Method != METHOD_TAB))) + { + throw new Exception("Boxes have to be defined on the root level of the renderer or as direct descendents of a tab"); + } + + if (CurrentDepth == 0) + { + Properties.Add(property); + } + else + { + ParentProperty.Children.Add(property); + } + + if (property.Builder != null) + { + CurrentDepth += 1; + + RenderProperty previousParent = ParentProperty; + + ParentProperty = property; + + property.Builder(); + + CurrentDepth -= 1; + ParentProperty = previousParent; + } + } + } +} diff --git a/zero.Core/Renderer/Options/AbstractFieldInputOptions.cs b/zero.Core/Renderer/Options/AbstractFieldInputOptions.cs new file mode 100644 index 00000000..673dd74b --- /dev/null +++ b/zero.Core/Renderer/Options/AbstractFieldInputOptions.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace zero.Core.Renderer +{ + public abstract class AbstractFieldInputOptions + { + public bool HideLabel { get; set; } + + public List Classes { get; set; } = new List(); + + public string HelpText { get; set; } + } +} diff --git a/zero.Core/Renderer/Options/AbstractFieldOptions.cs b/zero.Core/Renderer/Options/AbstractFieldOptions.cs index 92bc45d7..a3017a73 100644 --- a/zero.Core/Renderer/Options/AbstractFieldOptions.cs +++ b/zero.Core/Renderer/Options/AbstractFieldOptions.cs @@ -1,13 +1,11 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Text; -namespace zero.Core.Renderer +namespace zero.Core.Renderer.Options { - public abstract class AbstractFieldOptions + public class AbstractFieldOptions { - public bool HideLabel { get; set; } - public List Classes { get; set; } = new List(); - - public string HelpText { get; set; } } } diff --git a/zero.Core/Renderer/Options/DefaultRendererOptions.cs b/zero.Core/Renderer/Options/DefaultRendererOptions.cs index 449e8ffc..7db6bb6c 100644 --- a/zero.Core/Renderer/Options/DefaultRendererOptions.cs +++ b/zero.Core/Renderer/Options/DefaultRendererOptions.cs @@ -1,6 +1,6 @@ namespace zero.Core.Renderer { - public class DefaultRendererOptions : AbstractFieldOptions + public class DefaultRendererOptions : AbstractFieldInputOptions { } diff --git a/zero.Core/Renderer/Options/MediaOptions.cs b/zero.Core/Renderer/Options/MediaOptions.cs index e9987c14..67d6f804 100644 --- a/zero.Core/Renderer/Options/MediaOptions.cs +++ b/zero.Core/Renderer/Options/MediaOptions.cs @@ -1,10 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Text; +using System.Collections.Generic; namespace zero.Core.Renderer { - public class MediaOptions : AbstractFieldOptions + public class MediaOptions : AbstractFieldInputOptions { public uint Limit { get; set; } = 1; @@ -20,4 +18,22 @@ namespace zero.Core.Renderer public bool DisallowUpload { get; set; } } + + + public enum MediaOptionsDisplay + { + Default = 0, + Big = 1, + Grid = 2 + } + + + public enum MediaOptionsType + { + All = 0, + Image = 1, + Video = 2, + Document = 3, + Other = 99 + } } \ No newline at end of file diff --git a/zero.Core/Renderer/Options/MediaOptionsDisplay.cs b/zero.Core/Renderer/Options/MediaOptionsDisplay.cs deleted file mode 100644 index 40d488d4..00000000 --- a/zero.Core/Renderer/Options/MediaOptionsDisplay.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace zero.Core.Renderer -{ - public enum MediaOptionsDisplay - { - Default = 0, - Big = 1, - Grid = 2 - } -} diff --git a/zero.Core/Renderer/Options/MediaOptionsType.cs b/zero.Core/Renderer/Options/MediaOptionsType.cs deleted file mode 100644 index 87aa06ed..00000000 --- a/zero.Core/Renderer/Options/MediaOptionsType.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace zero.Core.Renderer -{ - public enum MediaOptionsType - { - All = 0, - Image = 1, - Video = 2, - Document = 3, - Other = 99 - } -} diff --git a/zero.Core/Renderer/Options/NestedOptions.cs b/zero.Core/Renderer/Options/NestedOptions.cs index f607a324..a521e3bf 100644 --- a/zero.Core/Renderer/Options/NestedOptions.cs +++ b/zero.Core/Renderer/Options/NestedOptions.cs @@ -4,7 +4,7 @@ using System.Text; namespace zero.Core.Renderer { - public class NestedOptions : AbstractFieldOptions + public class NestedOptions : AbstractFieldInputOptions { public int Limit { get; set; } = 10; diff --git a/zero.Core/Renderer/Options/NumberOptions.cs b/zero.Core/Renderer/Options/NumberOptions.cs index 062e5f67..1fb727a6 100644 --- a/zero.Core/Renderer/Options/NumberOptions.cs +++ b/zero.Core/Renderer/Options/NumberOptions.cs @@ -1,6 +1,6 @@ namespace zero.Core.Renderer { - public class NumberOptions : AbstractFieldOptions + public class NumberOptions : AbstractFieldInputOptions { public int MaxLength { get; set; } diff --git a/zero.Core/Renderer/Options/StateOptions.cs b/zero.Core/Renderer/Options/StateOptions.cs index eac8ba11..eb744733 100644 --- a/zero.Core/Renderer/Options/StateOptions.cs +++ b/zero.Core/Renderer/Options/StateOptions.cs @@ -2,7 +2,7 @@ namespace zero.Core.Renderer { - public class StateOptions : AbstractFieldOptions + public class StateOptions : AbstractFieldInputOptions { public class Item { diff --git a/zero.Core/Renderer/Options/TextOptions.cs b/zero.Core/Renderer/Options/TextOptions.cs index 14e6e084..527d8472 100644 --- a/zero.Core/Renderer/Options/TextOptions.cs +++ b/zero.Core/Renderer/Options/TextOptions.cs @@ -1,6 +1,6 @@ namespace zero.Core.Renderer { - public class TextOptions : AbstractFieldOptions + public class TextOptions : AbstractFieldInputOptions { public int MaxLength { get; set; } diff --git a/zero.Web.UI/App/components/tabs/tabs.vue b/zero.Web.UI/App/components/tabs/tabs.vue index 758abd02..7118aee8 100644 --- a/zero.Web.UI/App/components/tabs/tabs.vue +++ b/zero.Web.UI/App/components/tabs/tabs.vue @@ -177,7 +177,7 @@ &:before { - background: var(--color-line); + background: var(--color-primary); } &:after diff --git a/zero.Web.UI/App/directives/currency.js b/zero.Web.UI/App/directives/currency.js new file mode 100644 index 00000000..cd0712e1 --- /dev/null +++ b/zero.Web.UI/App/directives/currency.js @@ -0,0 +1,13 @@ +import Vue from 'vue'; +import Strings from 'zero/services/strings'; + +/// +/// Outputs a currency +/// +Vue.directive('currency', (el, binding) => +{ + if (binding.value !== binding.oldValue) + { + el.innerHTML = Strings.currency(binding.value); + } +}); \ No newline at end of file diff --git a/zero.Web.UI/App/directives/date.js b/zero.Web.UI/App/directives/date.js index 06e59b35..d0937961 100644 --- a/zero.Web.UI/App/directives/date.js +++ b/zero.Web.UI/App/directives/date.js @@ -10,7 +10,7 @@ Vue.directive('date', (el, binding) => { if (!binding.value) { - el.innerHTML = ''; + el.innerHTML = '-'; return; } diff --git a/zero.Web.UI/App/directives/globals.js b/zero.Web.UI/App/directives/globals.js index 4c69760f..e7bf4b62 100644 --- a/zero.Web.UI/App/directives/globals.js +++ b/zero.Web.UI/App/directives/globals.js @@ -1,6 +1,8 @@ +import './date'; import './localize'; import './resizable'; import './dropdown'; import './clickoutside'; -import './filesize'; \ No newline at end of file +import './filesize'; +import './currency'; \ No newline at end of file diff --git a/zero.Web.UI/App/navigation.vue b/zero.Web.UI/App/navigation.vue index 14cfb583..3fab0bbc 100644 --- a/zero.Web.UI/App/navigation.vue +++ b/zero.Web.UI/App/navigation.vue @@ -1,5 +1,5 @@