From 420e1387bb03dcb82ba40bcbe20e819898fa2007 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Mon, 27 Dec 2021 17:09:51 +0800 Subject: [PATCH 01/67] Improve Blazor module extensibility feature --- .../CheckExtensionProperty.razor | 18 +++++++-- .../CheckExtensionProperty.razor.cs | 16 +------- .../DateTimeExtensionProperty.razor | 22 +++++++---- .../DateTimeExtensionProperty.razor.cs | 13 ++----- .../ObjectExtending/ExtensionProperties.razor | 6 +-- .../ExtensionPropertyComponentBase.cs | 39 +++++++++++++++++++ .../LookupExtensionProperty.razor | 7 ++-- .../LookupExtensionProperty.razor.cs | 17 +++----- .../SelectExtensionProperty.razor | 26 ++++++++----- .../SelectExtensionProperty.razor.cs | 11 ++---- .../TextExtensionProperty.razor | 19 +++++---- .../TextExtensionProperty.razor.cs | 17 +------- .../TimeExtensionProperty.razor | 18 ++++++--- .../TimeExtensionProperty.razor.cs | 13 ++----- 14 files changed, 135 insertions(+), 107 deletions(-) create mode 100644 framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionPropertyComponentBase.cs diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/CheckExtensionProperty.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/CheckExtensionProperty.razor index ed9f1664fe..eebff3970d 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/CheckExtensionProperty.razor +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/CheckExtensionProperty.razor @@ -2,10 +2,20 @@ @typeparam TResourceType @using Volo.Abp.BlazoriseUI @using Volo.Abp.Localization +@inherits ExtensionPropertyComponentBase @if (PropertyInfo != null && Entity != null) { - - @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory) - -} \ No newline at end of file + + + + + @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory) + + + + + + + +} diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/CheckExtensionProperty.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/CheckExtensionProperty.razor.cs index 4f8a06a146..79662ab96c 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/CheckExtensionProperty.razor.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/CheckExtensionProperty.razor.cs @@ -1,22 +1,10 @@ -using Microsoft.AspNetCore.Components; -using Microsoft.Extensions.Localization; -using Volo.Abp.Data; -using Volo.Abp.ObjectExtending; +using Volo.Abp.Data; namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending; -public partial class CheckExtensionProperty : ComponentBase +public partial class CheckExtensionProperty where TEntity : IHasExtraProperties { - [Inject] - public IStringLocalizerFactory StringLocalizerFactory { get; set; } - - [Parameter] - public TEntity Entity { get; set; } - - [Parameter] - public ObjectExtensionPropertyInfo PropertyInfo { get; set; } - protected bool Value { get { return PropertyInfo.GetInputValueOrDefault(Entity.GetProperty(PropertyInfo.Name)); diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeExtensionProperty.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeExtensionProperty.razor index a9847d8e33..8fa7f0d777 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeExtensionProperty.razor +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeExtensionProperty.razor @@ -3,15 +3,21 @@ @using Volo.Abp.BlazoriseUI @using Volo.Abp.Localization @using Volo.Abp.ObjectExtending +@inherits ExtensionPropertyComponentBase @if (PropertyInfo != null && Entity != null) { - - @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory) - - - + + + @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory) + + + + + + + } diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeExtensionProperty.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeExtensionProperty.razor.cs index 30a8ecc1a1..9a39b7a02d 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeExtensionProperty.razor.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeExtensionProperty.razor.cs @@ -5,23 +5,16 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Blazorise; +using Volo.Abp.AspNetCore.Components.Web; using Volo.Abp.Data; using Volo.Abp.ObjectExtending; namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending; -public partial class DateTimeExtensionProperty : ComponentBase +public partial class DateTimeExtensionProperty where TEntity : IHasExtraProperties { - [Inject] - public IStringLocalizerFactory StringLocalizerFactory { get; set; } - - [Parameter] - public TEntity Entity { get; set; } - - [Parameter] - public ObjectExtensionPropertyInfo PropertyInfo { get; set; } - protected DateTime? Value { get { return PropertyInfo.GetInputValueOrDefault(Entity.GetProperty(PropertyInfo.Name)); diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionProperties.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionProperties.razor index f8aad7b5cd..9fe96c7a20 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionProperties.razor +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionProperties.razor @@ -1,7 +1,6 @@ @typeparam TEntityType @typeparam TResourceType @using Volo.Abp.ObjectExtending -@using Volo.Abp.Localization @using Volo.Abp.Data @{ @@ -13,11 +12,11 @@ { if (propertyInfo.Type.IsEnum) { - + } else if (!propertyInfo.Lookup.Url.IsNullOrEmpty()) { - + } else { @@ -25,6 +24,7 @@ __builder.OpenComponent(0, inputType.MakeGenericType(new[] { typeof(TEntityType), typeof(TResourceType) })); __builder.AddAttribute(1, "PropertyInfo", propertyInfo); __builder.AddAttribute(2, "Entity", Entity); + __builder.AddAttribute(3, "LH", LH); __builder.CloseComponent(); } } diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionPropertyComponentBase.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionPropertyComponentBase.cs new file mode 100644 index 0000000000..bb9657734d --- /dev/null +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionPropertyComponentBase.cs @@ -0,0 +1,39 @@ +using System.Linq; +using Blazorise; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Localization; +using Volo.Abp.AspNetCore.Components.Web; +using Volo.Abp.Data; +using Volo.Abp.ObjectExtending; + +namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending; + +public abstract class ExtensionPropertyComponentBase : OwningComponentBase + where TEntity : IHasExtraProperties +{ + [Inject] + public IStringLocalizerFactory StringLocalizerFactory { get; set; } + + [Parameter] + public TEntity Entity { get; set; } + + [Parameter] + public ObjectExtensionPropertyInfo PropertyInfo { get; set; } + + [Parameter] + public AbpBlazorMessageLocalizerHelper LH { get; set; } + + protected virtual void Validate(ValidatorEventArgs e) + { + e.Status = ValidationStatus.Success; + + var result = ExtensibleObjectValidator.GetValidationErrors(Entity, PropertyInfo.Name, e.Value); + if (!result.Any()) + { + return; + } + + e.Status = ValidationStatus.Error; + e.ErrorText = result.First().ErrorMessage; + } +} diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor index 4a305d606d..5a6a7c7c3e 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor @@ -2,18 +2,19 @@ @typeparam TResourceType @using Abp.Localization @using Blazorise.Components +@inherits ExtensionPropertyComponentBase @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory) - \ No newline at end of file diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor.cs index 725edf8e99..608bd16d9e 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor.cs @@ -9,6 +9,8 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Text.Json; using System.Threading.Tasks; +using Blazorise; +using Volo.Abp.AspNetCore.Components.Web; using Volo.Abp.AspNetCore.Components.Web.Extensibility; using Volo.Abp.Data; using Volo.Abp.Http; @@ -18,18 +20,11 @@ using Volo.Abp.ObjectExtending; namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending; -public partial class LookupExtensionProperty : ComponentBase +public partial class LookupExtensionProperty where TEntity : IHasExtraProperties { protected List> lookupItems; - [Inject] public IStringLocalizerFactory StringLocalizerFactory { get; set; } - - [Parameter] public TEntity Entity { get; set; } - - [Parameter] public ObjectExtensionPropertyInfo PropertyInfo { get; set; } - - [Inject] public ILookupApiRequestService LookupApiService { get; set; } public string TextPropertyName => PropertyInfo.Name + "_Text"; @@ -63,7 +58,7 @@ public partial class LookupExtensionProperty : Component protected virtual void UpdateLookupTextProperty(object value) { - var selectedItemText = lookupItems.SingleOrDefault(t => t.Value.Equals(value)).Text; + var selectedItemText = lookupItems.SingleOrDefault(t => t.Value.Equals(value))?.Text; Entity.SetProperty(TextPropertyName, selectedItemText); } @@ -101,12 +96,12 @@ public partial class LookupExtensionProperty : Component return Task.CompletedTask; } - protected async Task SearchFilterChangedAsync(string filter) + protected virtual async Task SearchFilterChangedAsync(string filter) { lookupItems = await GetLookupItemsAsync(filter); } - protected override async Task OnAfterRenderAsync(bool firstRender) + protected async override Task OnAfterRenderAsync(bool firstRender) { await base.OnAfterRenderAsync(firstRender); diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor index c70dc11237..cc1735c26a 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor @@ -1,13 +1,21 @@ @typeparam TEntity @typeparam TResourceType @using Abp.Localization +@inherits ExtensionPropertyComponentBase - - @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory) - - + + + @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory) + + + diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor.cs index e873ec27d1..ddc00a4c8b 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor.cs @@ -2,23 +2,20 @@ using Microsoft.Extensions.Localization; using System; using System.Collections.Generic; +using System.Linq; +using Blazorise; +using Volo.Abp.AspNetCore.Components.Web; using Volo.Abp.Data; using Volo.Abp.Localization; using Volo.Abp.ObjectExtending; namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending; -public partial class SelectExtensionProperty : ComponentBase +public partial class SelectExtensionProperty where TEntity : IHasExtraProperties { protected List> SelectItems = new(); - [Inject] public IStringLocalizerFactory StringLocalizerFactory { get; set; } - - [Parameter] public TEntity Entity { get; set; } - - [Parameter] public ObjectExtensionPropertyInfo PropertyInfo { get; set; } - public int SelectedValue { get { return Entity.GetProperty(PropertyInfo.Name); } set { Entity.SetProperty(PropertyInfo.Name, value, false); } diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextExtensionProperty.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextExtensionProperty.razor index ade78ee6d2..fc8b7b5398 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextExtensionProperty.razor +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextExtensionProperty.razor @@ -2,13 +2,18 @@ @typeparam TResourceType @using Volo.Abp.BlazoriseUI @using Volo.Abp.Localization +@inherits ExtensionPropertyComponentBase @if (PropertyInfo != null && Entity != null) { - - @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory) - - - - -} \ No newline at end of file + + + @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory) + + + + + + + +} diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextExtensionProperty.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextExtensionProperty.razor.cs index fd017d2472..6fe9c9fb71 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextExtensionProperty.razor.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextExtensionProperty.razor.cs @@ -1,23 +1,10 @@ -using Microsoft.AspNetCore.Components; -using Microsoft.Extensions.Localization; -using Volo.Abp.Data; -using Volo.Abp.ObjectExtending; +using Volo.Abp.Data; namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending; -public partial class TextExtensionProperty : ComponentBase +public partial class TextExtensionProperty where TEntity : IHasExtraProperties { - [Inject] - public IStringLocalizerFactory StringLocalizerFactory { get; set; } - - [Parameter] - public TEntity Entity { get; set; } - - [Parameter] - public ObjectExtensionPropertyInfo PropertyInfo { get; set; } - - protected string Value { get { return PropertyInfo.GetTextInputValueOrNull(Entity.GetProperty(PropertyInfo.Name)); diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TimeExtensionProperty.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TimeExtensionProperty.razor index ce2215e621..6ad15b2cb5 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TimeExtensionProperty.razor +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TimeExtensionProperty.razor @@ -2,12 +2,18 @@ @typeparam TResourceType @using Volo.Abp.BlazoriseUI @using Volo.Abp.Localization +@inherits ExtensionPropertyComponentBase @if (PropertyInfo != null && Entity != null) { - - @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)--> - - - -} \ No newline at end of file + + + @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)--> + + + + + + + +} diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TimeExtensionProperty.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TimeExtensionProperty.razor.cs index 6e582ef698..038283850c 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TimeExtensionProperty.razor.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TimeExtensionProperty.razor.cs @@ -5,23 +5,16 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Blazorise; +using Volo.Abp.AspNetCore.Components.Web; using Volo.Abp.Data; using Volo.Abp.ObjectExtending; namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending; -public partial class TimeExtensionProperty : ComponentBase +public partial class TimeExtensionProperty where TEntity : IHasExtraProperties { - [Inject] - public IStringLocalizerFactory StringLocalizerFactory { get; set; } - - [Parameter] - public TEntity Entity { get; set; } - - [Parameter] - public ObjectExtensionPropertyInfo PropertyInfo { get; set; } - protected TimeSpan? Value { get { return PropertyInfo.GetInputValueOrDefault(Entity.GetProperty(PropertyInfo.Name)); From 8023cd81378215fa95584360925513c2089f8269 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Mon, 27 Dec 2021 23:24:19 +0800 Subject: [PATCH 02/67] Localized error messages --- .../ExtensionPropertyComponentBase.cs | 44 ++++++++++++++++++- .../LookupExtensionProperty.razor.cs | 11 +++-- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionPropertyComponentBase.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionPropertyComponentBase.cs index bb9657734d..48c27f0243 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionPropertyComponentBase.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionPropertyComponentBase.cs @@ -1,5 +1,8 @@ -using System.Linq; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; using Blazorise; +using Blazorise.Utilities; using Microsoft.AspNetCore.Components; using Microsoft.Extensions.Localization; using Volo.Abp.AspNetCore.Components.Web; @@ -14,6 +17,9 @@ public abstract class ExtensionPropertyComponentBase : O [Inject] public IStringLocalizerFactory StringLocalizerFactory { get; set; } + [Inject] + public IValidationMessageLocalizerAttributeFinder ValidationMessageLocalizerAttributeFinder { get; set; } + [Parameter] public TEntity Entity { get; set; } @@ -33,7 +39,41 @@ public abstract class ExtensionPropertyComponentBase : O return; } + if (LH == null) + { + e.MemberNames = result.First().MemberNames; + e.Status = ValidationStatus.Error; + e.ErrorText = result.First().ErrorMessage; + return; + } + + + var formattedValidationAttributes = PropertyInfo.GetValidationAttributes(); + foreach (var validationAttribute in formattedValidationAttributes ) + { + if (validationAttribute.ErrorMessageResourceName == null) + { + ValidationAttributeHelper.SetDefaultErrorMessage(validationAttribute); + } + } + + var formattedResults = new List(); + var validationContext = new ValidationContext(Entity) + { + DisplayName = PropertyInfo.Name, + MemberName = PropertyInfo.Name + }; + + Validator.TryValidateValue(e.Value, validationContext, formattedResults, formattedValidationAttributes); + + var errorMessage = result.First().ErrorMessage; + var errorMessageString = ValidationAttributeHelper.RevertErrorMessagePlaceholders(formattedResults.First().ErrorMessage); + var errorMessageArguments = ValidationMessageLocalizerAttributeFinder.FindAll(errorMessage, errorMessageString) + ?.OrderBy(x => x.Index) + ?.Select(x => x.Argument); + + e.MemberNames = result.First().MemberNames; e.Status = ValidationStatus.Error; - e.ErrorText = result.First().ErrorMessage; + e.ErrorText = LH.Localize(errorMessageString, errorMessageArguments); } } diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor.cs index 608bd16d9e..516193d220 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor.cs @@ -48,11 +48,14 @@ public partial class LookupExtensionProperty var text = Entity.GetProperty(TextPropertyName); if (value != null && text != null) { - lookupItems.Add(new SelectItem + if (lookupItems.All(x => !x.Value.Equals(value))) { - Text = Entity.GetProperty(TextPropertyName).ToString(), - Value = value - }); + lookupItems.Add(new SelectItem + { + Text = Entity.GetProperty(TextPropertyName).ToString(), + Value = value + }); + } } } From 45ec807326054fa0a6ee24afca391882f72c8b92 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Tue, 28 Dec 2021 12:00:46 +0800 Subject: [PATCH 03/67] Update ExtensionPropertyComponentBase.cs --- .../ExtensionPropertyComponentBase.cs | 68 ++++++++++--------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionPropertyComponentBase.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionPropertyComponentBase.cs index 48c27f0243..4408741fef 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionPropertyComponentBase.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionPropertyComponentBase.cs @@ -33,47 +33,51 @@ public abstract class ExtensionPropertyComponentBase : O { e.Status = ValidationStatus.Success; - var result = ExtensibleObjectValidator.GetValidationErrors(Entity, PropertyInfo.Name, e.Value); - if (!result.Any()) + var validationAttributes = PropertyInfo.GetValidationAttributes(); + var validationContext = new ValidationContext(Entity) { - return; - } + DisplayName = PropertyInfo.Name, + MemberName = PropertyInfo.Name + }; - if (LH == null) + foreach (var validationAttribute in validationAttributes) { - e.MemberNames = result.First().MemberNames; + var result = validationAttribute.GetValidationResult(e.Value, validationContext); + if (result == ValidationResult.Success || result == null) + { + continue; + } + + var errorMessage = result.ErrorMessage; + if (LH != null) + { + var formattedErrorMessage = GetDefaultErrorMessage(validationAttribute); + var errorMessageString = ValidationAttributeHelper.RevertErrorMessagePlaceholders(formattedErrorMessage); + var errorMessageArguments = ValidationMessageLocalizerAttributeFinder.FindAll(errorMessage, errorMessageString) + ?.OrderBy(x => x.Index) + ?.Select(x => x.Argument); + + errorMessage = LH.Localize(errorMessageString, errorMessageArguments); + } + + e.MemberNames = result.MemberNames; e.Status = ValidationStatus.Error; - e.ErrorText = result.First().ErrorMessage; - return; + e.ErrorText = errorMessage; + break; } + } - - var formattedValidationAttributes = PropertyInfo.GetValidationAttributes(); - foreach (var validationAttribute in formattedValidationAttributes ) + private static string GetDefaultErrorMessage(ValidationAttribute validationAttribute) + { + if (validationAttribute is StringLengthAttribute stringLengthAttribute && stringLengthAttribute.MinimumLength != 0) { - if (validationAttribute.ErrorMessageResourceName == null) + var nullable = ValidationAttributeHelper.ValidationAttributeCustomErrorMessageSetProperty.GetValue((object) validationAttribute) as bool?; + var flag = true; + if (!(nullable.GetValueOrDefault() == flag & nullable.HasValue)) { - ValidationAttributeHelper.SetDefaultErrorMessage(validationAttribute); + return ValidationAttributeHelper.SetErrorMessagePlaceholders("The field {0} must be a string with a minimum length of {2} and a maximum length of {1}."); } } - - var formattedResults = new List(); - var validationContext = new ValidationContext(Entity) - { - DisplayName = PropertyInfo.Name, - MemberName = PropertyInfo.Name - }; - - Validator.TryValidateValue(e.Value, validationContext, formattedResults, formattedValidationAttributes); - - var errorMessage = result.First().ErrorMessage; - var errorMessageString = ValidationAttributeHelper.RevertErrorMessagePlaceholders(formattedResults.First().ErrorMessage); - var errorMessageArguments = ValidationMessageLocalizerAttributeFinder.FindAll(errorMessage, errorMessageString) - ?.OrderBy(x => x.Index) - ?.Select(x => x.Argument); - - e.MemberNames = result.First().MemberNames; - e.Status = ValidationStatus.Error; - e.ErrorText = LH.Localize(errorMessageString, errorMessageArguments); + return ValidationAttributeHelper.SetErrorMessagePlaceholders(ValidationAttributeHelper.ValidationAttributeErrorMessageStringProperty.GetValue((object) validationAttribute) as string); } } From 966e81bc129708b5bcc20040ec37a66a469205b8 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Thu, 30 Dec 2021 14:51:36 +0800 Subject: [PATCH 04/67] Improve --- .../Layout/PageHeader.razor.cs | 4 +-- .../Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs | 4 +-- .../LookupExtensionProperty.razor | 5 +-- .../LookupExtensionProperty.razor.cs | 33 ++++--------------- 4 files changed, 13 insertions(+), 33 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs index 594909cd52..fd6bd50942 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs @@ -37,7 +37,7 @@ public partial class PageHeader : ComponentBase ToolbarItemRenders = new List(); } - protected override async Task OnParametersSetAsync() + protected async override Task OnParametersSetAsync() { await base.OnParametersSetAsync(); if (Toolbar != null) @@ -65,7 +65,7 @@ public partial class PageHeader : ComponentBase } } - protected override async Task OnInitializedAsync() + protected async override Task OnInitializedAsync() { await base.OnInitializedAsync(); } diff --git a/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs b/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs index e2b188eec3..bcd07221e4 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs @@ -212,7 +212,7 @@ public abstract class AbpCrudPageBase< EntityActions = new EntityActionDictionary(); } - protected override async Task OnInitializedAsync() + protected async override Task OnInitializedAsync() { await SetPermissionsAsync(); await SetEntityActionsAsync(); @@ -220,7 +220,7 @@ public abstract class AbpCrudPageBase< await InvokeAsync(StateHasChanged); } - protected override async Task OnAfterRenderAsync(bool firstRender) + protected async override Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor index 5a6a7c7c3e..52369d6b46 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/LookupExtensionProperty.razor @@ -9,8 +9,9 @@ } } + public string SelectedText => Entity.GetProperty(TextPropertyName); + public LookupExtensionProperty() { lookupItems = new List>(); } - protected override void OnParametersSet() + protected async override Task OnInitializedAsync() { - var value = Entity.GetProperty(PropertyInfo.Name); - var text = Entity.GetProperty(TextPropertyName); - if (value != null && text != null) - { - if (lookupItems.All(x => !x.Value.Equals(value))) - { - lookupItems.Add(new SelectItem - { - Text = Entity.GetProperty(TextPropertyName).ToString(), - Value = value - }); - } - } + await base.OnInitializedAsync(); + await SearchFilterChangedAsync(string.Empty); } protected virtual void UpdateLookupTextProperty(object value) @@ -84,8 +75,7 @@ public partial class LookupExtensionProperty selectItems.Add(new SelectItem { Text = item.GetProperty(PropertyInfo.Lookup.DisplayPropertyName).GetString(), - Value = JsonSerializer.Deserialize( - item.GetProperty(PropertyInfo.Lookup.ValuePropertyName).GetRawText(), PropertyInfo.Type) + Value = JsonSerializer.Deserialize(item.GetProperty(PropertyInfo.Lookup.ValuePropertyName).GetRawText(), PropertyInfo.Type) }); } @@ -95,7 +85,6 @@ public partial class LookupExtensionProperty protected virtual Task SelectedValueChanged(object selectedItem) { SelectedValue = selectedItem; - return Task.CompletedTask; } @@ -103,14 +92,4 @@ public partial class LookupExtensionProperty { lookupItems = await GetLookupItemsAsync(filter); } - - protected async override Task OnAfterRenderAsync(bool firstRender) - { - await base.OnAfterRenderAsync(firstRender); - - if (firstRender) - { - await SearchFilterChangedAsync(string.Empty); - } - } } From bb4ee2a67235379f534313118a553e1e3ef33dbc Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 31 Dec 2021 10:47:18 +0800 Subject: [PATCH 05/67] Update codecov.yml --- codecov.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/codecov.yml b/codecov.yml index 7ad4672daf..a2bd04f1d8 100644 --- a/codecov.yml +++ b/codecov.yml @@ -2,3 +2,7 @@ codecov: branch: dev require_ci_to_pass: yes allow_coverage_offsets: true + status: + project: + default: + threshold: 1% From 3b9fcc77cdde390840fbd8113c001dbbed7f504f Mon Sep 17 00:00:00 2001 From: braim23 <94292623+braim23@users.noreply.github.com> Date: Sat, 1 Jan 2022 20:18:26 +0300 Subject: [PATCH 06/67] Update Part-1.md --- docs/en/Tutorials/Part-1.md | 45 ++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/docs/en/Tutorials/Part-1.md b/docs/en/Tutorials/Part-1.md index 210ecbe966..93bf3d4a0b 100644 --- a/docs/en/Tutorials/Part-1.md +++ b/docs/en/Tutorials/Part-1.md @@ -13,7 +13,7 @@ In this tutorial series, you will build an ABP based web application named `Acme * **{{DB_Value}}** as the database provider. * **{{UI_Value}}** as the UI Framework. -This tutorial is organized as the following parts; +This tutorial is organized as the following parts: - **Part 1: Creating the server side (this part)** - [Part 2: The book list page](Part-2.md) @@ -34,7 +34,7 @@ This tutorial has multiple versions based on your **UI** and **Database** prefer * [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) -> If you encounter the "filename too long" or "unzip error" on Windows, it's probably related to the Windows maximum file path limitation. Windows has a maximum file path limitation of 250 characters. To solve this, [enable the long path option in Windows 10](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later). +> If you encounter the "filename too long" or "unzip" error on Windows, it's probably related to the Windows maximum file path limitation. Windows has a maximum file path limitation of 250 characters. To solve this, [enable the long path option in Windows 10](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later). > If you face long path errors related to Git, try the following command to enable long paths in Windows. See https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path > `git config --system core.longpaths true` @@ -49,14 +49,14 @@ This part is also recorded as a video tutorial and ** @@ -147,7 +147,7 @@ public class BookStoreMongoDbContext : AbpMongoDbContext ### Map the Book Entity to a Database Table -Locate to `OnModelCreating` method in the `BookStoreDbContext` class and add the mapping code for the `Book` entity: +Navigate to the `OnModelCreating` method in the `BookStoreDbContext` class and add the mapping code for the `Book` entity: ````csharp using Acme.BookStore.Books; @@ -185,8 +185,8 @@ namespace Acme.BookStore.EntityFrameworkCore } ```` -* `BookStoreConsts` has constant values for schema and table prefixes for your tables. You don't have to use it, but suggested to control the table prefixes in a single point. -* `ConfigureByConvention()` method gracefully configures/maps the inherited properties. Always use it for all your entities. +* `BookStoreConsts` has constant values for the schema and table prefixes for your tables. You don't have to use it, but it's suggested to control the table prefixes in a single point. +* The `ConfigureByConvention()` method gracefully configures/maps the inherited properties. Always use it for all your entities. ### Add Database Migration @@ -202,13 +202,13 @@ This will add a new migration class to the project: ![bookstore-efcore-migration](./images/bookstore-efcore-migration.png) -> If you are using Visual Studio, you may want to use `Add-Migration Created_Book_Entity -c BookStoreMigrationsDbContext` and `Update-Database -c BookStoreMigrationsDbContext` commands in the *Package Manager Console (PMC)*. In this case, ensure that {{if UI=="MVC"}}`Acme.BookStore.Web`{{else if UI=="BlazorServer"}}`Acme.BookStore.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`Acme.BookStore.HttpApi.Host`{{end}} is the startup project and `Acme.BookStore.EntityFrameworkCore` is the *Default Project* in PMC. +> If you are using Visual Studio, you may want to use the `Add-Migration Created_Book_Entity -c BookStoreMigrationsDbContext` and `Update-Database -c BookStoreMigrationsDbContext` commands in the *Package Manager Console (PMC)*. In this case, ensure that {{if UI=="MVC"}}`Acme.BookStore.Web`{{else if UI=="BlazorServer"}}`Acme.BookStore.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`Acme.BookStore.HttpApi.Host`{{end}} is the startup project and `Acme.BookStore.EntityFrameworkCore` is the *Default Project* in PMC. {{end}} ### Add Sample Seed Data -> It's good to have some initial data in the database before running the application. This section introduces the [Data Seeding](../Data-Seeding.md) system of the ABP framework. You can skip this section if you don't want to create seed data, but it is suggested to follow it to learn this useful ABP Framework feature. +> It's good to have some initial data in the database before running the application. This section introduces the [Data Seeding](../Data-Seeding.md) system of the ABP framework. You can skip this section if you don't want to create the data seeding, but it is suggested to follow along and learn this useful ABP Framework feature. Create a class deriving from the `IDataSeedContributor` in the `*.Domain` project by copying the following code: @@ -263,7 +263,7 @@ namespace Acme.BookStore } ``` -* This code simply uses the `IRepository` (the default [repository](../Repositories.md)) to insert two books to the database, if there is no book currently in the database. +* This code simply uses the `IRepository` (the default [repository](../Repositories.md)) to insert two books to the database in case there weren't any books in it. ### Update the Database @@ -271,7 +271,6 @@ Run the `Acme.BookStore.DbMigrator` application to update the database: ![bookstore-dbmigrator-on-solution](images/bookstore-dbmigrator-on-solution.png) - `.DbMigrator` is a console application that can be run to **migrate the database schema** and **seed the data** on **development** and **production** environments. ## Create the Application Service @@ -307,10 +306,10 @@ namespace Acme.BookStore.Books ```` * **DTO** classes are used to **transfer data** between the *presentation layer* and the *application layer*. See the [Data Transfer Objects document](https://docs.abp.io/en/abp/latest/Data-Transfer-Objects) for more details. -* `BookDto` is used to transfer book data to the presentation layer in order to show the book information on the UI. -* `BookDto` is derived from the `AuditedEntityDto` which has audit properties just like the `Book` entity defined above. +* The `BookDto` is used to transfer the book data to the presentation layer in order to show the book information on the UI. +* The `BookDto` is derived from the `AuditedEntityDto` which has audit properties just like the `Book` entity defined above. -It will be needed to map `Book` entities to `BookDto` objects while returning books to the presentation layer. [AutoMapper](https://automapper.org) library can automate this conversion when you define the proper mapping. The startup template comes with AutoMapper pre-configured. So, you can just define the mapping in the `BookStoreApplicationAutoMapperProfile` class in the `Acme.BookStore.Application` project: +It will be needed to map the `Book` entities to the `BookDto` objects while returning books to the presentation layer. [AutoMapper](https://automapper.org) library can automate this conversion when you define the proper mapping. The startup template comes with AutoMapper pre-configured. So, you can just define the mapping in the `BookStoreApplicationAutoMapperProfile` class in the `Acme.BookStore.Application` project: ````csharp using Acme.BookStore.Books; @@ -359,10 +358,10 @@ namespace Acme.BookStore.Books } ```` -* This `DTO` class is used to get book information from the user interface while creating or updating a book. +* This `DTO` class is used to get a book information from the user interface while creating or updating the book. * It defines data annotation attributes (like `[Required]`) to define validations for the properties. `DTO`s are [automatically validated](https://docs.abp.io/en/abp/latest/Validation) by the ABP framework. -Just like done for the `BookDto` above, we should define the mapping from the `CreateUpdateBookDto` object to the `Book` entity. The final class will be like shown below: +As done to the `BookDto` above, we should define the mapping from the `CreateUpdateBookDto` object to the `Book` entity. The final class will be as shown below: ````csharp using Acme.BookStore.Books; @@ -440,13 +439,13 @@ namespace Acme.BookStore.Books * `BookAppService` is derived from `CrudAppService<...>` which implements all the CRUD (create, read, update, delete) methods defined by the `ICrudAppService`. * `BookAppService` injects `IRepository` which is the default repository for the `Book` entity. ABP automatically creates default repositories for each aggregate root (or entity). See the [repository document](https://docs.abp.io/en/abp/latest/Repositories). -* `BookAppService` uses `IObjectMapper` service ([see](../Object-To-Object-Mapping.md)) to map `Book` objects to `BookDto` objects and `CreateUpdateBookDto` objects to `Book` objects. The Startup template uses the [AutoMapper](http://automapper.org/) library as the object mapping provider. We have defined the mappings before, so it will work as expected. +* `BookAppService` uses `IObjectMapper` service ([see](../Object-To-Object-Mapping.md)) to map the `Book` objects to the `BookDto` objects and `CreateUpdateBookDto` objects to the `Book` objects. The Startup template uses the [AutoMapper](http://automapper.org/) library as the object mapping provider. We have defined the mappings before, so it will work as expected. ## Auto API Controllers -In a typical ASP.NET Core application, you create **API Controllers** to expose application services as **HTTP API** endpoints. This allows browsers or 3rd-party clients to call them over HTTP. +In a typical ASP.NET Core application, you create **API Controllers** to expose the application services as **HTTP API** endpoints. This allows browsers or 3rd-party clients to call them over HTTP. -ABP can [**automagically**](../API/Auto-API-Controllers.md) configures your application services as MVC API Controllers by convention. +ABP can [**automagically**](../API/Auto-API-Controllers.md) configure your application services as MVC API Controllers by convention. ### Swagger UI From dceb36b1d9d9969368035e19ebde3dce31dfbe1a Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Mon, 3 Jan 2022 13:30:05 +0300 Subject: [PATCH 07/67] Improve studio --- .../Abp/Studio/Modifying/CsprojFileManager.cs | 40 +++++++++++++++++++ .../Studio/Modifying/ICsprojFileManager.cs | 4 ++ .../ModuleInstallingPipelineBuilderBase.cs | 2 +- .../Steps/AddEfCoreConfigurationMethodStep.cs | 9 ++++- ...monPropsStep.cs => AssemblyVersionStep.cs} | 5 ++- 5 files changed, 56 insertions(+), 4 deletions(-) rename studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/{CommonPropsStep.cs => AssemblyVersionStep.cs} (77%) diff --git a/studio/src/Volo.Abp.Studio.Domain.CommonServices/Volo/Abp/Studio/Modifying/CsprojFileManager.cs b/studio/src/Volo.Abp.Studio.Domain.CommonServices/Volo/Abp/Studio/Modifying/CsprojFileManager.cs index c37321decf..a9f4227c34 100644 --- a/studio/src/Volo.Abp.Studio.Domain.CommonServices/Volo/Abp/Studio/Modifying/CsprojFileManager.cs +++ b/studio/src/Volo.Abp.Studio.Domain.CommonServices/Volo/Abp/Studio/Modifying/CsprojFileManager.cs @@ -92,6 +92,46 @@ public class CsprojFileManager : XmlFileManagerBase, ICsprojFileManager, ITransi await SaveXmlDocumentAsync(filePath, document); } + public async Task AddAssemblyVersionAsync(string filePath, string version) + { + var document = await GetXmlDocumentAsync(filePath); + + var matchedNodes = document.SelectNodes($"/Project/PropertyGroup"); + + if (matchedNodes.Count == 0) + { + return; + } + + var versionNode = document.CreateElement("Version"); + + versionNode.InnerText = version; + + matchedNodes[0].AppendChild(versionNode); + + await SaveXmlDocumentAsync(filePath, document); + } + + public async Task AddCopyLocalLockFileAssembliesAsync(string filePath) + { + var document = await GetXmlDocumentAsync(filePath); + + var matchedNodes = document.SelectNodes($"/Project/PropertyGroup"); + + if (matchedNodes.Count == 0) + { + return; + } + + var versionNode = document.CreateElement("CopyLocalLockFileAssemblies"); + + versionNode.InnerText = "True"; + + matchedNodes[0].AppendChild(versionNode); + + await SaveXmlDocumentAsync(filePath, document); + } + public async Task ConvertPackageReferenceToProjectReferenceAsync(string filePath, string projectToReference) { var document = await GetXmlDocumentAsync(filePath); diff --git a/studio/src/Volo.Abp.Studio.Domain.CommonServices/Volo/Abp/Studio/Modifying/ICsprojFileManager.cs b/studio/src/Volo.Abp.Studio.Domain.CommonServices/Volo/Abp/Studio/Modifying/ICsprojFileManager.cs index 287debad65..b0617f10f7 100644 --- a/studio/src/Volo.Abp.Studio.Domain.CommonServices/Volo/Abp/Studio/Modifying/ICsprojFileManager.cs +++ b/studio/src/Volo.Abp.Studio.Domain.CommonServices/Volo/Abp/Studio/Modifying/ICsprojFileManager.cs @@ -12,6 +12,10 @@ public interface ICsprojFileManager Task AddImportAsync(string filePath, string importFilePath); + Task AddAssemblyVersionAsync(string filePath, string version); + + Task AddCopyLocalLockFileAssembliesAsync(string filePath); + Task ConvertPackageReferenceToProjectReferenceAsync(string filePath, string projectToReference); diff --git a/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/ModuleInstallingPipelineBuilderBase.cs b/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/ModuleInstallingPipelineBuilderBase.cs index 5b3f953e1a..4c061ae87d 100644 --- a/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/ModuleInstallingPipelineBuilderBase.cs +++ b/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/ModuleInstallingPipelineBuilderBase.cs @@ -12,7 +12,7 @@ public abstract class ModuleInstallingPipelineBuilderBase if (context.WithSourceCode) { pipeline.Add(new SourceCodeDownloadStep()); - pipeline.Add(new CommonPropsStep()); + pipeline.Add(new AssemblyVersionStep()); if (context.AddToSolutionFile) { diff --git a/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/AddEfCoreConfigurationMethodStep.cs b/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/AddEfCoreConfigurationMethodStep.cs index 05e0d2073c..20caa109ba 100644 --- a/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/AddEfCoreConfigurationMethodStep.cs +++ b/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/AddEfCoreConfigurationMethodStep.cs @@ -36,7 +36,14 @@ public class AddEfCoreConfigurationMethodStep : ModuleInstallingPipelineStep foreach (var declaration in context.EfCoreConfigurationMethodDeclarations) { - _dbContextFileBuilderConfigureAdder.Add(dbContextFile, declaration.Namespace + ":" + declaration.MethodName); + try + { + _dbContextFileBuilderConfigureAdder.Add(dbContextFile, declaration.Namespace + ":" + declaration.MethodName); + } + catch (Exception e) + { + continue; + } } } } diff --git a/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/CommonPropsStep.cs b/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/AssemblyVersionStep.cs similarity index 77% rename from studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/CommonPropsStep.cs rename to studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/AssemblyVersionStep.cs index 519cc31c06..ecd83db1b1 100644 --- a/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/CommonPropsStep.cs +++ b/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/AssemblyVersionStep.cs @@ -5,7 +5,7 @@ using Volo.Abp.Studio.Packages.Modifying; namespace Volo.Abp.Studio.ModuleInstalling.Steps; -public class CommonPropsStep : ModuleInstallingPipelineStep +public class AssemblyVersionStep : ModuleInstallingPipelineStep { public async override Task ExecuteAsync(ModuleInstallingContext context) { @@ -23,7 +23,8 @@ public class CommonPropsStep : ModuleInstallingPipelineStep foreach (var csProjFile in csProjFiles) { - await _csprojFileManager.AddImportAsync(csProjFile, commonPropsFilePath); + await _csprojFileManager.AddAssemblyVersionAsync(csProjFile, context.Version); + await _csprojFileManager.AddCopyLocalLockFileAssembliesAsync(csProjFile); } } } From a281d5b07e6d1f69e7adedc3e0cf7d9b8a52d8a8 Mon Sep 17 00:00:00 2001 From: enisn Date: Mon, 3 Jan 2022 14:22:09 +0300 Subject: [PATCH 08/67] Add distributed cache prerequirement section to CMS Kit documentation --- docs/en/Modules/Cms-Kit/Index.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/en/Modules/Cms-Kit/Index.md b/docs/en/Modules/Cms-Kit/Index.md index 4c422b0bf3..e57bc3519a 100644 --- a/docs/en/Modules/Cms-Kit/Index.md +++ b/docs/en/Modules/Cms-Kit/Index.md @@ -18,6 +18,12 @@ Click to a feature to understand and learn how to use it. All features are individually usable. If you disable a feature, it completely disappears from your application, even from the database tables, by the help of the [Global Features](../../Global-Features.md) system. +## Pre Requirements + +CMS Kit uses [distributed cache](../../Caching.md) for responding faster. + +> Using a distributed cache such as [Redis](../../Redis-Cache.md) is highly recommented for data consistency. + ## How to Install > This module is depends on [BlobStoring](../../Blob-Storing.md) module, please install `BlobStoring` module first and add a provider. For more information, check the [documentation](../../Blob-Storing.md). From b51a9f21bc5c813d12678da0ad288cc61672a7dd Mon Sep 17 00:00:00 2001 From: enisn Date: Mon, 3 Jan 2022 14:24:09 +0300 Subject: [PATCH 09/67] Typo fix at CMS-Kit documentation --- docs/en/Modules/Cms-Kit/Index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Modules/Cms-Kit/Index.md b/docs/en/Modules/Cms-Kit/Index.md index e57bc3519a..cb2e341d16 100644 --- a/docs/en/Modules/Cms-Kit/Index.md +++ b/docs/en/Modules/Cms-Kit/Index.md @@ -22,7 +22,7 @@ All features are individually usable. If you disable a feature, it completely di CMS Kit uses [distributed cache](../../Caching.md) for responding faster. -> Using a distributed cache such as [Redis](../../Redis-Cache.md) is highly recommented for data consistency. +> Using a distributed cache such as [Redis](../../Redis-Cache.md) is highly recommended for data consistency. ## How to Install From e0e67a66dca04dd6550f6888cb4f187451fb49f5 Mon Sep 17 00:00:00 2001 From: enisn Date: Mon, 3 Jan 2022 14:26:53 +0300 Subject: [PATCH 10/67] Update Index.md --- docs/en/Modules/Cms-Kit/Index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Modules/Cms-Kit/Index.md b/docs/en/Modules/Cms-Kit/Index.md index cb2e341d16..fc28736a70 100644 --- a/docs/en/Modules/Cms-Kit/Index.md +++ b/docs/en/Modules/Cms-Kit/Index.md @@ -22,7 +22,7 @@ All features are individually usable. If you disable a feature, it completely di CMS Kit uses [distributed cache](../../Caching.md) for responding faster. -> Using a distributed cache such as [Redis](../../Redis-Cache.md) is highly recommended for data consistency. +> Using a distributed cache such as [Redis](../../Redis-Cache.md) is highly recommended for data consistency in tiered solutions. ## How to Install From f37988b1370477516dfcaa75737f54a5d7c773cc Mon Sep 17 00:00:00 2001 From: albert <9526587+ebicoglu@users.noreply.github.com> Date: Mon, 3 Jan 2022 17:07:07 +0300 Subject: [PATCH 11/67] Clearify HowManyProductsExplanation --- .../AbpIoLocalization/Commercial/Localization/Resources/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json index 6224c74049..d99821912d 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json @@ -172,7 +172,7 @@ "StartDevelopWithTutorials": "The downloaded solution is well architected and documented. You can start to develop your own business code based on it following the tutorials", "TryTheCommercialDemo": "You can try the demo to see a sample application created using the ABP Commercial startup template.", "HowManyProducts": "How many different products/solutions can I build using the ABP Commercial?", - "HowManyProductsExplanation": "There is no limit to create an ABP project. You can create as many project as you want, develop and upload them to different servers.", + "HowManyProductsExplanation": "You can create as many projects as you want during your active license period, there is no limit! After your license expires, you cannot create new projects, but you can continue to develop the projects you have downloaded and deploy them to an unlimited count of servers.", "HowManyDevelopers": "How many developers can work on the ABP Commercial?", "HowManyDevelopersExplanation": "ABP Commercial licenses are per developer. Different license types have different developer limits. However, you can add more developers to any license type whenever you need. See the prices page for license types, developer limits and additional developer costs.", "ChangingLicenseType": "Can I upgrade my license type later?", From 6e93d155ffcdeb7871d402b5b717588623ecdba5 Mon Sep 17 00:00:00 2001 From: braim23 <94292623+braim23@users.noreply.github.com> Date: Mon, 3 Jan 2022 17:42:28 +0300 Subject: [PATCH 12/67] Update Part-2.md --- docs/en/Tutorials/Part-2.md | 86 ++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/docs/en/Tutorials/Part-2.md b/docs/en/Tutorials/Part-2.md index 4b29231164..6d636d5ecb 100644 --- a/docs/en/Tutorials/Part-2.md +++ b/docs/en/Tutorials/Part-2.md @@ -13,7 +13,7 @@ In this tutorial series, you will build an ABP based web application named `Acme * **{{DB_Value}}** as the ORM provider. * **{{UI_Value}}** as the UI Framework. -This tutorial is organized as the following parts; +This tutorial is organized as the following parts: - [Part 1: Creating the server side](Part-1.md) - **Part 2: The book list page (this part)** @@ -53,7 +53,7 @@ This part is also recorded as a video tutorial and ** Razor Page** menu item. Name it as `Index`: +Create a `Books` folder under the `Pages` folder of the `Acme.BookStore.Web` project. Add a new Razor Page by right clicking the Books folder then selecting **Add > Razor Page** menu item. Name it as `Index`: ![bookstore-add-index-page](images/bookstore-add-index-page-v2.png) @@ -213,21 +213,21 @@ context.Menu.AddItem( ); ```` -Run the project, login to the application with the username `admin` and the password `1q2w3E*` and see the new menu item has been added to the main menu: +Run the project, login to the application with the username `admin` and the password `1q2w3E*` and you can see that the new menu item has been added to the main menu: ![bookstore-menu-items](images/bookstore-new-menu-item.png) -When you click to the Books menu item under the Book Store parent, you are being redirected to the new empty Books Page. +When you click on the Books menu item under the Book Store parent, you will be redirected to the new empty Books Page. ### Book List -We will use the [Datatables.net](https://datatables.net/) jQuery library to show the book list. Datatables library completely work via AJAX, it is fast, popular and provides a good user experience. +We will use the [Datatables.net](https://datatables.net/) jQuery library to show the book list. Datatables library completely works via AJAX, it is fast, popular and provides a good user experience. -> Datatables library is configured in the startup template, so you can directly use it in any page without including any style or script file to your page. +> Datatables library is configured in the startup template, so you can directly use it in any page without including any style or script file for your page. #### Index.cshtml -Change the `Pages/Books/Index.cshtml` as following: +Change the `Pages/Books/Index.cshtml` as the following: ````html @page @@ -250,8 +250,8 @@ Change the `Pages/Books/Index.cshtml` as following: ```` -* `abp-script` [tag helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro) is used to add external **scripts** to the page. It has many additional features compared to standard `script` tag. It handles **minification** and **versioning**. See the [bundling & minification document](../UI/AspNetCore/Bundling-Minification.md) for details. -* `abp-card` is a tag helper for Twitter Bootstrap's [card component](https://getbootstrap.com/docs/4.5/components/card/). There are other useful tag helpers provided by the ABP Framework to easily use most of the [bootstrap](https://getbootstrap.com/) components. You could use the regular HTML tags instead of these tag helpers, but using tag helpers reduces HTML code and prevents errors by help the of IntelliSense and compile time type checking. Further information, see the [tag helpers](../UI/AspNetCore/Tag-Helpers/Index.md) document. +* `abp-script` [tag helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro) is used to add external **scripts** to the page. It has many additional features compared to the standard `script` tag. It handles **minification** and **versioning**. Check the [bundling & minification document](../UI/AspNetCore/Bundling-Minification.md) for details. +* `abp-card` is a tag helper for Twitter Bootstrap's [card component](https://getbootstrap.com/docs/4.5/components/card/). There are other useful tag helpers provided by the ABP Framework to easily use most of [bootstrap](https://getbootstrap.com/)'s components. You could use the regular HTML tags instead of these tag helpers, but using tag helpers reduces HTML code and prevents errors by the help of the IntelliSense and compiles time type checking. For further information, check the [tag helpers](../UI/AspNetCore/Tag-Helpers/Index.md) document. #### Index.js @@ -316,9 +316,9 @@ $(function () { }); ```` -* `abp.localization.getResource` gets a function that is used to localize text using the same JSON file defined in the server side. In this way, you can share the localization values with the client side. +* `abp.localization.getResource` gets a function that is used to localize text using the same JSON file defined on the server side. In this way, you can share the localization values with the client side. * `abp.libs.datatables.normalizeConfiguration` is a helper function defined by the ABP Framework. There's no requirement to use it, but it simplifies the [Datatables](https://datatables.net/) configuration by providing conventional default values for missing options. -* `abp.libs.datatables.createAjax` is another helper function to adapt ABP's dynamic JavaScript API proxies to [Datatable](https://datatables.net/)'s expected parameter format +* `abp.libs.datatables.createAjax` is another helper function to adapt the ABP's dynamic JavaScript API proxies to the [Datatable](https://datatables.net/)'s expected parameter format * `acme.bookStore.books.book.getList` is the dynamic JavaScript proxy function introduced before. * [luxon](https://moment.github.io/luxon/) library is also a standard library that is pre-configured in the solution, so you can use to perform date/time operations easily. @@ -336,9 +336,9 @@ This is a fully working, server side paged, sorted and localized table of books. ## Install NPM packages -> Notice: This tutorial is based on the ABP Framework v3.1.0+ If your project version is older, then please upgrade your solution. See the [migration guide](../UI/Angular/Migration-Guide-v3.md) if you are upgrading an existing project with v2.x. +> Notice: This tutorial is based on the ABP Framework v3.1.0+ If your project version is older, then please upgrade your solution. Check the [migration guide](../UI/Angular/Migration-Guide-v3.md) if you are upgrading an existing project with v2.x. -If you haven't done it before, open a new command line interface (terminal window) and go to your `angular` folder and then run `yarn` command to install the NPM packages: +If you haven't done it before, open a new command line interface (terminal window) and go to your `angular` folder and then run the `yarn` command to install the NPM packages: ```bash yarn @@ -400,7 +400,7 @@ export class BookModule { } ### Routing -Generated code places the new route definition to the `src/app/app-routing.module.ts` file as shown below: +The generated code places the new route definition to the `src/app/app-routing.module.ts` file as shown below: ````js const routes: Routes = [ @@ -409,7 +409,7 @@ const routes: Routes = [ ]; ```` -Now, open the `src/app/route.provider.ts` file replace the `configureRoutes` function declaration as shown below: +Now, open the `src/app/route.provider.ts` file and replace the `configureRoutes` function declaration as shown below: ```js function configureRoutes(routes: RoutesService) { @@ -443,18 +443,18 @@ function configureRoutes(routes: RoutesService) { `RoutesService` is a service provided by the ABP Framework to configure the main menu and the routes. * `path` is the URL of the route. -* `name` is the localized menu item name (see the [localization document](../UI/Angular/Localization.md) for details). +* `name` is the localized menu item name (check the [localization document](../UI/Angular/Localization.md) for details). * `iconClass` is the icon of the menu item (you can use [Font Awesome](https://fontawesome.com/) icons by default). * `order` is the order of the menu item. * `layout` is the layout of the BooksModule's routes (there are three types of pre-defined layouts: `eLayoutType.application`, `eLayoutType.account` or `eLayoutType.empty`). -For more information, see the [RoutesService document](../UI/Angular/Modifying-the-Menu.md#via-routesservice). +For more information, check the [RoutesService document](../UI/Angular/Modifying-the-Menu.md#via-routesservice). ### Service Proxy Generation -[ABP CLI](../CLI.md) provides `generate-proxy` command that generates client proxies for your HTTP APIs to make easy to consume your HTTP APIs from the client side. Before running `generate-proxy` command, your host must be up and running. +[ABP CLI](../CLI.md) provides a `generate-proxy` command that generates client proxies for your HTTP APIs to make your HTTP APIs easy to consume by the client side. Before running the `generate-proxy` command, your host must be up and running. -> **Warning**: There is a problem with IIS Express; it doesn't allow to connect to the application from another process. If you are using Visual Studio, select the `Acme.BookStore.HttpApi.Host` instead of IIS Express in the run button drop-down list, as shown in the figure below: +> **Warning**: There is a problem with IIS Express; it doesn't allow connecting to the application from another process. If you are using Visual Studio, select the `Acme.BookStore.HttpApi.Host` instead of IIS Express in the run button drop-down list, as shown in the figure below: ![vs-run-without-iisexpress](images/vs-run-without-iisexpress.png) @@ -499,9 +499,9 @@ export class BookComponent implements OnInit { ``` * We imported and injected the generated `BookService`. -* We are using the [ListService](../UI/Angular/List-Service.md), a utility service of the ABP Framework which provides easy pagination, sorting and searching. +* We are using the [ListService](../UI/Angular/List-Service.md), a utility service from the ABP Framework which provides easy pagination, sorting and searching. -Open the `/src/app/book/book.component.html` and replace the content as below: +Open the `/src/app/book/book.component.html` and replace the content as shown below: ```html
@@ -546,7 +546,7 @@ Now you can see the final result on your browser: ## Create a Books Page -It's time to create something visible and usable! Right click to the `Pages` folder under the `Acme.BookStore.Blazor` project and add a new **razor component**, named `Books.razor`: +It's time to create something visible and usable! Right click on the `Pages` folder under the `Acme.BookStore.Blazor` project and add a new **razor component**, named `Books.razor`: ![blazor-add-books-component](images/blazor-add-books-component.png) @@ -562,7 +562,7 @@ Replace the contents of this component as shown below: } ```` -### Add Books Page to the Main Menu +### Add the Books Page to the Main Menu Open the `BookStoreMenuContributor` class in the `Blazor` project add the following code to the end of the `ConfigureMainMenuAsync` method: @@ -582,17 +582,17 @@ context.Menu.AddItem( ); ```` -Run the project, login to the application with the username `admin` and the password `1q2w3E*` and see the new menu item has been added to the main menu: +Run the project, login to the application with the username `admin` and the password `1q2w3E*` and see that the new menu item has been added to the main menu: ![blazor-menu-bookstore](images/blazor-menu-bookstore.png) -When you click to the Books menu item under the Book Store parent, you are being redirected to the new empty Books Page. +When you click on the Books menu item under the Book Store parent, you will be redirected to the new empty Books Page. ### Book List -We will use the [Blazorise library](https://blazorise.com/) as the UI component kit. It is a very powerful library that supports major HTML/CSS frameworks, including the Bootstrap. +We will use the [Blazorise library](https://blazorise.com/) as the UI component kit. It is a very powerful library that supports major HTML/CSS frameworks, including Bootstrap. -ABP Framework provides a generic base class, `AbpCrudPageBase<...>`, to create CRUD style pages. This base class is compatible to the `ICrudAppService` that was used to build the `IBookAppService`. So, we can inherit from the `AbpCrudPageBase` to automate the code behind for the standard CRUD stuff. +ABP Framework provides a generic base class - `AbpCrudPageBase<...>`, to create CRUD style pages. This base class is compatible with the `ICrudAppService` that was used to build the `IBookAppService`. So, we can inherit from the `AbpCrudPageBase` to automate the code behind for the standard CRUD stuff. Open the `Books.razor` and replace the content as the following: @@ -651,17 +651,17 @@ Open the `Books.razor` and replace the content as the following: ```` -> If you see some syntax errors, you can ignore them if your application properly built and run. Visual Studio still has some bugs with Blazor. +> If you see some syntax errors, you can ignore them if your application is properly built and running. Visual Studio still has some bugs with Blazor. -* Inherited from the `AbpCrudPageBase` which implements all the CRUD details for us. +* Inherited from `AbpCrudPageBase` which implements all the CRUD details for us. * `Entities`, `TotalCount`, `PageSize`, `OnDataGridReadAsync` are defined in the base class. * Injected `IStringLocalizer` (as `L` object) and used for localization. -While the code above pretty easy to understand, you can check the Blazorise [Card](https://blazorise.com/docs/components/card/) and [DataGrid](https://blazorise.com/docs/extensions/datagrid/) documents to understand them better. +While the code above is pretty easy to understand, you can check the Blazorise [Card](https://blazorise.com/docs/components/card/) and [DataGrid](https://blazorise.com/docs/extensions/datagrid/) documents to understand them better. #### About the AbpCrudPageBase -We will continue to benefit from the `AbpCrudPageBase` for the books page. You could just inject the `IBookAppService` and perform all the server side calls yourself (thanks to the [Dynamic C# HTTP API Client Proxy](../API/Dynamic-CSharp-API-Clients.md) system of the ABP Framework). We will do it manually for the authors page to demonstrate how to call server side HTTP APIs in your Blazor applications. +We will continue benefitting from `AbpCrudPageBase` for the books page. You could just inject the `IBookAppService` and perform all the server side calls yourself (thanks to the [Dynamic C# HTTP API Client Proxy](../API/Dynamic-CSharp-API-Clients.md) system of the ABP Framework). We will do it manually for the authors page to demonstrate how to call the server side HTTP APIs in your Blazor applications. ## Run the Final Application @@ -675,4 +675,4 @@ This is a fully working, server side paged, sorted and localized table of books. ## The Next Part -See the [next part](Part-3.md) of this tutorial. +Check the [next part](Part-3.md) of this tutorial. From f44022e23660804889f8c7b785789a4657db3678 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Tue, 4 Jan 2022 10:15:20 +0800 Subject: [PATCH 13/67] Run Gulp when gulpfile exist --- .../Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs index 4530b59142..e1a048b9e1 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs @@ -88,7 +88,7 @@ namespace Volo.Abp.Cli.ProjectModification RunYarn(fileDirectory); } - if (!IsAngularProject(fileDirectory)) + if (!IsAngularProject(fileDirectory) && GulpFileExistAsync(fileDirectory)) { Thread.Sleep(1000); RunGulp(fileDirectory); @@ -108,6 +108,11 @@ namespace Volo.Abp.Cli.ProjectModification return await Task.FromResult(File.Exists(Path.Combine(directoryName, ".npmrc"))); } + private static bool GulpFileExistAsync(string directoryName) + { + return File.Exists(Path.Combine(directoryName, "gulpfile.js")); + } + private async Task CreateNpmrcFileAsync(string directoryName) { var fileName = Path.Combine(directoryName, ".npmrc"); From d162b563bd7105e4faaf3657eead0ed5e3436f92 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 4 Jan 2022 11:42:51 +0800 Subject: [PATCH 14/67] Make more DTO classes extensible. --- .../Dtos/LimitedResultRequestDto.cs | 56 +++++++++++++++++-- .../Abp/Application/Dtos/ListResultDto.cs | 34 ++++++++++- .../Dtos/PagedAndSortedResultRequestDto.cs | 11 +++- .../Abp/Application/Dtos/PagedResultDto.cs | 32 ++++++++++- .../Application/Dtos/PagedResultRequestDto.cs | 12 +++- 5 files changed, 136 insertions(+), 9 deletions(-) diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/LimitedResultRequestDto.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/LimitedResultRequestDto.cs index 95c55174ad..eb646c5ceb 100644 --- a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/LimitedResultRequestDto.cs +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/LimitedResultRequestDto.cs @@ -39,14 +39,62 @@ namespace Volo.Abp.Application.Dtos yield return new ValidationResult( localizer[ - "MaxResultCountExceededExceptionMessage", + "MaxResultCountExceededExceptionMessage", nameof(MaxResultCount), - MaxMaxResultCount, - typeof(LimitedResultRequestDto).FullName, + MaxMaxResultCount, + typeof(LimitedResultRequestDto).FullName, nameof(MaxMaxResultCount) ], new[] { nameof(MaxResultCount) }); } } } -} \ No newline at end of file + + /// + /// Simply implements . + /// + [Serializable] + public class ExtensibleLimitedResultRequestDto : ExtensibleEntityDto, ILimitedResultRequest, IValidatableObject + { + /// + /// Default value: 10. + /// + public static int DefaultMaxResultCount { get; set; } = 10; + + /// + /// Maximum possible value of the . + /// Default value: 1,000. + /// + public static int MaxMaxResultCount { get; set; } = 1000; + + /// + /// Maximum result count should be returned. + /// This is generally used to limit result count on paging. + /// + [Range(1, int.MaxValue)] + public virtual int MaxResultCount { get; set; } = DefaultMaxResultCount; + + public override IEnumerable Validate(ValidationContext validationContext) + { + foreach(var result in base.Validate(validationContext)) + { + yield return result; + } + + if (MaxResultCount > MaxMaxResultCount) + { + var localizer = validationContext.GetRequiredService>(); + + yield return new ValidationResult( + localizer[ + "MaxResultCountExceededExceptionMessage", + nameof(MaxResultCount), + MaxMaxResultCount, + typeof(ExtensibleLimitedResultRequestDto).FullName, + nameof(MaxMaxResultCount) + ], + new[] { nameof(MaxResultCount) }); + } + } + } +} diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ListResultDto.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ListResultDto.cs index 6b3c897aa9..0dc9c56568 100644 --- a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ListResultDto.cs +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ListResultDto.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Volo.Abp.ObjectExtending; namespace Volo.Abp.Application.Dtos { @@ -19,7 +20,7 @@ namespace Volo.Abp.Application.Dtos /// public ListResultDto() { - + } /// @@ -31,4 +32,33 @@ namespace Volo.Abp.Application.Dtos Items = items; } } -} \ No newline at end of file + + [Serializable] + public class ExtensibleListResultDto : ExtensibleObject, IListResult + { + /// + public IReadOnlyList Items + { + get { return _items ?? (_items = new List()); } + set { _items = value; } + } + private IReadOnlyList _items; + + /// + /// Creates a new object. + /// + public ExtensibleListResultDto() + { + + } + + /// + /// Creates a new object. + /// + /// List of items + public ExtensibleListResultDto(IReadOnlyList items) + { + Items = items; + } + } +} diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/PagedAndSortedResultRequestDto.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/PagedAndSortedResultRequestDto.cs index 4f8d843046..1e87a6574a 100644 --- a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/PagedAndSortedResultRequestDto.cs +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/PagedAndSortedResultRequestDto.cs @@ -10,4 +10,13 @@ namespace Volo.Abp.Application.Dtos { public virtual string Sorting { get; set; } } -} \ No newline at end of file + + /// + /// Simply implements . + /// + [Serializable] + public class ExtensiblePagedAndSortedResultRequestDto : ExtensiblePagedResultRequestDto, IPagedAndSortedResultRequest + { + public virtual string Sorting { get; set; } + } +} diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/PagedResultDto.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/PagedResultDto.cs index b10d64211a..66348fc95d 100644 --- a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/PagedResultDto.cs +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/PagedResultDto.cs @@ -32,4 +32,34 @@ namespace Volo.Abp.Application.Dtos TotalCount = totalCount; } } -} \ No newline at end of file + + /// + /// Implements . + /// + /// Type of the items in the list + [Serializable] + public class ExtensiblePagedResultDto : ExtensibleListResultDto, IPagedResult + { + /// + public long TotalCount { get; set; } //TODO: Can be a long value..? + + /// + /// Creates a new object. + /// + public ExtensiblePagedResultDto() + { + + } + + /// + /// Creates a new object. + /// + /// Total count of Items + /// List of items in current page + public ExtensiblePagedResultDto(long totalCount, IReadOnlyList items) + : base(items) + { + TotalCount = totalCount; + } + } +} diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/PagedResultRequestDto.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/PagedResultRequestDto.cs index e028dd3f8d..6a05cceede 100644 --- a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/PagedResultRequestDto.cs +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/PagedResultRequestDto.cs @@ -12,4 +12,14 @@ namespace Volo.Abp.Application.Dtos [Range(0, int.MaxValue)] public virtual int SkipCount { get; set; } } -} \ No newline at end of file + + /// + /// Simply implements . + /// + [Serializable] + public class ExtensiblePagedResultRequestDto : ExtensibleLimitedResultRequestDto, IPagedResultRequest + { + [Range(0, int.MaxValue)] + public virtual int SkipCount { get; set; } + } +} From db01ccce1e48cbaf1faee27465f94877ee843ab8 Mon Sep 17 00:00:00 2001 From: Enis Necipoglu Date: Tue, 4 Jan 2022 08:04:27 +0300 Subject: [PATCH 15/67] Update docs/en/Modules/Cms-Kit/Index.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Halil İbrahim Kalkan --- docs/en/Modules/Cms-Kit/Index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Modules/Cms-Kit/Index.md b/docs/en/Modules/Cms-Kit/Index.md index fc28736a70..7d773973e0 100644 --- a/docs/en/Modules/Cms-Kit/Index.md +++ b/docs/en/Modules/Cms-Kit/Index.md @@ -22,7 +22,7 @@ All features are individually usable. If you disable a feature, it completely di CMS Kit uses [distributed cache](../../Caching.md) for responding faster. -> Using a distributed cache such as [Redis](../../Redis-Cache.md) is highly recommended for data consistency in tiered solutions. +> Using a distributed cache, such as [Redis](../../Redis-Cache.md), is highly recommended for data consistency in distributed/clustered deployments. ## How to Install From 470deed1d72bb5d1183847559c672cd91b5bb1ff Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Tue, 4 Jan 2022 15:18:25 +0800 Subject: [PATCH 16/67] Use Dynamic proxy in template by default --- .../MyCompanyName.MyProjectName.Web.Host.csproj | 2 +- .../MyProjectNameWebModule.cs | 3 +-- .../MyCompanyName.MyProjectName.Web.Host.csproj | 1 + .../MyProjectNameWebHostModule.cs | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj index 8ecfbf8fe7..c90a667f14 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj @@ -29,11 +29,11 @@ - + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs index 206e47abd9..31b20171bb 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs @@ -29,7 +29,6 @@ using Volo.Abp.AutoMapper; using Volo.Abp.Caching; using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.Http.Client.IdentityModel.Web; -using Volo.Abp.Http.Client.Web; using Volo.Abp.Identity.Web; using Volo.Abp.Modularity; using Volo.Abp.MultiTenancy; @@ -46,13 +45,13 @@ namespace MyCompanyName.MyProjectName.Web { [DependsOn( typeof(MyProjectNameHttpApiClientModule), + typeof(MyProjectNameHttpApiModule), typeof(AbpAspNetCoreAuthenticationOpenIdConnectModule), typeof(AbpAspNetCoreMvcClientModule), typeof(AbpAspNetCoreMvcUiBasicThemeModule), typeof(AbpAutofacModule), typeof(AbpCachingStackExchangeRedisModule), typeof(AbpSettingManagementWebModule), - typeof(AbpHttpClientWebModule), typeof(AbpHttpClientIdentityModelWebModule), typeof(AbpIdentityWebModule), typeof(AbpTenantManagementWebModule), diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj index 9536fdce15..29ab15443c 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj @@ -34,6 +34,7 @@ + diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs index df87db8359..58c5b42c7a 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs @@ -34,7 +34,6 @@ using Volo.Abp.Caching; using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.FeatureManagement; using Volo.Abp.Http.Client.IdentityModel.Web; -using Volo.Abp.Http.Client.Web; using Volo.Abp.Identity; using Volo.Abp.Identity.Web; using Volo.Abp.Modularity; @@ -55,12 +54,12 @@ namespace MyCompanyName.MyProjectName [DependsOn( typeof(MyProjectNameWebModule), typeof(MyProjectNameHttpApiClientModule), + typeof(MyProjectNameHttpApiModule), typeof(AbpAspNetCoreAuthenticationOpenIdConnectModule), typeof(AbpAspNetCoreMvcClientModule), typeof(AbpAspNetCoreMvcUiBasicThemeModule), typeof(AbpAutofacModule), typeof(AbpCachingStackExchangeRedisModule), - typeof(AbpHttpClientWebModule), typeof(AbpHttpClientIdentityModelWebModule), typeof(AbpIdentityWebModule), typeof(AbpIdentityHttpApiClientModule), From f3e25dc756f4779e54e6b39e31e9b71fc1848e04 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 4 Jan 2022 16:04:32 +0800 Subject: [PATCH 17/67] Update Authorization.md --- docs/en/Authorization.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/en/Authorization.md b/docs/en/Authorization.md index 66fded1a29..d96879c296 100644 --- a/docs/en/Authorization.md +++ b/docs/en/Authorization.md @@ -428,7 +428,7 @@ This is already done for the startup template integration tests. Claims are important elements of authentication and authorization. ABP uses the `IAbpClaimsPrincipalFactory` service to create claims on authentication. This service was designed as extensible. If you need to add your custom claims to the authentication ticket, you can implement the `IAbpClaimsPrincipalContributor` in your application. -**Example: Add a `SocialSecurityNumber` claim:** +**Example: Add a `SocialSecurityNumber` claim and get it:** ```csharp public class SocialSecurityNumberClaimsPrincipalContributor : IAbpClaimsPrincipalContributor, ITransientDependency @@ -448,6 +448,15 @@ public class SocialSecurityNumberClaimsPrincipalContributor : IAbpClaimsPrincipa } } } + + +public static class CurrentUserExtensions +{ + public static stromg GetSocialSecurityNumber(ICurrentUser currentUser) + { + return currentUser.FindClaimValue("SocialSecurityNumber"); + } +} ``` ## See Also From 18762d08e6f11688e5dccdd1460b1a294b48e6a8 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 4 Jan 2022 16:05:05 +0800 Subject: [PATCH 18/67] Update Authorization.md --- docs/en/Authorization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Authorization.md b/docs/en/Authorization.md index d96879c296..0d27d08403 100644 --- a/docs/en/Authorization.md +++ b/docs/en/Authorization.md @@ -452,7 +452,7 @@ public class SocialSecurityNumberClaimsPrincipalContributor : IAbpClaimsPrincipa public static class CurrentUserExtensions { - public static stromg GetSocialSecurityNumber(ICurrentUser currentUser) + public static string GetSocialSecurityNumber(ICurrentUser currentUser) { return currentUser.FindClaimValue("SocialSecurityNumber"); } From 80d1687f96a05852879b7f765ef46707ac3eea92 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 4 Jan 2022 16:08:46 +0800 Subject: [PATCH 19/67] Add this to the extension method. --- docs/en/Authorization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Authorization.md b/docs/en/Authorization.md index 0d27d08403..199b73d1c8 100644 --- a/docs/en/Authorization.md +++ b/docs/en/Authorization.md @@ -452,7 +452,7 @@ public class SocialSecurityNumberClaimsPrincipalContributor : IAbpClaimsPrincipa public static class CurrentUserExtensions { - public static string GetSocialSecurityNumber(ICurrentUser currentUser) + public static string GetSocialSecurityNumber(this ICurrentUser currentUser) { return currentUser.FindClaimValue("SocialSecurityNumber"); } From 00511943ed88501026c19160d4614378d507efd7 Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Tue, 4 Jan 2022 13:33:43 +0300 Subject: [PATCH 20/67] Set version from MicrosoftPackageVersion variable. Manual version breaks nightly builds. --- .../Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj index 918ac8ddf3..23ef9a5f0c 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj @@ -20,7 +20,7 @@ - + From 775acd13a173519183c787cd928d08b35e81fcbb Mon Sep 17 00:00:00 2001 From: Enis Necipoglu Date: Tue, 4 Jan 2022 13:40:57 +0300 Subject: [PATCH 21/67] Update CMSKit document --- docs/en/Modules/Cms-Kit/Index.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/en/Modules/Cms-Kit/Index.md b/docs/en/Modules/Cms-Kit/Index.md index 7d773973e0..46ecaad8c8 100644 --- a/docs/en/Modules/Cms-Kit/Index.md +++ b/docs/en/Modules/Cms-Kit/Index.md @@ -19,15 +19,14 @@ Click to a feature to understand and learn how to use it. All features are individually usable. If you disable a feature, it completely disappears from your application, even from the database tables, by the help of the [Global Features](../../Global-Features.md) system. ## Pre Requirements +- This module depends on [BlobStoring](../../Blob-Storing.md) module for keeping media content. +> Make sure `BlobStoring` module is installed and at leats one provider is configured properly. For more information, check the [documentation](../../Blob-Storing.md). -CMS Kit uses [distributed cache](../../Caching.md) for responding faster. - +- CMS Kit uses [distributed cache](../../Caching.md) for responding faster. > Using a distributed cache, such as [Redis](../../Redis-Cache.md), is highly recommended for data consistency in distributed/clustered deployments. ## How to Install -> This module is depends on [BlobStoring](../../Blob-Storing.md) module, please install `BlobStoring` module first and add a provider. For more information, check the [documentation](../../Blob-Storing.md). - [ABP CLI](../../CLI.md) allows installing a module to a solution using the `add-module` command. You can install the CMS Kit module in a command-line terminal with the following command: ```bash @@ -77,4 +76,4 @@ All tables/collections use the `Cms` prefix by default. Set static properties on This module uses `CmsKit` for the connection string name. If you don't define a connection string with this name, it fallbacks to the `Default` connection string. -See the [connection strings](https://docs.abp.io/en/abp/latest/Connection-Strings) documentation for details. \ No newline at end of file +See the [connection strings](https://docs.abp.io/en/abp/latest/Connection-Strings) documentation for details. From 7cc6dea0ea7aaba708df01e600c3cf59aecb1c85 Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Tue, 4 Jan 2022 14:04:50 +0300 Subject: [PATCH 22/67] remove already referenced package references by third party libs --- .../Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj | 1 - .../Volo.Abp.EntityFrameworkCore.Oracle.csproj | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj index 23ef9a5f0c..3bb22e24d8 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj @@ -20,7 +20,6 @@ - diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo.Abp.EntityFrameworkCore.Oracle.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo.Abp.EntityFrameworkCore.Oracle.csproj index abfb6e41a1..7d99c2035b 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo.Abp.EntityFrameworkCore.Oracle.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo.Abp.EntityFrameworkCore.Oracle.csproj @@ -19,8 +19,7 @@ - - + From 5504de63d286b5edc55ce7c04b95d3c3b61f84d5 Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Tue, 4 Jan 2022 15:24:55 +0300 Subject: [PATCH 23/67] Delete 0 --- nupkg/0 | Bin 8 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 nupkg/0 diff --git a/nupkg/0 b/nupkg/0 deleted file mode 100644 index cf175e3b0b668a96032b3e0d45584039f893e6a0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8 PcmezW&wzoKfr|kE5LyC7 From ff722325c2819600d4f59ef7974381bdf47ca8e1 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Tue, 4 Jan 2022 20:56:57 +0800 Subject: [PATCH 24/67] Update AbpCrudPageBase.cs --- framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs b/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs index bcd07221e4..f5d06f5ba1 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs @@ -350,6 +350,7 @@ public abstract class AbpCrudPageBase< protected virtual Task CloseCreateModalAsync() { + NewEntity = new TCreateViewModel(); return InvokeAsync(CreateModal.Hide); } @@ -464,6 +465,7 @@ public abstract class AbpCrudPageBase< protected virtual async Task OnCreatedEntityAsync() { + NewEntity = new TCreateViewModel(); await GetEntitiesAsync(); await InvokeAsync(CreateModal.Hide); From fc4473177e8acf3ede69bd8d50290f023554c353 Mon Sep 17 00:00:00 2001 From: Afresh Date: Tue, 4 Jan 2022 22:51:23 +0800 Subject: [PATCH 25/67] Rename Tentant-Management.md & Translate Tenant-Management.md --- docs/zh-Hans/Modules/Tenant-Management.md | 107 ++++++++++++++++++ docs/zh-Hans/Modules/Tentant-Management.md | 3 - docs/zh-Hans/images/features-modal.png | Bin 35412 -> 19528 bytes .../module-tenant-management-actions.png | Bin 0 -> 14401 bytes .../module-tenant-management-new-tenant.png | Bin 0 -> 18657 bytes .../images/module-tenant-management-page.png | Bin 0 -> 31934 bytes 6 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 docs/zh-Hans/Modules/Tenant-Management.md delete mode 100644 docs/zh-Hans/Modules/Tentant-Management.md create mode 100644 docs/zh-Hans/images/module-tenant-management-actions.png create mode 100644 docs/zh-Hans/images/module-tenant-management-new-tenant.png create mode 100644 docs/zh-Hans/images/module-tenant-management-page.png diff --git a/docs/zh-Hans/Modules/Tenant-Management.md b/docs/zh-Hans/Modules/Tenant-Management.md new file mode 100644 index 0000000000..7aa7ba1de7 --- /dev/null +++ b/docs/zh-Hans/Modules/Tenant-Management.md @@ -0,0 +1,107 @@ +# 租户管理模块 + +[多租户](../Multi-Tenancy.md) 是 ABP 框架的核心功能之一. 它提供了构建 SaaS (软件及服务) 解决方案的基础架构. ABP 的多租户系统通过提供 `ITenantStore` 接口来抽象租户存储的位置. 您需要做的就是实现该接口. + +**租户管理模块就是 `ITenantStore` 接口的实现. 它将租户存储在数据库中. 它还提供了 UI 来管理你的租户及其 [功能](../Features.md).** + +> 请参阅 [多租户](../Multi-Tenancy.md) 文档,以了解 ABP 框架的多租户系统. 本文重点介绍租户管理模块. + +### 关于商业版 SaaS 模块 + +[SaaS 模块](https://commercial.abp.io/modules/Volo.Saas) 是本模块的替代实现, 具有更多的功能和可能性. 它作为 [ABP 商业版](https://commercial.abp.io/) 订阅的一部分分发. + +## 如何安装 + +当你使用 ABP 框架 [创建一个新的解决方案](https://abp.io/get-started) 时,此模块将被预安装(作为 NuGet/NPM 包)。你可以继续用其作为包并轻松地获取更新,也可以将其源代码包含在解决方案中(请参阅 `get-source` [CLI](../CLI.md))以开发自定义模块。 + +### 源代码 + +可以 [在此处](https://github.com/abpframework/abp/tree/dev/modules/identity) 访问源代码。源代码使用 [MIT](https://choosealicense.com/licenses/mit/) 许可, 所以你可以免费使用和自定义它. + +## 用户界面 + +此模块将 "管理 -> 租户管理 -> 租户" 菜单项添加到应用程序的主菜单, 这将打开如下页面: + +![租户管理页面](../images/module-tenant-management-page.png) + +在这个页面中, 你可以查看所有租户. 你可以按照如下所示创建一个新的租户: + +![租户管理新增租户](../images/module-tenant-management-new-tenant.png) + +在这个模态框中; + +* **Name**: 租户唯一的名称. 如果为租户使用二级域名, 这将是二级域名名称. +* **Admin Email Address**: 租户管理员的邮件地址. +* **Admin Password**: 租户管理员的密码. + +当您点击租户附近的 *操作* 按钮时, 您将看见可以执行的操作: + +![租户管理操作](../images/module-tenant-management-actions.png) + +### 管理租户功能 + +功能操作会打开一个模态框, 来关于租户的启用/禁用/设置 [功能](../Features.md). 这有一个模态框的例子: + +![功能模态框](../images/features-modal.png) + +### 管理主机功能 + +如果您使用应用程序的功能也在主机端, *管理主机功能* 按钮则用于设置主机端的功能. + +## 内部结构 + +如果要 [自定义](../Customizing-Application-Modules-Guide.md) 此模块而不更改 [其源代码](https://github.com/abpframework/abp/tree/dev/modules/tenant-management), 则可以将此节作为参考. + +### 领域层 + +#### 聚合 + +* `Tenant` + +#### 仓储 + +* `ITenantRepository` + +#### 领域服务 + +* `TenantManager` + +### 应用层 + +#### 应用服务 + +* `TenantAppService` + +#### 权限 + +- `AbpTenantManagement.Tenants`: 租户管理. +- `AbpTenantManagement.Tenants.Create`: 创建一个新的租户. +- `AbpTenantManagement.Tenants.Update`: 编辑一个已存在的租户. +- `AbpTenantManagement.Tenants.Delete`: 删除一个已存在的租户. +- `AbpTenantManagement.Tenants.ManageFeatures`: 管理租户的功能. + +### EF Core 集成 + +* `TenantManagementDbContext` (实现了 `ITenantManagementDbContext`) + +**数据库表:** + +* `AbpTenants` +* `AbpTenantConnectionStrings` + +### MongoDB 集成 + +* `TenantManagementMongoDbContext` (实现了 `ITenantManagementMongoDbContext`) + +**数据库集合:** + +* `AbpTenants` (也包括连接字符串) + +## 注意事项 + +ABP 框架允许租户有专用的数据库, 以允许 *每个租户一个数据库*. 此模块具有使该实现成为可能 (查阅其源代码) 的基础架构, 但是它没有实现应用程序层和 UI 功能以使其开箱即用. 您可以自己实现这些功能, 也可以考虑使用已完全实现这些功能并提供了更多业务功能的 [ABP 商业版 Saas 模块](https://docs.abp.io/en/commercial/latest/modules/saas). + +## 另请参见 + +* [多租户](../Multi-Tenancy.md) +* [ABP 商业版 SaaS 模块](https://docs.abp.io/en/commercial/latest/modules/saas) diff --git a/docs/zh-Hans/Modules/Tentant-Management.md b/docs/zh-Hans/Modules/Tentant-Management.md deleted file mode 100644 index fa999428dd..0000000000 --- a/docs/zh-Hans/Modules/Tentant-Management.md +++ /dev/null @@ -1,3 +0,0 @@ -# 租户管理模块 - -TODO \ No newline at end of file diff --git a/docs/zh-Hans/images/features-modal.png b/docs/zh-Hans/images/features-modal.png index 74ee8aabc33189a420f3205ddc0c90215e5767c9..0fce7ecf5cfc4360a7a8d77f4e759e184fec0185 100644 GIT binary patch literal 19528 zcmdSBby!qU)HjNPbb}%t3P_`Lr+|bY-6<{I1H;fQh;(!#L(R!-2y`lF!zA( z`##_O?jN_l`#kSGf1TN9pMBP@wSMcj)}C;c_p&&cWSB@uNI380q*alSPzaEa9+jb^ z0wsxG@s^R0Xpr7XOQ?IM?=Rx{OiX4RAudpCkm&vBBfgY>3fp|aSaKHa|?mLT+pn@-IC^D6R)%0r;C$YjFwUAPQxlWHI; z!_KLTrG}nH-nhXc6B3f&duiYUZO{ZV_aSk59^UN^C~rMQyG^nx+W9Hio9RZt_J!Mc z#m*QtY{!Ffak$Z>n~(eE)NBrJ7(@gLER)?UjN0RN^()$#K`Lo4lqnL6ETTR2jh-60 zBXKJf9P=jQm$lTmos!7d)*c4BDHw$R2niHdHpcDysk!n!Z{R!w*nRindJ!_!A7v~1 z8LHZ=0tw4@$=V+BD4TN%lxWU{h~f1A8dY*8JzH{&l)-jxH+-#_=lb0P*AtCD@S0r4 zW;;nT8tn9*QOptb(&-6$G~_KoU#yQoUhTs5eRRmqV$T@ckE&*AQhXQ~g3JaGYgi{QQu(M$LLE56*> z=*=G5_+ASSSIL-tchD&b$)r>6^H8HCHKkx77lAIBn;FPB#Q(JYm)D}vUF(7KlV!M* zL>&TF2~9)VELDENYR%8IJhO}qUfz`0fO>s|4Y9k=7!@Q(~R& zh?YC=Ldeq{;CLT;gA_A3Yxp0VM3_8&ddl^D^0KM@Ihivq5|TK{_5}XwSb>6#jg9kN zT73zZ12Pg=?Qar~pjmzhLxx(LLq6yo$*$-GyaUdQpQ zfWggLB(6J+hL--Pk(9ad(i>nLAFj_+8f2onZpPYvJNj46lPNqklvxuRT8&%F~B8UCQf~jOydw ze3dT7zomb9BlG$BSra1t)h)bZD;@4ja5W>aMY1`VBsv*vj992d26k*@-}((C=Iht5 zrdjikGKlE7d3M$c6jDXOshgr_U+gnn%TRGBW|$ftv_v+C5M(uAX%3#qD~4!w-=8V* zWsp0rZ9&&m&onW5uXM@nA4$St^LyAHYxRT(+tN&8?-n^|*QPshDr}r1`KOp0W}{Q`W1L zXD|pwiMoh)1--t@XyHcGGCqHJy3LxEDOB_!Z)~y(vNk~DEt80FzfbFYS$;jFct z$Kev*LqYa5jr79}k|sK!se#MyspP-9#=*e;xWBY%{~J}=`AIAJ*}YP)$a4B%?8LoZ z^M3hB z>e#U=YKp7YQ#ZlOB@?jo=tff{PAMo)af5Mg{9m`5lkN-_{q1*5Ki7+B<~y4g9~ZIk z*d-$z!5gBK!~LU|64hzN^J=+_(|6Jx!VATJ<_nDM2Gu|v&;#E4Z?F8lEP`A!f-hG? zQ+e%Dzt_~vPs*5^7q}lTl#J%d?#(aXxd(X92!Q0mR7xgwu9&0UQauV_Pq&zO&Sok| zE2#DOwS|=xSn>yDHLXW`J}y^ZM`-+gmRNcMONd2&#C2+Xp)mIiN=+sATfPmPlWFLT z_UK_*p3(J1Q>vMn! zh}i}q$K~gN@!XO-@s&&4x7T||2_?*V;v8+Q+C%{Z&!Bw8ONy-g9eQG|cHzDy*leJ4 z9+5Yir7USh>E=)GPEkKkE}oLu_-1OQ_|xN;&KIp2eD2R6aK^rua%4R?^bwaOG>Y_P z?N%!6`I|GF^S!J~FJuu52FXvKOF?EeyqZCjq91Zd<|wc~@c*Qy;}#6OeQI9nj7y&d zQHW9Mc#CFB{z6~9!V+O$i zitM@o1V2`Yq2eI!zO#N*L%ed^IFABGBPD}A7Fce*61n_V-%CxQpONz}&SfqH9r>n) zh@qf>$4IPX+dzZlXZv{mYnHR4qP_ExL2R6v4KdhnMw~YiGL7rh?R)T40UJ;Ks(WOI zG{V(`NeEK#Gd|13rwyo8p9Z0Kkv=w&bz8Vvol1|K+-3tc_lQa5I7z2gU9NFVSEyWH z34_g~9c==~r-Z6@g1`QNUKpB3+h4HUH;3fv5*rY7eB|v6w77)7DqYtO^+`!*Z@Vhoq`q5X1+vq!!sg~=*dV{&f!7C!)-R$brI{RRY&tVr& z9-0JwwUP)J9Y;pVy9hyl^!s4WGS~~WU-3oic8uFjBL$a)r}(aQ z;8qQlWwt=`pQ^vWz#|L*NdfZA;pZIAd{~}NOhr49)9nA lzn&9(x1`KGQ^esH= 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 bBJ8LBM)mhByb?L(Ak#cu{an^LB{Ts5YhR2+ literal 35412 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 Q7XuJ@y85}Sb4q9e0P>=`F8}}l diff --git a/docs/zh-Hans/images/module-tenant-management-actions.png b/docs/zh-Hans/images/module-tenant-management-actions.png new file mode 100644 index 0000000000000000000000000000000000000000..899e731f8c7134fa01878944868d1ad08aef0044 GIT binary patch literal 14401 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 literal 0 HcmV?d00001 diff --git a/docs/zh-Hans/images/module-tenant-management-new-tenant.png b/docs/zh-Hans/images/module-tenant-management-new-tenant.png new file mode 100644 index 0000000000000000000000000000000000000000..7f0f50b42a73768ea907ab9d8281edb97e562dc7 GIT binary patch literal 18657 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 H=H)*DISdMm literal 0 HcmV?d00001 From f3e241d9d32455b320309472307e15ecac04ebbe Mon Sep 17 00:00:00 2001 From: Afresh Date: Tue, 4 Jan 2022 23:02:40 +0800 Subject: [PATCH 26/67] Update Tenant-Management.md translations --- docs/zh-Hans/Modules/Tenant-Management.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/zh-Hans/Modules/Tenant-Management.md b/docs/zh-Hans/Modules/Tenant-Management.md index 7aa7ba1de7..8f214f9a33 100644 --- a/docs/zh-Hans/Modules/Tenant-Management.md +++ b/docs/zh-Hans/Modules/Tenant-Management.md @@ -2,13 +2,13 @@ [多租户](../Multi-Tenancy.md) 是 ABP 框架的核心功能之一. 它提供了构建 SaaS (软件及服务) 解决方案的基础架构. ABP 的多租户系统通过提供 `ITenantStore` 接口来抽象租户存储的位置. 您需要做的就是实现该接口. -**租户管理模块就是 `ITenantStore` 接口的实现. 它将租户存储在数据库中. 它还提供了 UI 来管理你的租户及其 [功能](../Features.md).** +**租户管理模块是 `ITenantStore` 接口的实现. 它将租户存储在数据库中. 它还提供了 UI 来管理租户及其 [功能](../Features.md).** > 请参阅 [多租户](../Multi-Tenancy.md) 文档,以了解 ABP 框架的多租户系统. 本文重点介绍租户管理模块. ### 关于商业版 SaaS 模块 -[SaaS 模块](https://commercial.abp.io/modules/Volo.Saas) 是本模块的替代实现, 具有更多的功能和可能性. 它作为 [ABP 商业版](https://commercial.abp.io/) 订阅的一部分分发. +[SaaS 模块](https://commercial.abp.io/modules/Volo.Saas) 是此模块的替代实现, 具有更多的功能和可能性. 它作为 [ABP 商业版](https://commercial.abp.io/) 订阅的一部分分发. ## 如何安装 @@ -30,9 +30,9 @@ 在这个模态框中; -* **Name**: 租户唯一的名称. 如果为租户使用二级域名, 这将是二级域名名称. -* **Admin Email Address**: 租户管理员的邮件地址. -* **Admin Password**: 租户管理员的密码. +* **租户名称**: 租户唯一的名称. 如果为租户使用二级域名, 这将是二级域名名称. +* **管理员电子邮件地址**: 租户管理员的电子邮件地址. +* **管理员密码**: 租户管理员的密码. 当您点击租户附近的 *操作* 按钮时, 您将看见可以执行的操作: @@ -40,7 +40,7 @@ ### 管理租户功能 -功能操作会打开一个模态框, 来关于租户的启用/禁用/设置 [功能](../Features.md). 这有一个模态框的例子: +功能操作会打开一个模态框, 来对相关租户进行启用/禁用/设置 [功能](../Features.md). 这有一个模态框的例子: ![功能模态框](../images/features-modal.png) @@ -99,7 +99,7 @@ ## 注意事项 -ABP 框架允许租户有专用的数据库, 以允许 *每个租户一个数据库*. 此模块具有使该实现成为可能 (查阅其源代码) 的基础架构, 但是它没有实现应用程序层和 UI 功能以使其开箱即用. 您可以自己实现这些功能, 也可以考虑使用已完全实现这些功能并提供了更多业务功能的 [ABP 商业版 Saas 模块](https://docs.abp.io/en/commercial/latest/modules/saas). +ABP 框架允许租户有专用的数据库, 以允许 *每个租户用一个数据库*. 此模块具有使该实现成为可能 (查阅其源代码) 的基础架构, 但是它没有实现应用程序层和 UI 功能以使其开箱即用. 您可以自己实现这些功能, 也可以考虑使用已完全实现这些功能并提供了更多业务功能的 [ABP 商业版 Saas 模块](https://docs.abp.io/en/commercial/latest/modules/saas). ## 另请参见 From 3ab1f8a82e2342d81111b16e28ce453a4aacb0b7 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 5 Jan 2022 15:32:54 +0800 Subject: [PATCH 27/67] Build and test all projects. --- .github/workflows/build-and-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 2eba8b7118..0210efcec9 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -41,12 +41,12 @@ jobs: dotnet-version: 6.0.100 - name: Build All - run: .\build-all.ps1 + run: .\build-all.ps1 -f working-directory: .\build shell: powershell - name: Test All - run: .\test-all.ps1 + run: .\test-all.ps1 -f working-directory: .\build shell: powershell From e0b59618455e2b778e72668d44ae0150ba6ce834 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 5 Jan 2022 15:34:04 +0800 Subject: [PATCH 28/67] Update ICssMinifier.cs --- .../src/Volo.Abp.Minify/Volo/Abp/Minify/Styles/ICssMinifier.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.Minify/Volo/Abp/Minify/Styles/ICssMinifier.cs b/framework/src/Volo.Abp.Minify/Volo/Abp/Minify/Styles/ICssMinifier.cs index 4e231ca0e4..799d4117f0 100644 --- a/framework/src/Volo.Abp.Minify/Volo/Abp/Minify/Styles/ICssMinifier.cs +++ b/framework/src/Volo.Abp.Minify/Volo/Abp/Minify/Styles/ICssMinifier.cs @@ -4,4 +4,4 @@ namespace Volo.Abp.Minify.Styles { } -} \ No newline at end of file +} From e4ddd7d47c286e6d71791fb398dc22a69708e1d7 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Wed, 5 Jan 2022 15:52:27 +0800 Subject: [PATCH 29/67] Support proxy class --- .../HangfireBackgroundWorkerManager.cs | 3 ++- .../Quartz/QuartzBackgroundWorkerManager.cs | 3 ++- .../QuartzPeriodicBackgroundWorkerAdapter.cs | 7 ++++--- .../Volo/Abp/DynamicProxy/ProxyHelper.cs | 20 ++++++++++++++++--- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs index 2a9cb33a10..f9ff0eb4aa 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; using Hangfire; using Volo.Abp.DependencyInjection; +using Volo.Abp.DynamicProxy; using Volo.Abp.Threading; namespace Volo.Abp.BackgroundWorkers.Hangfire @@ -64,7 +65,7 @@ namespace Volo.Abp.BackgroundWorkers.Hangfire return; } - var adapterType = typeof(HangfirePeriodicBackgroundWorkerAdapter<>).MakeGenericType(worker.GetType()); + var adapterType = typeof(HangfirePeriodicBackgroundWorkerAdapter<>).MakeGenericType(ProxyHelper.GetUnProxiedType(worker)); var workerAdapter = Activator.CreateInstance(adapterType) as IHangfireBackgroundWorker; RecurringJob.AddOrUpdate(() => workerAdapter.DoWorkAsync(), GetCron(period.Value)); diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs index 582a7dd520..a2b51e0177 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs @@ -3,6 +3,7 @@ using System.Threading; using System.Threading.Tasks; using Quartz; using Volo.Abp.DependencyInjection; +using Volo.Abp.DynamicProxy; using Volo.Abp.Threading; namespace Volo.Abp.BackgroundWorkers.Quartz @@ -56,7 +57,7 @@ namespace Volo.Abp.BackgroundWorkers.Quartz } else { - var adapterType = typeof(QuartzPeriodicBackgroundWorkerAdapter<>).MakeGenericType(worker.GetType()); + var adapterType = typeof(QuartzPeriodicBackgroundWorkerAdapter<>).MakeGenericType(ProxyHelper.GetUnProxiedType(worker)); var workerAdapter = Activator.CreateInstance(adapterType) as IQuartzBackgroundWorkerAdapter; diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzPeriodicBackgroundWorkerAdapter.cs b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzPeriodicBackgroundWorkerAdapter.cs index 16286d3153..582370b192 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzPeriodicBackgroundWorkerAdapter.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzPeriodicBackgroundWorkerAdapter.cs @@ -2,6 +2,7 @@ using System.Reflection; using System.Threading.Tasks; using Quartz; +using Volo.Abp.DynamicProxy; using Volo.Abp.Threading; namespace Volo.Abp.BackgroundWorkers.Quartz @@ -26,16 +27,16 @@ namespace Volo.Abp.BackgroundWorkers.Quartz public void BuildWorker(IBackgroundWorker worker) { int? period; - var workerType = worker.GetType(); + var workerType = ProxyHelper.GetUnProxiedType(worker); if (worker is AsyncPeriodicBackgroundWorkerBase or PeriodicBackgroundWorkerBase) { - if (typeof(TWorker) != worker.GetType()) + if (typeof(TWorker) != workerType) { throw new ArgumentException($"{nameof(worker)} type is different from the generic type"); } - var timer = worker.GetType().GetProperty("Timer", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(worker); + var timer = workerType.GetProperty("Timer", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(worker); if (worker is AsyncPeriodicBackgroundWorkerBase) { diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/ProxyHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/ProxyHelper.cs index db7ff4b869..1f5db0b071 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/ProxyHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/ProxyHelper.cs @@ -7,9 +7,9 @@ namespace Volo.Abp.DynamicProxy public static class ProxyHelper { private const string ProxyNamespace = "Castle.Proxies"; - + /// - /// Returns dynamic proxy target object if this is a proxied object, otherwise returns the given object. + /// Returns dynamic proxy target object if this is a proxied object, otherwise returns the given object. /// It supports Castle Dynamic Proxies. /// public static object UnProxy(object obj) @@ -33,7 +33,21 @@ namespace Volo.Abp.DynamicProxy public static Type GetUnProxiedType(object obj) { - return UnProxy(obj).GetType(); + if (obj.GetType().Namespace == ProxyNamespace) + { + var target = UnProxy(obj); + if (target != null) + { + if (target == obj) + { + return obj.GetType().GetTypeInfo().BaseType; + } + + return target.GetType(); + } + } + + return obj.GetType(); } } } From 8178d4756275fa3a59fa8d96d7f1c4f801e89f8c Mon Sep 17 00:00:00 2001 From: Hamza Albreem <94292623+braim23@users.noreply.github.com> Date: Wed, 5 Jan 2022 11:25:22 +0300 Subject: [PATCH 30/67] Update FAQ --- .../Commercial/Localization/Resources/en.json | 84 +++++++++---------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json index d99821912d..a5251b601e 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json @@ -155,82 +155,82 @@ "WeAreHereToHelp": "We are Here to Help", "BrowseOrAskQuestion": "You can browse our help topics or search in frequently asked questions, or you can ask us a question by using the contact form.", "SearchQuestionPlaceholder": "Search in frequently asked questions", - "WhatIsTheABPCommercial": "What is the ABP Commercial?", - "WhatAreDifferencesThanAbpFramework": "What are the differences between the open source ABP Framework and the ABP Commercial?", - "ABPCommercialExplanation": "ABP Commercial is a set of premium modules, tools, themes and services built on top of the open source ABP framework. ABP Commercial is being developed and supported by the same team behind the ABP framework.", - "WhatAreDifferencesThanABPFrameworkExplanation": "

ABP framework is a modular, themeable, micro-service compatible application development framework for ASP.NET Core. It provides a complete architecture and a strong infrastructure to make you focusing on your own business code rather than repeating yourself for every new project. It is based on software development best practices and popular tools you already know.

ABP framework is completely free, open source and community-driven. It also provides a free theme and some pre-built modules (e.g. identity management and tenant management).

", - "VisitTheFrameworkVSCommercialDocument": "Visit the following link, for more information {1} ", - "ABPCommercialFollowingBenefits": "ABP Commercial adds the following benefits on top of the ABP framework;", + "WhatIsTheABPCommercial": "What is ABP Commercial?", + "WhatAreDifferencesThanAbpFramework": "What are the differences between the open source ABP Framework and ABP Commercial?", + "ABPCommercialExplanation": "ABP Commercial is a set of premium modules, tools, themes and services that are built on top of the open source ABP framework. ABP Commercial is being developed and supported by the same team behind the ABP framework.", + "WhatAreDifferencesThanABPFrameworkExplanation": "

ABP framework is a modular, themeable, micro-service compatible application development framework for ASP.NET Core. It provides a complete architecture and a strong infrastructure to let you focus on your own business code rather than repeating yourself for every new project. It is based on the best practices of software development and popular tools you already know.

ABP framework is completely free, open source and community-driven. It also provides a free theme and some pre-built modules (e.g. identity management and tenant management).

", + "VisitTheFrameworkVSCommercialDocument": "Visit the following link for more information {1} ", + "ABPCommercialFollowingBenefits": "ABP Commercial adds the following benefits on top of the ABP framework:", "Professional": "Professional", - "UIThemes": "UI themes", - "EnterpriseModules": "Enterprise ready, feature rich, pre-built application modules (e.g. Identity Server management, SaaS management, language management)", + "UIThemes": "UI Themes", + "EnterpriseModules": "Enterprise ready, feature rich, pre-built Application Modules (e.g. Identity Server management, SaaS management, language management)", "ToolingToSupport": "Tooling to support your development productivity (e.g. ABP Suite)", - "PremiumSupportLink": "Premium support", + "PremiumSupportLink": "Premium Support", "WhatDoIDownloadABPCommercial": "What do I download when I purchase the ABP Commercial?", "CreateUnlimitedSolutions": "Once you purchase an ABP Commercial license, you will be able to create unlimited solutions like described in the Getting Started document.", - "ABPCommercialSolutionExplanation": "When you create a new application, you get a Visual Studio solution (a startup template) based on your preferences. The downloaded solution has commercial modules and themes already installed and configured for you. You can remove a pre-installed module or add another module if you like. All modules and themes are used a NuGet/NPM packages by default.", - "StartDevelopWithTutorials": "The downloaded solution is well architected and documented. You can start to develop your own business code based on it following the tutorials", - "TryTheCommercialDemo": "You can try the demo to see a sample application created using the ABP Commercial startup template.", + "ABPCommercialSolutionExplanation": "When you create a new application, you get a Visual Studio solution (a startup template) based on your preferences. The downloaded solution has commercial modules and themes already installed and configured for you. You can remove a pre-installed module or add another module if you like. All modules and themes use NuGet/NPM packages by default.", + "StartDevelopWithTutorials": "The downloaded solution is well architected and documented. You can start developing your own business code based on it following the tutorials.", + "TryTheCommercialDemo": "You can try the Live Demo to see a sample application created using the ABP Commercial startup template.", "HowManyProducts": "How many different products/solutions can I build using the ABP Commercial?", "HowManyProductsExplanation": "You can create as many projects as you want during your active license period, there is no limit! After your license expires, you cannot create new projects, but you can continue to develop the projects you have downloaded and deploy them to an unlimited count of servers.", "HowManyDevelopers": "How many developers can work on the ABP Commercial?", - "HowManyDevelopersExplanation": "ABP Commercial licenses are per developer. Different license types have different developer limits. However, you can add more developers to any license type whenever you need. See the prices page for license types, developer limits and additional developer costs.", + "HowManyDevelopersExplanation": "ABP Commercial licenses are per developer. Different license types have different developer limits. However, you can add more developers to any license type whenever you need. Check out the Plans & Pricing page for license types, developer limits and additional developer costs.", "ChangingLicenseType": "Can I upgrade my license type later?", - "ChangingLicenseTypeExplanation": "You can upgrade to a higher license by paying the difference within your active license period. When you upgrade to a higher license plan, you get the benefits of the new plan, but the license upgrade does not change the license expiry date. Besides, you can also add new developer seats to your existing license, see \"How many developers can work on the ABP Commercial?\"", + "ChangingLicenseTypeExplanation": "You can upgrade to a higher license by paying the difference within your active license period. When you upgrade to a higher license plan, you get the benefits of the new plan, but the license upgrade does not change the license expiry date. Besides, you can also add new developer seats to your existing license, check out the \"How many developers can work on the ABP Commercial?\" FAQ.", "LicenseExtendUpgradeDiff": "What is the difference between license extend and upgrade?", - "LicenseExtendUpgradeDiffExplanation": "Extending: By extending/renewing your license, you will continue to get premium support and get major updates for the modules and themes. Besides, you will be able to continue creating new projects. And you will still be able to use ABP Suite which speeds up your development. When you extend your license, 1 year is added to your license expiry date.
Upgrading: By upgrading your license, you will promote to a higher license plan which will allow you to get additional benefits. See the license comparison table to check the differences between the license plans.On the other hand, when you upgrade, your license expiry date will not change!To extend your license end date, you need to extend your license.", + "LicenseExtendUpgradeDiffExplanation": "Extending: By extending/renewing your license, you will continue to get premium support and get major updates for the modules and themes. Besides, you will be able to continue creating new projects. And you will still be able to use ABP Suite which speeds up your development. When you extend your license, 1 year is added to your license expiry date.
Upgrading: By upgrading your license, you will promote to a higher license plan which will allow you to get additional benefits. Check out the license comparison table to see the differences between the license plans. On the other hand, when you upgrade, your license expiry date will not change! To extend your license end date, you need to extend your license.", "LicenseRenewalCost": "What is the license renewal cost after 1 year?", - "LicenseRenewalCostExplanation": "The renewal (extend) price of the standard Team License is ${0}, standard Business License is ${1} and standard Enterprise License is ${2}. If you are already a customer, log into your account to review the available renewal pricing.", + "LicenseRenewalCostExplanation": "The renewal (extend) price of the standard Team License is ${0}, standard Business License is ${1} and standard Enterprise License is ${2}. If you are already a customer, log into your account to review the current renewal pricing.", "HowDoIRenewMyLicense": "How do I renew my license?", - "HowDoIRenewMyLicenseExplanation": "You can renew your license by navigating to the organization management page. In order to take advantage of our discounted Early Renewal rates, make sure you renew before your license expires. Don't worry about not knowing when your Early Renewal opportunity closes, however. You'll receive 3 reminder e-mails before your subscription expires. We'll send them at 30 days, 7 days and 1 day before expiration.", + "HowDoIRenewMyLicenseExplanation": "You can renew your license by navigating to the organization management page. In order to take advantage of our discounted Early Renewal rates, make sure you renew before your license expires. Don't worry about not knowing when your Early Renewal opportunity closes, you'll however receive 3 reminder e-mails before your subscription expires. We'll send them 30 days, 7 days and 1 day before expiration.", "IsSourceCodeIncluded": "Does my license include the source code of the commercial modules and themes?", "IsSourceCodeIncludedExplanation1": "Depends on the license type you've purchased:", - "IsSourceCodeIncludedExplanation2": "Team: Your solution uses the modules and the themes as NuGet and NPM packages. It doesn't include their source code. In this way, you can easily upgrade these modules and themes whenever a new version is available. However, you can not get the source code of the modules and the themes.", + "IsSourceCodeIncludedExplanation2": "Team: Your solution uses the modules and themes as NuGet and NPM packages. It doesn't include their source code. In this way, you can easily upgrade these modules and themes whenever a new version is available. However, you can not get the source code of these modules and themes.", "IsSourceCodeIncludedExplanation3": "Business/Enterprise: In addition to the Team license, you are able to download the source code of any module or theme you need. You can even remove the NuGet/NPM package references for a particular module and add its source code directly to your solution to fully change it.", - "IsSourceCodeIncludedExplanation4": "

Including the source code of a module to your solution gives you the maximum freedom to customize that module. However, then it will not be possible to automatically upgrade the module when a new version is released.

None of the licenses include the ABP Suite source code, which is an external tool that generates code for you and assist to your development.

See the pricing page for other differences between the license types.

", + "IsSourceCodeIncludedExplanation4": "

Including the source code of a module to your solution gives you the maximum freedom to customize that module. However, it will then not be possible to automatically upgrade the module when a new version is released.

None of the licenses include the ABP Suite source code, which is an external tool that generates code for you and assists your development.

Check out the Plans & Pricing page for other differences between the license types.

", "ChangingDevelopers": "Can I change the registered developers of my organization in the future?", - "ChangingDevelopersExplanation": "In addition to add new developers to your license, you can also change the existing developers (you can remove a developer and add a new one to the same seat) without any additional cost.", + "ChangingDevelopersExplanation": "In addition to adding new developers to your license, you can also change the existing developers (you can remove a developer and add a new one to the same seat) without any additional cost.", "WhatHappensWhenLicenseEnds": "What happens when my license period ends?", - "WhatHappensWhenLicenseEndsExplanation1": "ABP Commercial license type is perpetual license. After your license expires, you can continue developing your project. And you are not obliged to renew your license. Your license comes with a one-year update and support plan out of the box. To continue to get new features, performance enhancements, bug fixes, support and continue to use ABP Suite, you need to renew your license. When your license expires, you will not get the following benefits;", - "WhatHappensWhenLicenseEndsExplanation2": "You can not create new solutions using the ABP Commercial, but you can continue to develop your existing applications forever.", - "WhatHappensWhenLicenseEndsExplanation3": "You will be able to get updates for the modules and themes within your MAJOR version (except RC or Preview versions). For example; if you are using v3.2.0 of a module, you can still get updates for v3.x.x (v3.3.0, v3.5.2... etc.) of that module. But you cannot get updates for the next major version (like v4.x, v5.x). For example, when your license expired, the latest release was v4.4.3 and the latest preview version was v5.0.0-rc.2, you can access the v4.X.X but you cannot access the v5.X.X.", + "WhatHappensWhenLicenseEndsExplanation1": "The ABP Commercial license is a perpetual license. After your license expires, you can continue developing your project. And you are not obliged to renew your license. Your license comes with a one-year update and support plan out of the box. In order to continue to get new features, performance enhancements, bug fixes, support and continue using ABP Suite, you need to renew your license. When your license expires, you will not get the following benefits:", + "WhatHappensWhenLicenseEndsExplanation2": "You can not create new solutions using the ABP Commercial, but you can continue developing your existing applications forever.", + "WhatHappensWhenLicenseEndsExplanation3": "You will be able to get updates for the modules and themes within your MAJOR version (except RC or Preview versions). For example: if you are using v3.2.0 of a module, you can still get updates for v3.x.x (v3.3.0, v3.5.2... etc.) of that module. But you cannot get updates for the next major version (like v4.x, v5.x). For example, when your license expired, the latest release was v4.4.3 and the latest preview version was v5.0.0-rc.2, you would be able to access the v4.X.X but you wouldn't be access the v5.X.X.", "WhatHappensWhenLicenseEndsExplanation4": "You can not install new modules and themes added to the ABP Commercial platform after your license ends.", "WhatHappensWhenLicenseEndsExplanation5": "You can not use the ABP Suite.", "WhatHappensWhenLicenseEndsExplanation6": "You can not get the premium support anymore.", - "WhatHappensWhenLicenseEndsExplanation7": "You can extend (renew) your license if you want to continue to get these benefits. If you extend your license within 1 month after your license expires, the following discounts will be applied: Team License {0}% discount, Business License {1}% discount, Enterprise License {2}% discount.", + "WhatHappensWhenLicenseEndsExplanation7": "You can extend (renew) your license if you want to continue getting these benefits. If you extend your license within 1 month after your license expires, the following discounts will be applied: Team License {0}% discount, Business License {1}% discount, Enterprise License {2}% discount.", "WhenShouldIRenewMyLicense": "When should I renew my license?", - "WhenShouldIRenewMyLicenseExplanation": "If you renew your license within 1 month after your license expires, the following discounts will be applied: Team License {0}% discount, Business License {1}% discount, Enterprise License {2}% discount. If you renew your license 1 month after the expiry date of your license, the renewal price will be the same as the license purchase price and there will be no discount on your renewal.", + "WhenShouldIRenewMyLicenseExplanation": "If you renew your license within 1 month after your license expires, the following discounts will be applied: Team License {0}% discount, Business License {1}% discount, Enterprise License {2}% discount. However, if you renew your license after 1 month since the expiry date of your license, the renewal price will be the same as the license purchase price and there will be no discount on your renewal.", "TrialPlan": "Do you have a trial plan?", "TrialPlanExplanation": "For now, ABP Commercial doesn't have a trial plan. For the Team licenses we provide 30 days money back guarantee. You can just request a refund in the first 30 days. For the Business and Enterprise licenses, we provide 60% refund in 30 days. This is because Business and Enterprise licenses include the full source code of all the modules and the themes.", - "DoYouAcceptBankWireTransfer": "Do you accept bank wire transfer?", - "DoYouAcceptBankWireTransferExplanation": "Yes, we accept bank wire transfer.
After sending the license fee via bank transfer, email us at accounting@abp.io your receipt and the type of license requested. Our international bank account information:", + "DoYouAcceptBankWireTransfer": "Do you accept bank wire transfers?", + "DoYouAcceptBankWireTransferExplanation": "Yes, we accept bank wire transfers.
After sending the license fee via bank transfer, email us your receipt and the type of license requested at accounting@abp.io, here's our international bank account information:", "HowToUpgrade": "How to upgrade existing applications when a new version is available?", - "HowToUpgradeExplanation1": "When you create a new application using ABP Commercial, all the modules and the theme are used as NuGet and NPM packages. So, you can easily upgrade the packages when a new version is available.", + "HowToUpgradeExplanation1": "When you create a new application using ABP Commercial, all the modules and theme are used as NuGet and NPM packages. So, you can easily upgrade the packages when a new version is available.", "HowToUpgradeExplanation2": "In addition to the standard NuGet/NPM upgrades, ABP CLI provides an update command that automatically finds and upgrades all ABP related packages in your solution.", "DatabaseSupport": "Which database systems are supported?", - "DatabaseSupportExplanation": "ABP Framework itself is database agnostic and can work with any database provider by its nature. See the data access document for a list of currently implemented providers.", + "DatabaseSupportExplanation": "ABP Framework itself is database agnostic and can work with any database provider by its nature. Check out the Data Access document for a list of currently implemented providers.", "UISupport": "Which UI frameworks are supported?", "Supported": "Supported", - "UISupportExplanation": "ABP Framework itself is UI framework agnostic and can work with any UI framework. However, startup templates, module UIs and themes were not implemented for all UI frameworks. See the getting started document for the up-to-date list of UI options.", + "UISupportExplanation": "ABP Framework itself is UI framework agnostic and can work with any UI framework. However, startup templates, module UIs and themes were not implemented for all UI frameworks. Check out the Getting Started document for the up-to-date list of UI options.", "MicroserviceSupport": "Does it support the micro-service architecture?", - "MicroserviceSupportExplanation1": "One of the major goals of the ABP framework is to provide a convenient infrastructure to create micro-service solutions. See the micro-service architecture document to understand how it helps to create micro-service systems.", - "MicroserviceSupportExplanation2": "All the ABP Commercial modules are designed to support micro-service deployment scenarios (with its own API and database) by following the module development best practices document.", - "MicroserviceSupportExplanation3": "We provide a sample micro-service demo solutionthat demonstrates a micro-service architecture implementation to help you to create your own solution.", - "MicroserviceSupportExplanation4": "So, the short answer is \"yes, it supports micro-service architecture\".", + "MicroserviceSupportExplanation1": "One of the major goals of the ABP framework is to provide a convenient infrastructure to create micro-service solutions. Check out the Micro-service Architecture document to understand how it helps with creating micro-service systems.", + "MicroserviceSupportExplanation2": "All the ABP Commercial modules are designed to support micro-service deployment scenarios (with its own API and database) by following the Module Development Best Practices document.", + "MicroserviceSupportExplanation3": "We provide a sample Micro-service Demo Solution that demonstrates a micro-service architecture implementation to help you create your own solution.", + "MicroserviceSupportExplanation4": "So, the short answer is: \"Yes, it supports micro-service architecture\".", "MicroserviceSupportExplanation5": "However, a micro-service system is a solution and every solution will have different requirements, network topology, communication scenarios, authentication possibilities, database separation/sharing decisions, runtime configurations, 3rd party system integrations and many more.", - "MicroserviceSupportExplanation6": "The ABP Framework and the ABP Commercial provides infrastructure for micro-service scenarios, micro-service compatible modules, samples and documentation to help you to build your own solution. But don't expect to directly download your dream solution pre-built for you. You will need to understand it and bring some parts together based on your requirements.", - "WhereCanIDownloadSourceCode": "Where can I download source-code?", - "WhereCanIDownloadSourceCodeExplanation": "You can download the source code of all ABP modules, Angular packages and themes via ABP Suite or ABP CLI. See How to download source-code?", + "MicroserviceSupportExplanation6": "The ABP Framework and ABP Commercial provide infrastructure for micro-service scenarios, micro-service compatible modules, samples and documentation to help you build your own solution. But don't expect to directly download your dream solution pre-built for you. You will need to understand it and bring specific parts together based on your requirements.", + "WhereCanIDownloadSourceCode": "Where can I download the source-code?", + "WhereCanIDownloadSourceCodeExplanation": "You can download the source code of all the ABP modules, Angular packages and themes via ABP Suite or ABP CLI. Check out How to download the source-code?", "ComputerLimitation": "How many computers can a developer login when developing ABP?", "ComputerLimitationExplanation": "We specifically permit {0} computers per individual/licensed developer. Whenever there is a need for a developer to develop ABP Commercial products on a third machine, an e-mail should be sent to license@abp.io explaining the situation and we will then make the appropriate allocation in our system.", "RefundPolicy": "Do you have a refund policy?", - "RefundPolicyExplanation": "You can request a refund within 30 days of your license purchase. The Business and Enterprise license types have source-code download option, therefore refunds are not available for the Business and Enterprise (and any licenses that include a right to receive source-code). In addition, no refunds are made for renewals and second license purchases.", + "RefundPolicyExplanation": "You can request a refund within 30 days of your license purchase. The Business and Enterprise license types have source-code download option, therefore refunds are not available for the Business and Enterprise (along with any licenses that include a right to receive source-code). In addition, no refunds are made for renewals and second license purchases.", "HowCanIRefundVat": "How can I refund VAT?", "HowCanIRefundVatExplanation1": "If you made the payment using 2Checkout, you can refund VAT via your 2Checkout account:", - "HowCanIRefundVatExplanation2": "Log in into your 2Checkout account", + "HowCanIRefundVatExplanation2": "Log in to your 2Checkout account", "HowCanIRefundVatExplanation3": "Find the appropriate order and press \"Refund Belated VAT\" (enter your VAT ID)", "HowCanIGetMyInvoice": "How can I get my invoice?", - "HowCanIGetMyInvoiceExplanation": "There are 2 payment gateways for purchasing a license: Iyzico and 2Checkout. If you purchase your license through the 2Checkout gateway, it sends the PDF invoice to your email address, see 2Checkout invoicing. If you purchase through the Iyzico gateway, with custom purchase link or via bank wire transfer, we will prepare and send your invoice. You can request or download your invoice from the organization management page. Before contacting us for the invoice, check your organization management page!", + "HowCanIGetMyInvoiceExplanation": "There are 2 payment gateways for purchasing a license: Iyzico and 2Checkout. If you purchase your license through the 2Checkout gateway, it sends the PDF invoice to your email address, check out 2Checkout invoicing. If you purchase through the Iyzico gateway, with a custom purchase link or via a bank wire transfer, we will prepare and send your invoice. You can request or download your invoice from the organization management page. Before contacting us for the invoice, check your organization management page!", "Forum": "Forum", "SupportExplanation": "ABP Commercial licenses provides a premium forum support by a team consists of the ABP Framework experts.", "PrivateTicket": "Private Ticket", @@ -289,7 +289,7 @@ "PrivateTicketEmailSupport": "Private ticket & email support", "BuyNow": "Buy Now", "PayViaAmexCard": "How can I pay via my AMEX card?", - "PayViaAmexCardDescription": "The default payment gateway 'Iyzico' may decline some AMEX credit cards due to the security measures. In this case, you can pay through the alternative payment gateway '2Checkout'.", + "PayViaAmexCardDescription": "The default payment gateway 'Iyzico' may decline some AMEX credit cards due to security measures. In this case, you can pay through the alternative payment gateway '2Checkout'.", "ThankYou": "Thank you", "InvalidReCaptchaErrorMessage": "There was an error verifying reCAPTCHA. Please try again.", "CompanyName": "Company name", @@ -391,7 +391,7 @@ "TrialLicenseExpiredInfo": "Your trial license period has expired!", "CommercialNewsletterConfirmationMessage": "I agree to the Terms & Conditions and Privacy Policy.", "DowngradeLicensePlan": "Can I downgrade to a lower license plan in the future?", - "DowngradeLicensePlanExplanation": "You cannot downgrade your existing license plan. But you can purchase a new lower license plan and continue to your development on the new license. After you purchase a lower license, you just need to login to your new license plan via ABP CLI command: ` abp login -o `.", + "DowngradeLicensePlanExplanation": "You cannot downgrade your existing license plan. But you can purchase a new lower license plan and continue your development on the new license. After you purchase a lower license, you just need to login to your new license plan via ABP CLI command: ` abp login -o `.", "LicenseTransfer": "Can a license be transferred from one developer to another?", "LicenseTransferExplanation": "Yes! When you purchase a license, you become the license holder, hence you will have access to the organization management page. An organization has owner and developer roles. Owners can manage the developer seats and assign developers. Each assigned developer will login via ABP CLI command into the system and will have development and support permissions.", "UserOwnerDescription": "The 'Owner' of the organization is the admin of this account. He/she manages the organization by purchasing licenses, allocating developers. An 'Owner' cannot write code in the ABP Commercial projects, cannot download the ABP sample projects, or cannot ask questions on the support website. If you want to do all these, you have to add yourself as a developer too.", From 8ded6446321ee284bb5fc80a9b90fc5f1e9c456f Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Wed, 5 Jan 2022 17:12:38 +0800 Subject: [PATCH 31/67] Update HangfireBackgroundWorkerManager.cs --- .../Hangfire/HangfireBackgroundWorkerManager.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs index f9ff0eb4aa..e6745e977b 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs @@ -26,14 +26,14 @@ namespace Volo.Abp.BackgroundWorkers.Hangfire { if (worker is IHangfireBackgroundWorker hangfireBackgroundWorker) { + var unProxyWorker = ProxyHelper.UnProxy(hangfireBackgroundWorker); if (hangfireBackgroundWorker.RecurringJobId.IsNullOrWhiteSpace()) { - RecurringJob.AddOrUpdate(() => hangfireBackgroundWorker.DoWorkAsync(), - hangfireBackgroundWorker.CronExpression); + RecurringJob.AddOrUpdate(() => ((IHangfireBackgroundWorker)unProxyWorker).DoWorkAsync(),hangfireBackgroundWorker.CronExpression); } else { - RecurringJob.AddOrUpdate(hangfireBackgroundWorker.RecurringJobId,() => hangfireBackgroundWorker.DoWorkAsync(), + RecurringJob.AddOrUpdate(hangfireBackgroundWorker.RecurringJobId,() => ((IHangfireBackgroundWorker)unProxyWorker).DoWorkAsync(), hangfireBackgroundWorker.CronExpression); } } From 5fd645bfabc4ed81a7dd309a6459f27adc7bb7ef Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Wed, 5 Jan 2022 17:43:51 +0800 Subject: [PATCH 32/67] update docucment --- docs/en/Background-Workers-Hangfire.md | 30 +++++++++++++++++++++ docs/zh-Hans/Background-Workers-Hangfire.md | 30 +++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/docs/en/Background-Workers-Hangfire.md b/docs/en/Background-Workers-Hangfire.md index e1e6fc71ad..2ea7fd633e 100644 --- a/docs/en/Background-Workers-Hangfire.md +++ b/docs/en/Background-Workers-Hangfire.md @@ -66,6 +66,33 @@ public class MyLogWorker : HangfireBackgroundWorkerBase > You can directly implement the `IHangfireBackgroundWorker`, but `HangfireBackgroundWorkerBase` provides some useful properties like Logger. +### UnitOfWork + +For use with `UnitOfWorkAttribute`, you need to define an interface for worker: + +```csharp +public interface IMyLogWorker : IHangfireBackgroundWorker +{ +} + +[ExposeServices(typeof(IMyLogWorker))] +public class MyLogWorker : HangfireBackgroundWorkerBase, IMyLogWorker +{ + public MyLogWorker() + { + RecurringJobId = nameof(MyLogWorker); + CronExpression = Cron.Daily(); + } + + [UnitOfWork] + public override Task DoWorkAsync() + { + Logger.LogInformation("Executed MyLogWorker..!"); + return Task.CompletedTask; + } +} +``` + ## Register BackgroundWorkerManager After creating a background worker class, you should add it to the `IBackgroundWorkerManager`. The most common place is the `OnApplicationInitialization` method of your module class: @@ -78,6 +105,9 @@ public class MyModule : AbpModule ApplicationInitializationContext context) { context.AddBackgroundWorker(); + + //If the interface is defined + //context.AddBackgroundWorker(); } } ```` diff --git a/docs/zh-Hans/Background-Workers-Hangfire.md b/docs/zh-Hans/Background-Workers-Hangfire.md index bd63ff91e9..5e53928ca1 100644 --- a/docs/zh-Hans/Background-Workers-Hangfire.md +++ b/docs/zh-Hans/Background-Workers-Hangfire.md @@ -67,6 +67,33 @@ public class MyLogWorker : HangfireBackgroundWorkerBase > 你可以直接实现 `IHangfireBackgroundWorker`, 但是 `HangfireBackgroundWorkerBase` 提供了一些有用的属性,例如 `Logger`. +### UnitOfWork + +使用 `UnitOfWorkAttribute` 你需要为工作者定义一个接口: + +```csharp +public interface IMyLogWorker : IHangfireBackgroundWorker +{ +} + +[ExposeServices(typeof(IMyLogWorker))] +public class MyLogWorker : HangfireBackgroundWorkerBase, IMyLogWorker +{ + public MyLogWorker() + { + RecurringJobId = nameof(MyLogWorker); + CronExpression = Cron.Daily(); + } + + [UnitOfWork] + public override Task DoWorkAsync() + { + Logger.LogInformation("Executed MyLogWorker..!"); + return Task.CompletedTask; + } +} +``` + ## 注册到后台工作者管理器 创建一个后台工作者后, 你应该添加到 `IBackgroundWorkerManager`, 最常用的地方是在你模块类的 `OnApplicationInitialization` 方法中: @@ -79,6 +106,9 @@ public class MyModule : AbpModule ApplicationInitializationContext context) { context.AddBackgroundWorker(); + + //如果定义了接口 + //context.AddBackgroundWorker(); } } ```` From 5dfca00c452d723a7a847c609a714fc5d84f8d45 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 5 Jan 2022 18:25:39 +0800 Subject: [PATCH 33/67] Add Web module as `CompiledRazorAssemblyPart`. Resolve #11183 --- .../MyProjectNameWebTestModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestModule.cs b/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestModule.cs index 8f7b9e2daa..15244f7e4b 100644 --- a/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestModule.cs +++ b/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestModule.cs @@ -27,7 +27,7 @@ namespace MyCompanyName.MyProjectName { context.Services.PreConfigure(builder => { - builder.PartManager.ApplicationParts.Add(new AssemblyPart(typeof(MyProjectNameWebModule).Assembly)); + builder.PartManager.ApplicationParts.Add(new CompiledRazorAssemblyPart(typeof(MyProjectNameWebModule).Assembly)); }); } From b7d59cb8147e5215bf75a6fb5a5d73158df331e3 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 5 Jan 2022 20:27:33 +0800 Subject: [PATCH 34/67] Update QuartzBackgroundWorkerManager.cs --- .../BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs index f7b2c17c69..060afd3ac6 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs @@ -34,9 +34,9 @@ public class QuartzBackgroundWorkerManager : IBackgroundWorkerManager, ISingleto } } - public virtual void Add(IBackgroundWorker worker) + public virtual async Task AddAsync(IBackgroundWorker worker) { - AsyncHelper.RunSync(() => ReScheduleJobAsync(worker)); + await ReScheduleJobAsync(worker); } protected virtual async Task ReScheduleJobAsync(IBackgroundWorker worker) From 3aee2f00dc23e429cd1eff8c04784b3210903324 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 5 Jan 2022 20:28:53 +0800 Subject: [PATCH 35/67] Update HangfireBackgroundWorkerManager.cs --- .../Hangfire/HangfireBackgroundWorkerManager.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs index ba6c9d83ba..2a4e0277cf 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs @@ -22,7 +22,7 @@ public class HangfireBackgroundWorkerManager : IBackgroundWorkerManager, ISingle return Task.CompletedTask; } - public void Add(IBackgroundWorker worker) + public Task AddAsync(IBackgroundWorker worker) { if (worker is IHangfireBackgroundWorker hangfireBackgroundWorker) { @@ -57,12 +57,12 @@ public class HangfireBackgroundWorkerManager : IBackgroundWorkerManager, ISingle } else { - return; + return Task.CompletedTask; } if (period == null) { - return; + return Task.CompletedTask; } var adapterType = typeof(HangfirePeriodicBackgroundWorkerAdapter<>).MakeGenericType(ProxyHelper.GetUnProxiedType(worker)); From b3757ad43742f1916ca559fd203d30f4105e6b9b Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 5 Jan 2022 20:29:31 +0800 Subject: [PATCH 36/67] Update HangfireBackgroundWorkerManager.cs --- .../Hangfire/HangfireBackgroundWorkerManager.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs index 2a4e0277cf..8449dc3df0 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs @@ -70,6 +70,8 @@ public class HangfireBackgroundWorkerManager : IBackgroundWorkerManager, ISingle RecurringJob.AddOrUpdate(() => workerAdapter.DoWorkAsync(), GetCron(period.Value)); } + + return Task.CompletedTask; } protected virtual string GetCron(int period) From bdb7db1f754a54d1d6facbe73995493833dd11e5 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Wed, 5 Jan 2022 21:24:36 +0800 Subject: [PATCH 37/67] Enhance handleAbpErrorResponse --- npm/packs/jquery/src/abp.jquery.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/npm/packs/jquery/src/abp.jquery.js b/npm/packs/jquery/src/abp.jquery.js index 81ebf1e2e1..4ae0d8cf64 100644 --- a/npm/packs/jquery/src/abp.jquery.js +++ b/npm/packs/jquery/src/abp.jquery.js @@ -204,15 +204,23 @@ var abp = abp || {}; handleAbpErrorResponse: function (jqXHR, userOptions, $dfd) { var messagePromise = null; + var responseJSON = null; + + if (jqXHR.responseJSON) { + responseJSON = jqXHR.responseJSON; + } + else { + responseJSON = JSON.parse(jqXHR.responseText) + } if (userOptions.abpHandleError !== false) { - messagePromise = abp.ajax.showError(jqXHR.responseJSON.error); + messagePromise = abp.ajax.showError(responseJSON.error); } - abp.ajax.logError(jqXHR.responseJSON.error); + abp.ajax.logError(responseJSON.error); - $dfd && $dfd.reject(jqXHR.responseJSON.error, jqXHR); - userOptions.error && userOptions.error(jqXHR.responseJSON.error, jqXHR); + $dfd && $dfd.reject(responseJSON.error, jqXHR); + userOptions.error && userOptions.error(responseJSON.error, jqXHR); if (jqXHR.status === 401 && userOptions.abpHandleError !== false) { abp.ajax.handleUnAuthorizedRequest(messagePromise); From 413b3e7b898df8beb3c991e7f481a9bf4ee34061 Mon Sep 17 00:00:00 2001 From: Afresh Date: Wed, 5 Jan 2022 23:23:50 +0800 Subject: [PATCH 38/67] zh-Hans translations. --- docs/zh-Hans/Modules/Cms-Kit.md | 3 - docs/zh-Hans/Modules/Cms-Kit/Blogging.md | 3 + docs/zh-Hans/Modules/Cms-Kit/Comments.md | 3 + docs/zh-Hans/Modules/Cms-Kit/Index.md | 79 +++++++++++++++++++++++ docs/zh-Hans/Modules/Cms-Kit/Menus.md | 3 + docs/zh-Hans/Modules/Cms-Kit/Pages.md | 3 + docs/zh-Hans/Modules/Cms-Kit/Ratings.md | 3 + docs/zh-Hans/Modules/Cms-Kit/Reactions.md | 3 + docs/zh-Hans/Modules/Cms-Kit/Tags.md | 3 + docs/zh-Hans/Modules/Identity.md | 2 +- docs/zh-Hans/Modules/Tenant-Management.md | 2 +- docs/zh-Hans/docs-nav.json | 2 +- 12 files changed, 103 insertions(+), 6 deletions(-) delete mode 100644 docs/zh-Hans/Modules/Cms-Kit.md create mode 100644 docs/zh-Hans/Modules/Cms-Kit/Blogging.md create mode 100644 docs/zh-Hans/Modules/Cms-Kit/Comments.md create mode 100644 docs/zh-Hans/Modules/Cms-Kit/Index.md create mode 100644 docs/zh-Hans/Modules/Cms-Kit/Menus.md create mode 100644 docs/zh-Hans/Modules/Cms-Kit/Pages.md create mode 100644 docs/zh-Hans/Modules/Cms-Kit/Ratings.md create mode 100644 docs/zh-Hans/Modules/Cms-Kit/Reactions.md create mode 100644 docs/zh-Hans/Modules/Cms-Kit/Tags.md diff --git a/docs/zh-Hans/Modules/Cms-Kit.md b/docs/zh-Hans/Modules/Cms-Kit.md deleted file mode 100644 index e13f1e585b..0000000000 --- a/docs/zh-Hans/Modules/Cms-Kit.md +++ /dev/null @@ -1,3 +0,0 @@ -# CMS Kit Module - -TODO \ No newline at end of file diff --git a/docs/zh-Hans/Modules/Cms-Kit/Blogging.md b/docs/zh-Hans/Modules/Cms-Kit/Blogging.md new file mode 100644 index 0000000000..1d2c3ecd9e --- /dev/null +++ b/docs/zh-Hans/Modules/Cms-Kit/Blogging.md @@ -0,0 +1,3 @@ +# CMS Kit: Blogging + +TODO... \ No newline at end of file diff --git a/docs/zh-Hans/Modules/Cms-Kit/Comments.md b/docs/zh-Hans/Modules/Cms-Kit/Comments.md new file mode 100644 index 0000000000..faeb6116c9 --- /dev/null +++ b/docs/zh-Hans/Modules/Cms-Kit/Comments.md @@ -0,0 +1,3 @@ +# CMS Kit: Comments + +TODO... \ No newline at end of file diff --git a/docs/zh-Hans/Modules/Cms-Kit/Index.md b/docs/zh-Hans/Modules/Cms-Kit/Index.md new file mode 100644 index 0000000000..6a52609527 --- /dev/null +++ b/docs/zh-Hans/Modules/Cms-Kit/Index.md @@ -0,0 +1,79 @@ +# 内容管理系统套件模块 + +此模块为您的应用程序提供内容管理系统 (Content Management System, CMS) 功能. 它提供 **核心构建块** 和完整工作的 **子系统**, 以创建启用 CMS 功能的您自己的网站, 或出于任何目的使用网站中的构建块. + +> **此模块目前仅适用于 MVC / Razor 页面 UI**. 虽然没有官方的 Blazor 软件包, 但它也可以在 Blazor 服务器 UI 中工作, 因为实际上 Blazor 服务器 UI 实际上是一个运行在 ASP.NET Core MVC / Razor 页面应用程序的混合型应用程序. + +目前提供以下功能: + +* 提供 [**页面**](Pages.md) 管理系统来管理具有动态 URL 的动态页面. +* 提供 [**博客**](Blogging.md) 系统来创建发表具有多种博客支持的博客文章. +* 提供 [**标签**](Tags.md) 系统来标记任何资源, 如博客文章. +* 提供 [**评论**](Comments.md) 系统来添加对任何资源的评论功能, 如博客文章或产品评价页面. +* 提供 [**反应**](Reactions.md) 系统来添加对任何资源的反应 (表情符号) 功能, 如博客文章或评论. +* 提供 [**评级**](Ratings.md) 系统来添加对任何资源的评级功能. +* 提供 [**菜单**](Menus.md) 系统来动态管理公共菜单. + +点击功能以了解和学习如何去使用它. + +所有功能均可单独使用. 如果你禁用了一个功能, 则在 [全局功能](../../Global-Features.md) 系统的帮助下, 该功能会从你的应用程序甚至数据库表中完全消失. + +## 预备要求 +- 此模块依赖于 [Blob 存储](../../Blob-Storing.md) 模块来保存媒体内容. +> 确保 `BlobStoring` 模块已安装并至少正确地配置了一个提供程序. 请查阅 [documentation](../../Blob-Storing.md) 了解更多信息. + +- CMS 套件使用 [分布式缓存](../../Caching.md) 来提高响应速度. +> 强烈建议在分布式/集群部署中为实现数据一致性使用分布式缓存, 如 [Redis](../../Redis-Cache.md). + +## 如何安装 + +可以使用 [ABP CLI](../../CLI.md) 的 `add-module` 命令为解决方案安装模块. 您可以使用以下命令在命令行中安装 CMS 套件模块: + +```bash +abp add-module Volo.CmsKit +``` + +> 默认情况下, Cms-Kit 通过 `GlobalFeature` 被禁用. 因此初始迁移将为空. 所以, 当你使用 EF Core 安装时,你可以添加 `--skip-db-migrations` 命令来跳过迁移. 启用 Cms-Kit 全局功能后, 请添加新的迁移. + +安装过程完成后, 在您的解决方案 `Domain.Shared` 项目中打开 `GlobalFeatureConfigurator` 类, 并将以下代码写入 `Configure` 方法中, 以启用内容管理系统套件模块的全部功能. + +```csharp +GlobalFeatureManager.Instance.Modules.CmsKit(cmsKit => +{ + cmsKit.EnableAll(); +}); +``` + +你可能更愿意逐个启用这些功能, 而不是启用全部功能. 以下示例仅启用了 [标签](Tags.md) 和 [评论](Comments.md) 功能: + +````csharp +GlobalFeatureManager.Instance.Modules.CmsKit(cmsKit => +{ + cmsKit.Tags.Enable(); + cmsKit.Comments.Enable(); +}); +```` + +> 如果你使用 EF Core, 不要忘记添加一个新的迁移并更新你的数据库. + +## 软件包 + +此模块遵循 [模块开发最佳实践指南](https://docs.abp.io/zh-Hans/abp/latest/Best-Practices/Index), 有多个 NuGet 和 NPM 软件包组成. 如果你想了解软件包及其之间的关系, 请参阅指南. + +CMS 套件软件包专为各种使用场景而设计. 如果您查阅了 [CMS 套件软件包](https://www.nuget.org/packages?q=Volo.CmsKit) 您将看到一些有 `Admin` 和 `Public` 后缀的软件包. 该模块有两个应用程序层, 原因是他们可能被用于不同类型的应用程序. 这些应用程序层仅使用一个领域层. + + - `Volo.CmsKit.Admin.*` 软件包包括管理员 (后台) 应用程序所必须的功能. + - `Volo.CmsKit.Public.*` 软件包包括被用于用户阅读博客文章和发表评论的公共网站上的功能. + - `Volo.CmsKit.*` (不带 Admin/Public 后缀) 软件包称为统一包. 统一包分别是添加 Admin 和 Public (相关层的) 软件包的快照. 如果您有一个用于管理和公共网站的单应用程序, 您可以使用这些软件包. + +## 内部结构 + +### 表/集合 前缀&架构 + +所有表/集合使用 `Cms` 作为默认前缀. 如果需要更改表的前缀或者设置一个架构名称 (如果你的数据库提供程序支持), 请在 `CmsKitDbProperties` 类中设置静态属性. + +### 连接字符串 + +此模块使用 `CmsKit` 作为连接字符串的名称. 如果您未使用此名称定义连接字符串, 它将回退为 `Default` 连接字符串. + +有关详细信息, 请参阅 [连接字符串](https://docs.abp.io/en/abp/latest/Connection-Strings) 文档. diff --git a/docs/zh-Hans/Modules/Cms-Kit/Menus.md b/docs/zh-Hans/Modules/Cms-Kit/Menus.md new file mode 100644 index 0000000000..fb214e358c --- /dev/null +++ b/docs/zh-Hans/Modules/Cms-Kit/Menus.md @@ -0,0 +1,3 @@ +# CMS Kit: Pages + +TODO... \ No newline at end of file diff --git a/docs/zh-Hans/Modules/Cms-Kit/Pages.md b/docs/zh-Hans/Modules/Cms-Kit/Pages.md new file mode 100644 index 0000000000..fb214e358c --- /dev/null +++ b/docs/zh-Hans/Modules/Cms-Kit/Pages.md @@ -0,0 +1,3 @@ +# CMS Kit: Pages + +TODO... \ No newline at end of file diff --git a/docs/zh-Hans/Modules/Cms-Kit/Ratings.md b/docs/zh-Hans/Modules/Cms-Kit/Ratings.md new file mode 100644 index 0000000000..2c6cf44460 --- /dev/null +++ b/docs/zh-Hans/Modules/Cms-Kit/Ratings.md @@ -0,0 +1,3 @@ +# Rating System + +TODO... \ No newline at end of file diff --git a/docs/zh-Hans/Modules/Cms-Kit/Reactions.md b/docs/zh-Hans/Modules/Cms-Kit/Reactions.md new file mode 100644 index 0000000000..9b714adf26 --- /dev/null +++ b/docs/zh-Hans/Modules/Cms-Kit/Reactions.md @@ -0,0 +1,3 @@ +# Reaction System + +TODO... \ No newline at end of file diff --git a/docs/zh-Hans/Modules/Cms-Kit/Tags.md b/docs/zh-Hans/Modules/Cms-Kit/Tags.md new file mode 100644 index 0000000000..3977d06f5a --- /dev/null +++ b/docs/zh-Hans/Modules/Cms-Kit/Tags.md @@ -0,0 +1,3 @@ +# Tag Management + +TODO... \ No newline at end of file diff --git a/docs/zh-Hans/Modules/Identity.md b/docs/zh-Hans/Modules/Identity.md index 73f05af7bb..bf715bc7b6 100644 --- a/docs/zh-Hans/Modules/Identity.md +++ b/docs/zh-Hans/Modules/Identity.md @@ -4,7 +4,7 @@ ## 如何安装 -当你使用 ABP 框架 [创建一个新的解决方案](https://abp.io/get-started) 时,此模块将被预安装(作为 NuGet/NPM 包)。你可以继续用其作为包并轻松地获取更新,也可以将其源代码包含在解决方案中(请参阅 `get-source` [CLI](../CLI.md))以开发自定义模块。 +当你使用 ABP 框架 [创建一个新的解决方案](https://abp.io/get-started) 时, 此模块将被预安装 (作为 NuGet/NPM 包). 你可以继续用其作为包并轻松地获取更新, 也可以将其源代码包含在解决方案中(请参阅 `get-source` [CLI](../CLI.md))以开发自定义模块. ### 源代码 diff --git a/docs/zh-Hans/Modules/Tenant-Management.md b/docs/zh-Hans/Modules/Tenant-Management.md index 8f214f9a33..f8b0d60aa7 100644 --- a/docs/zh-Hans/Modules/Tenant-Management.md +++ b/docs/zh-Hans/Modules/Tenant-Management.md @@ -12,7 +12,7 @@ ## 如何安装 -当你使用 ABP 框架 [创建一个新的解决方案](https://abp.io/get-started) 时,此模块将被预安装(作为 NuGet/NPM 包)。你可以继续用其作为包并轻松地获取更新,也可以将其源代码包含在解决方案中(请参阅 `get-source` [CLI](../CLI.md))以开发自定义模块。 +当你使用 ABP 框架 [创建一个新的解决方案](https://abp.io/get-started) 时, 此模块将被预安装(作为 NuGet/NPM 包). 你可以继续用其作为包并轻松地获取更新, 也可以将其源代码包含在解决方案中(请参阅 `get-source` [CLI](../CLI.md))以开发自定义模块. ### 源代码 diff --git a/docs/zh-Hans/docs-nav.json b/docs/zh-Hans/docs-nav.json index 74a44c8445..f63354c194 100644 --- a/docs/zh-Hans/docs-nav.json +++ b/docs/zh-Hans/docs-nav.json @@ -692,7 +692,7 @@ }, { "text": "CMS Kit", - "path": "Modules/Cms-Kit.md" + "path": "Modules/Cms-Kit/Index.md" }, { "text": "文档", From e5fb341581b75de07a4298567117d0bcd3c71748 Mon Sep 17 00:00:00 2001 From: Afresh Date: Wed, 5 Jan 2022 23:34:49 +0800 Subject: [PATCH 39/67] Update docs/zh-Hans/Modules/Cms-Kit/Index.md --- docs/zh-Hans/Modules/Cms-Kit/Index.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/zh-Hans/Modules/Cms-Kit/Index.md b/docs/zh-Hans/Modules/Cms-Kit/Index.md index 6a52609527..0751eb0ad0 100644 --- a/docs/zh-Hans/Modules/Cms-Kit/Index.md +++ b/docs/zh-Hans/Modules/Cms-Kit/Index.md @@ -20,22 +20,22 @@ ## 预备要求 - 此模块依赖于 [Blob 存储](../../Blob-Storing.md) 模块来保存媒体内容. -> 确保 `BlobStoring` 模块已安装并至少正确地配置了一个提供程序. 请查阅 [documentation](../../Blob-Storing.md) 了解更多信息. +> 确保 `BlobStoring` 模块已安装并至少正确地配置了一个提供程序. 请查阅 [文档](../../Blob-Storing.md) 了解更多信息. -- CMS 套件使用 [分布式缓存](../../Caching.md) 来提高响应速度. +- CMS Kit 使用 [分布式缓存](../../Caching.md) 来提高响应速度. > 强烈建议在分布式/集群部署中为实现数据一致性使用分布式缓存, 如 [Redis](../../Redis-Cache.md). ## 如何安装 -可以使用 [ABP CLI](../../CLI.md) 的 `add-module` 命令为解决方案安装模块. 您可以使用以下命令在命令行中安装 CMS 套件模块: +可以使用 [ABP CLI](../../CLI.md) 的 `add-module` 命令为解决方案安装模块. 您可以使用以下命令在命令行中安装 CMS Kit 模块: ```bash abp add-module Volo.CmsKit ``` -> 默认情况下, Cms-Kit 通过 `GlobalFeature` 被禁用. 因此初始迁移将为空. 所以, 当你使用 EF Core 安装时,你可以添加 `--skip-db-migrations` 命令来跳过迁移. 启用 Cms-Kit 全局功能后, 请添加新的迁移. +> 默认情况下, Cms-Kit `GlobalFeature` 被禁用. 因此初始迁移将为空. 所以, 当你使用 EF Core 安装时,你可以添加 `--skip-db-migrations` 命令来跳过迁移. 启用 Cms-Kit 全局功能后, 请添加新的迁移. -安装过程完成后, 在您的解决方案 `Domain.Shared` 项目中打开 `GlobalFeatureConfigurator` 类, 并将以下代码写入 `Configure` 方法中, 以启用内容管理系统套件模块的全部功能. +安装过程完成后, 在您的解决方案 `Domain.Shared` 项目中打开 `GlobalFeatureConfigurator` 类, 并将以下代码写入 `Configure` 方法中, 以启用 CMS Kit 模块的全部功能. ```csharp GlobalFeatureManager.Instance.Modules.CmsKit(cmsKit => @@ -58,9 +58,9 @@ GlobalFeatureManager.Instance.Modules.CmsKit(cmsKit => ## 软件包 -此模块遵循 [模块开发最佳实践指南](https://docs.abp.io/zh-Hans/abp/latest/Best-Practices/Index), 有多个 NuGet 和 NPM 软件包组成. 如果你想了解软件包及其之间的关系, 请参阅指南. +此模块遵循 [模块开发最佳实践指南](https://docs.abp.io/zh-Hans/abp/latest/Best-Practices/Index), 由多个 NuGet 和 NPM 软件包组成. 如果你想了解软件包及其之间的关系, 请参阅指南. -CMS 套件软件包专为各种使用场景而设计. 如果您查阅了 [CMS 套件软件包](https://www.nuget.org/packages?q=Volo.CmsKit) 您将看到一些有 `Admin` 和 `Public` 后缀的软件包. 该模块有两个应用程序层, 原因是他们可能被用于不同类型的应用程序. 这些应用程序层仅使用一个领域层. +CMS Kit 软件包专为各种使用场景而设计. 如果您查阅了 [CMS Kit 软件包](https://www.nuget.org/packages?q=Volo.CmsKit) 您将看到一些有 `Admin` 和 `Public` 后缀的软件包. 该模块有两个应用程序层, 原因是他们可能被用于不同类型的应用程序. 这些应用程序层仅使用一个领域层. - `Volo.CmsKit.Admin.*` 软件包包括管理员 (后台) 应用程序所必须的功能. - `Volo.CmsKit.Public.*` 软件包包括被用于用户阅读博客文章和发表评论的公共网站上的功能. From 4db4d1aeb0f3f6dc29831ecfaffba73c5241ad72 Mon Sep 17 00:00:00 2001 From: Luke Ni Date: Thu, 6 Jan 2022 09:14:07 +0800 Subject: [PATCH 40/67] translate to zh-Hans --- docs/zh-Hans/Tutorials/Part-8.md | 575 ++++++++++++++++++++++++++++++- 1 file changed, 574 insertions(+), 1 deletion(-) diff --git a/docs/zh-Hans/Tutorials/Part-8.md b/docs/zh-Hans/Tutorials/Part-8.md index 602306c484..4727b8392e 100644 --- a/docs/zh-Hans/Tutorials/Part-8.md +++ b/docs/zh-Hans/Tutorials/Part-8.md @@ -1 +1,574 @@ -TODO.. \ No newline at end of file +# Web应用程序开发教程 - 第八章: 作者: 应用服务层 +````json +//[doc-params] +{ + "UI": ["MVC","Blazor","BlazorServer","NG"], + "DB": ["EF","Mongo"] +} +```` +## 关于本教程 + +在本系列教程中, 你将构建一个名为 `Acme.BookStore` 的用于管理书籍及其作者列表的基于ABP的应用程序. 它是使用以下技术开发的: + +* **{{DB_Text}}** 做为ORM提供程序. +* **{{UI_Value}}** 做为UI框架. + +本教程分为以下部分: + +- [Part 1: 创建服务端](Part-1.md) +- [Part 2: 图书列表页面](Part-2.md) +- [Part 3: 创建,更新和删除图书](Part-2.md) +- [Part 4: 集成测试](Part-4.md) +- [Part 5: 授权](Part-5.md) +- [Part 6: 作者: 领域层](Part-6.md) +- [Part 7: 作者: 数据库集成](Part-7.md) +- [Part 8: 作者: 应用服务层](本章) +- [Part 9: 作者: 用户页面](Part-9.md) +- [Part 10: 图书到作者的关系](Part-10.md) + +## 下载源码 + +本教程根据你的**UI** 和 **数据库**偏好有多个版本,我们准备了几种可供下载的源码组合: + +* [MVC (Razor Pages) UI 与 EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Mvc-EfCore) +* [Blazor UI 与 EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore) +* [Angular UI 与 MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) + +> 如果你在Windows中遇到 "文件名太长" or "解压错误", 很可能与Windows最大文件路径限制有关. Windows文件路径的最大长度为250字符. 为了解决这个问题,参阅 [在Windows 10中启用长路径](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later). + +> 如果你遇到与Git相关的长路径错误, 尝试使用下面的命令在Windows中启用长路径. 参阅 https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path +> `git config --system core.longpaths true` + +## 简介 + +这章阐述如何为前一章介绍的 `作者` 实体创建应用服务层. + +## IAuthorAppService + +我们首先创建 [应用服务](../Application-Services.md) 接口和相关的 [DTO](../Data-Transfer-Objects.md)s. 在 `Acme.BookStore.Application.Contracts` 项目的 `Authors` 命名空间 (文件夹) 创建一个新接口 `IAuthorAppService`: + +````csharp +using System; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace Acme.BookStore.Authors +{ + public interface IAuthorAppService : IApplicationService + { + Task GetAsync(Guid id); + + Task> GetListAsync(GetAuthorListDto input); + + Task CreateAsync(CreateAuthorDto input); + + Task UpdateAsync(Guid id, UpdateAuthorDto input); + + Task DeleteAsync(Guid id); + } +} +```` + +* `IApplicationService` 是一个常规接口, 所有应用服务都继承自它, 所以 ABP 框架可以识别它们. +* 在 `Author` 实体中定义标准方法用于CRUD操作. +* `PagedResultDto` 是一个ABP框架中预定义的 DTO 类. 它拥有一个 `Items` 集合 和一个 `TotalCount` 属性, 用于返回分页结果. +* 优先从 `CreateAsync` 方法返回 `AuthorDto` (新创建的作者), 虽然在这个程序中没有这么做 - 这里只是展示一种不同用法. + +这个类使用下面定义的DTOs (为你的项目创建它们). + +### AuthorDto + +````csharp +using System; +using Volo.Abp.Application.Dtos; + +namespace Acme.BookStore.Authors +{ + public class AuthorDto : EntityDto + { + public string Name { get; set; } + + public DateTime BirthDate { get; set; } + + public string ShortBio { get; set; } + } +} +```` + +* `EntityDto` 只有一个类型为指定泛型参数的 `Id` 属性. 你可以自己创建 `Id` 属性, 而不是继承自 `EntityDto`. + +### GetAuthorListDto + +````csharp +using Volo.Abp.Application.Dtos; + +namespace Acme.BookStore.Authors +{ + public class GetAuthorListDto : PagedAndSortedResultRequestDto + { + public string Filter { get; set; } + } +} +```` + +* `Filter` 用于搜索作者. 它可以是 `null` (或空字符串) 以获得所有用户. +* `PagedAndSortedResultRequestDto` 具有标准分页和排序属性: `int MaxResultCount`, `int SkipCount` 和 `string Sorting`. + +> ABP 框架拥有这些基本的DTO类以简化并标准化你的DTOs. 参阅 [DTO 文档](../Data-Transfer-Objects.md) 获得所有DTO类的详细信息. + +### CreateAuthorDto + +````csharp +using System; +using System.ComponentModel.DataAnnotations; + +namespace Acme.BookStore.Authors +{ + public class CreateAuthorDto + { + [Required] + [StringLength(AuthorConsts.MaxNameLength)] + public string Name { get; set; } + + [Required] + public DateTime BirthDate { get; set; } + + public string ShortBio { get; set; } + } +} +```` + +数据标记特性可以用来验证DTO. 参阅 [验证文档](../Validation.md) 获得详细信息. + +### UpdateAuthorDto + +````csharp +using System; +using System.ComponentModel.DataAnnotations; + +namespace Acme.BookStore.Authors +{ + public class UpdateAuthorDto + { + [Required] + [StringLength(AuthorConsts.MaxNameLength)] + public string Name { get; set; } + + [Required] + public DateTime BirthDate { get; set; } + + public string ShortBio { get; set; } + } +} +```` + +> 我们可以在创建和更新操作间分享 (重用) 相同的DTO. 虽然可以这么做, 但我们推荐为这些操作创建不同的DTOs, 因为我们发现随着时间的推移, 它们通常会变得有差异. 所以, 与紧耦合相比, 代码重复也是合理的. + +## AuthorAppService + +是时候实现 `IAuthorAppService` 接口了. 在 `Acme.BookStore.Application` 项目的 `Authors` 命名空间 (文件夹) 中创建一个新类 `AuthorAppService` : + +````csharp +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Acme.BookStore.Permissions; +using Microsoft.AspNetCore.Authorization; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Domain.Repositories; + +namespace Acme.BookStore.Authors +{ + [Authorize(BookStorePermissions.Authors.Default)] + public class AuthorAppService : BookStoreAppService, IAuthorAppService + { + private readonly IAuthorRepository _authorRepository; + private readonly AuthorManager _authorManager; + + public AuthorAppService( + IAuthorRepository authorRepository, + AuthorManager authorManager) + { + _authorRepository = authorRepository; + _authorManager = authorManager; + } + + //...SERVICE METHODS WILL COME HERE... + } +} +```` + +* `[Authorize(BookStorePermissions.Authors.Default)]` 是一个检查权限(策略)的声明式方法, 用来给当前用户授权. 参阅 [授权文档](../Authorization.md) 获得详细信息. `BookStorePermissions` 类在后文会被更新, 现在不需要担心编译错误. +* 由 `BookStoreAppService` 派生, 这个类是一个简单基类, 可以做为模板. 它继承自标准的 `ApplicationService` 类. +* 实现上面定义的 `IAuthorAppService` . +* 注入 `IAuthorRepository` 和 `AuthorManager` 以使用服务方法. + +现在, 我们逐个介绍服务方法. 复制这些方法到 `AuthorAppService` 类. + +### GetAsync + +````csharp +public async Task GetAsync(Guid id) +{ + var author = await _authorRepository.GetAsync(id); + return ObjectMapper.Map(author); +} +```` + +这个方法根据 `Id` 获得 `Author` 实体, 使用 [对象到对象映射](../Object-To-Object-Mapping.md) 转换为 `AuthorDto`. 这需要配置AutoMapper, 后面会介绍. + +### GetListAsync + +````csharp +public async Task> GetListAsync(GetAuthorListDto input) +{ + if (input.Sorting.IsNullOrWhiteSpace()) + { + input.Sorting = nameof(Author.Name); + } + + var authors = await _authorRepository.GetListAsync( + input.SkipCount, + input.MaxResultCount, + input.Sorting, + input.Filter + ); + + var totalCount = input.Filter == null + ? await _authorRepository.CountAsync() + : await _authorRepository.CountAsync( + author => author.Name.Contains(input.Filter)); + + return new PagedResultDto( + totalCount, + ObjectMapper.Map, List>(authors) + ); +} +```` + +* 为处理客户端没有设置的情况, 在方法的开头设置默认排序是 "根据作者名". +* 使用 `IAuthorRepository.GetListAsync` 从数据库中获得分页的, 排序的和过滤的作者列表. 我们已经在教程的前一章中实现了它. 再一次强调, 实际上不需要创建这个方法, 因为我们可以从数据库中直接查询, 这里只是演示如何创建自定义repository方法. +* 直接查询 `AuthorRepository` , 得到作者的数量. 如果客户端发送了过滤条件, 会得到过滤后的作者数量. +* 最后, 通过映射 `Author` 列表到 `AuthorDto` 列表, 返回分页后的结果. + +### CreateAsync + +````csharp +[Authorize(BookStorePermissions.Authors.Create)] +public async Task CreateAsync(CreateAuthorDto input) +{ + var author = await _authorManager.CreateAsync( + input.Name, + input.BirthDate, + input.ShortBio + ); + + await _authorRepository.InsertAsync(author); + + return ObjectMapper.Map(author); +} +```` + +* `CreateAsync` 需要 `BookStorePermissions.Authors.Create` 权限 (另外包括 `AuthorAppService` 类声明的 `BookStorePermissions.Authors.Default` 权限). +* 使用 `AuthorManager` (领域服务) 创建新作者. +* 使用 `IAuthorRepository.InsertAsync` 插入新作者到数据库. +* 使用 `ObjectMapper` 返回 `AuthorDto` , 代表新创建的作者. + +> **DDD提示**: 一些开发者可能会发现可以在 `_authorManager.CreateAsync` 插入新实体. 我们认为把它留给应用层是更好的设计, 因为应用层更了解应该何时插入实体到数据库(在插入实体前可能需要额外的工作. 如果在领域层插入, 可能需要额外的更新操作). 但是, 你拥有最终的决定权. + +### UpdateAsync + +````csharp +[Authorize(BookStorePermissions.Authors.Edit)] +public async Task UpdateAsync(Guid id, UpdateAuthorDto input) +{ + var author = await _authorRepository.GetAsync(id); + + if (author.Name != input.Name) + { + await _authorManager.ChangeNameAsync(author, input.Name); + } + + author.BirthDate = input.BirthDate; + author.ShortBio = input.ShortBio; + + await _authorRepository.UpdateAsync(author); +} +```` + +* `UpdateAsync` 需要额外的 `BookStorePermissions.Authors.Edit` 权限. +* 使用 `IAuthorRepository.GetAsync` 从数据库中获得作者实体. 如果给定的id没有找到作者, `GetAsync` 抛出 `EntityNotFoundException`, 这在web应用程序中导致一个 `404` HTTP 状态码. 在更新操作中先获取实体再更新它, 是一个好的实践. +* 如果客户端请求, 使用 `AuthorManager.ChangeNameAsync` (领域服务方法) 修改作者姓名. +* 因为没有任何业务逻辑, 直接更新 `BirthDate` 和 `ShortBio`, 它们可以接受任何值. +* 最后, 调用 `IAuthorRepository.UpdateAsync` 更新实体到数据库. + +{{if DB == "EF"}} + +> **EF Core 提示**: Entity Framework Core 拥有 **change tracking** 系统并在unit of work 结束时 **自动保存** 任何修改到实体 (你可以简单地认为APB框架在方法结束时自动调用 `SaveChanges`). 所以, 即使你在方法结束时没有调用 `_authorRepository.UpdateAsync(...)` , 它依然可以工作. 如果你不考虑以后修改EF Core, 你可以移除这一行. + +{{end}} + +### DeleteAsync + +````csharp +[Authorize(BookStorePermissions.Authors.Delete)] +public async Task DeleteAsync(Guid id) +{ + await _authorRepository.DeleteAsync(id); +} +```` + +* `DeleteAsync` 需要额外的 `BookStorePermissions.Authors.Delete` 权限. +* 直接使用repository的 `DeleteAsync` 方法. + +## 权限定义 + +你还不能编译代码, 因为它需要 `BookStorePermissions` 类定义中一些常数. + +打开 `Acme.BookStore.Application.Contracts` 项目中的 `BookStorePermissions` 类 (在 `Permissions` 文件夹中), 修改为如下代码: + +````csharp +namespace Acme.BookStore.Permissions +{ + public static class BookStorePermissions + { + public const string GroupName = "BookStore"; + + public static class Books + { + public const string Default = GroupName + ".Books"; + public const string Create = Default + ".Create"; + public const string Edit = Default + ".Edit"; + public const string Delete = Default + ".Delete"; + } + + // *** ADDED a NEW NESTED CLASS *** + public static class Authors + { + public const string Default = GroupName + ".Authors"; + public const string Create = Default + ".Create"; + public const string Edit = Default + ".Edit"; + public const string Delete = Default + ".Delete"; + } + } +} +```` + +然后打开同一项目中的 `BookStorePermissionDefinitionProvider`, 在 `Define` 方法的结尾加入以下行: + +````csharp +var authorsPermission = bookStoreGroup.AddPermission( + BookStorePermissions.Authors.Default, L("Permission:Authors")); + +authorsPermission.AddChild( + BookStorePermissions.Authors.Create, L("Permission:Authors.Create")); + +authorsPermission.AddChild( + BookStorePermissions.Authors.Edit, L("Permission:Authors.Edit")); + +authorsPermission.AddChild( + BookStorePermissions.Authors.Delete, L("Permission:Authors.Delete")); +```` + +最后, 在 `Acme.BookStore.Domain.Shared` 项目中的 `Localization/BookStore/en.json` 加入以下项, 用以本地化权限名称: + +````csharp +"Permission:Authors": "Author Management", +"Permission:Authors.Create": "Creating new authors", +"Permission:Authors.Edit": "Editing the authors", +"Permission:Authors.Delete": "Deleting the authors" +```` + +## 对象到对象映射 + +`AuthorAppService` 使用 `ObjectMapper` 将 `Author` 对象 转换为 `AuthorDto` 对象. 所以, 我们需要在 AutoMapper 配置中定义映射. + +打开 `Acme.BookStore.Application` 项目中的 `BookStoreApplicationAutoMapperProfile` 类, 加入以下行到构造函数: + +````csharp +CreateMap(); +```` + +## 种子数据 + +如同图书管理部分所做的, 在数据库中生成一些初始作者实体. 不仅当第一次运行应用程序时是有用的, 对自动化测试也是很有用的. + +打开 `Acme.BookStore.Domain` 项目中的 `BookStoreDataSeederContributor`, 修改文件内容如下: + +````csharp +using System; +using System.Threading.Tasks; +using Acme.BookStore.Authors; +using Acme.BookStore.Books; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories; + +namespace Acme.BookStore +{ + public class BookStoreDataSeederContributor + : IDataSeedContributor, ITransientDependency + { + private readonly IRepository _bookRepository; + private readonly IAuthorRepository _authorRepository; + private readonly AuthorManager _authorManager; + + public BookStoreDataSeederContributor( + IRepository bookRepository, + IAuthorRepository authorRepository, + AuthorManager authorManager) + { + _bookRepository = bookRepository; + _authorRepository = authorRepository; + _authorManager = authorManager; + } + + public async Task SeedAsync(DataSeedContext context) + { + if (await _bookRepository.GetCountAsync() <= 0) + { + await _bookRepository.InsertAsync( + new Book + { + Name = "1984", + Type = BookType.Dystopia, + PublishDate = new DateTime(1949, 6, 8), + Price = 19.84f + }, + autoSave: true + ); + + await _bookRepository.InsertAsync( + new Book + { + Name = "The Hitchhiker's Guide to the Galaxy", + Type = BookType.ScienceFiction, + PublishDate = new DateTime(1995, 9, 27), + Price = 42.0f + }, + autoSave: true + ); + } + + // ADDED SEED DATA FOR AUTHORS + + if (await _authorRepository.GetCountAsync() <= 0) + { + await _authorRepository.InsertAsync( + await _authorManager.CreateAsync( + "George Orwell", + new DateTime(1903, 06, 25), + "Orwell produced literary criticism and poetry, fiction and polemical journalism; and is best known for the allegorical novella Animal Farm (1945) and the dystopian novel Nineteen Eighty-Four (1949)." + ) + ); + + await _authorRepository.InsertAsync( + await _authorManager.CreateAsync( + "Douglas Adams", + new DateTime(1952, 03, 11), + "Douglas Adams was an English author, screenwriter, essayist, humorist, satirist and dramatist. Adams was an advocate for environmentalism and conservation, a lover of fast cars, technological innovation and the Apple Macintosh, and a self-proclaimed 'radical atheist'." + ) + ); + } + } + } +} +```` + +{{if DB=="EF"}} + +你现在可以运行 `.DbMigrator` 控制台应用程序, **迁移** **数据库 schema** 并生成 **种子** 初始数据. + +{{else if DB=="Mongo"}} + +你现在可以运行 `.DbMigrator` 控制台应用程序, **迁移** **数据库 schema** 并生成 **种子** 初始数据. + +{{end}} + +## 测试作者应用服务 + +最后, 你可以为 `IAuthorAppService` 写一些测试. 在 `Acme.BookStore.Application.Tests` 项目的 `Authors` 命名空间(文件夹)中加入一个名为 `AuthorAppService_Tests` 新类: + +````csharp +using System; +using System.Threading.Tasks; +using Shouldly; +using Xunit; + +namespace Acme.BookStore.Authors +{ {{if DB=="Mongo"}} + [Collection(BookStoreTestConsts.CollectionDefinitionName)]{{end}} + public class AuthorAppService_Tests : BookStoreApplicationTestBase + { + private readonly IAuthorAppService _authorAppService; + + public AuthorAppService_Tests() + { + _authorAppService = GetRequiredService(); + } + + [Fact] + public async Task Should_Get_All_Authors_Without_Any_Filter() + { + var result = await _authorAppService.GetListAsync(new GetAuthorListDto()); + + result.TotalCount.ShouldBeGreaterThanOrEqualTo(2); + result.Items.ShouldContain(author => author.Name == "George Orwell"); + result.Items.ShouldContain(author => author.Name == "Douglas Adams"); + } + + [Fact] + public async Task Should_Get_Filtered_Authors() + { + var result = await _authorAppService.GetListAsync( + new GetAuthorListDto {Filter = "George"}); + + result.TotalCount.ShouldBeGreaterThanOrEqualTo(1); + result.Items.ShouldContain(author => author.Name == "George Orwell"); + result.Items.ShouldNotContain(author => author.Name == "Douglas Adams"); + } + + [Fact] + public async Task Should_Create_A_New_Author() + { + var authorDto = await _authorAppService.CreateAsync( + new CreateAuthorDto + { + Name = "Edward Bellamy", + BirthDate = new DateTime(1850, 05, 22), + ShortBio = "Edward Bellamy was an American author..." + } + ); + + authorDto.Id.ShouldNotBe(Guid.Empty); + authorDto.Name.ShouldBe("Edward Bellamy"); + } + + [Fact] + public async Task Should_Not_Allow_To_Create_Duplicate_Author() + { + await Assert.ThrowsAsync(async () => + { + await _authorAppService.CreateAsync( + new CreateAuthorDto + { + Name = "Douglas Adams", + BirthDate = DateTime.Now, + ShortBio = "..." + } + ); + }); + } + + //TODO: Test other methods... + } +} +```` + +完成应用服务方法的测试, 它们应该很容易理解. + +## 下一章 + +查看本教程的[下一章](Part-9.md). From 411cbe2aaec76eaa5274f410a403de27c32d5016 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Thu, 6 Jan 2022 11:32:07 +0800 Subject: [PATCH 41/67] Update abp.jquery.js --- npm/packs/jquery/src/abp.jquery.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/npm/packs/jquery/src/abp.jquery.js b/npm/packs/jquery/src/abp.jquery.js index 4ae0d8cf64..b0af0c2582 100644 --- a/npm/packs/jquery/src/abp.jquery.js +++ b/npm/packs/jquery/src/abp.jquery.js @@ -204,14 +204,8 @@ var abp = abp || {}; handleAbpErrorResponse: function (jqXHR, userOptions, $dfd) { var messagePromise = null; - var responseJSON = null; - if (jqXHR.responseJSON) { - responseJSON = jqXHR.responseJSON; - } - else { - responseJSON = JSON.parse(jqXHR.responseText) - } + var responseJSON = jqXHR.responseJSON ?? JSON.parse(jqXHR.responseText); if (userOptions.abpHandleError !== false) { messagePromise = abp.ajax.showError(responseJSON.error); From 99b5c703f060e92d1a9514a95b678ae7d63aff7a Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Thu, 6 Jan 2022 11:56:39 +0800 Subject: [PATCH 42/67] Update abp.jquery.js --- npm/packs/jquery/src/abp.jquery.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/packs/jquery/src/abp.jquery.js b/npm/packs/jquery/src/abp.jquery.js index b0af0c2582..76dfd3897f 100644 --- a/npm/packs/jquery/src/abp.jquery.js +++ b/npm/packs/jquery/src/abp.jquery.js @@ -205,7 +205,7 @@ var abp = abp || {}; handleAbpErrorResponse: function (jqXHR, userOptions, $dfd) { var messagePromise = null; - var responseJSON = jqXHR.responseJSON ?? JSON.parse(jqXHR.responseText); + var responseJSON = jqXHR.responseJSON ? jqXHR.responseJSON : JSON.parse(jqXHR.responseText); if (userOptions.abpHandleError !== false) { messagePromise = abp.ajax.showError(responseJSON.error); From ae174aa366798d75a188e466e5322286bb4bf750 Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 6 Jan 2022 12:09:11 +0800 Subject: [PATCH 43/67] Add `bootstrap.enable.popovers.everywhere.js` --- .../Mvc/UI/Packages/Bootstrap/BootstrapScriptContributor.cs | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/src/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ .../bootstrap/js/bootstrap.enable.popovers.everywhere.js | 5 +++++ 22 files changed, 110 insertions(+) create mode 100644 modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 modules/blogging/app/Volo.BloggingTestApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 modules/client-simulation/demo/Volo.ClientSimulation.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 modules/cms-kit/host/Volo.CmsKit.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 modules/cms-kit/host/Volo.CmsKit.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 modules/docs/app/VoloDocs.Web/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 npm/packs/bootstrap/src/bootstrap.enable.popovers.everywhere.js create mode 100644 templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js create mode 100644 templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Bootstrap/BootstrapScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Bootstrap/BootstrapScriptContributor.cs index 53cb32a088..783705382d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Bootstrap/BootstrapScriptContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Bootstrap/BootstrapScriptContributor.cs @@ -12,6 +12,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Bootstrap { context.Files.AddIfNotContains("/libs/bootstrap/js/bootstrap.bundle.js"); context.Files.AddIfNotContains("/libs/bootstrap/js/bootstrap.enable.tooltips.everywhere.js"); + + if (context.FileProvider.GetFileInfo("/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js").Exists) + { + context.Files.AddIfNotContains("/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js"); + } } } } diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/modules/blogging/app/Volo.BloggingTestApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/blogging/app/Volo.BloggingTestApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/modules/blogging/app/Volo.BloggingTestApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/modules/client-simulation/demo/Volo.ClientSimulation.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/client-simulation/demo/Volo.ClientSimulation.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/modules/client-simulation/demo/Volo.ClientSimulation.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/modules/cms-kit/host/Volo.CmsKit.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/cms-kit/host/Volo.CmsKit.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/modules/docs/app/VoloDocs.Web/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/docs/app/VoloDocs.Web/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/modules/docs/app/VoloDocs.Web/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/npm/packs/bootstrap/src/bootstrap.enable.popovers.everywhere.js b/npm/packs/bootstrap/src/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/npm/packs/bootstrap/src/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js new file mode 100644 index 0000000000..7400532dce --- /dev/null +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -0,0 +1,5 @@ +(function () { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl) + }) +})(); From fea2d4308ce6ce6304c8b6f8fe30a097455f4b1f Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 6 Jan 2022 13:11:25 +0800 Subject: [PATCH 44/67] Update bootstrap.enable.popovers.everywhere.js --- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- npm/packs/bootstrap/src/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- .../libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/modules/blogging/app/Volo.BloggingTestApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/blogging/app/Volo.BloggingTestApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/modules/blogging/app/Volo.BloggingTestApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/modules/blogging/app/Volo.BloggingTestApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/modules/client-simulation/demo/Volo.ClientSimulation.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/client-simulation/demo/Volo.ClientSimulation.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/modules/client-simulation/demo/Volo.ClientSimulation.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/modules/client-simulation/demo/Volo.ClientSimulation.Demo/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/modules/cms-kit/host/Volo.CmsKit.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/modules/cms-kit/host/Volo.CmsKit.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/cms-kit/host/Volo.CmsKit.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/modules/docs/app/VoloDocs.Web/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/docs/app/VoloDocs.Web/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/modules/docs/app/VoloDocs.Web/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/modules/docs/app/VoloDocs.Web/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/npm/packs/bootstrap/src/bootstrap.enable.popovers.everywhere.js b/npm/packs/bootstrap/src/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/npm/packs/bootstrap/src/bootstrap.enable.popovers.everywhere.js +++ b/npm/packs/bootstrap/src/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js index 7400532dce..a02a2a7a5e 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/wwwroot/libs/bootstrap/js/bootstrap.enable.popovers.everywhere.js @@ -1,5 +1,5 @@ (function () { - [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]').map(function (popoverTriggerEl) { + [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')).map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl) }) })(); From ce3dd00bd0474285b579ae68d7e2f7f04df029ef Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Thu, 6 Jan 2022 14:56:29 +0800 Subject: [PATCH 45/67] Upgrade Blazorise to 0.9.5.4 --- .../src/Volo.Abp.BlazoriseUI/Volo.Abp.BlazoriseUI.csproj | 8 ++++---- ...yCompanyName.MyProjectName.Blazor.Server.Tiered.csproj | 4 ++-- .../MyCompanyName.MyProjectName.Blazor.Server.csproj | 4 ++-- .../MyCompanyName.MyProjectName.Blazor.csproj | 4 ++-- .../MyCompanyName.MyProjectName.Blazor/wwwroot/global.css | 2 +- .../MyCompanyName.MyProjectName.Blazor/wwwroot/index.html | 4 ++-- .../MyCompanyName.MyProjectName.Blazor.Host.csproj | 4 ++-- .../wwwroot/global.css | 2 +- .../wwwroot/index.html | 4 ++-- .../MyCompanyName.MyProjectName.Blazor.Server.Host.csproj | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/framework/src/Volo.Abp.BlazoriseUI/Volo.Abp.BlazoriseUI.csproj b/framework/src/Volo.Abp.BlazoriseUI/Volo.Abp.BlazoriseUI.csproj index 3ef6aa04bd..a9fe114ecc 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Volo.Abp.BlazoriseUI.csproj +++ b/framework/src/Volo.Abp.BlazoriseUI/Volo.Abp.BlazoriseUI.csproj @@ -14,10 +14,10 @@ - - - - + + + + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyCompanyName.MyProjectName.Blazor.Server.Tiered.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyCompanyName.MyProjectName.Blazor.Server.Tiered.csproj index 46ebc4d4e2..caf905fa6c 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyCompanyName.MyProjectName.Blazor.Server.Tiered.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyCompanyName.MyProjectName.Blazor.Server.Tiered.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj index 9fdc0d234a..31ad680028 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyCompanyName.MyProjectName.Blazor.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyCompanyName.MyProjectName.Blazor.csproj index f976bf65d8..25fa91e40d 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyCompanyName.MyProjectName.Blazor.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyCompanyName.MyProjectName.Blazor.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/wwwroot/global.css b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/wwwroot/global.css index 7c71980d56..9b8609312c 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/wwwroot/global.css +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/wwwroot/global.css @@ -14,6 +14,6 @@ body:before{content:"mobile";display:none;visibility:hidden}@media(min-width:768px){body:before{content:"tablet"}}@media(min-width:992px){body:before{content:"desktop"}}@media(min-width:1200px){body:before{content:"widescreen"}}@media(min-width:1400px){body:before{content:"fullhd"}}hr.divider.divider-solid{border-top:var(--b-divider-thickness,1px) solid var(--b-divider-color,#999)}hr.divider.divider-dashed{border-top:var(--b-divider-thickness,1px) dashed var(--b-divider-color,#999)}hr.divider.divider-dotted{border-top:var(--b-divider-thickness,1px) dotted var(--b-divider-color,#999)}hr.divider.divider-text{position:relative;border:none;height:var(--b-divider-thickness,1px);background:var(--b-divider-color,#999)}hr.divider.divider-text::before{content:attr(data-content);display:inline-block;background:#fff;font-weight:bold;font-size:var(--b-divider-font-size,.85rem);color:var(--b-divider-color,#999);border-radius:30rem;padding:.2rem 2rem;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.b-input-color-picker{padding:.6rem}.b-input-color-picker>.b-input-color-picker-preview{position:relative;z-index:1;width:100%;height:100%;display:flex;flex-direction:row;justify-content:space-between}.b-input-color-picker>.b-input-color-picker-preview::before{position:absolute;content:'';top:0;left:0;width:100%;height:100%;background:url('data:image/svg+xml;utf8, ');background-size:.5em;border-radius:.15em;z-index:-1}.b-input-color-picker>.b-input-color-picker-preview>.b-input-color-picker-curent-color{display:inline-block;width:100%;height:100%}.b-input-color-picker[aria-disabled='true']{opacity:.65}.progress.progress-xs{height:.25rem}.progress.progress-sm{height:.5rem}.progress.progress-md{height:1rem}.progress.progress-lg{height:1.5rem}.progress.progress-xl{height:2rem}.b-page-progress{width:100%;height:4px;z-index:9999;top:0;left:0;position:fixed;display:none}.b-page-progress .b-page-progress-indicator{width:0;height:100%;transition:height .3s;background-color:#000;transition:width 1s}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-indeterminate{width:30%;animation:running-page-progress 2s cubic-bezier(.4,0,.2,1) infinite}.b-page-progress.b-page-progress-active{display:block}@keyframes running-page-progress{0%{margin-left:0;margin-right:100%}50%{margin-left:25%;margin-right:0%}100%{margin-left:100%;margin-right:0}}.tippy-box[data-animation=scale][data-placement^=top]{transform-origin:bottom}.tippy-box[data-animation=scale][data-placement^=bottom]{transform-origin:top}.tippy-box[data-animation=scale][data-placement^=left]{transform-origin:right}.tippy-box[data-animation=scale][data-placement^=right]{transform-origin:left}.tippy-box[data-animation=scale][data-state=hidden]{transform:scale(.5);opacity:0}.tippy-box[data-theme~='blazorise']{background-color:RGBA(var(--b-tooltip-background-color-r,128),var(--b-tooltip-background-color-g,128),var(--b-tooltip-background-color-b,128),var(--b-tooltip-background-opacity,.9));color:var(--b-tooltip-color,#fff)}.tippy-box[data-theme~='blazorise'][data-placement^='top']>.tippy-arrow::before{border-top-color:RGBA(var(--b-tooltip-background-color-r,128),var(--b-tooltip-background-color-g,128),var(--b-tooltip-background-color-b,128),var(--b-tooltip-background-opacity,.9))}.tippy-box[data-theme~='blazorise'][data-placement^='bottom']>.tippy-arrow::before{border-bottom-color:RGBA(var(--b-tooltip-background-color-r,128),var(--b-tooltip-background-color-g,128),var(--b-tooltip-background-color-b,128),var(--b-tooltip-background-opacity,.9))}.tippy-box[data-theme~='blazorise'][data-placement^='left']>.tippy-arrow::before{border-left-color:RGBA(var(--b-tooltip-background-color-r,128),var(--b-tooltip-background-color-g,128),var(--b-tooltip-background-color-b,128),var(--b-tooltip-background-opacity,.9))}.tippy-box[data-theme~='blazorise'][data-placement^='right']>.tippy-arrow::before{border-right-color:RGBA(var(--b-tooltip-background-color-r,128),var(--b-tooltip-background-color-g,128),var(--b-tooltip-background-color-b,128),var(--b-tooltip-background-opacity,.9))}.tippy-box[data-theme~='blazorise']>.tippy-svg-arrow{fill:RGBA(var(--b-tooltip-background-color-r,128),var(--b-tooltip-background-color-g,128),var(--b-tooltip-background-color-b,128),var(--b-tooltip-background-opacity,.9))}.b-tooltip-inline{display:inline-block}.b-layout{display:flex;flex:auto;flex-direction:column}.b-layout.b-layout-root{height:100vh}.b-layout,.b-layout *{box-sizing:border-box}@keyframes spinner{0%{transform:translate3d(-50%,-50%,0) rotate(0deg)}100%{transform:translate3d(-50%,-50%,0) rotate(360deg)}}.b-layout>.b-layout-loading{z-index:9999;position:fixed;width:100%;height:100%;background:rgba(0,0,0,.3)}.b-layout>.b-layout-loading:before{animation:1s linear infinite spinner;border:solid 3px #eee;border-bottom-color:var(--b-theme-primary);border-radius:50%;height:40px;left:50%;position:absolute;top:50%;transform:translate3d(-50%,-50%,0);width:40px;content:' '}.b-layout.b-layout-has-sider{flex-direction:row;min-height:0}.b-layout.b-layout-has-sider .b-layout{overflow-x:hidden}.b-layout-header,.b-layout-footer{flex:0 0 auto}.b-layout-header{color:rgba(0,0,0,.65)}.b-layout.b-layout-root.b-layout-has-sider>.b-layout-header-fixed,.b-layout.b-layout-root.b-layout-has-sider>.b-layout>.b-layout-header-fixed{position:sticky;top:0;width:100%;flex:0}.b-layout.b-layout-root:not(.b-layout-has-sider) .b-layout-header-fixed,.b-layout.b-layout-root:not(.b-layout-has-sider)>.b-layout .b-layout-header-fixed{position:fixed;top:0;left:0;right:0;flex:0}.b-layout.b-layout-root:not(.b-layout-has-sider) .b-layout-header-fixed+.b-layout-content,.b-layout.b-layout-root:not(.b-layout-has-sider)>.b-layout .b-layout-header-fixed+.b-layout-content{margin-top:var(--b-bar-horizontal-height,auto)}.b-layout.b-layout-root>.b-layout-header.b-layout-header-fixed+.b-layout.b-layout-has-sider{margin-top:var(--b-bar-horizontal-height,auto)}.b-layout-footer{color:rgba(0,0,0,.65)}.b-layout-footer-fixed{position:sticky;z-index:1;bottom:0;flex:0}.b-layout-content{flex:1}.b-layout-sider{display:flex;position:relative;background:#001529}.b-layout-sider-content{position:sticky;top:0;z-index:2}.b-layout-header .navbar{line-height:inherit}.b-bar-horizontal[data-collapse=hide]{flex-wrap:nowrap}.b-bar-horizontal[data-collapse=hide][data-broken=true]{height:auto}.b-bar-horizontal[data-broken=false]{height:auto}.b-layout>.b-layout-header .b-bar-horizontal[data-collapse=hide][data-broken=true]{height:var(--b-bar-horizontal-height,auto)}.b-layout>.b-layout-header .b-bar-horizontal[data-broken=false]{height:var(--b-bar-horizontal-height,auto)}.b-bar-initial{display:none !important}.b-bar-vertical-inline,.b-bar-vertical-popout,.b-bar-vertical-small{display:flex;flex-direction:column;flex-wrap:nowrap;position:sticky;top:0;padding:0;min-width:var(--b-vertical-bar-width,230px);max-width:var(--b-vertical-bar-width,230px);width:var(--b-vertical-bar-width,230px);box-shadow:2px 0 6px rgba(0,21,41,.35);height:100%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.b-bar-vertical-inline:not(.b-bar-initial),.b-bar-vertical-popout:not(.b-bar-initial),.b-bar-vertical-small:not(.b-bar-initial){transition:width 200ms ease-in-out,min-width 200ms ease-in-out}.b-bar-vertical-inline .b-bar-menu,.b-bar-vertical-popout .b-bar-menu,.b-bar-vertical-small .b-bar-menu{width:100%;display:flex;flex:1;justify-content:space-between;flex-direction:column;align-self:stretch}.b-bar-vertical-inline .b-bar-brand,.b-bar-vertical-popout .b-bar-brand,.b-bar-vertical-small .b-bar-brand{width:100%;display:flex;height:var(--b-vertical-bar-brand-height,64px);min-height:var(--b-vertical-bar-brand-height,64px)}.b-bar-vertical-inline .b-bar-toggler-inline,.b-bar-vertical-popout .b-bar-toggler-inline,.b-bar-vertical-small .b-bar-toggler-inline{height:var(--b-vertical-bar-brand-height,64px);padding:12px;display:inline-flex;cursor:pointer;position:absolute;right:0}.b-bar-vertical-inline .b-bar-toggler-inline>*,.b-bar-vertical-popout .b-bar-toggler-inline>*,.b-bar-vertical-small .b-bar-toggler-inline>*{margin:auto}.b-bar-vertical-inline .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-popout .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-small .b-bar-toggler-popout:not(.b-bar-mobile-toggle){display:flex;position:fixed;left:var(--b-vertical-bar-width,230px);border-radius:0 10px 10px 0;border:0;width:10px;height:40px;padding:5px;align-items:center;box-shadow:2px 0 6px rgba(0,21,41,.35);cursor:pointer}.b-bar-vertical-inline .b-bar-toggler-popout:not(.b-bar-mobile-toggle):not(.b-bar-initial),.b-bar-vertical-popout .b-bar-toggler-popout:not(.b-bar-mobile-toggle):not(.b-bar-initial),.b-bar-vertical-small .b-bar-toggler-popout:not(.b-bar-mobile-toggle):not(.b-bar-initial){transition:width 200ms ease-in-out,left 200ms ease-in-out}.b-bar-vertical-inline .b-bar-toggler-popout:not(.b-bar-mobile-toggle)>*,.b-bar-vertical-popout .b-bar-toggler-popout:not(.b-bar-mobile-toggle)>*,.b-bar-vertical-small .b-bar-toggler-popout:not(.b-bar-mobile-toggle)>*{margin:auto;display:none}.b-bar-vertical-inline .b-bar-toggler-popout:not(.b-bar-mobile-toggle):hover,.b-bar-vertical-popout .b-bar-toggler-popout:not(.b-bar-mobile-toggle):hover,.b-bar-vertical-small .b-bar-toggler-popout:not(.b-bar-mobile-toggle):hover{width:45px}.b-bar-vertical-inline .b-bar-toggler-popout:not(.b-bar-mobile-toggle):hover>*,.b-bar-vertical-popout .b-bar-toggler-popout:not(.b-bar-mobile-toggle):hover>*,.b-bar-vertical-small .b-bar-toggler-popout:not(.b-bar-mobile-toggle):hover>*{display:block}.b-bar-vertical-inline .b-bar-item,.b-bar-vertical-popout .b-bar-item,.b-bar-vertical-small .b-bar-item{margin:auto;flex-grow:1;min-height:40px}.b-bar-vertical-inline .b-bar-item .b-bar-icon,.b-bar-vertical-popout .b-bar-item .b-bar-icon,.b-bar-vertical-small .b-bar-item .b-bar-icon{font-size:1.25rem;vertical-align:middle;margin:3px;display:inline-block}.b-bar-vertical-inline .b-bar-start,.b-bar-vertical-popout .b-bar-start,.b-bar-vertical-small .b-bar-start{width:100%;display:block}.b-bar-vertical-inline .b-bar-end,.b-bar-vertical-popout .b-bar-end,.b-bar-vertical-small .b-bar-end{padding-bottom:1rem;width:100%;padding-top:1rem;display:block}.b-bar-vertical-inline .b-bar-link,.b-bar-vertical-popout .b-bar-link,.b-bar-vertical-small .b-bar-link{display:block;width:100%;text-decoration:none;padding:.5rem .5rem .5rem 1.5rem;cursor:pointer;overflow-x:hidden;line-height:1.5rem;vertical-align:middle;transition:font-size 150ms ease-in}.b-bar-vertical-inline .b-bar-label,.b-bar-vertical-popout .b-bar-label,.b-bar-vertical-small .b-bar-label{background:transparent;color:#adb5bd;padding:.375rem 1.25rem;font-size:.75rem;text-overflow:ellipsis;overflow-x:hidden}.b-bar-vertical-inline .b-bar-dropdown .b-bar-dropdown-toggle:before,.b-bar-vertical-popout .b-bar-dropdown .b-bar-dropdown-toggle:before,.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-toggle:before{content:" ";border:solid;border-width:0 2px 2px 0;display:inline-block;padding:2px;right:1rem;transition:transform 200ms ease-out;float:right;position:relative;-webkit-transform:rotate(225deg);transform:rotate(225deg);top:.7rem}.b-bar-vertical-inline .b-bar-dropdown:not([data-visible=true]) .b-bar-dropdown-toggle:before,.b-bar-vertical-popout .b-bar-dropdown:not([data-visible=true]) .b-bar-dropdown-toggle:before,.b-bar-vertical-small .b-bar-dropdown:not([data-visible=true]) .b-bar-dropdown-toggle:before{-webkit-transform:rotate(45deg);transform:rotate(45deg);top:.5rem}.b-bar-vertical-inline .b-bar-dropdown .b-bar-dropdown-menu,.b-bar-vertical-popout .b-bar-dropdown .b-bar-dropdown-menu,.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu{display:none;background:inherit;color:inherit;float:none;padding:5px 0}.b-bar-vertical-inline .b-bar-dropdown .b-bar-dropdown-menu[data-visible=true],.b-bar-vertical-popout .b-bar-dropdown .b-bar-dropdown-menu[data-visible=true],.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu[data-visible=true]{display:block}.b-bar-vertical-inline .b-bar-dropdown .b-bar-dropdown-menu .b-bar-dropdown-item,.b-bar-vertical-popout .b-bar-dropdown .b-bar-dropdown-menu .b-bar-dropdown-item,.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu .b-bar-dropdown-item{position:relative;color:inherit;transition:background 100ms ease-in-out,color 100ms ease-in-out;text-decoration:none;display:block;width:100%;overflow-x:hidden}.b-bar-vertical-inline .b-bar-dropdown .b-bar-dropdown-menu .b-bar-dropdown-item i,.b-bar-vertical-popout .b-bar-dropdown .b-bar-dropdown-menu .b-bar-dropdown-item i,.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu .b-bar-dropdown-item i{margin-right:.3rem}.b-bar-vertical-inline .b-bar-dropdown .b-bar-dropdown-menu:before,.b-bar-vertical-popout .b-bar-dropdown .b-bar-dropdown-menu:before,.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu:before{background:inherit;box-shadow:none}.b-bar-vertical-inline .b-bar-mobile-toggle,.b-bar-vertical-popout .b-bar-mobile-toggle,.b-bar-vertical-small .b-bar-mobile-toggle{right:20px;margin:auto;display:none}.b-bar-vertical-inline .b-bar-item-multi-line,.b-bar-vertical-popout .b-bar-item-multi-line,.b-bar-vertical-small .b-bar-item-multi-line{display:-webkit-box !important;-webkit-box-orient:vertical;-webkit-line-clamp:var(--b-bar-item-lines,2);white-space:normal !important;overflow:hidden;text-overflow:ellipsis}.b-bar-vertical-inline.b-bar-dark,.b-bar-vertical-popout.b-bar-dark,.b-bar-vertical-small.b-bar-dark{background:var(--b-bar-dark-background,#001529);color:var(--b-bar-dark-color,rgba(255,255,255,.5))}.b-bar-vertical-inline.b-bar-dark .b-bar-brand,.b-bar-vertical-popout.b-bar-dark .b-bar-brand,.b-bar-vertical-small.b-bar-dark .b-bar-brand{background:var(--b-bar-brand-dark-background,rgba(255,255,255,.025))}.b-bar-vertical-inline.b-bar-dark .b-bar-brand .b-bar-link,.b-bar-vertical-popout.b-bar-dark .b-bar-brand .b-bar-link,.b-bar-vertical-small.b-bar-dark .b-bar-brand .b-bar-link{color:#fff}.b-bar-vertical-inline.b-bar-dark .b-bar-brand .b-bar-link.active,.b-bar-vertical-popout.b-bar-dark .b-bar-brand .b-bar-link.active,.b-bar-vertical-small.b-bar-dark .b-bar-brand .b-bar-link.active{color:#fff;background:inherit}.b-bar-vertical-inline.b-bar-dark .b-bar-brand .b-bar-link:hover,.b-bar-vertical-popout.b-bar-dark .b-bar-brand .b-bar-link:hover,.b-bar-vertical-small.b-bar-dark .b-bar-brand .b-bar-link:hover{color:#fff;background:inherit}.b-bar-vertical-inline.b-bar-dark .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-popout.b-bar-dark .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-small.b-bar-dark .b-bar-toggler-popout:not(.b-bar-mobile-toggle){background:var(--b-bar-dark-background,#001529);color:var(--b-bar-dark-color,rgba(255,255,255,.5))}.b-bar-vertical-inline.b-bar-dark .b-bar-dropdown-menu,.b-bar-vertical-popout.b-bar-dark .b-bar-dropdown-menu,.b-bar-vertical-small.b-bar-dark .b-bar-dropdown-menu{background:var(--b-bar-dropdown-dark-background,#000c17)}.b-bar-vertical-inline.b-bar-dark .b-bar-dropdown-menu .b-bar-dropdown-item.active,.b-bar-vertical-popout.b-bar-dark .b-bar-dropdown-menu .b-bar-dropdown-item.active,.b-bar-vertical-small.b-bar-dark .b-bar-dropdown-menu .b-bar-dropdown-item.active{color:var(--b-bar-item-dark-active-color,#fff);background:var(--b-bar-item-dark-active-background,#0288d1)}.b-bar-vertical-inline.b-bar-dark .b-bar-dropdown-menu .b-bar-dropdown-item:hover,.b-bar-vertical-popout.b-bar-dark .b-bar-dropdown-menu .b-bar-dropdown-item:hover,.b-bar-vertical-small.b-bar-dark .b-bar-dropdown-menu .b-bar-dropdown-item:hover{color:var(--b-bar-item-dark-hover-color,#fff);background:var(--b-bar-item-dark-hover-background,rgba(255,255,255,.3))}.b-bar-vertical-inline.b-bar-dark .b-bar-link,.b-bar-vertical-popout.b-bar-dark .b-bar-link,.b-bar-vertical-small.b-bar-dark .b-bar-link{color:inherit}.b-bar-vertical-inline.b-bar-dark .b-bar-link.active,.b-bar-vertical-popout.b-bar-dark .b-bar-link.active,.b-bar-vertical-small.b-bar-dark .b-bar-link.active{color:var(--b-bar-item-dark-active-color,#fff);background:var(--b-bar-item-dark-active-background,#0288d1)}.b-bar-vertical-inline.b-bar-dark .b-bar-link:hover,.b-bar-vertical-popout.b-bar-dark .b-bar-link:hover,.b-bar-vertical-small.b-bar-dark .b-bar-link:hover{color:var(--b-bar-item-dark-hover-color,#fff);background:var(--b-bar-item-dark-hover-background,rgba(255,255,255,.3))}.b-bar-vertical-inline.b-bar-light,.b-bar-vertical-popout.b-bar-light,.b-bar-vertical-small.b-bar-light{background:var(--b-bar-light-background,#fff);color:var(--b-bar-light-color,rgba(0,0,0,.7))}.b-bar-vertical-inline.b-bar-light .b-bar-brand,.b-bar-vertical-popout.b-bar-light .b-bar-brand,.b-bar-vertical-small.b-bar-light .b-bar-brand{background:var(--b-bar-brand-light-background,rgba(0,0,0,.025))}.b-bar-vertical-inline.b-bar-light .b-bar-brand .b-bar-link,.b-bar-vertical-popout.b-bar-light .b-bar-brand .b-bar-link,.b-bar-vertical-small.b-bar-light .b-bar-brand .b-bar-link{color:#000}.b-bar-vertical-inline.b-bar-light .b-bar-brand .b-bar-link.active,.b-bar-vertical-popout.b-bar-light .b-bar-brand .b-bar-link.active,.b-bar-vertical-small.b-bar-light .b-bar-brand .b-bar-link.active{background:inherit}.b-bar-vertical-inline.b-bar-light .b-bar-brand .b-bar-link:hover,.b-bar-vertical-popout.b-bar-light .b-bar-brand .b-bar-link:hover,.b-bar-vertical-small.b-bar-light .b-bar-brand .b-bar-link:hover{background:inherit}.b-bar-vertical-inline.b-bar-light .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-popout.b-bar-light .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-small.b-bar-light .b-bar-toggler-popout:not(.b-bar-mobile-toggle){background:var(--b-bar-brand-light-background,#fff);color:var(--b-bar-light-color,rgba(0,0,0,.7))}.b-bar-vertical-inline.b-bar-light .b-bar-dropdown-menu,.b-bar-vertical-popout.b-bar-light .b-bar-dropdown-menu,.b-bar-vertical-small.b-bar-light .b-bar-dropdown-menu{background:var(--b-bar-dropdown-light-background,#f2f2f2)}.b-bar-vertical-inline.b-bar-light .b-bar-dropdown-menu .b-bar-dropdown-item.active,.b-bar-vertical-popout.b-bar-light .b-bar-dropdown-menu .b-bar-dropdown-item.active,.b-bar-vertical-small.b-bar-light .b-bar-dropdown-menu .b-bar-dropdown-item.active{color:var(--b-bar-item-light-active-color,#000);background:var(--b-bar-item-light-active-background,#0288d1)}.b-bar-vertical-inline.b-bar-light .b-bar-dropdown-menu .b-bar-dropdown-item:hover,.b-bar-vertical-popout.b-bar-light .b-bar-dropdown-menu .b-bar-dropdown-item:hover,.b-bar-vertical-small.b-bar-light .b-bar-dropdown-menu .b-bar-dropdown-item:hover{color:var(--b-bar-item-light-hover-color,#000);background:var(--b-bar-item-light-hover-background,rgba(0,0,0,.3))}.b-bar-vertical-inline.b-bar-light .b-bar-link,.b-bar-vertical-popout.b-bar-light .b-bar-link,.b-bar-vertical-small.b-bar-light .b-bar-link{color:inherit}.b-bar-vertical-inline.b-bar-light .b-bar-link.active,.b-bar-vertical-popout.b-bar-light .b-bar-link.active,.b-bar-vertical-small.b-bar-light .b-bar-link.active{color:var(--b-bar-item-light-active-color,#000);background:var(--b-bar-item-light-active-background,#0288d1)}.b-bar-vertical-inline.b-bar-light .b-bar-link:hover,.b-bar-vertical-popout.b-bar-light .b-bar-link:hover,.b-bar-vertical-small.b-bar-light .b-bar-link:hover{color:var(--b-bar-item-light-hover-color,#000);background:var(--b-bar-item-light-hover-background,rgba(0,0,0,.3))}.b-bar-vertical-small,.b-bar-vertical-inline[data-collapse=small],.b-bar-vertical-popout[data-collapse=small]{width:var(--b-vertical-bar-small-width,64px);min-width:var(--b-vertical-bar-small-width,64px)}.b-bar-vertical-small:not(.b-bar-initial),.b-bar-vertical-inline[data-collapse=small]:not(.b-bar-initial),.b-bar-vertical-popout[data-collapse=small]:not(.b-bar-initial){transition:width 200ms ease-in-out,min-width 200ms ease-in-out}.b-bar-vertical-small .b-bar-toggler-inline,.b-bar-vertical-inline[data-collapse=small] .b-bar-toggler-inline,.b-bar-vertical-popout[data-collapse=small] .b-bar-toggler-inline{position:relative;width:100%}.b-bar-vertical-small .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-inline[data-collapse=small] .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-popout[data-collapse=small] .b-bar-toggler-popout:not(.b-bar-mobile-toggle){left:var(--b-vertical-bar-small-width,64px)}.b-bar-vertical-small .b-bar-item>.b-bar-dropdown>.b-bar-dropdown-toggle:before,.b-bar-vertical-inline[data-collapse=small] .b-bar-item>.b-bar-dropdown>.b-bar-dropdown-toggle:before,.b-bar-vertical-popout[data-collapse=small] .b-bar-item>.b-bar-dropdown>.b-bar-dropdown-toggle:before{display:none}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container{z-index:100;max-height:50vh;position:absolute !important;margin:-42px 5px 0 5px;display:flex;width:var(--b-vertical-bar-popout-menu-width,180px);left:var(--b-vertical-bar-small-width,64px)}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container.b-bar-right,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container.b-bar-right,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container.b-bar-right{right:var(--b-vertical-bar-small-width,64px);left:unset}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu{box-shadow:0 3px 6px -4px rgba(0,0,0,.12),0 6px 16px 0 rgba(0,0,0,.08),0 9px 28px 8px rgba(0,0,0,.05);border-radius:3px;overflow-y:auto;overflow-x:hidden;flex:1 100%}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu .b-bar-dropdown-item,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu .b-bar-dropdown-item,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu .b-bar-dropdown-item{padding:.5rem .5rem .5rem 1.5rem}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu:before,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu:before,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu:before{position:absolute;top:0;left:-7px;right:0;bottom:0;width:100%;height:100%;opacity:.0001;content:' ';z-index:-1}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu.b-bar-right:before,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu.b-bar-right:before,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu.b-bar-right:before{left:unset;right:-7px}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-menu-container,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-menu-container,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-menu-container{left:var(--b-vertical-bar-popout-menu-width,180px)}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-menu-container.b-bar-right,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-menu-container.b-bar-right,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-menu-container.b-bar-right{right:var(--b-vertical-bar-popout-menu-width,180px)}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-toggle:before,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-toggle:before,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-toggle:before{content:" ";border:solid;border-width:0 2px 2px 0;display:inline-block;padding:2px;right:1rem;transition:transform 200ms ease-out;float:right;position:relative;-webkit-transform:rotate(315deg);transform:rotate(315deg)}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown:not([data-visible=true]) .b-bar-dropdown-toggle:before,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown:not([data-visible=true]) .b-bar-dropdown-toggle:before,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown:not([data-visible=true]) .b-bar-dropdown-toggle:before{-webkit-transform:rotate(135deg);transform:rotate(135deg);right:.8rem}@keyframes b-bar-link-small{to{text-align:center;padding-left:0;padding-right:0}}.b-bar-vertical-small .b-bar-item>.b-bar-link,.b-bar-vertical-small .b-bar-item>.b-bar-dropdown>.b-bar-link,.b-bar-vertical-inline[data-collapse=small] .b-bar-item>.b-bar-link,.b-bar-vertical-inline[data-collapse=small] .b-bar-item>.b-bar-dropdown>.b-bar-link,.b-bar-vertical-popout[data-collapse=small] .b-bar-item>.b-bar-link,.b-bar-vertical-popout[data-collapse=small] .b-bar-item>.b-bar-dropdown>.b-bar-link{animation:b-bar-link-small forwards;animation-delay:170ms;font-size:0;transition:font-size 100ms ease-out}.b-bar-vertical-small .b-bar-item>.b-bar-link:after,.b-bar-vertical-small .b-bar-item>.b-bar-dropdown>.b-bar-link:after,.b-bar-vertical-inline[data-collapse=small] .b-bar-item>.b-bar-link:after,.b-bar-vertical-inline[data-collapse=small] .b-bar-item>.b-bar-dropdown>.b-bar-link:after,.b-bar-vertical-popout[data-collapse=small] .b-bar-item>.b-bar-link:after,.b-bar-vertical-popout[data-collapse=small] .b-bar-item>.b-bar-dropdown>.b-bar-link:after{display:none}.b-bar-vertical-small .b-bar-label,.b-bar-vertical-inline[data-collapse=small] .b-bar-label,.b-bar-vertical-popout[data-collapse=small] .b-bar-label{text-align:center}.b-bar-vertical-inline:not([data-collapse]){overflow-y:auto;overflow-x:hidden}.b-bar-vertical-inline:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container{position:relative}.b-bar-vertical-inline:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu{position:relative !important;border:none;border-radius:0;box-shadow:none}.b-bar-vertical-inline:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu .b-bar-dropdown-item{padding:.5rem .5rem .5rem 3rem}.b-bar-vertical-inline:not([data-collapse]) .b-bar-brand .b-bar-link{display:flex;align-items:center}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-toggle:before{content:" ";border:solid;border-width:0 2px 2px 0;display:inline-block;padding:2px;right:1rem;transition:transform 200ms ease-out;float:right;position:relative;-webkit-transform:rotate(315deg);transform:rotate(315deg)}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown:not([data-visible=true]) .b-bar-dropdown-toggle:before{-webkit-transform:rotate(135deg);transform:rotate(135deg);right:.8rem}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container{z-index:100;max-height:50vh;position:absolute !important;margin:-42px 5px 0 5px;display:flex;width:var(--b-vertical-bar-popout-menu-width,180px);left:var(--b-vertical-bar-width,230px)}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container.b-bar-right{right:var(--b-vertical-bar-width,230px);left:unset}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu{box-shadow:0 3px 6px -4px rgba(0,0,0,.12),0 6px 16px 0 rgba(0,0,0,.08),0 9px 28px 8px rgba(0,0,0,.05);border-radius:3px;overflow-y:auto;overflow-x:hidden;flex:1 100%}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu .b-bar-dropdown-item{padding:.5rem .5rem .5rem 1.5rem}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu:before{position:absolute;top:0;left:-7px;right:0;bottom:0;width:100%;height:100%;opacity:.0001;content:' ';z-index:-1}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu.b-bar-right:before{left:unset;right:-7px}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-menu-container{left:var(--b-vertical-bar-popout-menu-width,180px)}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-menu-container.b-bar-right{right:var(--b-vertical-bar-popout-menu-width,180px)}.b-bar-vertical-inline[data-collapse=hide],.b-bar-vertical-popout[data-collapse=hide],.b-bar-vertical-small[data-collapse=hide]{width:0;min-width:0;overflow-y:hidden;visibility:hidden}.b-bar-vertical-inline[data-collapse=hide]:not(.b-bar-initial),.b-bar-vertical-popout[data-collapse=hide]:not(.b-bar-initial),.b-bar-vertical-small[data-collapse=hide]:not(.b-bar-initial){transition:width 200ms ease-in-out,min-width 200ms ease-in-out,visibility 100ms}.b-bar-vertical-inline[data-collapse=hide] .b-bar-toggler-inline,.b-bar-vertical-popout[data-collapse=hide] .b-bar-toggler-inline,.b-bar-vertical-small[data-collapse=hide] .b-bar-toggler-inline{display:none}.b-bar-vertical-inline[data-collapse=hide] .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-popout[data-collapse=hide] .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-small[data-collapse=hide] .b-bar-toggler-popout:not(.b-bar-mobile-toggle){visibility:visible;left:0}@media only screen and (max-width:576px){.b-bar-vertical-inline:not([data-collapse]){min-width:100vw}.b-bar-vertical-inline:not([data-collapse]) .b-bar-toggler-inline:not(.b-bar-mobile-toggle){display:none}.b-bar-vertical-inline:not([data-collapse]) .b-bar-toggler-popout:not(.b-bar-mobile-toggle){left:100vw}.b-bar-vertical-inline:not([data-collapse]) .b-bar-mobile-toggle{display:flex}}.b-table.table{position:relative}.b-table.table .b-table-resizer{position:absolute;top:0;right:0;width:5px;cursor:col-resize;user-select:none;z-index:1}.b-table.table .b-table-resizer:hover,.b-table.table .b-table-resizing{cursor:col-resize !important;border-right:2px solid var(--b-theme-primary,#00f)}.b-table.table .b-table-resizing{cursor:col-resize !important}thead tr th{position:relative}.b-character-casing-lower{text-transform:lowercase}.b-character-casing-upper{text-transform:uppercase}.b-character-casing-title{text-transform:lowercase}.b-character-casing-title::first-letter {text-transform:uppercase}.flatpickr-calendar{background:transparent;opacity:0;display:none;text-align:center;visibility:hidden;padding:0;-webkit-animation:none;animation:none;direction:ltr;border:0;font-size:14px;line-height:24px;border-radius:5px;position:absolute;width:307.875px;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-touch-action:manipulation;touch-action:manipulation;background:#fff;-webkit-box-shadow:1px 0 0 #e6e6e6,-1px 0 0 #e6e6e6,0 1px 0 #e6e6e6,0 -1px 0 #e6e6e6,0 3px 13px rgba(0,0,0,.08);box-shadow:1px 0 0 #e6e6e6,-1px 0 0 #e6e6e6,0 1px 0 #e6e6e6,0 -1px 0 #e6e6e6,0 3px 13px rgba(0,0,0,.08)}.flatpickr-calendar.open,.flatpickr-calendar.inline{opacity:1;max-height:640px;visibility:visible}.flatpickr-calendar.open{display:inline-block;z-index:99999}.flatpickr-calendar.animate.open{-webkit-animation:fpFadeInDown 300ms cubic-bezier(.23,1,.32,1);animation:fpFadeInDown 300ms cubic-bezier(.23,1,.32,1)}.flatpickr-calendar.inline{display:block;position:relative;top:2px}.flatpickr-calendar.static{position:absolute;top:calc(100% + 2px)}.flatpickr-calendar.static.open{z-index:999;display:block}.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+1) .flatpickr-day.inRange:nth-child(7n+7){-webkit-box-shadow:none !important;box-shadow:none !important}.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+2) .flatpickr-day.inRange:nth-child(7n+1){-webkit-box-shadow:-2px 0 0 #e6e6e6,5px 0 0 #e6e6e6;box-shadow:-2px 0 0 #e6e6e6,5px 0 0 #e6e6e6}.flatpickr-calendar .hasWeeks .dayContainer,.flatpickr-calendar .hasTime .dayContainer{border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.flatpickr-calendar .hasWeeks .dayContainer{border-left:0}.flatpickr-calendar.hasTime .flatpickr-time{height:40px;border-top:1px solid #e6e6e6}.flatpickr-calendar.noCalendar.hasTime .flatpickr-time{height:auto}.flatpickr-calendar:before,.flatpickr-calendar:after{position:absolute;display:block;pointer-events:none;border:solid transparent;content:'';height:0;width:0;left:22px}.flatpickr-calendar.rightMost:before,.flatpickr-calendar.arrowRight:before,.flatpickr-calendar.rightMost:after,.flatpickr-calendar.arrowRight:after{left:auto;right:22px}.flatpickr-calendar.arrowCenter:before,.flatpickr-calendar.arrowCenter:after{left:50%;right:50%}.flatpickr-calendar:before{border-width:5px;margin:0 -5px}.flatpickr-calendar:after{border-width:4px;margin:0 -4px}.flatpickr-calendar.arrowTop:before,.flatpickr-calendar.arrowTop:after{bottom:100%}.flatpickr-calendar.arrowTop:before{border-bottom-color:#e6e6e6}.flatpickr-calendar.arrowTop:after{border-bottom-color:#fff}.flatpickr-calendar.arrowBottom:before,.flatpickr-calendar.arrowBottom:after{top:100%}.flatpickr-calendar.arrowBottom:before{border-top-color:#e6e6e6}.flatpickr-calendar.arrowBottom:after{border-top-color:#fff}.flatpickr-calendar:focus{outline:0}.flatpickr-wrapper{position:relative;display:inline-block}.flatpickr-months{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.flatpickr-months .flatpickr-month{background:transparent;color:rgba(0,0,0,.9);fill:rgba(0,0,0,.9);height:34px;line-height:1;text-align:center;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;overflow:hidden;-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}.flatpickr-months .flatpickr-prev-month,.flatpickr-months .flatpickr-next-month{text-decoration:none;cursor:pointer;position:absolute;top:0;height:34px;padding:10px;z-index:3;color:rgba(0,0,0,.9);fill:rgba(0,0,0,.9)}.flatpickr-months .flatpickr-prev-month.flatpickr-disabled,.flatpickr-months .flatpickr-next-month.flatpickr-disabled{display:none}.flatpickr-months .flatpickr-prev-month i,.flatpickr-months .flatpickr-next-month i{position:relative}.flatpickr-months .flatpickr-prev-month.flatpickr-prev-month,.flatpickr-months .flatpickr-next-month.flatpickr-prev-month{left:0}.flatpickr-months .flatpickr-prev-month.flatpickr-next-month,.flatpickr-months .flatpickr-next-month.flatpickr-next-month{right:0}.flatpickr-months .flatpickr-prev-month:hover,.flatpickr-months .flatpickr-next-month:hover{color:#959ea9}.flatpickr-months .flatpickr-prev-month:hover svg,.flatpickr-months .flatpickr-next-month:hover svg{fill:#f64747}.flatpickr-months .flatpickr-prev-month svg,.flatpickr-months .flatpickr-next-month svg{width:14px;height:14px}.flatpickr-months .flatpickr-prev-month svg path,.flatpickr-months .flatpickr-next-month svg path{-webkit-transition:fill .1s;transition:fill .1s;fill:inherit}.numInputWrapper{position:relative;height:auto}.numInputWrapper input,.numInputWrapper span{display:inline-block}.numInputWrapper input{width:100%}.numInputWrapper input::-ms-clear{display:none}.numInputWrapper input::-webkit-outer-spin-button,.numInputWrapper input::-webkit-inner-spin-button{margin:0;-webkit-appearance:none}.numInputWrapper span{position:absolute;right:0;width:14px;padding:0 4px 0 2px;height:50%;line-height:50%;opacity:0;cursor:pointer;border:1px solid rgba(57,57,57,.15);-webkit-box-sizing:border-box;box-sizing:border-box}.numInputWrapper span:hover{background:rgba(0,0,0,.1)}.numInputWrapper span:active{background:rgba(0,0,0,.2)}.numInputWrapper span:after{display:block;content:"";position:absolute}.numInputWrapper span.arrowUp{top:0;border-bottom:0}.numInputWrapper span.arrowUp:after{border-left:4px solid transparent;border-right:4px solid transparent;border-bottom:4px solid rgba(57,57,57,.6);top:26%}.numInputWrapper span.arrowDown{top:50%}.numInputWrapper span.arrowDown:after{border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid rgba(57,57,57,.6);top:40%}.numInputWrapper span svg{width:inherit;height:auto}.numInputWrapper span svg path{fill:rgba(0,0,0,.5)}.numInputWrapper:hover{background:rgba(0,0,0,.05)}.numInputWrapper:hover span{opacity:1}.flatpickr-current-month{font-size:135%;line-height:inherit;font-weight:300;color:inherit;position:absolute;width:75%;left:12.5%;padding:7.48px 0 0 0;line-height:1;height:34px;display:inline-block;text-align:center;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.flatpickr-current-month span.cur-month{font-family:inherit;font-weight:700;color:inherit;display:inline-block;margin-left:.5ch;padding:0}.flatpickr-current-month span.cur-month:hover{background:rgba(0,0,0,.05)}.flatpickr-current-month .numInputWrapper{width:6ch;width:7ch\0;display:inline-block}.flatpickr-current-month .numInputWrapper span.arrowUp:after{border-bottom-color:rgba(0,0,0,.9)}.flatpickr-current-month .numInputWrapper span.arrowDown:after{border-top-color:rgba(0,0,0,.9)}.flatpickr-current-month input.cur-year{background:transparent;-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;cursor:text;padding:0 0 0 .5ch;margin:0;display:inline-block;font-size:inherit;font-family:inherit;font-weight:300;line-height:inherit;height:auto;border:0;border-radius:0;vertical-align:initial;-webkit-appearance:textfield;-moz-appearance:textfield;appearance:textfield}.flatpickr-current-month input.cur-year:focus{outline:0}.flatpickr-current-month input.cur-year[disabled],.flatpickr-current-month input.cur-year[disabled]:hover{font-size:100%;color:rgba(0,0,0,.5);background:transparent;pointer-events:none}.flatpickr-current-month .flatpickr-monthDropdown-months{appearance:menulist;background:transparent;border:none;border-radius:0;box-sizing:border-box;color:inherit;cursor:pointer;font-size:inherit;font-family:inherit;font-weight:300;height:auto;line-height:inherit;margin:-1px 0 0 0;outline:none;padding:0 0 0 .5ch;position:relative;vertical-align:initial;-webkit-box-sizing:border-box;-webkit-appearance:menulist;-moz-appearance:menulist;width:auto}.flatpickr-current-month .flatpickr-monthDropdown-months:focus,.flatpickr-current-month .flatpickr-monthDropdown-months:active{outline:none}.flatpickr-current-month .flatpickr-monthDropdown-months:hover{background:rgba(0,0,0,.05)}.flatpickr-current-month .flatpickr-monthDropdown-months .flatpickr-monthDropdown-month{background-color:transparent;outline:none;padding:0}.flatpickr-weekdays{background:transparent;text-align:center;overflow:hidden;width:100%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;height:28px}.flatpickr-weekdays .flatpickr-weekdaycontainer{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}span.flatpickr-weekday{cursor:default;font-size:90%;background:transparent;color:rgba(0,0,0,.54);line-height:1;margin:0;text-align:center;display:block;-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;font-weight:bolder}.dayContainer,.flatpickr-weeks{padding:1px 0 0 0}.flatpickr-days{position:relative;overflow:hidden;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:start;-webkit-align-items:flex-start;-ms-flex-align:start;align-items:flex-start;width:307.875px}.flatpickr-days:focus{outline:0}.dayContainer{padding:0;outline:0;text-align:left;width:307.875px;min-width:307.875px;max-width:307.875px;-webkit-box-sizing:border-box;box-sizing:border-box;display:inline-block;display:-ms-flexbox;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-wrap:wrap;-ms-flex-pack:justify;-webkit-justify-content:space-around;justify-content:space-around;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}.dayContainer+.dayContainer{-webkit-box-shadow:-1px 0 0 #e6e6e6;box-shadow:-1px 0 0 #e6e6e6}.flatpickr-day{background:none;border:1px solid transparent;border-radius:150px;-webkit-box-sizing:border-box;box-sizing:border-box;color:#393939;cursor:pointer;font-weight:400;width:14.2857143%;-webkit-flex-basis:14.2857143%;-ms-flex-preferred-size:14.2857143%;flex-basis:14.2857143%;max-width:39px;height:39px;line-height:39px;margin:0;display:inline-block;position:relative;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center}.flatpickr-day.inRange,.flatpickr-day.prevMonthDay.inRange,.flatpickr-day.nextMonthDay.inRange,.flatpickr-day.today.inRange,.flatpickr-day.prevMonthDay.today.inRange,.flatpickr-day.nextMonthDay.today.inRange,.flatpickr-day:hover,.flatpickr-day.prevMonthDay:hover,.flatpickr-day.nextMonthDay:hover,.flatpickr-day:focus,.flatpickr-day.prevMonthDay:focus,.flatpickr-day.nextMonthDay:focus{cursor:pointer;outline:0;background:#e6e6e6;border-color:#e6e6e6}.flatpickr-day.today{border-color:#959ea9}.flatpickr-day.today:hover,.flatpickr-day.today:focus{border-color:#959ea9;background:#959ea9;color:#fff}.flatpickr-day.selected,.flatpickr-day.startRange,.flatpickr-day.endRange,.flatpickr-day.selected.inRange,.flatpickr-day.startRange.inRange,.flatpickr-day.endRange.inRange,.flatpickr-day.selected:focus,.flatpickr-day.startRange:focus,.flatpickr-day.endRange:focus,.flatpickr-day.selected:hover,.flatpickr-day.startRange:hover,.flatpickr-day.endRange:hover,.flatpickr-day.selected.prevMonthDay,.flatpickr-day.startRange.prevMonthDay,.flatpickr-day.endRange.prevMonthDay,.flatpickr-day.selected.nextMonthDay,.flatpickr-day.startRange.nextMonthDay,.flatpickr-day.endRange.nextMonthDay{background:#569ff7;-webkit-box-shadow:none;box-shadow:none;color:#fff;border-color:#569ff7}.flatpickr-day.selected.startRange,.flatpickr-day.startRange.startRange,.flatpickr-day.endRange.startRange{border-radius:50px 0 0 50px}.flatpickr-day.selected.endRange,.flatpickr-day.startRange.endRange,.flatpickr-day.endRange.endRange{border-radius:0 50px 50px 0}.flatpickr-day.selected.startRange+.endRange:not(:nth-child(7n+1)),.flatpickr-day.startRange.startRange+.endRange:not(:nth-child(7n+1)),.flatpickr-day.endRange.startRange+.endRange:not(:nth-child(7n+1)){-webkit-box-shadow:-10px 0 0 #569ff7;box-shadow:-10px 0 0 #569ff7}.flatpickr-day.selected.startRange.endRange,.flatpickr-day.startRange.startRange.endRange,.flatpickr-day.endRange.startRange.endRange{border-radius:50px}.flatpickr-day.inRange{border-radius:0;-webkit-box-shadow:-5px 0 0 #e6e6e6,5px 0 0 #e6e6e6;box-shadow:-5px 0 0 #e6e6e6,5px 0 0 #e6e6e6}.flatpickr-day.flatpickr-disabled,.flatpickr-day.flatpickr-disabled:hover,.flatpickr-day.prevMonthDay,.flatpickr-day.nextMonthDay,.flatpickr-day.notAllowed,.flatpickr-day.notAllowed.prevMonthDay,.flatpickr-day.notAllowed.nextMonthDay{color:rgba(57,57,57,.3);background:transparent;border-color:transparent;cursor:default}.flatpickr-day.flatpickr-disabled,.flatpickr-day.flatpickr-disabled:hover{cursor:not-allowed;color:rgba(57,57,57,.1)}.flatpickr-day.week.selected{border-radius:0;-webkit-box-shadow:-5px 0 0 #569ff7,5px 0 0 #569ff7;box-shadow:-5px 0 0 #569ff7,5px 0 0 #569ff7}.flatpickr-day.hidden{visibility:hidden}.rangeMode .flatpickr-day{margin-top:1px}.flatpickr-weekwrapper{float:left}.flatpickr-weekwrapper .flatpickr-weeks{padding:0 12px;-webkit-box-shadow:1px 0 0 #e6e6e6;box-shadow:1px 0 0 #e6e6e6}.flatpickr-weekwrapper .flatpickr-weekday{float:none;width:100%;line-height:28px}.flatpickr-weekwrapper span.flatpickr-day,.flatpickr-weekwrapper span.flatpickr-day:hover{display:block;width:100%;max-width:none;color:rgba(57,57,57,.3);background:transparent;cursor:default;border:none}.flatpickr-innerContainer{display:block;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden}.flatpickr-rContainer{display:inline-block;padding:0;-webkit-box-sizing:border-box;box-sizing:border-box}.flatpickr-time{text-align:center;outline:0;display:block;height:0;line-height:40px;max-height:40px;-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.flatpickr-time:after{content:"";display:table;clear:both}.flatpickr-time .numInputWrapper{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;width:40%;height:40px;float:left}.flatpickr-time .numInputWrapper span.arrowUp:after{border-bottom-color:#393939}.flatpickr-time .numInputWrapper span.arrowDown:after{border-top-color:#393939}.flatpickr-time.hasSeconds .numInputWrapper{width:26%}.flatpickr-time.time24hr .numInputWrapper{width:49%}.flatpickr-time input{background:transparent;-webkit-box-shadow:none;box-shadow:none;border:0;border-radius:0;text-align:center;margin:0;padding:0;height:inherit;line-height:inherit;color:#393939;font-size:14px;position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:textfield;-moz-appearance:textfield;appearance:textfield}.flatpickr-time input.flatpickr-hour{font-weight:bold}.flatpickr-time input.flatpickr-minute,.flatpickr-time input.flatpickr-second{font-weight:400}.flatpickr-time input:focus{outline:0;border:0}.flatpickr-time .flatpickr-time-separator,.flatpickr-time .flatpickr-am-pm{height:inherit;float:left;line-height:inherit;color:#393939;font-weight:bold;width:2%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-align-self:center;-ms-flex-item-align:center;align-self:center}.flatpickr-time .flatpickr-am-pm{outline:0;width:18%;cursor:pointer;text-align:center;font-weight:400}.flatpickr-time input:hover,.flatpickr-time .flatpickr-am-pm:hover,.flatpickr-time input:focus,.flatpickr-time .flatpickr-am-pm:focus{background:#eee}.flatpickr-input[readonly]{cursor:pointer}@-webkit-keyframes fpFadeInDown{from{opacity:0;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:1;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes fpFadeInDown{from{opacity:0;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:1;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.flatpickr-monthSelect-months{margin:10px 1px 3px 1px;flex-wrap:wrap}.flatpickr-monthSelect-month{background:none;border:0;border-radius:2px;-webkit-box-sizing:border-box;box-sizing:border-box;color:#393939;cursor:pointer;display:inline-block;font-weight:400;margin:.5px;justify-content:center;padding:10px;position:relative;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;text-align:center;width:33%}.flatpickr-monthSelect-month.disabled{color:#eee}.flatpickr-monthSelect-month.disabled:hover,.flatpickr-monthSelect-month.disabled:focus{cursor:not-allowed;background:none !important}.flatpickr-monthSelect-theme-dark{background:#3f4458}.flatpickr-monthSelect-theme-dark .flatpickr-current-month input.cur-year{color:#fff}.flatpickr-monthSelect-theme-dark .flatpickr-months .flatpickr-prev-month,.flatpickr-monthSelect-theme-dark .flatpickr-months .flatpickr-next-month{color:#fff;fill:#fff}.flatpickr-monthSelect-theme-dark .flatpickr-monthSelect-month{color:rgba(255,255,255,.95)}.flatpickr-monthSelect-month:hover,.flatpickr-monthSelect-month:focus{background:#e6e6e6;cursor:pointer;outline:0}.flatpickr-monthSelect-theme-dark .flatpickr-monthSelect-month:hover,.flatpickr-monthSelect-theme-dark .flatpickr-monthSelect-month:focus{background:#646c8c;border-color:#646c8c}.flatpickr-monthSelect-month.selected{background-color:#569ff7;color:#fff}.flatpickr-monthSelect-theme-dark .flatpickr-monthSelect-month.selected{background:#80cbc4;-webkit-box-shadow:none;box-shadow:none;color:#fff;border-color:#80cbc4} /*! Pickr 1.8.2 MIT | https://github.com/Simonwep/pickr */ .pickr{position:relative;overflow:visible;transform:translateY(0)}.pickr *{box-sizing:border-box;outline:none;border:none;-webkit-appearance:none}.pickr .pcr-button{position:relative;height:2em;width:2em;padding:.5em;cursor:pointer;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Helvetica Neue",Arial,sans-serif;border-radius:.15em;background:url('data:image/svg+xml;utf8, ') no-repeat center;background-size:0;transition:all .3s}.pickr .pcr-button::before{position:absolute;content:'';top:0;left:0;width:100%;height:100%;background:url('data:image/svg+xml;utf8, ');background-size:.5em;border-radius:.15em;z-index:-1}.pickr .pcr-button::before{z-index:initial}.pickr .pcr-button::after{position:absolute;content:'';top:0;left:0;height:100%;width:100%;transition:background .3s;background:var(--pcr-color);border-radius:.15em}.pickr .pcr-button.clear{background-size:70%}.pickr .pcr-button.clear::before{opacity:0}.pickr .pcr-button.clear:focus{box-shadow:0 0 0 1px rgba(255,255,255,.85),0 0 0 3px var(--pcr-color)}.pickr .pcr-button.disabled{cursor:not-allowed}.pickr *,.pcr-app *{box-sizing:border-box;outline:none;border:none;-webkit-appearance:none}.pickr input:focus,.pickr input.pcr-active,.pickr button:focus,.pickr button.pcr-active,.pcr-app input:focus,.pcr-app input.pcr-active,.pcr-app button:focus,.pcr-app button.pcr-active{box-shadow:0 0 0 1px rgba(255,255,255,.85),0 0 0 3px var(--pcr-color)}.pickr .pcr-palette,.pickr .pcr-slider,.pcr-app .pcr-palette,.pcr-app .pcr-slider{transition:box-shadow .3s}.pickr .pcr-palette:focus,.pickr .pcr-slider:focus,.pcr-app .pcr-palette:focus,.pcr-app .pcr-slider:focus{box-shadow:0 0 0 1px rgba(255,255,255,.85),0 0 0 3px rgba(0,0,0,.25)}.pcr-app{position:fixed;display:flex;flex-direction:column;z-index:10000;border-radius:.1em;background:#fff;opacity:0;visibility:hidden;transition:opacity .3s,visibility 0s .3s;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Helvetica Neue",Arial,sans-serif;box-shadow:0 .15em 1.5em 0 rgba(0,0,0,.1),0 0 1em 0 rgba(0,0,0,.03);left:0;top:0}.pcr-app.visible{transition:opacity .3s;visibility:visible;opacity:1}.pcr-app .pcr-swatches{display:flex;flex-wrap:wrap;margin-top:.75em}.pcr-app .pcr-swatches.pcr-last{margin:0}@supports (display:grid){.pcr-app .pcr-swatches{display:grid;align-items:center;grid-template-columns:repeat(auto-fit,1.75em)}}.pcr-app .pcr-swatches>button{font-size:1em;position:relative;width:calc(1.75em - 5px);height:calc(1.75em - 5px);border-radius:.15em;cursor:pointer;margin:2.5px;flex-shrink:0;justify-self:center;transition:all .15s;overflow:hidden;background:transparent;z-index:1}.pcr-app .pcr-swatches>button::before{position:absolute;content:'';top:0;left:0;width:100%;height:100%;background:url('data:image/svg+xml;utf8, ');background-size:6px;border-radius:.15em;z-index:-1}.pcr-app .pcr-swatches>button::after{content:'';position:absolute;top:0;left:0;width:100%;height:100%;background:var(--pcr-color);border:1px solid rgba(0,0,0,.05);border-radius:.15em;box-sizing:border-box}.pcr-app .pcr-swatches>button:hover{filter:brightness(1.05)}.pcr-app .pcr-swatches>button:not(.pcr-active){box-shadow:none}.pcr-app .pcr-interaction{display:flex;flex-wrap:wrap;align-items:center;margin:0 -.2em 0 -.2em}.pcr-app .pcr-interaction>*{margin:0 .2em}.pcr-app .pcr-interaction input{letter-spacing:.07em;font-size:.75em;text-align:center;cursor:pointer;color:#75797e;background:#f1f3f4;border-radius:.15em;transition:all .15s;padding:.45em .5em;margin-top:.75em}.pcr-app .pcr-interaction input:hover{filter:brightness(.975)}.pcr-app .pcr-interaction input:focus{box-shadow:0 0 0 1px rgba(255,255,255,.85),0 0 0 3px rgba(66,133,244,.75)}.pcr-app .pcr-interaction .pcr-result{color:#75797e;text-align:left;flex:1 1 8em;min-width:8em;transition:all .2s;border-radius:.15em;background:#f1f3f4;cursor:text}.pcr-app .pcr-interaction .pcr-result::-moz-selection{background:#4285f4;color:#fff}.pcr-app .pcr-interaction .pcr-result::selection{background:#4285f4;color:#fff}.pcr-app .pcr-interaction .pcr-type.active{color:#fff;background:#4285f4}.pcr-app .pcr-interaction .pcr-save,.pcr-app .pcr-interaction .pcr-cancel,.pcr-app .pcr-interaction .pcr-clear{color:#fff;width:auto}.pcr-app .pcr-interaction .pcr-save,.pcr-app .pcr-interaction .pcr-cancel,.pcr-app .pcr-interaction .pcr-clear{color:#fff}.pcr-app .pcr-interaction .pcr-save:hover,.pcr-app .pcr-interaction .pcr-cancel:hover,.pcr-app .pcr-interaction .pcr-clear:hover{filter:brightness(.925)}.pcr-app .pcr-interaction .pcr-save{background:#4285f4}.pcr-app .pcr-interaction .pcr-clear,.pcr-app .pcr-interaction .pcr-cancel{background:#f44250}.pcr-app .pcr-interaction .pcr-clear:focus,.pcr-app .pcr-interaction .pcr-cancel:focus{box-shadow:0 0 0 1px rgba(255,255,255,.85),0 0 0 3px rgba(244,66,80,.75)}.pcr-app .pcr-selection .pcr-picker{position:absolute;height:18px;width:18px;border:2px solid #fff;border-radius:100%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.pcr-app .pcr-selection .pcr-color-palette,.pcr-app .pcr-selection .pcr-color-chooser,.pcr-app .pcr-selection .pcr-color-opacity{position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:flex;flex-direction:column;cursor:grab;cursor:-webkit-grab}.pcr-app .pcr-selection .pcr-color-palette:active,.pcr-app .pcr-selection .pcr-color-chooser:active,.pcr-app .pcr-selection .pcr-color-opacity:active{cursor:grabbing;cursor:-webkit-grabbing}.pcr-app[data-theme='monolith']{width:14.25em;max-width:95vw;padding:.8em}.pcr-app[data-theme='monolith'] .pcr-selection{display:flex;flex-direction:column;justify-content:space-between;flex-grow:1}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-preview{position:relative;z-index:1;width:100%;height:1em;display:flex;flex-direction:row;justify-content:space-between;margin-bottom:.5em}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-preview::before{position:absolute;content:'';top:0;left:0;width:100%;height:100%;background:url('data:image/svg+xml;utf8, ');background-size:.5em;border-radius:.15em;z-index:-1}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-preview .pcr-last-color{cursor:pointer;transition:background-color .3s,box-shadow .3s;border-radius:.15em 0 0 .15em;z-index:2}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-preview .pcr-current-color{border-radius:0 .15em .15em 0}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-preview .pcr-last-color,.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-preview .pcr-current-color{background:var(--pcr-color);width:50%;height:100%}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-palette{width:100%;height:8em;z-index:1}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-palette .pcr-palette{border-radius:.15em;width:100%;height:100%}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-palette .pcr-palette::before{position:absolute;content:'';top:0;left:0;width:100%;height:100%;background:url('data:image/svg+xml;utf8, ');background-size:.5em;border-radius:.15em;z-index:-1}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-chooser,.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-opacity{height:.5em;margin-top:.75em}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-chooser .pcr-picker,.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-opacity .pcr-picker{top:50%;transform:translateY(-50%)}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-chooser .pcr-slider,.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-opacity .pcr-slider{flex-grow:1;border-radius:50em}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-chooser .pcr-slider{background:linear-gradient(to right,#f00,#ff0,#0f0,#0ff,#00f,#f0f,#f00)}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-opacity .pcr-slider{background:linear-gradient(to right,transparent,#000),url('data:image/svg+xml;utf8, ');background-size:100%,.25em} -@keyframes fadeIn{0%{opacity:0}100%{opacity:1}0%{opacity:0}}@keyframes slideIn{0%{transform:translateY(1rem);opacity:0}100%{transform:translateY(0);opacity:1}0%{transform:translateY(1rem);opacity:0}}.badge-close{cursor:pointer}.badge-close::before{height:2px;width:50%}.badge-close::after{height:50%;width:2px}.badge-close:hover,.badge-close:focus{background-color:rgba(10,10,10,.3)}.badge-close:active{background-color:rgba(10,10,10,.4)}.navbar-nav .nav-item:hover{cursor:pointer}.navbar-nav .nav-link:hover{cursor:pointer}.nav .nav-link:hover{cursor:pointer}.nav-item{position:relative}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-item{width:100%}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-item::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-item:empty::after{margin-left:0}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-item::after{transform:rotate(-90deg);position:absolute;right:10%;top:45%}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-menu{top:0;left:100%;margin-left:0;margin-right:.1rem}.btn-group>.b-tooltip:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.b-tooltip:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group.btn-group-toggle .btn.active.disabled{opacity:1}.btn-group-vertical>.b-tooltip:not(:last-child)>.btn{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.b-tooltip:not(:first-child)>.btn{border-top-left-radius:0;border-top-right-radius:0}.btn-xs,.btn-group-xs>.btn{padding:.15rem .5rem;font-size:.75rem;line-height:1.5;border-radius:.15rem}.btn-md,.btn-group-md>.btn{padding:.47rem 1rem;font-size:1.125rem;line-height:1.5;border-radius:.25rem}.btn-xl,.btn-group-xl>.btn{padding:.5rem 1rem;font-size:1.5rem;line-height:1.5;border-radius:.4rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.dropdown-toggle.dropdown-toggle-hidden::after{content:none !important}.dropdown-toggle.dropdown-toggle-hidden::before{content:none !important}.dropdown-menu.show{animation-duration:.3s;animation-fill-mode:both;animation-name:fadeIn}.dropdown-menu a:not([href]).dropdown-item:not(.disabled){cursor:pointer}.dropdown-menu.dropdown-menu-scrollable{max-height:var(--dropdown-list-menu-max-height,200px);overflow-y:scroll}.b-is-autocomplete .dropdown-menu{width:100%;max-height:var(--autocomplete-menu-max-height,200px);overflow-y:scroll}.b-is-autocomplete.b-is-autocomplete-multipleselection{max-width:100%;width:100%;cursor:text;height:calc(1.5em + .75rem + 2px);border:1px solid #ced4da;border-radius:.25rem}.b-is-autocomplete.b-is-autocomplete-multipleselection>input.form-control{display:inline-block;border:none;box-shadow:none;outline:none;background-color:transparent;max-width:inherit;width:auto}.b-is-autocomplete.b-is-autocomplete-multipleselection.focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.dropdown.btn-group>.btn.dropdown-toggle-split+.dropdown-menu.show{top:100%}.dropdown>.dropdown-menu>.dropdown{position:relative}.dropdown>.dropdown-menu>.dropdown::after{transform:rotate(-90deg);position:absolute;right:6px;top:.8em}.dropdown>.dropdown-menu>.dropdown>.dropdown-toggle{width:100%}.dropdown>.dropdown-menu>.dropdown>.dropdown-toggle::after{transform:rotate(-90deg);position:absolute;right:10%;top:45%}.dropdown>.dropdown-menu>.dropdown>.dropdown-menu{top:0;left:100%;margin-left:0;margin-right:.1rem}.dropdown-menu-start{right:auto;left:0}.dropdown-menu-end{right:0;left:auto}@media(min-width:576px){.dropdown-menu-sm-start{right:auto;left:0}.dropdown-menu-sm-end{right:0;left:auto}}@media(min-width:768px){.dropdown-menu-md-start{right:auto;left:0}.dropdown-menu-md-end{right:0;left:auto}}@media(min-width:992px){.dropdown-menu-lg-start{right:auto;left:0}.dropdown-menu-lg-end{right:0;left:auto}}@media(min-width:1200px){.dropdown-menu-xl-start{right:auto;left:0}.dropdown-menu-xl-end{right:0;left:auto}}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.snackbar{z-index:1060 !important}.figure-is-16x16{height:16px;width:16px}.figure-is-24x24{height:24px;width:24px}.figure-is-32x32{height:32px;width:32px}.figure-is-48x48{height:48px;width:48px}.figure-is-64x64{height:64px;width:64px}.figure-is-96x96{height:96px;width:96px}.figure-is-128x128{height:128px;width:128px}.figure-is-256x256{height:256px;width:256px}.figure-is-512x512{height:512px;width:512px}.form-check>.form-check-input.form-check-input-pointer,.form-check>.form-check-label.form-check-label-pointer,.form-switch>.form-check-input.form-check-input-pointer,.form-switch>.form-check-label.form-check-label-pointer{cursor:pointer}.form-control-plaintext.form-control-xs,.form-control-plaintext.form-control-md,.form-control-plaintext.form-control-xl{padding-right:0;padding-left:0}.form-control-xs{height:calc(1.5em + .3rem + 2px);padding:.15rem .5rem;font-size:.75rem;line-height:1.5;border-radius:.15rem}.form-control-md{height:calc(1.5em + .94rem + 2px);padding:.47rem 1rem;font-size:1.125rem;line-height:1.5;border-radius:.25rem}.form-control-xl{height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.5rem;line-height:1.5;border-radius:.4rem}.form-select-xs{height:calc(1.5em + .3rem + 2px);padding-top:.15rem;padding-bottom:.15rem;padding-left:.5rem;font-size:.75rem}.form-select-md{height:calc(1.5em + .94rem + 2px);padding-top:.47rem;padding-bottom:.47rem;padding-left:1rem;font-size:1.125rem}.form-select-xl{height:calc(1.5em + 1rem + 2px);padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.5rem}.input-group>.b-numeric:not(:last-child)>input{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.b-numeric:not(:first-child)>input{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-xs>.form-control:not(textarea),.input-group-xs>.form-select,.input-group-xs>.b-numeric>input{height:calc(1.5em + .3rem + 2px)}.input-group-xs>.form-control,.input-group-xs>.form-select,.input-group-xs>.input-group-text,.input-group-xs>.btn,.input-group-xs>.b-numeric>input{padding:.15rem .5rem;font-size:.75rem;line-height:1.5;border-radius:.15rem}.input-group-sm>.b-numeric>input{height:calc(1.5em + .5rem + 2px)}.input-group-sm>.b-numeric>input{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-md>.form-control:not(textarea),.input-group-md>.form-select,.input-group-md>.b-numeric>input{height:calc(1.5em + .94rem + 2px)}.input-group-md>.form-control,.input-group-md>.form-select,.input-group-md>.input-group-text,.input-group-md>.btn,.input-group-md>.b-numeric>input{padding:.47rem 1rem;font-size:1.125rem;line-height:1.5;border-radius:.25rem}.input-group-lg>.b-numeric>input{height:calc(1.5em + 1rem + 2px)}.input-group-lg>.b-numeric>input{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-xl>.form-control:not(textarea),.input-group-xl>.form-select,.input-group-xl>.b-numeric>input{height:calc(1.5em + 1rem + 2px)}.input-group-xl>.form-control,.input-group-xl>.form-select,.input-group-xl>.input-group-text,.input-group-xl>.btn,.input-group-xl>.b-numeric>input{padding:.5rem 1rem;font-size:1.5rem;line-height:1.5;border-radius:.4rem}.input-group-xs>.form-select,.input-group-md>.form-select,.input-group-xl>.form-select{padding-right:1.75rem}.input-group:not(.has-validation)>.dropdown:first-child>.btn:not(:last-child).dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown>.btn:not(:last-child).dropdown-toggle,.input-group.has-validation>.dropdown>.btn:not(:last-child):not(.dropdown-toggle){border-top-left-radius:0;border-bottom-left-radius:0}.form-check>.form-check-input.form-check-input-xs{width:.7rem;height:.7rem}.form-check>.form-check-input.form-check-input-xs+.form-check-label{line-height:"normal";padding-left:0}.form-check>.form-check-input.form-check-input-sm{width:.8rem;height:.8rem}.form-check>.form-check-input.form-check-input-sm+.form-check-label{line-height:"normal";padding-left:0}.form-check>.form-check-input.form-check-input-md{width:1.25rem;height:1.25rem}.form-check>.form-check-input.form-check-input-md+.form-check-label{line-height:1.7rem;padding-left:3px}.form-check>.form-check-input.form-check-input-lg{width:1.55rem;height:1.55rem}.form-check>.form-check-input.form-check-input-lg+.form-check-label{line-height:2rem;padding-left:6px}.form-check>.form-check-input.form-check-input-xl{width:1.85rem;height:1.85rem}.form-check>.form-check-input.form-check-input-xl+.form-check-label{line-height:2.5rem;padding-left:10px}select[readonly]{pointer-events:none}select[readonly] option,select[readonly] optgroup{display:none}.b-numeric{position:relative;width:100%}.b-numeric:hover>.b-numeric-handler-wrap{opacity:1}.b-numeric-handler-wrap{position:absolute;top:0;right:0;width:22px;height:100%;background:#fff;border:1px solid #d9d9d9;opacity:0}.input-group .b-numeric{-ms-flex:1 1 auto;flex:1 1 auto;width:1%}.b-numeric-handler-wrap .b-numeric-handler.b-numeric-handler-down{border-top:1px solid #d9d9d9}.b-numeric-handler{position:relative;display:flex;width:100%;height:50%;overflow:hidden;color:rgba(0,0,0,.45);font-weight:700;line-height:0;align-items:center;justify-content:center}.b-numeric-handler.btn{padding:0}.form-control+.b-numeric-handler-wrap{font-size:1rem;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.form-control-xs+.b-numeric-handler-wrap{font-size:.75rem;border-top-right-radius:.15rem;border-bottom-right-radius:.15rem}.form-control-xs+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:.75rem}.form-control-sm+.b-numeric-handler-wrap{font-size:.875rem;border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.form-control-sm+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:.875rem}.form-control-md+.b-numeric-handler-wrap{font-size:1.125rem;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.form-control-md+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:1.125rem}.form-control-lg+.b-numeric-handler-wrap{font-size:1.25rem;border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.form-control-lg+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:1.25rem}.form-control-xl+.b-numeric-handler-wrap{font-size:1.5rem;border-top-right-radius:.4rem;border-bottom-right-radius:.4rem}.form-control-xl+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:1.5rem}.custom-file-label{overflow:hidden}input[readonly][type=range],input[readonly="readonly"][type=range]{pointer-events:none}input[readonly][type=range]::-webkit-slider-thumb,input[readonly="readonly"][type=range]::-webkit-slider-thumb{pointer-events:none}input[readonly][type=range]::-moz-range-thumb,input[readonly="readonly"][type=range]::-moz-range-thumb{pointer-events:none}input[readonly][type=range]::-ms-thumb,input[readonly="readonly"][type=range]::-ms-thumb{pointer-events:none}.form-group{margin-bottom:1rem}.form-inline{display:flex;flex-flow:row wrap;align-items:center}.form-inline .form-check{width:100%}@media(min-width:576px){.form-inline label{display:flex;align-items:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:flex;flex:0 0 auto;flex-flow:row wrap;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .input-group,.form-inline .custom-select{width:auto}.form-inline .form-check{display:flex;align-items:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;flex-shrink:0;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .form-select{align-items:center;justify-content:center}.form-inline .form-check-label{margin-bottom:0}}.b-input-color-picker{padding:.5rem .6rem}.b-input-color-picker>.b-input-color-picker-preview{height:.55rem}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media(min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.jumbotron.jumbotron-primary{background-color:#007bff;color:#fff}.jumbotron.jumbotron-secondary{background-color:#6c757d;color:#fff}.jumbotron.jumbotron-success{background-color:#28a745;color:#fff}.jumbotron.jumbotron-info{background-color:#17a2b8;color:#fff}.jumbotron.jumbotron-warning{background-color:#ffc107;color:#212529}.jumbotron.jumbotron-danger{background-color:#dc3545;color:#fff}.jumbotron.jumbotron-light{background-color:#f8f9fa;color:#212529}.jumbotron.jumbotron-dark{background-color:#343a40;color:#fff}.jumbotron.jumbotron-link{background-color:#3273dc;color:#fff}.b-layout-header-fixed{z-index:1030}.b-layout-footer-fixed{z-index:1030}.b-layout-sider-content{z-index:1031}li.list-group-item-action{cursor:pointer}.b-list-view{overflow-y:scroll}.media{display:flex;align-items:flex-start}.media-body{flex:1}.modal.show{animation-duration:.25s;animation-fill-mode:both;animation-name:fadeIn}.page-item:not(.disabled) .page-link{cursor:pointer}.pagination-xs .page-link{padding:.125rem .25rem;font-size:.75rem;line-height:1.5}.pagination-xs .page-item:first-child .page-link{border-top-left-radius:.15rem;border-bottom-left-radius:.15rem}.pagination-xs .page-item:last-child .page-link{border-top-right-radius:.15rem;border-bottom-right-radius:.15rem}.pagination-md .page-link{padding:.625rem 1.25rem;font-size:1.125rem;line-height:1.5}.pagination-md .page-item:first-child .page-link{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.pagination-md .page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.pagination-xl .page-link{padding:1rem 2rem;font-size:1.5rem;line-height:1.5}.pagination-xl .page-item:first-child .page-link{border-top-left-radius:.4rem;border-bottom-left-radius:.4rem}.pagination-xl .page-item:last-child .page-link{border-top-right-radius:.4rem;border-bottom-right-radius:.4rem}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-primary{background-color:#007bff}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-secondary{background-color:#6c757d}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-success{background-color:#28a745}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-info{background-color:#17a2b8}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-warning{background-color:#ffc107}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-danger{background-color:#dc3545}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-light{background-color:#f8f9fa}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-dark{background-color:#343a40}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-link{background-color:#3273dc}.rating:not(.rating-disabled):not(.rating-readonly):hover .rating-item{cursor:pointer}.rating.rating-disabled{opacity:.65}.rating .rating-item.rating-item-primary{color:#007bff}.rating .rating-item.rating-item-secondary{color:#6c757d}.rating .rating-item.rating-item-success{color:#28a745}.rating .rating-item.rating-item-info{color:#17a2b8}.rating .rating-item.rating-item-warning{color:#ffc107}.rating .rating-item.rating-item-danger{color:#dc3545}.rating .rating-item.rating-item-light{color:#f8f9fa}.rating .rating-item.rating-item-dark{color:#343a40}.rating .rating-item.rating-item-link{color:#3273dc}.rating .rating-item.rating-item-hover{opacity:.7}.steps{padding:0;margin:0;list-style:none;display:flex;overflow-x:auto}.steps .step:first-child{margin-left:auto}.steps .step:last-child{margin-right:auto}.step:first-of-type .step-circle::before{display:none}.step:last-of-type .step-container{padding-right:0}.step-container{box-sizing:content-box;display:flex;align-items:center;flex-direction:column;width:5rem;min-width:5rem;max-width:5rem;padding-top:.5rem;padding-right:1rem}.step-circle{position:relative;display:flex;justify-content:center;align-items:center;width:1.5rem;height:1.5rem;color:#adb5bd;border:2px solid #adb5bd;border-radius:100%;background-color:#fff}.step-circle::before{content:'';display:block;position:absolute;top:50%;left:-2px;width:calc(5rem + 1rem - 1.5rem);height:2px;transform:translate(-100%,-50%);color:#adb5bd;background-color:currentColor}.step-text{color:#adb5bd;word-break:break-all;margin-top:.25em}.step-completed .step-circle{color:#fff;background-color:#28a745;border-color:#28a745}.step-completed .step-circle::before{color:#28a745}.step-completed .step-text{color:#28a745}.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-active .step-circle::before{color:#007bff}.step-active .step-text{color:#007bff}.step-primary .step-circle{color:#007bff;border-color:#007bff}.step-primary.step-completed .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-primary.step-completed .step-circle::before{color:#007bff}.step-primary.step-completed .step-text{color:#007bff}.step-primary.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-primary.step-active::before{color:#007bff}.step-primary.step-active .step-text{color:#007bff}.step-secondary .step-circle{color:#6c757d;border-color:#6c757d}.step-secondary.step-completed .step-circle{color:#fff;background-color:#6c757d;border-color:#6c757d}.step-secondary.step-completed .step-circle::before{color:#6c757d}.step-secondary.step-completed .step-text{color:#6c757d}.step-secondary.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-secondary.step-active::before{color:#007bff}.step-secondary.step-active .step-text{color:#007bff}.step-success .step-circle{color:#28a745;border-color:#28a745}.step-success.step-completed .step-circle{color:#fff;background-color:#28a745;border-color:#28a745}.step-success.step-completed .step-circle::before{color:#28a745}.step-success.step-completed .step-text{color:#28a745}.step-success.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-success.step-active::before{color:#007bff}.step-success.step-active .step-text{color:#007bff}.step-info .step-circle{color:#17a2b8;border-color:#17a2b8}.step-info.step-completed .step-circle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.step-info.step-completed .step-circle::before{color:#17a2b8}.step-info.step-completed .step-text{color:#17a2b8}.step-info.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-info.step-active::before{color:#007bff}.step-info.step-active .step-text{color:#007bff}.step-warning .step-circle{color:#ffc107;border-color:#ffc107}.step-warning.step-completed .step-circle{color:#fff;background-color:#ffc107;border-color:#ffc107}.step-warning.step-completed .step-circle::before{color:#ffc107}.step-warning.step-completed .step-text{color:#ffc107}.step-warning.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-warning.step-active::before{color:#007bff}.step-warning.step-active .step-text{color:#007bff}.step-danger .step-circle{color:#dc3545;border-color:#dc3545}.step-danger.step-completed .step-circle{color:#fff;background-color:#dc3545;border-color:#dc3545}.step-danger.step-completed .step-circle::before{color:#dc3545}.step-danger.step-completed .step-text{color:#dc3545}.step-danger.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-danger.step-active::before{color:#007bff}.step-danger.step-active .step-text{color:#007bff}.step-light .step-circle{color:#f8f9fa;border-color:#f8f9fa}.step-light.step-completed .step-circle{color:#fff;background-color:#f8f9fa;border-color:#f8f9fa}.step-light.step-completed .step-circle::before{color:#f8f9fa}.step-light.step-completed .step-text{color:#f8f9fa}.step-light.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-light.step-active::before{color:#007bff}.step-light.step-active .step-text{color:#007bff}.step-dark .step-circle{color:#343a40;border-color:#343a40}.step-dark.step-completed .step-circle{color:#fff;background-color:#343a40;border-color:#343a40}.step-dark.step-completed .step-circle::before{color:#343a40}.step-dark.step-completed .step-text{color:#343a40}.step-dark.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-dark.step-active::before{color:#007bff}.step-dark.step-active .step-text{color:#007bff}.step-link .step-circle{color:#3273dc;border-color:#3273dc}.step-link.step-completed .step-circle{color:#fff;background-color:#3273dc;border-color:#3273dc}.step-link.step-completed .step-circle::before{color:#3273dc}.step-link.step-completed .step-text{color:#3273dc}.step-link.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-link.step-active::before{color:#007bff}.step-link.step-active .step-text{color:#007bff}.steps-content{margin:1rem 0}.steps-content>.step-panel{display:none}.steps-content>.active{display:block}.form-check.form-switch .form-check-input.form-check-input-primary:checked{background-color:#007bff;border-color:#007bff}.form-check.form-switch .form-check-input.form-check-input-secondary:checked{background-color:#6c757d;border-color:#6c757d}.form-check.form-switch .form-check-input.form-check-input-success:checked{background-color:#28a745;border-color:#28a745}.form-check.form-switch .form-check-input.form-check-input-info:checked{background-color:#17a2b8;border-color:#17a2b8}.form-check.form-switch .form-check-input.form-check-input-warning:checked{background-color:#ffc107;border-color:#ffc107}.form-check.form-switch .form-check-input.form-check-input-danger:checked{background-color:#dc3545;border-color:#dc3545}.form-check.form-switch .form-check-input.form-check-input-light:checked{background-color:#f8f9fa;border-color:#f8f9fa}.form-check.form-switch .form-check-input.form-check-input-dark:checked{background-color:#343a40;border-color:#343a40}.form-check.form-switch .form-check-input.form-check-input-link:checked{background-color:#3273dc;border-color:#3273dc}.form-check.form-switch .form-check-input.form-check-input-xs{width:calc(.75rem + (.5rem/2));height:.5rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-xs+.form-check-label{line-height:1rem;vertical-align:middle;padding-left:0}.form-check.form-switch .form-check-input.form-check-input-xs:checked~.form-check-label::after{transform:translateX(calc(.75rem - (.5rem/2)))}.form-check.form-switch .form-check-input.form-check-input-sm{width:calc(1rem + (.75rem/2));height:.75rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-sm+.form-check-label{line-height:1.25rem;vertical-align:middle;padding-left:.75rem}.form-check.form-switch .form-check-input.form-check-input-sm:checked~.form-check-label::after{transform:translateX(calc(1rem - (.75rem/2)))}.form-check.form-switch .form-check-input.form-check-input-md{width:calc(2rem + (1.5rem/2));height:1.5rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-md+.form-check-label{line-height:2rem;vertical-align:middle;padding-left:.75rem}.form-check.form-switch .form-check-input.form-check-input-md:checked~.form-check-label::after{transform:translateX(calc(2rem - (1.5rem/2)))}.form-check.form-switch .form-check-input.form-check-input-lg{width:calc(3rem + (2rem/2));height:2rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-lg+.form-check-label{line-height:2.5rem;vertical-align:middle;padding-left:.75rem}.form-check.form-switch .form-check-input.form-check-input-lg:checked~.form-check-label::after{transform:translateX(calc(3rem - (2rem/2)))}.form-check.form-switch .form-check-input.form-check-input-xl{width:calc(4rem + (2.5rem/2));height:2.5rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-xl+.form-check-label{line-height:3rem;vertical-align:middle;padding-left:.75rem}.form-check.form-switch .form-check-input.form-check-input-xl:checked~.form-check-label::after{transform:translateX(calc(4rem - (2.5rem/2)))}table.table tbody tr.selected{background-color:var(--primary)}tr.table-row-selectable:hover{cursor:pointer}.table-fixed-header{overflow-y:auto}.table-fixed-header>.table{border-collapse:separate;border-spacing:0}.table-fixed-header>.table>thead>tr>th{border-top:none;position:sticky;background:#fff;z-index:10}.table-fixed-header>.table>thead>tr:nth-child(1)>th{top:0}.table-fixed-header>.table-bordered>:not(caption)>*>*{border-width:1px 1px}.overflow-auto-auto{overflow:auto auto !important}.overflow-auto-hidden{overflow:auto hidden !important}.overflow-auto-visible{overflow:auto visible !important}.overflow-auto-scroll{overflow:auto scroll !important}.overflow-hidden-auto{overflow:hidden auto !important}.overflow-hidden-hidden{overflow:hidden hidden !important}.overflow-hidden-visible{overflow:hidden visible !important}.overflow-hidden-scroll{overflow:hidden scroll !important}.overflow-visible-auto{overflow:visible auto !important}.overflow-visible-hidden{overflow:visible hidden !important}.overflow-visible-visible{overflow:visible visible !important}.overflow-visible-scroll{overflow:visible scroll !important}.overflow-scroll-auto{overflow:scroll auto !important}.overflow-scroll-hidden{overflow:scroll hidden !important}.overflow-scroll-visible{overflow:scroll visible !important}.overflow-scroll-scroll{overflow:scroll scroll !important}ol.ordered-list-lower-alpha{list-style-type:lower-alpha}ol.ordered-list-lower-roman{list-style-type:lower-roman}ol.ordered-list-upper-alpha{list-style-type:upper-alpha}ol.ordered-list-upper-roman{list-style-type:upper-roman}.flatpickr-months{margin:.5rem 0}.flatpickr-months .flatpickr-month,.flatpickr-months .flatpickr-next-month,.flatpickr-months .flatpickr-prev-month{height:auto;position:relative}.flatpickr-months .flatpickr-month:hover svg,.flatpickr-months .flatpickr-next-month:hover svg,.flatpickr-months .flatpickr-prev-month:hover svg{fill:#007bff}.flatpickr-months .flatpickr-month{color:#212529}.flatpickr-current-month{padding:13px 0 0 0;font-size:115%}.flatpickr-current-month span.cur-month{font-weight:700}.flatpickr-current-month span.cur-month:hover{background:rgba(0,123,255,.15)}.numInputWrapper:hover{background:rgba(0,123,255,.15)}.flatpickr-day{border-radius:.25rem;font-weight:500;color:#212529}.flatpickr-day.today{border-color:#007bff}.flatpickr-day.today:hover{background:#007bff;border-color:#007bff}.flatpickr-day:hover{background:rgba(0,123,255,.1);border-color:rgba(0,0,0,0)}span.flatpickr-weekday{color:#212529}.flatpickr-day.selected,.flatpickr-day.startRange,.flatpickr-day.endRange,.flatpickr-day.selected.inRange,.flatpickr-day.startRange.inRange,.flatpickr-day.endRange.inRange,.flatpickr-day.selected:focus,.flatpickr-day.startRange:focus,.flatpickr-day.endRange:focus,.flatpickr-day.selected:hover,.flatpickr-day.startRange:hover,.flatpickr-day.endRange:hover,.flatpickr-day.selected.prevMonthDay,.flatpickr-day.startRange.prevMonthDay,.flatpickr-day.endRange.prevMonthDay,.flatpickr-day.selected.nextMonthDay,.flatpickr-day.startRange.nextMonthDay,.flatpickr-day.endRange.nextMonthDay{background:#007bff;border-color:#007bff}.flatpickr-day.selected.startRange+.endRange:not(:nth-child(7n+1)),.flatpickr-day.startRange.startRange+.endRange:not(:nth-child(7n+1)),.flatpickr-day.endRange.startRange+.endRange:not(:nth-child(7n+1)){box-shadow:-10px 0 0 #007bff}.flatpickr-day.selected.startRange,.flatpickr-day.startRange.startRange,.flatpickr-day.endRange.startRange{border-radius:.25rem 0 0 .25rem}.flatpickr-day.selected.endRange,.flatpickr-day.startRange.endRange,.flatpickr-day.endRange.endRange{border-radius:0 .25rem .25rem 0}.flatpickr-monthSelect-month:hover,.flatpickr-monthSelect-month:focus{background:rgba(0,123,255,.1)}.flatpickr-monthSelect-month.selected{background-color:#007bff} +@keyframes fadeIn{0%{opacity:0}100%{opacity:1}0%{opacity:0}}@keyframes slideIn{0%{transform:translateY(1rem);opacity:0}100%{transform:translateY(0);opacity:1}0%{transform:translateY(1rem);opacity:0}}.badge-close{cursor:pointer}.badge-close::before{height:2px;width:50%}.badge-close::after{height:50%;width:2px}.badge-close:hover,.badge-close:focus{background-color:rgba(10,10,10,.3)}.badge-close:active{background-color:rgba(10,10,10,.4)}.navbar-nav .nav-item:hover{cursor:pointer}.navbar-nav .nav-link:hover{cursor:pointer}.nav .nav-link:hover{cursor:pointer}.nav-item{position:relative}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-item{width:100%}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-item::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-item:empty::after{margin-left:0}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-item::after{transform:rotate(-90deg);position:absolute;right:10%;top:45%}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-menu{top:0;left:100%;margin-left:0;margin-right:.1rem}.btn-group>.b-tooltip:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.b-tooltip:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group.btn-group-toggle .btn.active.disabled{opacity:1}.btn-group-vertical>.b-tooltip:not(:last-child)>.btn{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.b-tooltip:not(:first-child)>.btn{border-top-left-radius:0;border-top-right-radius:0}.btn-xs,.btn-group-xs>.btn{padding:.15rem .5rem;font-size:.75rem;line-height:1.5;border-radius:.15rem}.btn-md,.btn-group-md>.btn{padding:.47rem 1rem;font-size:1.125rem;line-height:1.5;border-radius:.25rem}.btn-xl,.btn-group-xl>.btn{padding:.5rem 1rem;font-size:1.5rem;line-height:1.5;border-radius:.4rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.dropdown-toggle.dropdown-toggle-hidden::after{content:none !important}.dropdown-toggle.dropdown-toggle-hidden::before{content:none !important}.dropdown-menu.show{animation-duration:.3s;animation-fill-mode:both;animation-name:fadeIn}.dropdown-menu a:not([href]).dropdown-item:not(.disabled){cursor:pointer}.dropdown-menu.dropdown-menu-scrollable{max-height:var(--dropdown-list-menu-max-height,200px);overflow-y:scroll}.b-is-autocomplete .dropdown-menu{width:100%;max-height:var(--autocomplete-menu-max-height,200px);overflow-y:scroll}.b-is-autocomplete.b-is-autocomplete-multipleselection{max-width:100%;width:100%;cursor:text;height:calc(1.5em + .75rem + 2px);border:1px solid #ced4da;border-radius:.25rem}.b-is-autocomplete.b-is-autocomplete-multipleselection>input.form-control{display:inline-block;border:none;box-shadow:none;outline:none;background-color:transparent;max-width:inherit;width:auto}.b-is-autocomplete.b-is-autocomplete-multipleselection.focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.dropdown.btn-group>.btn.dropdown-toggle-split+.dropdown-menu.show{top:100%}.dropdown>.dropdown-menu>.dropdown{position:relative}.dropdown>.dropdown-menu>.dropdown::after{transform:rotate(-90deg);position:absolute;right:6px;top:.8em}.dropdown>.dropdown-menu>.dropdown>.dropdown-toggle{width:100%}.dropdown>.dropdown-menu>.dropdown>.dropdown-toggle::after{transform:rotate(-90deg);position:absolute;right:10%;top:45%}.dropdown>.dropdown-menu>.dropdown>.dropdown-menu{top:0;left:100%;margin-left:0;margin-right:.1rem}.dropdown-menu-start{right:auto;left:0}.dropdown-menu-end{right:0;left:auto}@media(min-width:576px){.dropdown-menu-sm-start{right:auto;left:0}.dropdown-menu-sm-end{right:0;left:auto}}@media(min-width:768px){.dropdown-menu-md-start{right:auto;left:0}.dropdown-menu-md-end{right:0;left:auto}}@media(min-width:992px){.dropdown-menu-lg-start{right:auto;left:0}.dropdown-menu-lg-end{right:0;left:auto}}@media(min-width:1200px){.dropdown-menu-xl-start{right:auto;left:0}.dropdown-menu-xl-end{right:0;left:auto}}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}hr.divider.divider-text{position:unset}hr.divider.divider-text::before{top:unset}.snackbar{z-index:1060 !important}.figure.figure-is-16x16{height:16px;width:16px}.figure.figure-is-24x24{height:24px;width:24px}.figure.figure-is-32x32{height:32px;width:32px}.figure.figure-is-48x48{height:48px;width:48px}.figure.figure-is-64x64{height:64px;width:64px}.figure.figure-is-96x96{height:96px;width:96px}.figure.figure-is-128x128{height:128px;width:128px}.figure.figure-is-256x256{height:256px;width:256px}.figure.figure-is-512x512{height:512px;width:512px}.form-check>.form-check-input.form-check-input-pointer,.form-check>.form-check-label.form-check-label-pointer,.form-switch>.form-check-input.form-check-input-pointer,.form-switch>.form-check-label.form-check-label-pointer{cursor:pointer}.form-control-plaintext.form-control-xs,.form-control-plaintext.form-control-md,.form-control-plaintext.form-control-xl{padding-right:0;padding-left:0}.form-control-xs{height:calc(1.5em + .3rem + 2px);padding:.15rem .5rem;font-size:.75rem;line-height:1.5;border-radius:.15rem}.form-control-md{height:calc(1.5em + .94rem + 2px);padding:.47rem 1rem;font-size:1.125rem;line-height:1.5;border-radius:.25rem}.form-control-xl{height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.5rem;line-height:1.5;border-radius:.4rem}.form-select-xs{height:calc(1.5em + .3rem + 2px);padding-top:.15rem;padding-bottom:.15rem;padding-left:.5rem;font-size:.75rem}.form-select-md{height:calc(1.5em + .94rem + 2px);padding-top:.47rem;padding-bottom:.47rem;padding-left:1rem;font-size:1.125rem}.form-select-xl{height:calc(1.5em + 1rem + 2px);padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.5rem}.input-group>.b-numeric:not(:last-child)>input{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.b-numeric:not(:first-child)>input{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-xs>.form-control:not(textarea),.input-group-xs>.form-select,.input-group-xs>.b-numeric>input{height:calc(1.5em + .3rem + 2px)}.input-group-xs>.form-control,.input-group-xs>.form-select,.input-group-xs>.input-group-text,.input-group-xs>.btn,.input-group-xs>.b-numeric>input{padding:.15rem .5rem;font-size:.75rem;line-height:1.5;border-radius:.15rem}.input-group-sm>.b-numeric>input{height:calc(1.5em + .5rem + 2px)}.input-group-sm>.b-numeric>input{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-md>.form-control:not(textarea),.input-group-md>.form-select,.input-group-md>.b-numeric>input{height:calc(1.5em + .94rem + 2px)}.input-group-md>.form-control,.input-group-md>.form-select,.input-group-md>.input-group-text,.input-group-md>.btn,.input-group-md>.b-numeric>input{padding:.47rem 1rem;font-size:1.125rem;line-height:1.5;border-radius:.25rem}.input-group-lg>.b-numeric>input{height:calc(1.5em + 1rem + 2px)}.input-group-lg>.b-numeric>input{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-xl>.form-control:not(textarea),.input-group-xl>.form-select,.input-group-xl>.b-numeric>input{height:calc(1.5em + 1rem + 2px)}.input-group-xl>.form-control,.input-group-xl>.form-select,.input-group-xl>.input-group-text,.input-group-xl>.btn,.input-group-xl>.b-numeric>input{padding:.5rem 1rem;font-size:1.5rem;line-height:1.5;border-radius:.4rem}.input-group-xs>.form-select,.input-group-md>.form-select,.input-group-xl>.form-select{padding-right:1.75rem}.input-group:not(.has-validation)>.dropdown:first-child>.btn:not(:last-child).dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown>.btn:not(:last-child).dropdown-toggle,.input-group.has-validation>.dropdown>.btn:not(:last-child):not(.dropdown-toggle){border-top-left-radius:0;border-bottom-left-radius:0}.form-check>.form-check-input.form-check-input-xs{width:.7rem;height:.7rem}.form-check>.form-check-input.form-check-input-xs+.form-check-label{line-height:"normal";padding-left:0}.form-check>.form-check-input.form-check-input-sm{width:.8rem;height:.8rem}.form-check>.form-check-input.form-check-input-sm+.form-check-label{line-height:"normal";padding-left:0}.form-check>.form-check-input.form-check-input-md{width:1.25rem;height:1.25rem}.form-check>.form-check-input.form-check-input-md+.form-check-label{line-height:1.7rem;padding-left:3px}.form-check>.form-check-input.form-check-input-lg{width:1.55rem;height:1.55rem}.form-check>.form-check-input.form-check-input-lg+.form-check-label{line-height:2rem;padding-left:6px}.form-check>.form-check-input.form-check-input-xl{width:1.85rem;height:1.85rem}.form-check>.form-check-input.form-check-input-xl+.form-check-label{line-height:2.5rem;padding-left:10px}select[readonly]{pointer-events:none}select[readonly] option,select[readonly] optgroup{display:none}.b-numeric{position:relative;width:100%}.b-numeric:hover>.b-numeric-handler-wrap{opacity:1}.b-numeric-handler-wrap{position:absolute;top:0;right:0;width:22px;height:100%;background:#fff;border:1px solid #d9d9d9;opacity:0}.input-group .b-numeric{-ms-flex:1 1 auto;flex:1 1 auto;width:1%}.b-numeric-handler-wrap .b-numeric-handler.b-numeric-handler-down{border-top:1px solid #d9d9d9}.b-numeric-handler{position:relative;display:flex;width:100%;height:50%;overflow:hidden;color:rgba(0,0,0,.45);font-weight:700;line-height:0;align-items:center;justify-content:center}.b-numeric-handler.btn{padding:0}.form-control+.b-numeric-handler-wrap{font-size:1rem;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.form-control-xs+.b-numeric-handler-wrap{font-size:.75rem;border-top-right-radius:.15rem;border-bottom-right-radius:.15rem}.form-control-xs+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:.75rem}.form-control-sm+.b-numeric-handler-wrap{font-size:.875rem;border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.form-control-sm+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:.875rem}.form-control-md+.b-numeric-handler-wrap{font-size:1.125rem;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.form-control-md+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:1.125rem}.form-control-lg+.b-numeric-handler-wrap{font-size:1.25rem;border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.form-control-lg+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:1.25rem}.form-control-xl+.b-numeric-handler-wrap{font-size:1.5rem;border-top-right-radius:.4rem;border-bottom-right-radius:.4rem}.form-control-xl+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:1.5rem}.custom-file-label{overflow:hidden}input[readonly][type=range],input[readonly=readonly][type=range]{pointer-events:none}input[readonly][type=range]::-webkit-slider-thumb,input[readonly=readonly][type=range]::-webkit-slider-thumb{pointer-events:none}input[readonly][type=range]::-moz-range-thumb,input[readonly=readonly][type=range]::-moz-range-thumb{pointer-events:none}input[readonly][type=range]::-ms-thumb,input[readonly=readonly][type=range]::-ms-thumb{pointer-events:none}.form-group{margin-bottom:1rem}.form-inline{display:flex;flex-flow:row wrap;align-items:center}.form-inline .form-check{width:100%}@media(min-width:576px){.form-inline label{display:flex;align-items:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:flex;flex:0 0 auto;flex-flow:row wrap;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .input-group,.form-inline .custom-select{width:auto}.form-inline .form-check{display:flex;align-items:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;flex-shrink:0;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .form-select{align-items:center;justify-content:center}.form-inline .form-check-label{margin-bottom:0}}.b-input-color-picker{padding:.5rem .6rem}.b-input-color-picker>.b-input-color-picker-preview{height:.55rem}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media(min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.jumbotron.jumbotron-primary{background-color:#007bff;color:#fff}.jumbotron.jumbotron-secondary{background-color:#6c757d;color:#fff}.jumbotron.jumbotron-success{background-color:#28a745;color:#fff}.jumbotron.jumbotron-info{background-color:#17a2b8;color:#fff}.jumbotron.jumbotron-warning{background-color:#ffc107;color:#212529}.jumbotron.jumbotron-danger{background-color:#dc3545;color:#fff}.jumbotron.jumbotron-light{background-color:#f8f9fa;color:#212529}.jumbotron.jumbotron-dark{background-color:#343a40;color:#fff}.jumbotron.jumbotron-link{background-color:#3273dc;color:#fff}.b-layout-header-fixed{z-index:1030}.b-layout-footer-fixed{z-index:1030}.b-layout-sider-content{z-index:1031}li.list-group-item-action{cursor:pointer}.b-list-view{overflow-y:scroll}.media{display:flex;align-items:flex-start}.media-body{flex:1}.modal.show{animation-duration:.25s;animation-fill-mode:both;animation-name:fadeIn}.page-item:not(.disabled) .page-link{cursor:pointer}.pagination-xs .page-link{padding:.125rem .25rem;font-size:.75rem;line-height:1.5}.pagination-xs .page-item:first-child .page-link{border-top-left-radius:.15rem;border-bottom-left-radius:.15rem}.pagination-xs .page-item:last-child .page-link{border-top-right-radius:.15rem;border-bottom-right-radius:.15rem}.pagination-md .page-link{padding:.625rem 1.25rem;font-size:1.125rem;line-height:1.5}.pagination-md .page-item:first-child .page-link{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.pagination-md .page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.pagination-xl .page-link{padding:1rem 2rem;font-size:1.5rem;line-height:1.5}.pagination-xl .page-item:first-child .page-link{border-top-left-radius:.4rem;border-bottom-left-radius:.4rem}.pagination-xl .page-item:last-child .page-link{border-top-right-radius:.4rem;border-bottom-right-radius:.4rem}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-primary{background-color:#007bff}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-secondary{background-color:#6c757d}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-success{background-color:#28a745}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-info{background-color:#17a2b8}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-warning{background-color:#ffc107}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-danger{background-color:#dc3545}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-light{background-color:#f8f9fa}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-dark{background-color:#343a40}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-link{background-color:#3273dc}.rating:not(.rating-disabled):not(.rating-readonly):hover .rating-item{cursor:pointer}.rating.rating-disabled{opacity:.65}.rating .rating-item.rating-item-primary{color:#007bff}.rating .rating-item.rating-item-secondary{color:#6c757d}.rating .rating-item.rating-item-success{color:#28a745}.rating .rating-item.rating-item-info{color:#17a2b8}.rating .rating-item.rating-item-warning{color:#ffc107}.rating .rating-item.rating-item-danger{color:#dc3545}.rating .rating-item.rating-item-light{color:#f8f9fa}.rating .rating-item.rating-item-dark{color:#343a40}.rating .rating-item.rating-item-link{color:#3273dc}.rating .rating-item.rating-item-hover{opacity:.7}.steps{padding:0;margin:0;list-style:none;display:flex;overflow-x:auto}.steps .step:first-child{margin-left:auto}.steps .step:last-child{margin-right:auto}.step:first-of-type .step-circle::before{display:none}.step:last-of-type .step-container{padding-right:0}.step-container{box-sizing:content-box;display:flex;align-items:center;flex-direction:column;width:5rem;min-width:5rem;max-width:5rem;padding-top:.5rem;padding-right:1rem}.step-circle{position:relative;display:flex;justify-content:center;align-items:center;width:1.5rem;height:1.5rem;color:#adb5bd;border:2px solid #adb5bd;border-radius:100%;background-color:#fff}.step-circle::before{content:"";display:block;position:absolute;top:50%;left:-2px;width:calc(5rem + 1rem - 1.5rem);height:2px;transform:translate(-100%,-50%);color:#adb5bd;background-color:currentColor}.step-text{color:#adb5bd;word-break:break-all;margin-top:.25em}.step-completed .step-circle{color:#fff;background-color:#28a745;border-color:#28a745}.step-completed .step-circle::before{color:#28a745}.step-completed .step-text{color:#28a745}.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-active .step-circle::before{color:#007bff}.step-active .step-text{color:#007bff}.step-primary .step-circle{color:#007bff;border-color:#007bff}.step-primary.step-completed .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-primary.step-completed .step-circle::before{color:#007bff}.step-primary.step-completed .step-text{color:#007bff}.step-primary.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-primary.step-active::before{color:#007bff}.step-primary.step-active .step-text{color:#007bff}.step-secondary .step-circle{color:#6c757d;border-color:#6c757d}.step-secondary.step-completed .step-circle{color:#fff;background-color:#6c757d;border-color:#6c757d}.step-secondary.step-completed .step-circle::before{color:#6c757d}.step-secondary.step-completed .step-text{color:#6c757d}.step-secondary.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-secondary.step-active::before{color:#007bff}.step-secondary.step-active .step-text{color:#007bff}.step-success .step-circle{color:#28a745;border-color:#28a745}.step-success.step-completed .step-circle{color:#fff;background-color:#28a745;border-color:#28a745}.step-success.step-completed .step-circle::before{color:#28a745}.step-success.step-completed .step-text{color:#28a745}.step-success.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-success.step-active::before{color:#007bff}.step-success.step-active .step-text{color:#007bff}.step-info .step-circle{color:#17a2b8;border-color:#17a2b8}.step-info.step-completed .step-circle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.step-info.step-completed .step-circle::before{color:#17a2b8}.step-info.step-completed .step-text{color:#17a2b8}.step-info.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-info.step-active::before{color:#007bff}.step-info.step-active .step-text{color:#007bff}.step-warning .step-circle{color:#ffc107;border-color:#ffc107}.step-warning.step-completed .step-circle{color:#fff;background-color:#ffc107;border-color:#ffc107}.step-warning.step-completed .step-circle::before{color:#ffc107}.step-warning.step-completed .step-text{color:#ffc107}.step-warning.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-warning.step-active::before{color:#007bff}.step-warning.step-active .step-text{color:#007bff}.step-danger .step-circle{color:#dc3545;border-color:#dc3545}.step-danger.step-completed .step-circle{color:#fff;background-color:#dc3545;border-color:#dc3545}.step-danger.step-completed .step-circle::before{color:#dc3545}.step-danger.step-completed .step-text{color:#dc3545}.step-danger.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-danger.step-active::before{color:#007bff}.step-danger.step-active .step-text{color:#007bff}.step-light .step-circle{color:#f8f9fa;border-color:#f8f9fa}.step-light.step-completed .step-circle{color:#fff;background-color:#f8f9fa;border-color:#f8f9fa}.step-light.step-completed .step-circle::before{color:#f8f9fa}.step-light.step-completed .step-text{color:#f8f9fa}.step-light.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-light.step-active::before{color:#007bff}.step-light.step-active .step-text{color:#007bff}.step-dark .step-circle{color:#343a40;border-color:#343a40}.step-dark.step-completed .step-circle{color:#fff;background-color:#343a40;border-color:#343a40}.step-dark.step-completed .step-circle::before{color:#343a40}.step-dark.step-completed .step-text{color:#343a40}.step-dark.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-dark.step-active::before{color:#007bff}.step-dark.step-active .step-text{color:#007bff}.step-link .step-circle{color:#3273dc;border-color:#3273dc}.step-link.step-completed .step-circle{color:#fff;background-color:#3273dc;border-color:#3273dc}.step-link.step-completed .step-circle::before{color:#3273dc}.step-link.step-completed .step-text{color:#3273dc}.step-link.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-link.step-active::before{color:#007bff}.step-link.step-active .step-text{color:#007bff}.steps-content{margin:1rem 0}.steps-content>.step-panel{display:none}.steps-content>.active{display:block}.form-check.form-switch .form-check-input.form-check-input-primary:checked{background-color:#007bff;border-color:#007bff}.form-check.form-switch .form-check-input.form-check-input-secondary:checked{background-color:#6c757d;border-color:#6c757d}.form-check.form-switch .form-check-input.form-check-input-success:checked{background-color:#28a745;border-color:#28a745}.form-check.form-switch .form-check-input.form-check-input-info:checked{background-color:#17a2b8;border-color:#17a2b8}.form-check.form-switch .form-check-input.form-check-input-warning:checked{background-color:#ffc107;border-color:#ffc107}.form-check.form-switch .form-check-input.form-check-input-danger:checked{background-color:#dc3545;border-color:#dc3545}.form-check.form-switch .form-check-input.form-check-input-light:checked{background-color:#f8f9fa;border-color:#f8f9fa}.form-check.form-switch .form-check-input.form-check-input-dark:checked{background-color:#343a40;border-color:#343a40}.form-check.form-switch .form-check-input.form-check-input-link:checked{background-color:#3273dc;border-color:#3273dc}.form-check.form-switch .form-check-input.form-check-input-xs{width:calc(.75rem + (.5rem/2));height:.5rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-xs+.form-check-label{line-height:1rem;vertical-align:middle;padding-left:0}.form-check.form-switch .form-check-input.form-check-input-xs:checked~.form-check-label::after{transform:translateX(calc(.75rem - (.5rem/2)))}.form-check.form-switch .form-check-input.form-check-input-sm{width:calc(1rem + (.75rem/2));height:.75rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-sm+.form-check-label{line-height:1.25rem;vertical-align:middle;padding-left:.75rem}.form-check.form-switch .form-check-input.form-check-input-sm:checked~.form-check-label::after{transform:translateX(calc(1rem - (.75rem/2)))}.form-check.form-switch .form-check-input.form-check-input-md{width:calc(2rem + (1.5rem/2));height:1.5rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-md+.form-check-label{line-height:2rem;vertical-align:middle;padding-left:.75rem}.form-check.form-switch .form-check-input.form-check-input-md:checked~.form-check-label::after{transform:translateX(calc(2rem - (1.5rem/2)))}.form-check.form-switch .form-check-input.form-check-input-lg{width:calc(3rem + (2rem/2));height:2rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-lg+.form-check-label{line-height:2.5rem;vertical-align:middle;padding-left:.75rem}.form-check.form-switch .form-check-input.form-check-input-lg:checked~.form-check-label::after{transform:translateX(calc(3rem - (2rem/2)))}.form-check.form-switch .form-check-input.form-check-input-xl{width:calc(4rem + (2.5rem/2));height:2.5rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-xl+.form-check-label{line-height:3rem;vertical-align:middle;padding-left:.75rem}.form-check.form-switch .form-check-input.form-check-input-xl:checked~.form-check-label::after{transform:translateX(calc(4rem - (2.5rem/2)))}table.table tbody tr.selected{background-color:var(--primary)}tr.table-row-selectable:hover{cursor:pointer}.table-fixed-header{overflow-y:auto}.table-fixed-header>.table{border-collapse:separate;border-spacing:0}.table-fixed-header>.table>thead>tr>th{border-top:none;position:sticky;background:#fff;z-index:10}.table-fixed-header>.table>thead>tr:nth-child(1)>th{top:0}.table-fixed-header>.table-bordered>:not(caption)>*>*{border-width:1px 1px}.overflow-auto-auto{overflow:auto auto !important}.overflow-auto-hidden{overflow:auto hidden !important}.overflow-auto-visible{overflow:auto visible !important}.overflow-auto-scroll{overflow:auto scroll !important}.overflow-hidden-auto{overflow:hidden auto !important}.overflow-hidden-hidden{overflow:hidden hidden !important}.overflow-hidden-visible{overflow:hidden visible !important}.overflow-hidden-scroll{overflow:hidden scroll !important}.overflow-visible-auto{overflow:visible auto !important}.overflow-visible-hidden{overflow:visible hidden !important}.overflow-visible-visible{overflow:visible visible !important}.overflow-visible-scroll{overflow:visible scroll !important}.overflow-scroll-auto{overflow:scroll auto !important}.overflow-scroll-hidden{overflow:scroll hidden !important}.overflow-scroll-visible{overflow:scroll visible !important}.overflow-scroll-scroll{overflow:scroll scroll !important}ol.ordered-list-lower-alpha{list-style-type:lower-alpha}ol.ordered-list-lower-roman{list-style-type:lower-roman}ol.ordered-list-upper-alpha{list-style-type:upper-alpha}ol.ordered-list-upper-roman{list-style-type:upper-roman}.flatpickr-months{margin:.5rem 0}.flatpickr-months .flatpickr-month,.flatpickr-months .flatpickr-next-month,.flatpickr-months .flatpickr-prev-month{height:auto;position:relative}.flatpickr-months .flatpickr-month:hover svg,.flatpickr-months .flatpickr-next-month:hover svg,.flatpickr-months .flatpickr-prev-month:hover svg{fill:#007bff}.flatpickr-months .flatpickr-month{color:#212529}.flatpickr-current-month{padding:13px 0 0 0;font-size:115%}.flatpickr-current-month span.cur-month{font-weight:700}.flatpickr-current-month span.cur-month:hover{background:rgba(0,123,255,.15)}.numInputWrapper:hover{background:rgba(0,123,255,.15)}.flatpickr-day{border-radius:.25rem;font-weight:500;color:#212529}.flatpickr-day.today{border-color:#007bff}.flatpickr-day.today:hover{background:#007bff;border-color:#007bff}.flatpickr-day:hover{background:rgba(0,123,255,.1);border-color:rgba(0,0,0,0)}span.flatpickr-weekday{color:#212529}.flatpickr-day.selected,.flatpickr-day.startRange,.flatpickr-day.endRange,.flatpickr-day.selected.inRange,.flatpickr-day.startRange.inRange,.flatpickr-day.endRange.inRange,.flatpickr-day.selected:focus,.flatpickr-day.startRange:focus,.flatpickr-day.endRange:focus,.flatpickr-day.selected:hover,.flatpickr-day.startRange:hover,.flatpickr-day.endRange:hover,.flatpickr-day.selected.prevMonthDay,.flatpickr-day.startRange.prevMonthDay,.flatpickr-day.endRange.prevMonthDay,.flatpickr-day.selected.nextMonthDay,.flatpickr-day.startRange.nextMonthDay,.flatpickr-day.endRange.nextMonthDay{background:#007bff;border-color:#007bff}.flatpickr-day.selected.startRange+.endRange:not(:nth-child(7n+1)),.flatpickr-day.startRange.startRange+.endRange:not(:nth-child(7n+1)),.flatpickr-day.endRange.startRange+.endRange:not(:nth-child(7n+1)){box-shadow:-10px 0 0 #007bff}.flatpickr-day.selected.startRange,.flatpickr-day.startRange.startRange,.flatpickr-day.endRange.startRange{border-radius:.25rem 0 0 .25rem}.flatpickr-day.selected.endRange,.flatpickr-day.startRange.endRange,.flatpickr-day.endRange.endRange{border-radius:0 .25rem .25rem 0}.flatpickr-monthSelect-month:hover,.flatpickr-monthSelect-month:focus{background:rgba(0,123,255,.1)}.flatpickr-monthSelect-month.selected{background-color:#007bff} .snackbar{align-items:center;background-color:var(--b-snackbar-background,#323232);color:var(--b-snackbar-text-color,#fff);font-size:.875rem;line-height:1.42857;opacity:0;padding:.875rem 1.5rem;position:fixed;bottom:0;left:0;transform:translateY(100%);transition:opacity 0s .195s,transform .195s cubic-bezier(.4,0,1,1);width:100%;z-index:60}@media(min-width:768px){.snackbar{border-radius:2px;max-width:35.5rem;min-width:18rem;left:50%;transform:translate(-50%,100%);width:auto}}@media(min-width:768px){.snackbar{transition:opacity 0s .2535s,transform .2535s cubic-bezier(.4,0,1,1)}}@media(min-width:1200px){.snackbar{transition:opacity 0s .13s,transform .13s cubic-bezier(.4,0,1,1)}}@media screen and (prefers-reduced-motion:reduce){.snackbar{transition:none}}.snackbar.snackbar-show{transition-duration:.225s;transition-property:transform;transition-timing-function:cubic-bezier(0,0,.2,1);opacity:1;transform:translateY(0)}@media(min-width:768px){.snackbar.snackbar-show{transition-duration:.2925s}}@media(min-width:1200px){.snackbar.snackbar-show{transition-duration:.15s}}@media screen and (prefers-reduced-motion:reduce){.snackbar.snackbar-show{transition:none}}@media(min-width:768px){.snackbar.snackbar-show{transform:translate(-50%,-1.5rem)}}.snackbar-header{display:flex;-ms-flex-pack:justify;justify-content:space-between;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background-color:DARKEN(var(--b-snackbar-background,#323232),30%);margin-right:auto;min-width:0;font-weight:bold;padding-bottom:.875rem}.snackbar-footer{display:flex;-ms-flex-pack:justify;justify-content:space-between;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background-color:DARKEN(var(--b-snackbar-background,#323232),30%);margin-right:auto;min-width:0;padding-top:.875rem}.snackbar-body{display:flex;-ms-flex-pack:justify;justify-content:space-between;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-right:auto;max-height:100%;min-width:0}.snackbar-action-button{transition-duration:.3s;transition-property:background-color,background-image;transition-timing-function:cubic-bezier(.4,0,.2,1);background-color:transparent;background-image:none;border:0;color:var(--b-snackbar-button-color,var(--b-snackbar-button-color,#ff4081));cursor:pointer;display:block;flex-shrink:0;font-size:inherit;font-weight:500;line-height:inherit;padding:0;text-transform:uppercase;white-space:nowrap}@media(min-width:768px){.snackbar-action-button{transition-duration:.39s}}@media(min-width:1200px){.snackbar-action-button{transition-duration:.2s}}@media screen and (prefers-reduced-motion:reduce){.snackbar-action-button{transition:none}}.snackbar-action-button:focus,.snackbar-action-button:hover{color:var(--b-snackbar-button-hover-color,var(--b-snackbar-button-hover-color,#ff80ab));text-decoration:none}@media(min-width:768px){.snackbar-action-button{margin-left:3rem}}.snackbar-action-button:focus{outline:0}@media(min-width:768px){.snackbar-left,.snackbar-right{transform:translateY(100%)}.snackbar-left.snackbar-show,.snackbar-right.snackbar-show{transform:translateY(-1.5rem)}}@media(min-width:768px){.snackbar-left{left:1.5rem}}@media(min-width:768px){.snackbar-right{right:1.5rem;left:auto}}.snackbar-multi-line{padding-top:1.25rem;padding-bottom:1.25rem}.snackbar-multi-line .snackbar-body{white-space:normal}.snackbar-primary{background-color:var(--b-snackbar-background-primary,#cce5ff);color:var(--b-snackbar-text-primary,#004085)}.snackbar-action-button-primary{color:var(--b-snackbar-button-primary,#ff4081)}.snackbar-action-button-primary:focus,.snackbar-action-button-primary:hover{color:var(--b-snackbar-button-hover-primary,#ff80ab)}.snackbar-secondary{background-color:var(--b-snackbar-background-secondary,#e2e3e5);color:var(--b-snackbar-text-secondary,#383d41)}.snackbar-action-button-secondary{color:var(--b-snackbar-button-secondary,#ff4081)}.snackbar-action-button-secondary:focus,.snackbar-action-button-secondary:hover{color:var(--b-snackbar-button-hover-secondary,#ff80ab)}.snackbar-success{background-color:var(--b-snackbar-background-success,#d4edda);color:var(--b-snackbar-text-success,#155724)}.snackbar-action-button-success{color:var(--b-snackbar-button-success,#ff4081)}.snackbar-action-button-success:focus,.snackbar-action-button-success:hover{color:var(--b-snackbar-button-hover-success,#ff80ab)}.snackbar-danger{background-color:var(--b-snackbar-background-danger,#f8d7da);color:var(--b-snackbar-text-danger,#721c24)}.snackbar-action-button-danger{color:var(--b-snackbar-button-danger,#ff4081)}.snackbar-action-button-danger:focus,.snackbar-action-button-danger:hover{color:var(--b-snackbar-button-hover-danger,#ff80ab)}.snackbar-warning{background-color:var(--b-snackbar-background-warning,#fff3cd);color:var(--b-snackbar-text-warning,#856404)}.snackbar-action-button-warning{color:var(--b-snackbar-button-warning,#ff4081)}.snackbar-action-button-warning:focus,.snackbar-action-button-warning:hover{color:var(--b-snackbar-button-hover-warning,#ff80ab)}.snackbar-info{background-color:var(--b-snackbar-background-info,#d1ecf1);color:var(--b-snackbar-text-info,#0c5460)}.snackbar-action-button-info{color:var(--b-snackbar-button-info,#ff4081)}.snackbar-action-button-info:focus,.snackbar-action-button-info:hover{color:var(--b-snackbar-button-hover-info,#ff80ab)}.snackbar-light{background-color:var(--b-snackbar-background-light,#fefefe);color:var(--b-snackbar-text-light,#818182)}.snackbar-action-button-light{color:var(--b-snackbar-button-light,#ff4081)}.snackbar-action-button-light:focus,.snackbar-action-button-light:hover{color:var(--b-snackbar-button-hover-light,#ff80ab)}.snackbar-dark{background-color:var(--b-snackbar-background-dark,#d6d8d9);color:var(--b-snackbar-text-dark,#1b1e21)}.snackbar-action-button-dark{color:var(--b-snackbar-button-dark,#ff4081)}.snackbar-action-button-dark:focus,.snackbar-action-button-dark:hover{color:var(--b-snackbar-button-hover-dark,#ff80ab)}.snackbar-stack{display:flex;flex-direction:column;position:fixed;z-index:60;bottom:0}.snackbar-stack .snackbar{position:relative;flex-direction:row;margin-bottom:0}.snackbar-stack .snackbar:not(:last-child){margin-bottom:1.5rem}@media(min-width:576px){.snackbar-stack-center{left:50%;transform:translate(-50%,0%)}.snackbar-stack-left{left:1.5rem}.snackbar-stack-right{right:1.5rem}} #main-navbar-tools a.dropdown-toggle{text-decoration:none;color:#fff}.navbar .dropdown-submenu{position:relative}.navbar .dropdown-menu{margin:0;padding:0}.navbar .dropdown-menu a{font-size:.9em;padding:10px 15px;display:block;min-width:210px;text-align:left;border-radius:.25rem;min-height:44px}.navbar .dropdown-submenu a::after{transform:rotate(-90deg);position:absolute;right:16px;top:18px}.navbar .dropdown-submenu .dropdown-menu{top:0;left:100%}.card-header .btn{padding:2px 6px}.card-header h5{margin:0}.container>.card{box-shadow:0 .125rem .25rem rgba(0,0,0,.075) !important}@media screen and (min-width:768px){.navbar .dropdown:hover>.dropdown-menu{display:block}.navbar .dropdown-submenu:hover>.dropdown-menu{display:block}}.input-validation-error{border-color:#dc3545}.field-validation-error{font-size:.8em}.dataTables_scrollBody{min-height:248px}div.dataTables_wrapper div.dataTables_info{padding-top:11px;white-space:nowrap}div.dataTables_wrapper div.dataTables_length label{padding-top:10px;margin-bottom:0}.rtl .dropdown-menu-right{right:auto;left:0}.rtl .dropdown-menu-right a{text-align:right}.rtl .navbar .dropdown-menu a{text-align:right}.rtl .navbar .dropdown-submenu .dropdown-menu{top:0;left:auto;right:100%}.navbar-dark .navbar-nav .nav-link{color:#000 !important}.navbar-nav>.nav-item>.nav-link,.navbar-nav>.nav-item>.dropdown>.nav-link{color:#fff !important}.navbar-nav>.nav-item>div>button{color:#fff}.btn span.spinner-border{margin-right:.5rem}.radar-spinner,.radar-spinner *{box-sizing:border-box}.radar-spinner{height:60px;width:60px;position:relative}.radar-spinner .circle{position:absolute;height:100%;width:100%;top:0;left:0;animation:radar-spinner-animation 2s infinite}.radar-spinner .circle:nth-child(1){padding:calc(60px*5*2*0/110);animation-delay:300ms}.radar-spinner .circle:nth-child(2){padding:calc(60px*5*2*1/110);animation-delay:300ms}.radar-spinner .circle:nth-child(3){padding:calc(60px*5*2*2/110);animation-delay:300ms}.radar-spinner .circle:nth-child(4){padding:calc(60px*5*2*3/110);animation-delay:0ms}.radar-spinner .circle-inner,.radar-spinner .circle-inner-container{height:100%;width:100%;border-radius:50%;border:calc(60px*5/110) solid transparent}.radar-spinner .circle-inner{border-left-color:var(--secondary,#ff1d5e);border-right-color:var(--secondary,#ff1d5e)}@keyframes radar-spinner-animation{50%{transform:rotate(180deg)}100%{transform:rotate(0deg)}} diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/wwwroot/index.html b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/wwwroot/index.html index 2cf5fe3fc8..401df405e4 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/wwwroot/index.html +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/wwwroot/index.html @@ -8,7 +8,7 @@ - + @@ -23,7 +23,7 @@
- + diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Host/MyCompanyName.MyProjectName.Blazor.Host.csproj b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Host/MyCompanyName.MyProjectName.Blazor.Host.csproj index 1e027b9852..15cb537c32 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Host/MyCompanyName.MyProjectName.Blazor.Host.csproj +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Host/MyCompanyName.MyProjectName.Blazor.Host.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Host/wwwroot/global.css b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Host/wwwroot/global.css index 7c71980d56..9b8609312c 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Host/wwwroot/global.css +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Host/wwwroot/global.css @@ -14,6 +14,6 @@ body:before{content:"mobile";display:none;visibility:hidden}@media(min-width:768px){body:before{content:"tablet"}}@media(min-width:992px){body:before{content:"desktop"}}@media(min-width:1200px){body:before{content:"widescreen"}}@media(min-width:1400px){body:before{content:"fullhd"}}hr.divider.divider-solid{border-top:var(--b-divider-thickness,1px) solid var(--b-divider-color,#999)}hr.divider.divider-dashed{border-top:var(--b-divider-thickness,1px) dashed var(--b-divider-color,#999)}hr.divider.divider-dotted{border-top:var(--b-divider-thickness,1px) dotted var(--b-divider-color,#999)}hr.divider.divider-text{position:relative;border:none;height:var(--b-divider-thickness,1px);background:var(--b-divider-color,#999)}hr.divider.divider-text::before{content:attr(data-content);display:inline-block;background:#fff;font-weight:bold;font-size:var(--b-divider-font-size,.85rem);color:var(--b-divider-color,#999);border-radius:30rem;padding:.2rem 2rem;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.b-input-color-picker{padding:.6rem}.b-input-color-picker>.b-input-color-picker-preview{position:relative;z-index:1;width:100%;height:100%;display:flex;flex-direction:row;justify-content:space-between}.b-input-color-picker>.b-input-color-picker-preview::before{position:absolute;content:'';top:0;left:0;width:100%;height:100%;background:url('data:image/svg+xml;utf8, ');background-size:.5em;border-radius:.15em;z-index:-1}.b-input-color-picker>.b-input-color-picker-preview>.b-input-color-picker-curent-color{display:inline-block;width:100%;height:100%}.b-input-color-picker[aria-disabled='true']{opacity:.65}.progress.progress-xs{height:.25rem}.progress.progress-sm{height:.5rem}.progress.progress-md{height:1rem}.progress.progress-lg{height:1.5rem}.progress.progress-xl{height:2rem}.b-page-progress{width:100%;height:4px;z-index:9999;top:0;left:0;position:fixed;display:none}.b-page-progress .b-page-progress-indicator{width:0;height:100%;transition:height .3s;background-color:#000;transition:width 1s}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-indeterminate{width:30%;animation:running-page-progress 2s cubic-bezier(.4,0,.2,1) infinite}.b-page-progress.b-page-progress-active{display:block}@keyframes running-page-progress{0%{margin-left:0;margin-right:100%}50%{margin-left:25%;margin-right:0%}100%{margin-left:100%;margin-right:0}}.tippy-box[data-animation=scale][data-placement^=top]{transform-origin:bottom}.tippy-box[data-animation=scale][data-placement^=bottom]{transform-origin:top}.tippy-box[data-animation=scale][data-placement^=left]{transform-origin:right}.tippy-box[data-animation=scale][data-placement^=right]{transform-origin:left}.tippy-box[data-animation=scale][data-state=hidden]{transform:scale(.5);opacity:0}.tippy-box[data-theme~='blazorise']{background-color:RGBA(var(--b-tooltip-background-color-r,128),var(--b-tooltip-background-color-g,128),var(--b-tooltip-background-color-b,128),var(--b-tooltip-background-opacity,.9));color:var(--b-tooltip-color,#fff)}.tippy-box[data-theme~='blazorise'][data-placement^='top']>.tippy-arrow::before{border-top-color:RGBA(var(--b-tooltip-background-color-r,128),var(--b-tooltip-background-color-g,128),var(--b-tooltip-background-color-b,128),var(--b-tooltip-background-opacity,.9))}.tippy-box[data-theme~='blazorise'][data-placement^='bottom']>.tippy-arrow::before{border-bottom-color:RGBA(var(--b-tooltip-background-color-r,128),var(--b-tooltip-background-color-g,128),var(--b-tooltip-background-color-b,128),var(--b-tooltip-background-opacity,.9))}.tippy-box[data-theme~='blazorise'][data-placement^='left']>.tippy-arrow::before{border-left-color:RGBA(var(--b-tooltip-background-color-r,128),var(--b-tooltip-background-color-g,128),var(--b-tooltip-background-color-b,128),var(--b-tooltip-background-opacity,.9))}.tippy-box[data-theme~='blazorise'][data-placement^='right']>.tippy-arrow::before{border-right-color:RGBA(var(--b-tooltip-background-color-r,128),var(--b-tooltip-background-color-g,128),var(--b-tooltip-background-color-b,128),var(--b-tooltip-background-opacity,.9))}.tippy-box[data-theme~='blazorise']>.tippy-svg-arrow{fill:RGBA(var(--b-tooltip-background-color-r,128),var(--b-tooltip-background-color-g,128),var(--b-tooltip-background-color-b,128),var(--b-tooltip-background-opacity,.9))}.b-tooltip-inline{display:inline-block}.b-layout{display:flex;flex:auto;flex-direction:column}.b-layout.b-layout-root{height:100vh}.b-layout,.b-layout *{box-sizing:border-box}@keyframes spinner{0%{transform:translate3d(-50%,-50%,0) rotate(0deg)}100%{transform:translate3d(-50%,-50%,0) rotate(360deg)}}.b-layout>.b-layout-loading{z-index:9999;position:fixed;width:100%;height:100%;background:rgba(0,0,0,.3)}.b-layout>.b-layout-loading:before{animation:1s linear infinite spinner;border:solid 3px #eee;border-bottom-color:var(--b-theme-primary);border-radius:50%;height:40px;left:50%;position:absolute;top:50%;transform:translate3d(-50%,-50%,0);width:40px;content:' '}.b-layout.b-layout-has-sider{flex-direction:row;min-height:0}.b-layout.b-layout-has-sider .b-layout{overflow-x:hidden}.b-layout-header,.b-layout-footer{flex:0 0 auto}.b-layout-header{color:rgba(0,0,0,.65)}.b-layout.b-layout-root.b-layout-has-sider>.b-layout-header-fixed,.b-layout.b-layout-root.b-layout-has-sider>.b-layout>.b-layout-header-fixed{position:sticky;top:0;width:100%;flex:0}.b-layout.b-layout-root:not(.b-layout-has-sider) .b-layout-header-fixed,.b-layout.b-layout-root:not(.b-layout-has-sider)>.b-layout .b-layout-header-fixed{position:fixed;top:0;left:0;right:0;flex:0}.b-layout.b-layout-root:not(.b-layout-has-sider) .b-layout-header-fixed+.b-layout-content,.b-layout.b-layout-root:not(.b-layout-has-sider)>.b-layout .b-layout-header-fixed+.b-layout-content{margin-top:var(--b-bar-horizontal-height,auto)}.b-layout.b-layout-root>.b-layout-header.b-layout-header-fixed+.b-layout.b-layout-has-sider{margin-top:var(--b-bar-horizontal-height,auto)}.b-layout-footer{color:rgba(0,0,0,.65)}.b-layout-footer-fixed{position:sticky;z-index:1;bottom:0;flex:0}.b-layout-content{flex:1}.b-layout-sider{display:flex;position:relative;background:#001529}.b-layout-sider-content{position:sticky;top:0;z-index:2}.b-layout-header .navbar{line-height:inherit}.b-bar-horizontal[data-collapse=hide]{flex-wrap:nowrap}.b-bar-horizontal[data-collapse=hide][data-broken=true]{height:auto}.b-bar-horizontal[data-broken=false]{height:auto}.b-layout>.b-layout-header .b-bar-horizontal[data-collapse=hide][data-broken=true]{height:var(--b-bar-horizontal-height,auto)}.b-layout>.b-layout-header .b-bar-horizontal[data-broken=false]{height:var(--b-bar-horizontal-height,auto)}.b-bar-initial{display:none !important}.b-bar-vertical-inline,.b-bar-vertical-popout,.b-bar-vertical-small{display:flex;flex-direction:column;flex-wrap:nowrap;position:sticky;top:0;padding:0;min-width:var(--b-vertical-bar-width,230px);max-width:var(--b-vertical-bar-width,230px);width:var(--b-vertical-bar-width,230px);box-shadow:2px 0 6px rgba(0,21,41,.35);height:100%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.b-bar-vertical-inline:not(.b-bar-initial),.b-bar-vertical-popout:not(.b-bar-initial),.b-bar-vertical-small:not(.b-bar-initial){transition:width 200ms ease-in-out,min-width 200ms ease-in-out}.b-bar-vertical-inline .b-bar-menu,.b-bar-vertical-popout .b-bar-menu,.b-bar-vertical-small .b-bar-menu{width:100%;display:flex;flex:1;justify-content:space-between;flex-direction:column;align-self:stretch}.b-bar-vertical-inline .b-bar-brand,.b-bar-vertical-popout .b-bar-brand,.b-bar-vertical-small .b-bar-brand{width:100%;display:flex;height:var(--b-vertical-bar-brand-height,64px);min-height:var(--b-vertical-bar-brand-height,64px)}.b-bar-vertical-inline .b-bar-toggler-inline,.b-bar-vertical-popout .b-bar-toggler-inline,.b-bar-vertical-small .b-bar-toggler-inline{height:var(--b-vertical-bar-brand-height,64px);padding:12px;display:inline-flex;cursor:pointer;position:absolute;right:0}.b-bar-vertical-inline .b-bar-toggler-inline>*,.b-bar-vertical-popout .b-bar-toggler-inline>*,.b-bar-vertical-small .b-bar-toggler-inline>*{margin:auto}.b-bar-vertical-inline .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-popout .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-small .b-bar-toggler-popout:not(.b-bar-mobile-toggle){display:flex;position:fixed;left:var(--b-vertical-bar-width,230px);border-radius:0 10px 10px 0;border:0;width:10px;height:40px;padding:5px;align-items:center;box-shadow:2px 0 6px rgba(0,21,41,.35);cursor:pointer}.b-bar-vertical-inline .b-bar-toggler-popout:not(.b-bar-mobile-toggle):not(.b-bar-initial),.b-bar-vertical-popout .b-bar-toggler-popout:not(.b-bar-mobile-toggle):not(.b-bar-initial),.b-bar-vertical-small .b-bar-toggler-popout:not(.b-bar-mobile-toggle):not(.b-bar-initial){transition:width 200ms ease-in-out,left 200ms ease-in-out}.b-bar-vertical-inline .b-bar-toggler-popout:not(.b-bar-mobile-toggle)>*,.b-bar-vertical-popout .b-bar-toggler-popout:not(.b-bar-mobile-toggle)>*,.b-bar-vertical-small .b-bar-toggler-popout:not(.b-bar-mobile-toggle)>*{margin:auto;display:none}.b-bar-vertical-inline .b-bar-toggler-popout:not(.b-bar-mobile-toggle):hover,.b-bar-vertical-popout .b-bar-toggler-popout:not(.b-bar-mobile-toggle):hover,.b-bar-vertical-small .b-bar-toggler-popout:not(.b-bar-mobile-toggle):hover{width:45px}.b-bar-vertical-inline .b-bar-toggler-popout:not(.b-bar-mobile-toggle):hover>*,.b-bar-vertical-popout .b-bar-toggler-popout:not(.b-bar-mobile-toggle):hover>*,.b-bar-vertical-small .b-bar-toggler-popout:not(.b-bar-mobile-toggle):hover>*{display:block}.b-bar-vertical-inline .b-bar-item,.b-bar-vertical-popout .b-bar-item,.b-bar-vertical-small .b-bar-item{margin:auto;flex-grow:1;min-height:40px}.b-bar-vertical-inline .b-bar-item .b-bar-icon,.b-bar-vertical-popout .b-bar-item .b-bar-icon,.b-bar-vertical-small .b-bar-item .b-bar-icon{font-size:1.25rem;vertical-align:middle;margin:3px;display:inline-block}.b-bar-vertical-inline .b-bar-start,.b-bar-vertical-popout .b-bar-start,.b-bar-vertical-small .b-bar-start{width:100%;display:block}.b-bar-vertical-inline .b-bar-end,.b-bar-vertical-popout .b-bar-end,.b-bar-vertical-small .b-bar-end{padding-bottom:1rem;width:100%;padding-top:1rem;display:block}.b-bar-vertical-inline .b-bar-link,.b-bar-vertical-popout .b-bar-link,.b-bar-vertical-small .b-bar-link{display:block;width:100%;text-decoration:none;padding:.5rem .5rem .5rem 1.5rem;cursor:pointer;overflow-x:hidden;line-height:1.5rem;vertical-align:middle;transition:font-size 150ms ease-in}.b-bar-vertical-inline .b-bar-label,.b-bar-vertical-popout .b-bar-label,.b-bar-vertical-small .b-bar-label{background:transparent;color:#adb5bd;padding:.375rem 1.25rem;font-size:.75rem;text-overflow:ellipsis;overflow-x:hidden}.b-bar-vertical-inline .b-bar-dropdown .b-bar-dropdown-toggle:before,.b-bar-vertical-popout .b-bar-dropdown .b-bar-dropdown-toggle:before,.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-toggle:before{content:" ";border:solid;border-width:0 2px 2px 0;display:inline-block;padding:2px;right:1rem;transition:transform 200ms ease-out;float:right;position:relative;-webkit-transform:rotate(225deg);transform:rotate(225deg);top:.7rem}.b-bar-vertical-inline .b-bar-dropdown:not([data-visible=true]) .b-bar-dropdown-toggle:before,.b-bar-vertical-popout .b-bar-dropdown:not([data-visible=true]) .b-bar-dropdown-toggle:before,.b-bar-vertical-small .b-bar-dropdown:not([data-visible=true]) .b-bar-dropdown-toggle:before{-webkit-transform:rotate(45deg);transform:rotate(45deg);top:.5rem}.b-bar-vertical-inline .b-bar-dropdown .b-bar-dropdown-menu,.b-bar-vertical-popout .b-bar-dropdown .b-bar-dropdown-menu,.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu{display:none;background:inherit;color:inherit;float:none;padding:5px 0}.b-bar-vertical-inline .b-bar-dropdown .b-bar-dropdown-menu[data-visible=true],.b-bar-vertical-popout .b-bar-dropdown .b-bar-dropdown-menu[data-visible=true],.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu[data-visible=true]{display:block}.b-bar-vertical-inline .b-bar-dropdown .b-bar-dropdown-menu .b-bar-dropdown-item,.b-bar-vertical-popout .b-bar-dropdown .b-bar-dropdown-menu .b-bar-dropdown-item,.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu .b-bar-dropdown-item{position:relative;color:inherit;transition:background 100ms ease-in-out,color 100ms ease-in-out;text-decoration:none;display:block;width:100%;overflow-x:hidden}.b-bar-vertical-inline .b-bar-dropdown .b-bar-dropdown-menu .b-bar-dropdown-item i,.b-bar-vertical-popout .b-bar-dropdown .b-bar-dropdown-menu .b-bar-dropdown-item i,.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu .b-bar-dropdown-item i{margin-right:.3rem}.b-bar-vertical-inline .b-bar-dropdown .b-bar-dropdown-menu:before,.b-bar-vertical-popout .b-bar-dropdown .b-bar-dropdown-menu:before,.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu:before{background:inherit;box-shadow:none}.b-bar-vertical-inline .b-bar-mobile-toggle,.b-bar-vertical-popout .b-bar-mobile-toggle,.b-bar-vertical-small .b-bar-mobile-toggle{right:20px;margin:auto;display:none}.b-bar-vertical-inline .b-bar-item-multi-line,.b-bar-vertical-popout .b-bar-item-multi-line,.b-bar-vertical-small .b-bar-item-multi-line{display:-webkit-box !important;-webkit-box-orient:vertical;-webkit-line-clamp:var(--b-bar-item-lines,2);white-space:normal !important;overflow:hidden;text-overflow:ellipsis}.b-bar-vertical-inline.b-bar-dark,.b-bar-vertical-popout.b-bar-dark,.b-bar-vertical-small.b-bar-dark{background:var(--b-bar-dark-background,#001529);color:var(--b-bar-dark-color,rgba(255,255,255,.5))}.b-bar-vertical-inline.b-bar-dark .b-bar-brand,.b-bar-vertical-popout.b-bar-dark .b-bar-brand,.b-bar-vertical-small.b-bar-dark .b-bar-brand{background:var(--b-bar-brand-dark-background,rgba(255,255,255,.025))}.b-bar-vertical-inline.b-bar-dark .b-bar-brand .b-bar-link,.b-bar-vertical-popout.b-bar-dark .b-bar-brand .b-bar-link,.b-bar-vertical-small.b-bar-dark .b-bar-brand .b-bar-link{color:#fff}.b-bar-vertical-inline.b-bar-dark .b-bar-brand .b-bar-link.active,.b-bar-vertical-popout.b-bar-dark .b-bar-brand .b-bar-link.active,.b-bar-vertical-small.b-bar-dark .b-bar-brand .b-bar-link.active{color:#fff;background:inherit}.b-bar-vertical-inline.b-bar-dark .b-bar-brand .b-bar-link:hover,.b-bar-vertical-popout.b-bar-dark .b-bar-brand .b-bar-link:hover,.b-bar-vertical-small.b-bar-dark .b-bar-brand .b-bar-link:hover{color:#fff;background:inherit}.b-bar-vertical-inline.b-bar-dark .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-popout.b-bar-dark .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-small.b-bar-dark .b-bar-toggler-popout:not(.b-bar-mobile-toggle){background:var(--b-bar-dark-background,#001529);color:var(--b-bar-dark-color,rgba(255,255,255,.5))}.b-bar-vertical-inline.b-bar-dark .b-bar-dropdown-menu,.b-bar-vertical-popout.b-bar-dark .b-bar-dropdown-menu,.b-bar-vertical-small.b-bar-dark .b-bar-dropdown-menu{background:var(--b-bar-dropdown-dark-background,#000c17)}.b-bar-vertical-inline.b-bar-dark .b-bar-dropdown-menu .b-bar-dropdown-item.active,.b-bar-vertical-popout.b-bar-dark .b-bar-dropdown-menu .b-bar-dropdown-item.active,.b-bar-vertical-small.b-bar-dark .b-bar-dropdown-menu .b-bar-dropdown-item.active{color:var(--b-bar-item-dark-active-color,#fff);background:var(--b-bar-item-dark-active-background,#0288d1)}.b-bar-vertical-inline.b-bar-dark .b-bar-dropdown-menu .b-bar-dropdown-item:hover,.b-bar-vertical-popout.b-bar-dark .b-bar-dropdown-menu .b-bar-dropdown-item:hover,.b-bar-vertical-small.b-bar-dark .b-bar-dropdown-menu .b-bar-dropdown-item:hover{color:var(--b-bar-item-dark-hover-color,#fff);background:var(--b-bar-item-dark-hover-background,rgba(255,255,255,.3))}.b-bar-vertical-inline.b-bar-dark .b-bar-link,.b-bar-vertical-popout.b-bar-dark .b-bar-link,.b-bar-vertical-small.b-bar-dark .b-bar-link{color:inherit}.b-bar-vertical-inline.b-bar-dark .b-bar-link.active,.b-bar-vertical-popout.b-bar-dark .b-bar-link.active,.b-bar-vertical-small.b-bar-dark .b-bar-link.active{color:var(--b-bar-item-dark-active-color,#fff);background:var(--b-bar-item-dark-active-background,#0288d1)}.b-bar-vertical-inline.b-bar-dark .b-bar-link:hover,.b-bar-vertical-popout.b-bar-dark .b-bar-link:hover,.b-bar-vertical-small.b-bar-dark .b-bar-link:hover{color:var(--b-bar-item-dark-hover-color,#fff);background:var(--b-bar-item-dark-hover-background,rgba(255,255,255,.3))}.b-bar-vertical-inline.b-bar-light,.b-bar-vertical-popout.b-bar-light,.b-bar-vertical-small.b-bar-light{background:var(--b-bar-light-background,#fff);color:var(--b-bar-light-color,rgba(0,0,0,.7))}.b-bar-vertical-inline.b-bar-light .b-bar-brand,.b-bar-vertical-popout.b-bar-light .b-bar-brand,.b-bar-vertical-small.b-bar-light .b-bar-brand{background:var(--b-bar-brand-light-background,rgba(0,0,0,.025))}.b-bar-vertical-inline.b-bar-light .b-bar-brand .b-bar-link,.b-bar-vertical-popout.b-bar-light .b-bar-brand .b-bar-link,.b-bar-vertical-small.b-bar-light .b-bar-brand .b-bar-link{color:#000}.b-bar-vertical-inline.b-bar-light .b-bar-brand .b-bar-link.active,.b-bar-vertical-popout.b-bar-light .b-bar-brand .b-bar-link.active,.b-bar-vertical-small.b-bar-light .b-bar-brand .b-bar-link.active{background:inherit}.b-bar-vertical-inline.b-bar-light .b-bar-brand .b-bar-link:hover,.b-bar-vertical-popout.b-bar-light .b-bar-brand .b-bar-link:hover,.b-bar-vertical-small.b-bar-light .b-bar-brand .b-bar-link:hover{background:inherit}.b-bar-vertical-inline.b-bar-light .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-popout.b-bar-light .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-small.b-bar-light .b-bar-toggler-popout:not(.b-bar-mobile-toggle){background:var(--b-bar-brand-light-background,#fff);color:var(--b-bar-light-color,rgba(0,0,0,.7))}.b-bar-vertical-inline.b-bar-light .b-bar-dropdown-menu,.b-bar-vertical-popout.b-bar-light .b-bar-dropdown-menu,.b-bar-vertical-small.b-bar-light .b-bar-dropdown-menu{background:var(--b-bar-dropdown-light-background,#f2f2f2)}.b-bar-vertical-inline.b-bar-light .b-bar-dropdown-menu .b-bar-dropdown-item.active,.b-bar-vertical-popout.b-bar-light .b-bar-dropdown-menu .b-bar-dropdown-item.active,.b-bar-vertical-small.b-bar-light .b-bar-dropdown-menu .b-bar-dropdown-item.active{color:var(--b-bar-item-light-active-color,#000);background:var(--b-bar-item-light-active-background,#0288d1)}.b-bar-vertical-inline.b-bar-light .b-bar-dropdown-menu .b-bar-dropdown-item:hover,.b-bar-vertical-popout.b-bar-light .b-bar-dropdown-menu .b-bar-dropdown-item:hover,.b-bar-vertical-small.b-bar-light .b-bar-dropdown-menu .b-bar-dropdown-item:hover{color:var(--b-bar-item-light-hover-color,#000);background:var(--b-bar-item-light-hover-background,rgba(0,0,0,.3))}.b-bar-vertical-inline.b-bar-light .b-bar-link,.b-bar-vertical-popout.b-bar-light .b-bar-link,.b-bar-vertical-small.b-bar-light .b-bar-link{color:inherit}.b-bar-vertical-inline.b-bar-light .b-bar-link.active,.b-bar-vertical-popout.b-bar-light .b-bar-link.active,.b-bar-vertical-small.b-bar-light .b-bar-link.active{color:var(--b-bar-item-light-active-color,#000);background:var(--b-bar-item-light-active-background,#0288d1)}.b-bar-vertical-inline.b-bar-light .b-bar-link:hover,.b-bar-vertical-popout.b-bar-light .b-bar-link:hover,.b-bar-vertical-small.b-bar-light .b-bar-link:hover{color:var(--b-bar-item-light-hover-color,#000);background:var(--b-bar-item-light-hover-background,rgba(0,0,0,.3))}.b-bar-vertical-small,.b-bar-vertical-inline[data-collapse=small],.b-bar-vertical-popout[data-collapse=small]{width:var(--b-vertical-bar-small-width,64px);min-width:var(--b-vertical-bar-small-width,64px)}.b-bar-vertical-small:not(.b-bar-initial),.b-bar-vertical-inline[data-collapse=small]:not(.b-bar-initial),.b-bar-vertical-popout[data-collapse=small]:not(.b-bar-initial){transition:width 200ms ease-in-out,min-width 200ms ease-in-out}.b-bar-vertical-small .b-bar-toggler-inline,.b-bar-vertical-inline[data-collapse=small] .b-bar-toggler-inline,.b-bar-vertical-popout[data-collapse=small] .b-bar-toggler-inline{position:relative;width:100%}.b-bar-vertical-small .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-inline[data-collapse=small] .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-popout[data-collapse=small] .b-bar-toggler-popout:not(.b-bar-mobile-toggle){left:var(--b-vertical-bar-small-width,64px)}.b-bar-vertical-small .b-bar-item>.b-bar-dropdown>.b-bar-dropdown-toggle:before,.b-bar-vertical-inline[data-collapse=small] .b-bar-item>.b-bar-dropdown>.b-bar-dropdown-toggle:before,.b-bar-vertical-popout[data-collapse=small] .b-bar-item>.b-bar-dropdown>.b-bar-dropdown-toggle:before{display:none}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container{z-index:100;max-height:50vh;position:absolute !important;margin:-42px 5px 0 5px;display:flex;width:var(--b-vertical-bar-popout-menu-width,180px);left:var(--b-vertical-bar-small-width,64px)}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container.b-bar-right,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container.b-bar-right,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container.b-bar-right{right:var(--b-vertical-bar-small-width,64px);left:unset}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu{box-shadow:0 3px 6px -4px rgba(0,0,0,.12),0 6px 16px 0 rgba(0,0,0,.08),0 9px 28px 8px rgba(0,0,0,.05);border-radius:3px;overflow-y:auto;overflow-x:hidden;flex:1 100%}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu .b-bar-dropdown-item,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu .b-bar-dropdown-item,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu .b-bar-dropdown-item{padding:.5rem .5rem .5rem 1.5rem}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu:before,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu:before,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu:before{position:absolute;top:0;left:-7px;right:0;bottom:0;width:100%;height:100%;opacity:.0001;content:' ';z-index:-1}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu.b-bar-right:before,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu.b-bar-right:before,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu.b-bar-right:before{left:unset;right:-7px}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-menu-container,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-menu-container,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-menu-container{left:var(--b-vertical-bar-popout-menu-width,180px)}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-menu-container.b-bar-right,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-menu-container.b-bar-right,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-menu-container.b-bar-right{right:var(--b-vertical-bar-popout-menu-width,180px)}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-toggle:before,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-toggle:before,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-toggle:before{content:" ";border:solid;border-width:0 2px 2px 0;display:inline-block;padding:2px;right:1rem;transition:transform 200ms ease-out;float:right;position:relative;-webkit-transform:rotate(315deg);transform:rotate(315deg)}.b-bar-vertical-small .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown:not([data-visible=true]) .b-bar-dropdown-toggle:before,.b-bar-vertical-inline[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown:not([data-visible=true]) .b-bar-dropdown-toggle:before,.b-bar-vertical-popout[data-collapse=small] .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown:not([data-visible=true]) .b-bar-dropdown-toggle:before{-webkit-transform:rotate(135deg);transform:rotate(135deg);right:.8rem}@keyframes b-bar-link-small{to{text-align:center;padding-left:0;padding-right:0}}.b-bar-vertical-small .b-bar-item>.b-bar-link,.b-bar-vertical-small .b-bar-item>.b-bar-dropdown>.b-bar-link,.b-bar-vertical-inline[data-collapse=small] .b-bar-item>.b-bar-link,.b-bar-vertical-inline[data-collapse=small] .b-bar-item>.b-bar-dropdown>.b-bar-link,.b-bar-vertical-popout[data-collapse=small] .b-bar-item>.b-bar-link,.b-bar-vertical-popout[data-collapse=small] .b-bar-item>.b-bar-dropdown>.b-bar-link{animation:b-bar-link-small forwards;animation-delay:170ms;font-size:0;transition:font-size 100ms ease-out}.b-bar-vertical-small .b-bar-item>.b-bar-link:after,.b-bar-vertical-small .b-bar-item>.b-bar-dropdown>.b-bar-link:after,.b-bar-vertical-inline[data-collapse=small] .b-bar-item>.b-bar-link:after,.b-bar-vertical-inline[data-collapse=small] .b-bar-item>.b-bar-dropdown>.b-bar-link:after,.b-bar-vertical-popout[data-collapse=small] .b-bar-item>.b-bar-link:after,.b-bar-vertical-popout[data-collapse=small] .b-bar-item>.b-bar-dropdown>.b-bar-link:after{display:none}.b-bar-vertical-small .b-bar-label,.b-bar-vertical-inline[data-collapse=small] .b-bar-label,.b-bar-vertical-popout[data-collapse=small] .b-bar-label{text-align:center}.b-bar-vertical-inline:not([data-collapse]){overflow-y:auto;overflow-x:hidden}.b-bar-vertical-inline:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container{position:relative}.b-bar-vertical-inline:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu{position:relative !important;border:none;border-radius:0;box-shadow:none}.b-bar-vertical-inline:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu .b-bar-dropdown-item{padding:.5rem .5rem .5rem 3rem}.b-bar-vertical-inline:not([data-collapse]) .b-bar-brand .b-bar-link{display:flex;align-items:center}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-toggle:before{content:" ";border:solid;border-width:0 2px 2px 0;display:inline-block;padding:2px;right:1rem;transition:transform 200ms ease-out;float:right;position:relative;-webkit-transform:rotate(315deg);transform:rotate(315deg)}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown:not([data-visible=true]) .b-bar-dropdown-toggle:before{-webkit-transform:rotate(135deg);transform:rotate(135deg);right:.8rem}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container{z-index:100;max-height:50vh;position:absolute !important;margin:-42px 5px 0 5px;display:flex;width:var(--b-vertical-bar-popout-menu-width,180px);left:var(--b-vertical-bar-width,230px)}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container.b-bar-right{right:var(--b-vertical-bar-width,230px);left:unset}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu{box-shadow:0 3px 6px -4px rgba(0,0,0,.12),0 6px 16px 0 rgba(0,0,0,.08),0 9px 28px 8px rgba(0,0,0,.05);border-radius:3px;overflow-y:auto;overflow-x:hidden;flex:1 100%}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu .b-bar-dropdown-item{padding:.5rem .5rem .5rem 1.5rem}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu:before{position:absolute;top:0;left:-7px;right:0;bottom:0;width:100%;height:100%;opacity:.0001;content:' ';z-index:-1}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu.b-bar-right:before{left:unset;right:-7px}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-menu-container{left:var(--b-vertical-bar-popout-menu-width,180px)}.b-bar-vertical-popout:not([data-collapse]) .b-bar-dropdown .b-bar-dropdown-menu-container .b-bar-dropdown-menu>.b-bar-dropdown .b-bar-dropdown-menu-container.b-bar-right{right:var(--b-vertical-bar-popout-menu-width,180px)}.b-bar-vertical-inline[data-collapse=hide],.b-bar-vertical-popout[data-collapse=hide],.b-bar-vertical-small[data-collapse=hide]{width:0;min-width:0;overflow-y:hidden;visibility:hidden}.b-bar-vertical-inline[data-collapse=hide]:not(.b-bar-initial),.b-bar-vertical-popout[data-collapse=hide]:not(.b-bar-initial),.b-bar-vertical-small[data-collapse=hide]:not(.b-bar-initial){transition:width 200ms ease-in-out,min-width 200ms ease-in-out,visibility 100ms}.b-bar-vertical-inline[data-collapse=hide] .b-bar-toggler-inline,.b-bar-vertical-popout[data-collapse=hide] .b-bar-toggler-inline,.b-bar-vertical-small[data-collapse=hide] .b-bar-toggler-inline{display:none}.b-bar-vertical-inline[data-collapse=hide] .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-popout[data-collapse=hide] .b-bar-toggler-popout:not(.b-bar-mobile-toggle),.b-bar-vertical-small[data-collapse=hide] .b-bar-toggler-popout:not(.b-bar-mobile-toggle){visibility:visible;left:0}@media only screen and (max-width:576px){.b-bar-vertical-inline:not([data-collapse]){min-width:100vw}.b-bar-vertical-inline:not([data-collapse]) .b-bar-toggler-inline:not(.b-bar-mobile-toggle){display:none}.b-bar-vertical-inline:not([data-collapse]) .b-bar-toggler-popout:not(.b-bar-mobile-toggle){left:100vw}.b-bar-vertical-inline:not([data-collapse]) .b-bar-mobile-toggle{display:flex}}.b-table.table{position:relative}.b-table.table .b-table-resizer{position:absolute;top:0;right:0;width:5px;cursor:col-resize;user-select:none;z-index:1}.b-table.table .b-table-resizer:hover,.b-table.table .b-table-resizing{cursor:col-resize !important;border-right:2px solid var(--b-theme-primary,#00f)}.b-table.table .b-table-resizing{cursor:col-resize !important}thead tr th{position:relative}.b-character-casing-lower{text-transform:lowercase}.b-character-casing-upper{text-transform:uppercase}.b-character-casing-title{text-transform:lowercase}.b-character-casing-title::first-letter {text-transform:uppercase}.flatpickr-calendar{background:transparent;opacity:0;display:none;text-align:center;visibility:hidden;padding:0;-webkit-animation:none;animation:none;direction:ltr;border:0;font-size:14px;line-height:24px;border-radius:5px;position:absolute;width:307.875px;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-touch-action:manipulation;touch-action:manipulation;background:#fff;-webkit-box-shadow:1px 0 0 #e6e6e6,-1px 0 0 #e6e6e6,0 1px 0 #e6e6e6,0 -1px 0 #e6e6e6,0 3px 13px rgba(0,0,0,.08);box-shadow:1px 0 0 #e6e6e6,-1px 0 0 #e6e6e6,0 1px 0 #e6e6e6,0 -1px 0 #e6e6e6,0 3px 13px rgba(0,0,0,.08)}.flatpickr-calendar.open,.flatpickr-calendar.inline{opacity:1;max-height:640px;visibility:visible}.flatpickr-calendar.open{display:inline-block;z-index:99999}.flatpickr-calendar.animate.open{-webkit-animation:fpFadeInDown 300ms cubic-bezier(.23,1,.32,1);animation:fpFadeInDown 300ms cubic-bezier(.23,1,.32,1)}.flatpickr-calendar.inline{display:block;position:relative;top:2px}.flatpickr-calendar.static{position:absolute;top:calc(100% + 2px)}.flatpickr-calendar.static.open{z-index:999;display:block}.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+1) .flatpickr-day.inRange:nth-child(7n+7){-webkit-box-shadow:none !important;box-shadow:none !important}.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+2) .flatpickr-day.inRange:nth-child(7n+1){-webkit-box-shadow:-2px 0 0 #e6e6e6,5px 0 0 #e6e6e6;box-shadow:-2px 0 0 #e6e6e6,5px 0 0 #e6e6e6}.flatpickr-calendar .hasWeeks .dayContainer,.flatpickr-calendar .hasTime .dayContainer{border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.flatpickr-calendar .hasWeeks .dayContainer{border-left:0}.flatpickr-calendar.hasTime .flatpickr-time{height:40px;border-top:1px solid #e6e6e6}.flatpickr-calendar.noCalendar.hasTime .flatpickr-time{height:auto}.flatpickr-calendar:before,.flatpickr-calendar:after{position:absolute;display:block;pointer-events:none;border:solid transparent;content:'';height:0;width:0;left:22px}.flatpickr-calendar.rightMost:before,.flatpickr-calendar.arrowRight:before,.flatpickr-calendar.rightMost:after,.flatpickr-calendar.arrowRight:after{left:auto;right:22px}.flatpickr-calendar.arrowCenter:before,.flatpickr-calendar.arrowCenter:after{left:50%;right:50%}.flatpickr-calendar:before{border-width:5px;margin:0 -5px}.flatpickr-calendar:after{border-width:4px;margin:0 -4px}.flatpickr-calendar.arrowTop:before,.flatpickr-calendar.arrowTop:after{bottom:100%}.flatpickr-calendar.arrowTop:before{border-bottom-color:#e6e6e6}.flatpickr-calendar.arrowTop:after{border-bottom-color:#fff}.flatpickr-calendar.arrowBottom:before,.flatpickr-calendar.arrowBottom:after{top:100%}.flatpickr-calendar.arrowBottom:before{border-top-color:#e6e6e6}.flatpickr-calendar.arrowBottom:after{border-top-color:#fff}.flatpickr-calendar:focus{outline:0}.flatpickr-wrapper{position:relative;display:inline-block}.flatpickr-months{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.flatpickr-months .flatpickr-month{background:transparent;color:rgba(0,0,0,.9);fill:rgba(0,0,0,.9);height:34px;line-height:1;text-align:center;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;overflow:hidden;-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}.flatpickr-months .flatpickr-prev-month,.flatpickr-months .flatpickr-next-month{text-decoration:none;cursor:pointer;position:absolute;top:0;height:34px;padding:10px;z-index:3;color:rgba(0,0,0,.9);fill:rgba(0,0,0,.9)}.flatpickr-months .flatpickr-prev-month.flatpickr-disabled,.flatpickr-months .flatpickr-next-month.flatpickr-disabled{display:none}.flatpickr-months .flatpickr-prev-month i,.flatpickr-months .flatpickr-next-month i{position:relative}.flatpickr-months .flatpickr-prev-month.flatpickr-prev-month,.flatpickr-months .flatpickr-next-month.flatpickr-prev-month{left:0}.flatpickr-months .flatpickr-prev-month.flatpickr-next-month,.flatpickr-months .flatpickr-next-month.flatpickr-next-month{right:0}.flatpickr-months .flatpickr-prev-month:hover,.flatpickr-months .flatpickr-next-month:hover{color:#959ea9}.flatpickr-months .flatpickr-prev-month:hover svg,.flatpickr-months .flatpickr-next-month:hover svg{fill:#f64747}.flatpickr-months .flatpickr-prev-month svg,.flatpickr-months .flatpickr-next-month svg{width:14px;height:14px}.flatpickr-months .flatpickr-prev-month svg path,.flatpickr-months .flatpickr-next-month svg path{-webkit-transition:fill .1s;transition:fill .1s;fill:inherit}.numInputWrapper{position:relative;height:auto}.numInputWrapper input,.numInputWrapper span{display:inline-block}.numInputWrapper input{width:100%}.numInputWrapper input::-ms-clear{display:none}.numInputWrapper input::-webkit-outer-spin-button,.numInputWrapper input::-webkit-inner-spin-button{margin:0;-webkit-appearance:none}.numInputWrapper span{position:absolute;right:0;width:14px;padding:0 4px 0 2px;height:50%;line-height:50%;opacity:0;cursor:pointer;border:1px solid rgba(57,57,57,.15);-webkit-box-sizing:border-box;box-sizing:border-box}.numInputWrapper span:hover{background:rgba(0,0,0,.1)}.numInputWrapper span:active{background:rgba(0,0,0,.2)}.numInputWrapper span:after{display:block;content:"";position:absolute}.numInputWrapper span.arrowUp{top:0;border-bottom:0}.numInputWrapper span.arrowUp:after{border-left:4px solid transparent;border-right:4px solid transparent;border-bottom:4px solid rgba(57,57,57,.6);top:26%}.numInputWrapper span.arrowDown{top:50%}.numInputWrapper span.arrowDown:after{border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid rgba(57,57,57,.6);top:40%}.numInputWrapper span svg{width:inherit;height:auto}.numInputWrapper span svg path{fill:rgba(0,0,0,.5)}.numInputWrapper:hover{background:rgba(0,0,0,.05)}.numInputWrapper:hover span{opacity:1}.flatpickr-current-month{font-size:135%;line-height:inherit;font-weight:300;color:inherit;position:absolute;width:75%;left:12.5%;padding:7.48px 0 0 0;line-height:1;height:34px;display:inline-block;text-align:center;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.flatpickr-current-month span.cur-month{font-family:inherit;font-weight:700;color:inherit;display:inline-block;margin-left:.5ch;padding:0}.flatpickr-current-month span.cur-month:hover{background:rgba(0,0,0,.05)}.flatpickr-current-month .numInputWrapper{width:6ch;width:7ch\0;display:inline-block}.flatpickr-current-month .numInputWrapper span.arrowUp:after{border-bottom-color:rgba(0,0,0,.9)}.flatpickr-current-month .numInputWrapper span.arrowDown:after{border-top-color:rgba(0,0,0,.9)}.flatpickr-current-month input.cur-year{background:transparent;-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;cursor:text;padding:0 0 0 .5ch;margin:0;display:inline-block;font-size:inherit;font-family:inherit;font-weight:300;line-height:inherit;height:auto;border:0;border-radius:0;vertical-align:initial;-webkit-appearance:textfield;-moz-appearance:textfield;appearance:textfield}.flatpickr-current-month input.cur-year:focus{outline:0}.flatpickr-current-month input.cur-year[disabled],.flatpickr-current-month input.cur-year[disabled]:hover{font-size:100%;color:rgba(0,0,0,.5);background:transparent;pointer-events:none}.flatpickr-current-month .flatpickr-monthDropdown-months{appearance:menulist;background:transparent;border:none;border-radius:0;box-sizing:border-box;color:inherit;cursor:pointer;font-size:inherit;font-family:inherit;font-weight:300;height:auto;line-height:inherit;margin:-1px 0 0 0;outline:none;padding:0 0 0 .5ch;position:relative;vertical-align:initial;-webkit-box-sizing:border-box;-webkit-appearance:menulist;-moz-appearance:menulist;width:auto}.flatpickr-current-month .flatpickr-monthDropdown-months:focus,.flatpickr-current-month .flatpickr-monthDropdown-months:active{outline:none}.flatpickr-current-month .flatpickr-monthDropdown-months:hover{background:rgba(0,0,0,.05)}.flatpickr-current-month .flatpickr-monthDropdown-months .flatpickr-monthDropdown-month{background-color:transparent;outline:none;padding:0}.flatpickr-weekdays{background:transparent;text-align:center;overflow:hidden;width:100%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;height:28px}.flatpickr-weekdays .flatpickr-weekdaycontainer{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}span.flatpickr-weekday{cursor:default;font-size:90%;background:transparent;color:rgba(0,0,0,.54);line-height:1;margin:0;text-align:center;display:block;-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;font-weight:bolder}.dayContainer,.flatpickr-weeks{padding:1px 0 0 0}.flatpickr-days{position:relative;overflow:hidden;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:start;-webkit-align-items:flex-start;-ms-flex-align:start;align-items:flex-start;width:307.875px}.flatpickr-days:focus{outline:0}.dayContainer{padding:0;outline:0;text-align:left;width:307.875px;min-width:307.875px;max-width:307.875px;-webkit-box-sizing:border-box;box-sizing:border-box;display:inline-block;display:-ms-flexbox;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-wrap:wrap;-ms-flex-pack:justify;-webkit-justify-content:space-around;justify-content:space-around;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}.dayContainer+.dayContainer{-webkit-box-shadow:-1px 0 0 #e6e6e6;box-shadow:-1px 0 0 #e6e6e6}.flatpickr-day{background:none;border:1px solid transparent;border-radius:150px;-webkit-box-sizing:border-box;box-sizing:border-box;color:#393939;cursor:pointer;font-weight:400;width:14.2857143%;-webkit-flex-basis:14.2857143%;-ms-flex-preferred-size:14.2857143%;flex-basis:14.2857143%;max-width:39px;height:39px;line-height:39px;margin:0;display:inline-block;position:relative;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center}.flatpickr-day.inRange,.flatpickr-day.prevMonthDay.inRange,.flatpickr-day.nextMonthDay.inRange,.flatpickr-day.today.inRange,.flatpickr-day.prevMonthDay.today.inRange,.flatpickr-day.nextMonthDay.today.inRange,.flatpickr-day:hover,.flatpickr-day.prevMonthDay:hover,.flatpickr-day.nextMonthDay:hover,.flatpickr-day:focus,.flatpickr-day.prevMonthDay:focus,.flatpickr-day.nextMonthDay:focus{cursor:pointer;outline:0;background:#e6e6e6;border-color:#e6e6e6}.flatpickr-day.today{border-color:#959ea9}.flatpickr-day.today:hover,.flatpickr-day.today:focus{border-color:#959ea9;background:#959ea9;color:#fff}.flatpickr-day.selected,.flatpickr-day.startRange,.flatpickr-day.endRange,.flatpickr-day.selected.inRange,.flatpickr-day.startRange.inRange,.flatpickr-day.endRange.inRange,.flatpickr-day.selected:focus,.flatpickr-day.startRange:focus,.flatpickr-day.endRange:focus,.flatpickr-day.selected:hover,.flatpickr-day.startRange:hover,.flatpickr-day.endRange:hover,.flatpickr-day.selected.prevMonthDay,.flatpickr-day.startRange.prevMonthDay,.flatpickr-day.endRange.prevMonthDay,.flatpickr-day.selected.nextMonthDay,.flatpickr-day.startRange.nextMonthDay,.flatpickr-day.endRange.nextMonthDay{background:#569ff7;-webkit-box-shadow:none;box-shadow:none;color:#fff;border-color:#569ff7}.flatpickr-day.selected.startRange,.flatpickr-day.startRange.startRange,.flatpickr-day.endRange.startRange{border-radius:50px 0 0 50px}.flatpickr-day.selected.endRange,.flatpickr-day.startRange.endRange,.flatpickr-day.endRange.endRange{border-radius:0 50px 50px 0}.flatpickr-day.selected.startRange+.endRange:not(:nth-child(7n+1)),.flatpickr-day.startRange.startRange+.endRange:not(:nth-child(7n+1)),.flatpickr-day.endRange.startRange+.endRange:not(:nth-child(7n+1)){-webkit-box-shadow:-10px 0 0 #569ff7;box-shadow:-10px 0 0 #569ff7}.flatpickr-day.selected.startRange.endRange,.flatpickr-day.startRange.startRange.endRange,.flatpickr-day.endRange.startRange.endRange{border-radius:50px}.flatpickr-day.inRange{border-radius:0;-webkit-box-shadow:-5px 0 0 #e6e6e6,5px 0 0 #e6e6e6;box-shadow:-5px 0 0 #e6e6e6,5px 0 0 #e6e6e6}.flatpickr-day.flatpickr-disabled,.flatpickr-day.flatpickr-disabled:hover,.flatpickr-day.prevMonthDay,.flatpickr-day.nextMonthDay,.flatpickr-day.notAllowed,.flatpickr-day.notAllowed.prevMonthDay,.flatpickr-day.notAllowed.nextMonthDay{color:rgba(57,57,57,.3);background:transparent;border-color:transparent;cursor:default}.flatpickr-day.flatpickr-disabled,.flatpickr-day.flatpickr-disabled:hover{cursor:not-allowed;color:rgba(57,57,57,.1)}.flatpickr-day.week.selected{border-radius:0;-webkit-box-shadow:-5px 0 0 #569ff7,5px 0 0 #569ff7;box-shadow:-5px 0 0 #569ff7,5px 0 0 #569ff7}.flatpickr-day.hidden{visibility:hidden}.rangeMode .flatpickr-day{margin-top:1px}.flatpickr-weekwrapper{float:left}.flatpickr-weekwrapper .flatpickr-weeks{padding:0 12px;-webkit-box-shadow:1px 0 0 #e6e6e6;box-shadow:1px 0 0 #e6e6e6}.flatpickr-weekwrapper .flatpickr-weekday{float:none;width:100%;line-height:28px}.flatpickr-weekwrapper span.flatpickr-day,.flatpickr-weekwrapper span.flatpickr-day:hover{display:block;width:100%;max-width:none;color:rgba(57,57,57,.3);background:transparent;cursor:default;border:none}.flatpickr-innerContainer{display:block;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden}.flatpickr-rContainer{display:inline-block;padding:0;-webkit-box-sizing:border-box;box-sizing:border-box}.flatpickr-time{text-align:center;outline:0;display:block;height:0;line-height:40px;max-height:40px;-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.flatpickr-time:after{content:"";display:table;clear:both}.flatpickr-time .numInputWrapper{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;width:40%;height:40px;float:left}.flatpickr-time .numInputWrapper span.arrowUp:after{border-bottom-color:#393939}.flatpickr-time .numInputWrapper span.arrowDown:after{border-top-color:#393939}.flatpickr-time.hasSeconds .numInputWrapper{width:26%}.flatpickr-time.time24hr .numInputWrapper{width:49%}.flatpickr-time input{background:transparent;-webkit-box-shadow:none;box-shadow:none;border:0;border-radius:0;text-align:center;margin:0;padding:0;height:inherit;line-height:inherit;color:#393939;font-size:14px;position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:textfield;-moz-appearance:textfield;appearance:textfield}.flatpickr-time input.flatpickr-hour{font-weight:bold}.flatpickr-time input.flatpickr-minute,.flatpickr-time input.flatpickr-second{font-weight:400}.flatpickr-time input:focus{outline:0;border:0}.flatpickr-time .flatpickr-time-separator,.flatpickr-time .flatpickr-am-pm{height:inherit;float:left;line-height:inherit;color:#393939;font-weight:bold;width:2%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-align-self:center;-ms-flex-item-align:center;align-self:center}.flatpickr-time .flatpickr-am-pm{outline:0;width:18%;cursor:pointer;text-align:center;font-weight:400}.flatpickr-time input:hover,.flatpickr-time .flatpickr-am-pm:hover,.flatpickr-time input:focus,.flatpickr-time .flatpickr-am-pm:focus{background:#eee}.flatpickr-input[readonly]{cursor:pointer}@-webkit-keyframes fpFadeInDown{from{opacity:0;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:1;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes fpFadeInDown{from{opacity:0;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:1;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.flatpickr-monthSelect-months{margin:10px 1px 3px 1px;flex-wrap:wrap}.flatpickr-monthSelect-month{background:none;border:0;border-radius:2px;-webkit-box-sizing:border-box;box-sizing:border-box;color:#393939;cursor:pointer;display:inline-block;font-weight:400;margin:.5px;justify-content:center;padding:10px;position:relative;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;text-align:center;width:33%}.flatpickr-monthSelect-month.disabled{color:#eee}.flatpickr-monthSelect-month.disabled:hover,.flatpickr-monthSelect-month.disabled:focus{cursor:not-allowed;background:none !important}.flatpickr-monthSelect-theme-dark{background:#3f4458}.flatpickr-monthSelect-theme-dark .flatpickr-current-month input.cur-year{color:#fff}.flatpickr-monthSelect-theme-dark .flatpickr-months .flatpickr-prev-month,.flatpickr-monthSelect-theme-dark .flatpickr-months .flatpickr-next-month{color:#fff;fill:#fff}.flatpickr-monthSelect-theme-dark .flatpickr-monthSelect-month{color:rgba(255,255,255,.95)}.flatpickr-monthSelect-month:hover,.flatpickr-monthSelect-month:focus{background:#e6e6e6;cursor:pointer;outline:0}.flatpickr-monthSelect-theme-dark .flatpickr-monthSelect-month:hover,.flatpickr-monthSelect-theme-dark .flatpickr-monthSelect-month:focus{background:#646c8c;border-color:#646c8c}.flatpickr-monthSelect-month.selected{background-color:#569ff7;color:#fff}.flatpickr-monthSelect-theme-dark .flatpickr-monthSelect-month.selected{background:#80cbc4;-webkit-box-shadow:none;box-shadow:none;color:#fff;border-color:#80cbc4} /*! Pickr 1.8.2 MIT | https://github.com/Simonwep/pickr */ .pickr{position:relative;overflow:visible;transform:translateY(0)}.pickr *{box-sizing:border-box;outline:none;border:none;-webkit-appearance:none}.pickr .pcr-button{position:relative;height:2em;width:2em;padding:.5em;cursor:pointer;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Helvetica Neue",Arial,sans-serif;border-radius:.15em;background:url('data:image/svg+xml;utf8, ') no-repeat center;background-size:0;transition:all .3s}.pickr .pcr-button::before{position:absolute;content:'';top:0;left:0;width:100%;height:100%;background:url('data:image/svg+xml;utf8, ');background-size:.5em;border-radius:.15em;z-index:-1}.pickr .pcr-button::before{z-index:initial}.pickr .pcr-button::after{position:absolute;content:'';top:0;left:0;height:100%;width:100%;transition:background .3s;background:var(--pcr-color);border-radius:.15em}.pickr .pcr-button.clear{background-size:70%}.pickr .pcr-button.clear::before{opacity:0}.pickr .pcr-button.clear:focus{box-shadow:0 0 0 1px rgba(255,255,255,.85),0 0 0 3px var(--pcr-color)}.pickr .pcr-button.disabled{cursor:not-allowed}.pickr *,.pcr-app *{box-sizing:border-box;outline:none;border:none;-webkit-appearance:none}.pickr input:focus,.pickr input.pcr-active,.pickr button:focus,.pickr button.pcr-active,.pcr-app input:focus,.pcr-app input.pcr-active,.pcr-app button:focus,.pcr-app button.pcr-active{box-shadow:0 0 0 1px rgba(255,255,255,.85),0 0 0 3px var(--pcr-color)}.pickr .pcr-palette,.pickr .pcr-slider,.pcr-app .pcr-palette,.pcr-app .pcr-slider{transition:box-shadow .3s}.pickr .pcr-palette:focus,.pickr .pcr-slider:focus,.pcr-app .pcr-palette:focus,.pcr-app .pcr-slider:focus{box-shadow:0 0 0 1px rgba(255,255,255,.85),0 0 0 3px rgba(0,0,0,.25)}.pcr-app{position:fixed;display:flex;flex-direction:column;z-index:10000;border-radius:.1em;background:#fff;opacity:0;visibility:hidden;transition:opacity .3s,visibility 0s .3s;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Helvetica Neue",Arial,sans-serif;box-shadow:0 .15em 1.5em 0 rgba(0,0,0,.1),0 0 1em 0 rgba(0,0,0,.03);left:0;top:0}.pcr-app.visible{transition:opacity .3s;visibility:visible;opacity:1}.pcr-app .pcr-swatches{display:flex;flex-wrap:wrap;margin-top:.75em}.pcr-app .pcr-swatches.pcr-last{margin:0}@supports (display:grid){.pcr-app .pcr-swatches{display:grid;align-items:center;grid-template-columns:repeat(auto-fit,1.75em)}}.pcr-app .pcr-swatches>button{font-size:1em;position:relative;width:calc(1.75em - 5px);height:calc(1.75em - 5px);border-radius:.15em;cursor:pointer;margin:2.5px;flex-shrink:0;justify-self:center;transition:all .15s;overflow:hidden;background:transparent;z-index:1}.pcr-app .pcr-swatches>button::before{position:absolute;content:'';top:0;left:0;width:100%;height:100%;background:url('data:image/svg+xml;utf8, ');background-size:6px;border-radius:.15em;z-index:-1}.pcr-app .pcr-swatches>button::after{content:'';position:absolute;top:0;left:0;width:100%;height:100%;background:var(--pcr-color);border:1px solid rgba(0,0,0,.05);border-radius:.15em;box-sizing:border-box}.pcr-app .pcr-swatches>button:hover{filter:brightness(1.05)}.pcr-app .pcr-swatches>button:not(.pcr-active){box-shadow:none}.pcr-app .pcr-interaction{display:flex;flex-wrap:wrap;align-items:center;margin:0 -.2em 0 -.2em}.pcr-app .pcr-interaction>*{margin:0 .2em}.pcr-app .pcr-interaction input{letter-spacing:.07em;font-size:.75em;text-align:center;cursor:pointer;color:#75797e;background:#f1f3f4;border-radius:.15em;transition:all .15s;padding:.45em .5em;margin-top:.75em}.pcr-app .pcr-interaction input:hover{filter:brightness(.975)}.pcr-app .pcr-interaction input:focus{box-shadow:0 0 0 1px rgba(255,255,255,.85),0 0 0 3px rgba(66,133,244,.75)}.pcr-app .pcr-interaction .pcr-result{color:#75797e;text-align:left;flex:1 1 8em;min-width:8em;transition:all .2s;border-radius:.15em;background:#f1f3f4;cursor:text}.pcr-app .pcr-interaction .pcr-result::-moz-selection{background:#4285f4;color:#fff}.pcr-app .pcr-interaction .pcr-result::selection{background:#4285f4;color:#fff}.pcr-app .pcr-interaction .pcr-type.active{color:#fff;background:#4285f4}.pcr-app .pcr-interaction .pcr-save,.pcr-app .pcr-interaction .pcr-cancel,.pcr-app .pcr-interaction .pcr-clear{color:#fff;width:auto}.pcr-app .pcr-interaction .pcr-save,.pcr-app .pcr-interaction .pcr-cancel,.pcr-app .pcr-interaction .pcr-clear{color:#fff}.pcr-app .pcr-interaction .pcr-save:hover,.pcr-app .pcr-interaction .pcr-cancel:hover,.pcr-app .pcr-interaction .pcr-clear:hover{filter:brightness(.925)}.pcr-app .pcr-interaction .pcr-save{background:#4285f4}.pcr-app .pcr-interaction .pcr-clear,.pcr-app .pcr-interaction .pcr-cancel{background:#f44250}.pcr-app .pcr-interaction .pcr-clear:focus,.pcr-app .pcr-interaction .pcr-cancel:focus{box-shadow:0 0 0 1px rgba(255,255,255,.85),0 0 0 3px rgba(244,66,80,.75)}.pcr-app .pcr-selection .pcr-picker{position:absolute;height:18px;width:18px;border:2px solid #fff;border-radius:100%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.pcr-app .pcr-selection .pcr-color-palette,.pcr-app .pcr-selection .pcr-color-chooser,.pcr-app .pcr-selection .pcr-color-opacity{position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:flex;flex-direction:column;cursor:grab;cursor:-webkit-grab}.pcr-app .pcr-selection .pcr-color-palette:active,.pcr-app .pcr-selection .pcr-color-chooser:active,.pcr-app .pcr-selection .pcr-color-opacity:active{cursor:grabbing;cursor:-webkit-grabbing}.pcr-app[data-theme='monolith']{width:14.25em;max-width:95vw;padding:.8em}.pcr-app[data-theme='monolith'] .pcr-selection{display:flex;flex-direction:column;justify-content:space-between;flex-grow:1}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-preview{position:relative;z-index:1;width:100%;height:1em;display:flex;flex-direction:row;justify-content:space-between;margin-bottom:.5em}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-preview::before{position:absolute;content:'';top:0;left:0;width:100%;height:100%;background:url('data:image/svg+xml;utf8, ');background-size:.5em;border-radius:.15em;z-index:-1}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-preview .pcr-last-color{cursor:pointer;transition:background-color .3s,box-shadow .3s;border-radius:.15em 0 0 .15em;z-index:2}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-preview .pcr-current-color{border-radius:0 .15em .15em 0}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-preview .pcr-last-color,.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-preview .pcr-current-color{background:var(--pcr-color);width:50%;height:100%}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-palette{width:100%;height:8em;z-index:1}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-palette .pcr-palette{border-radius:.15em;width:100%;height:100%}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-palette .pcr-palette::before{position:absolute;content:'';top:0;left:0;width:100%;height:100%;background:url('data:image/svg+xml;utf8, ');background-size:.5em;border-radius:.15em;z-index:-1}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-chooser,.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-opacity{height:.5em;margin-top:.75em}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-chooser .pcr-picker,.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-opacity .pcr-picker{top:50%;transform:translateY(-50%)}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-chooser .pcr-slider,.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-opacity .pcr-slider{flex-grow:1;border-radius:50em}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-chooser .pcr-slider{background:linear-gradient(to right,#f00,#ff0,#0f0,#0ff,#00f,#f0f,#f00)}.pcr-app[data-theme='monolith'] .pcr-selection .pcr-color-opacity .pcr-slider{background:linear-gradient(to right,transparent,#000),url('data:image/svg+xml;utf8, ');background-size:100%,.25em} -@keyframes fadeIn{0%{opacity:0}100%{opacity:1}0%{opacity:0}}@keyframes slideIn{0%{transform:translateY(1rem);opacity:0}100%{transform:translateY(0);opacity:1}0%{transform:translateY(1rem);opacity:0}}.badge-close{cursor:pointer}.badge-close::before{height:2px;width:50%}.badge-close::after{height:50%;width:2px}.badge-close:hover,.badge-close:focus{background-color:rgba(10,10,10,.3)}.badge-close:active{background-color:rgba(10,10,10,.4)}.navbar-nav .nav-item:hover{cursor:pointer}.navbar-nav .nav-link:hover{cursor:pointer}.nav .nav-link:hover{cursor:pointer}.nav-item{position:relative}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-item{width:100%}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-item::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-item:empty::after{margin-left:0}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-item::after{transform:rotate(-90deg);position:absolute;right:10%;top:45%}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-menu{top:0;left:100%;margin-left:0;margin-right:.1rem}.btn-group>.b-tooltip:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.b-tooltip:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group.btn-group-toggle .btn.active.disabled{opacity:1}.btn-group-vertical>.b-tooltip:not(:last-child)>.btn{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.b-tooltip:not(:first-child)>.btn{border-top-left-radius:0;border-top-right-radius:0}.btn-xs,.btn-group-xs>.btn{padding:.15rem .5rem;font-size:.75rem;line-height:1.5;border-radius:.15rem}.btn-md,.btn-group-md>.btn{padding:.47rem 1rem;font-size:1.125rem;line-height:1.5;border-radius:.25rem}.btn-xl,.btn-group-xl>.btn{padding:.5rem 1rem;font-size:1.5rem;line-height:1.5;border-radius:.4rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.dropdown-toggle.dropdown-toggle-hidden::after{content:none !important}.dropdown-toggle.dropdown-toggle-hidden::before{content:none !important}.dropdown-menu.show{animation-duration:.3s;animation-fill-mode:both;animation-name:fadeIn}.dropdown-menu a:not([href]).dropdown-item:not(.disabled){cursor:pointer}.dropdown-menu.dropdown-menu-scrollable{max-height:var(--dropdown-list-menu-max-height,200px);overflow-y:scroll}.b-is-autocomplete .dropdown-menu{width:100%;max-height:var(--autocomplete-menu-max-height,200px);overflow-y:scroll}.b-is-autocomplete.b-is-autocomplete-multipleselection{max-width:100%;width:100%;cursor:text;height:calc(1.5em + .75rem + 2px);border:1px solid #ced4da;border-radius:.25rem}.b-is-autocomplete.b-is-autocomplete-multipleselection>input.form-control{display:inline-block;border:none;box-shadow:none;outline:none;background-color:transparent;max-width:inherit;width:auto}.b-is-autocomplete.b-is-autocomplete-multipleselection.focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.dropdown.btn-group>.btn.dropdown-toggle-split+.dropdown-menu.show{top:100%}.dropdown>.dropdown-menu>.dropdown{position:relative}.dropdown>.dropdown-menu>.dropdown::after{transform:rotate(-90deg);position:absolute;right:6px;top:.8em}.dropdown>.dropdown-menu>.dropdown>.dropdown-toggle{width:100%}.dropdown>.dropdown-menu>.dropdown>.dropdown-toggle::after{transform:rotate(-90deg);position:absolute;right:10%;top:45%}.dropdown>.dropdown-menu>.dropdown>.dropdown-menu{top:0;left:100%;margin-left:0;margin-right:.1rem}.dropdown-menu-start{right:auto;left:0}.dropdown-menu-end{right:0;left:auto}@media(min-width:576px){.dropdown-menu-sm-start{right:auto;left:0}.dropdown-menu-sm-end{right:0;left:auto}}@media(min-width:768px){.dropdown-menu-md-start{right:auto;left:0}.dropdown-menu-md-end{right:0;left:auto}}@media(min-width:992px){.dropdown-menu-lg-start{right:auto;left:0}.dropdown-menu-lg-end{right:0;left:auto}}@media(min-width:1200px){.dropdown-menu-xl-start{right:auto;left:0}.dropdown-menu-xl-end{right:0;left:auto}}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.snackbar{z-index:1060 !important}.figure-is-16x16{height:16px;width:16px}.figure-is-24x24{height:24px;width:24px}.figure-is-32x32{height:32px;width:32px}.figure-is-48x48{height:48px;width:48px}.figure-is-64x64{height:64px;width:64px}.figure-is-96x96{height:96px;width:96px}.figure-is-128x128{height:128px;width:128px}.figure-is-256x256{height:256px;width:256px}.figure-is-512x512{height:512px;width:512px}.form-check>.form-check-input.form-check-input-pointer,.form-check>.form-check-label.form-check-label-pointer,.form-switch>.form-check-input.form-check-input-pointer,.form-switch>.form-check-label.form-check-label-pointer{cursor:pointer}.form-control-plaintext.form-control-xs,.form-control-plaintext.form-control-md,.form-control-plaintext.form-control-xl{padding-right:0;padding-left:0}.form-control-xs{height:calc(1.5em + .3rem + 2px);padding:.15rem .5rem;font-size:.75rem;line-height:1.5;border-radius:.15rem}.form-control-md{height:calc(1.5em + .94rem + 2px);padding:.47rem 1rem;font-size:1.125rem;line-height:1.5;border-radius:.25rem}.form-control-xl{height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.5rem;line-height:1.5;border-radius:.4rem}.form-select-xs{height:calc(1.5em + .3rem + 2px);padding-top:.15rem;padding-bottom:.15rem;padding-left:.5rem;font-size:.75rem}.form-select-md{height:calc(1.5em + .94rem + 2px);padding-top:.47rem;padding-bottom:.47rem;padding-left:1rem;font-size:1.125rem}.form-select-xl{height:calc(1.5em + 1rem + 2px);padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.5rem}.input-group>.b-numeric:not(:last-child)>input{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.b-numeric:not(:first-child)>input{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-xs>.form-control:not(textarea),.input-group-xs>.form-select,.input-group-xs>.b-numeric>input{height:calc(1.5em + .3rem + 2px)}.input-group-xs>.form-control,.input-group-xs>.form-select,.input-group-xs>.input-group-text,.input-group-xs>.btn,.input-group-xs>.b-numeric>input{padding:.15rem .5rem;font-size:.75rem;line-height:1.5;border-radius:.15rem}.input-group-sm>.b-numeric>input{height:calc(1.5em + .5rem + 2px)}.input-group-sm>.b-numeric>input{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-md>.form-control:not(textarea),.input-group-md>.form-select,.input-group-md>.b-numeric>input{height:calc(1.5em + .94rem + 2px)}.input-group-md>.form-control,.input-group-md>.form-select,.input-group-md>.input-group-text,.input-group-md>.btn,.input-group-md>.b-numeric>input{padding:.47rem 1rem;font-size:1.125rem;line-height:1.5;border-radius:.25rem}.input-group-lg>.b-numeric>input{height:calc(1.5em + 1rem + 2px)}.input-group-lg>.b-numeric>input{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-xl>.form-control:not(textarea),.input-group-xl>.form-select,.input-group-xl>.b-numeric>input{height:calc(1.5em + 1rem + 2px)}.input-group-xl>.form-control,.input-group-xl>.form-select,.input-group-xl>.input-group-text,.input-group-xl>.btn,.input-group-xl>.b-numeric>input{padding:.5rem 1rem;font-size:1.5rem;line-height:1.5;border-radius:.4rem}.input-group-xs>.form-select,.input-group-md>.form-select,.input-group-xl>.form-select{padding-right:1.75rem}.input-group:not(.has-validation)>.dropdown:first-child>.btn:not(:last-child).dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown>.btn:not(:last-child).dropdown-toggle,.input-group.has-validation>.dropdown>.btn:not(:last-child):not(.dropdown-toggle){border-top-left-radius:0;border-bottom-left-radius:0}.form-check>.form-check-input.form-check-input-xs{width:.7rem;height:.7rem}.form-check>.form-check-input.form-check-input-xs+.form-check-label{line-height:"normal";padding-left:0}.form-check>.form-check-input.form-check-input-sm{width:.8rem;height:.8rem}.form-check>.form-check-input.form-check-input-sm+.form-check-label{line-height:"normal";padding-left:0}.form-check>.form-check-input.form-check-input-md{width:1.25rem;height:1.25rem}.form-check>.form-check-input.form-check-input-md+.form-check-label{line-height:1.7rem;padding-left:3px}.form-check>.form-check-input.form-check-input-lg{width:1.55rem;height:1.55rem}.form-check>.form-check-input.form-check-input-lg+.form-check-label{line-height:2rem;padding-left:6px}.form-check>.form-check-input.form-check-input-xl{width:1.85rem;height:1.85rem}.form-check>.form-check-input.form-check-input-xl+.form-check-label{line-height:2.5rem;padding-left:10px}select[readonly]{pointer-events:none}select[readonly] option,select[readonly] optgroup{display:none}.b-numeric{position:relative;width:100%}.b-numeric:hover>.b-numeric-handler-wrap{opacity:1}.b-numeric-handler-wrap{position:absolute;top:0;right:0;width:22px;height:100%;background:#fff;border:1px solid #d9d9d9;opacity:0}.input-group .b-numeric{-ms-flex:1 1 auto;flex:1 1 auto;width:1%}.b-numeric-handler-wrap .b-numeric-handler.b-numeric-handler-down{border-top:1px solid #d9d9d9}.b-numeric-handler{position:relative;display:flex;width:100%;height:50%;overflow:hidden;color:rgba(0,0,0,.45);font-weight:700;line-height:0;align-items:center;justify-content:center}.b-numeric-handler.btn{padding:0}.form-control+.b-numeric-handler-wrap{font-size:1rem;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.form-control-xs+.b-numeric-handler-wrap{font-size:.75rem;border-top-right-radius:.15rem;border-bottom-right-radius:.15rem}.form-control-xs+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:.75rem}.form-control-sm+.b-numeric-handler-wrap{font-size:.875rem;border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.form-control-sm+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:.875rem}.form-control-md+.b-numeric-handler-wrap{font-size:1.125rem;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.form-control-md+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:1.125rem}.form-control-lg+.b-numeric-handler-wrap{font-size:1.25rem;border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.form-control-lg+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:1.25rem}.form-control-xl+.b-numeric-handler-wrap{font-size:1.5rem;border-top-right-radius:.4rem;border-bottom-right-radius:.4rem}.form-control-xl+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:1.5rem}.custom-file-label{overflow:hidden}input[readonly][type=range],input[readonly="readonly"][type=range]{pointer-events:none}input[readonly][type=range]::-webkit-slider-thumb,input[readonly="readonly"][type=range]::-webkit-slider-thumb{pointer-events:none}input[readonly][type=range]::-moz-range-thumb,input[readonly="readonly"][type=range]::-moz-range-thumb{pointer-events:none}input[readonly][type=range]::-ms-thumb,input[readonly="readonly"][type=range]::-ms-thumb{pointer-events:none}.form-group{margin-bottom:1rem}.form-inline{display:flex;flex-flow:row wrap;align-items:center}.form-inline .form-check{width:100%}@media(min-width:576px){.form-inline label{display:flex;align-items:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:flex;flex:0 0 auto;flex-flow:row wrap;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .input-group,.form-inline .custom-select{width:auto}.form-inline .form-check{display:flex;align-items:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;flex-shrink:0;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .form-select{align-items:center;justify-content:center}.form-inline .form-check-label{margin-bottom:0}}.b-input-color-picker{padding:.5rem .6rem}.b-input-color-picker>.b-input-color-picker-preview{height:.55rem}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media(min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.jumbotron.jumbotron-primary{background-color:#007bff;color:#fff}.jumbotron.jumbotron-secondary{background-color:#6c757d;color:#fff}.jumbotron.jumbotron-success{background-color:#28a745;color:#fff}.jumbotron.jumbotron-info{background-color:#17a2b8;color:#fff}.jumbotron.jumbotron-warning{background-color:#ffc107;color:#212529}.jumbotron.jumbotron-danger{background-color:#dc3545;color:#fff}.jumbotron.jumbotron-light{background-color:#f8f9fa;color:#212529}.jumbotron.jumbotron-dark{background-color:#343a40;color:#fff}.jumbotron.jumbotron-link{background-color:#3273dc;color:#fff}.b-layout-header-fixed{z-index:1030}.b-layout-footer-fixed{z-index:1030}.b-layout-sider-content{z-index:1031}li.list-group-item-action{cursor:pointer}.b-list-view{overflow-y:scroll}.media{display:flex;align-items:flex-start}.media-body{flex:1}.modal.show{animation-duration:.25s;animation-fill-mode:both;animation-name:fadeIn}.page-item:not(.disabled) .page-link{cursor:pointer}.pagination-xs .page-link{padding:.125rem .25rem;font-size:.75rem;line-height:1.5}.pagination-xs .page-item:first-child .page-link{border-top-left-radius:.15rem;border-bottom-left-radius:.15rem}.pagination-xs .page-item:last-child .page-link{border-top-right-radius:.15rem;border-bottom-right-radius:.15rem}.pagination-md .page-link{padding:.625rem 1.25rem;font-size:1.125rem;line-height:1.5}.pagination-md .page-item:first-child .page-link{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.pagination-md .page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.pagination-xl .page-link{padding:1rem 2rem;font-size:1.5rem;line-height:1.5}.pagination-xl .page-item:first-child .page-link{border-top-left-radius:.4rem;border-bottom-left-radius:.4rem}.pagination-xl .page-item:last-child .page-link{border-top-right-radius:.4rem;border-bottom-right-radius:.4rem}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-primary{background-color:#007bff}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-secondary{background-color:#6c757d}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-success{background-color:#28a745}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-info{background-color:#17a2b8}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-warning{background-color:#ffc107}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-danger{background-color:#dc3545}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-light{background-color:#f8f9fa}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-dark{background-color:#343a40}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-link{background-color:#3273dc}.rating:not(.rating-disabled):not(.rating-readonly):hover .rating-item{cursor:pointer}.rating.rating-disabled{opacity:.65}.rating .rating-item.rating-item-primary{color:#007bff}.rating .rating-item.rating-item-secondary{color:#6c757d}.rating .rating-item.rating-item-success{color:#28a745}.rating .rating-item.rating-item-info{color:#17a2b8}.rating .rating-item.rating-item-warning{color:#ffc107}.rating .rating-item.rating-item-danger{color:#dc3545}.rating .rating-item.rating-item-light{color:#f8f9fa}.rating .rating-item.rating-item-dark{color:#343a40}.rating .rating-item.rating-item-link{color:#3273dc}.rating .rating-item.rating-item-hover{opacity:.7}.steps{padding:0;margin:0;list-style:none;display:flex;overflow-x:auto}.steps .step:first-child{margin-left:auto}.steps .step:last-child{margin-right:auto}.step:first-of-type .step-circle::before{display:none}.step:last-of-type .step-container{padding-right:0}.step-container{box-sizing:content-box;display:flex;align-items:center;flex-direction:column;width:5rem;min-width:5rem;max-width:5rem;padding-top:.5rem;padding-right:1rem}.step-circle{position:relative;display:flex;justify-content:center;align-items:center;width:1.5rem;height:1.5rem;color:#adb5bd;border:2px solid #adb5bd;border-radius:100%;background-color:#fff}.step-circle::before{content:'';display:block;position:absolute;top:50%;left:-2px;width:calc(5rem + 1rem - 1.5rem);height:2px;transform:translate(-100%,-50%);color:#adb5bd;background-color:currentColor}.step-text{color:#adb5bd;word-break:break-all;margin-top:.25em}.step-completed .step-circle{color:#fff;background-color:#28a745;border-color:#28a745}.step-completed .step-circle::before{color:#28a745}.step-completed .step-text{color:#28a745}.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-active .step-circle::before{color:#007bff}.step-active .step-text{color:#007bff}.step-primary .step-circle{color:#007bff;border-color:#007bff}.step-primary.step-completed .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-primary.step-completed .step-circle::before{color:#007bff}.step-primary.step-completed .step-text{color:#007bff}.step-primary.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-primary.step-active::before{color:#007bff}.step-primary.step-active .step-text{color:#007bff}.step-secondary .step-circle{color:#6c757d;border-color:#6c757d}.step-secondary.step-completed .step-circle{color:#fff;background-color:#6c757d;border-color:#6c757d}.step-secondary.step-completed .step-circle::before{color:#6c757d}.step-secondary.step-completed .step-text{color:#6c757d}.step-secondary.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-secondary.step-active::before{color:#007bff}.step-secondary.step-active .step-text{color:#007bff}.step-success .step-circle{color:#28a745;border-color:#28a745}.step-success.step-completed .step-circle{color:#fff;background-color:#28a745;border-color:#28a745}.step-success.step-completed .step-circle::before{color:#28a745}.step-success.step-completed .step-text{color:#28a745}.step-success.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-success.step-active::before{color:#007bff}.step-success.step-active .step-text{color:#007bff}.step-info .step-circle{color:#17a2b8;border-color:#17a2b8}.step-info.step-completed .step-circle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.step-info.step-completed .step-circle::before{color:#17a2b8}.step-info.step-completed .step-text{color:#17a2b8}.step-info.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-info.step-active::before{color:#007bff}.step-info.step-active .step-text{color:#007bff}.step-warning .step-circle{color:#ffc107;border-color:#ffc107}.step-warning.step-completed .step-circle{color:#fff;background-color:#ffc107;border-color:#ffc107}.step-warning.step-completed .step-circle::before{color:#ffc107}.step-warning.step-completed .step-text{color:#ffc107}.step-warning.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-warning.step-active::before{color:#007bff}.step-warning.step-active .step-text{color:#007bff}.step-danger .step-circle{color:#dc3545;border-color:#dc3545}.step-danger.step-completed .step-circle{color:#fff;background-color:#dc3545;border-color:#dc3545}.step-danger.step-completed .step-circle::before{color:#dc3545}.step-danger.step-completed .step-text{color:#dc3545}.step-danger.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-danger.step-active::before{color:#007bff}.step-danger.step-active .step-text{color:#007bff}.step-light .step-circle{color:#f8f9fa;border-color:#f8f9fa}.step-light.step-completed .step-circle{color:#fff;background-color:#f8f9fa;border-color:#f8f9fa}.step-light.step-completed .step-circle::before{color:#f8f9fa}.step-light.step-completed .step-text{color:#f8f9fa}.step-light.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-light.step-active::before{color:#007bff}.step-light.step-active .step-text{color:#007bff}.step-dark .step-circle{color:#343a40;border-color:#343a40}.step-dark.step-completed .step-circle{color:#fff;background-color:#343a40;border-color:#343a40}.step-dark.step-completed .step-circle::before{color:#343a40}.step-dark.step-completed .step-text{color:#343a40}.step-dark.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-dark.step-active::before{color:#007bff}.step-dark.step-active .step-text{color:#007bff}.step-link .step-circle{color:#3273dc;border-color:#3273dc}.step-link.step-completed .step-circle{color:#fff;background-color:#3273dc;border-color:#3273dc}.step-link.step-completed .step-circle::before{color:#3273dc}.step-link.step-completed .step-text{color:#3273dc}.step-link.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-link.step-active::before{color:#007bff}.step-link.step-active .step-text{color:#007bff}.steps-content{margin:1rem 0}.steps-content>.step-panel{display:none}.steps-content>.active{display:block}.form-check.form-switch .form-check-input.form-check-input-primary:checked{background-color:#007bff;border-color:#007bff}.form-check.form-switch .form-check-input.form-check-input-secondary:checked{background-color:#6c757d;border-color:#6c757d}.form-check.form-switch .form-check-input.form-check-input-success:checked{background-color:#28a745;border-color:#28a745}.form-check.form-switch .form-check-input.form-check-input-info:checked{background-color:#17a2b8;border-color:#17a2b8}.form-check.form-switch .form-check-input.form-check-input-warning:checked{background-color:#ffc107;border-color:#ffc107}.form-check.form-switch .form-check-input.form-check-input-danger:checked{background-color:#dc3545;border-color:#dc3545}.form-check.form-switch .form-check-input.form-check-input-light:checked{background-color:#f8f9fa;border-color:#f8f9fa}.form-check.form-switch .form-check-input.form-check-input-dark:checked{background-color:#343a40;border-color:#343a40}.form-check.form-switch .form-check-input.form-check-input-link:checked{background-color:#3273dc;border-color:#3273dc}.form-check.form-switch .form-check-input.form-check-input-xs{width:calc(.75rem + (.5rem/2));height:.5rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-xs+.form-check-label{line-height:1rem;vertical-align:middle;padding-left:0}.form-check.form-switch .form-check-input.form-check-input-xs:checked~.form-check-label::after{transform:translateX(calc(.75rem - (.5rem/2)))}.form-check.form-switch .form-check-input.form-check-input-sm{width:calc(1rem + (.75rem/2));height:.75rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-sm+.form-check-label{line-height:1.25rem;vertical-align:middle;padding-left:.75rem}.form-check.form-switch .form-check-input.form-check-input-sm:checked~.form-check-label::after{transform:translateX(calc(1rem - (.75rem/2)))}.form-check.form-switch .form-check-input.form-check-input-md{width:calc(2rem + (1.5rem/2));height:1.5rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-md+.form-check-label{line-height:2rem;vertical-align:middle;padding-left:.75rem}.form-check.form-switch .form-check-input.form-check-input-md:checked~.form-check-label::after{transform:translateX(calc(2rem - (1.5rem/2)))}.form-check.form-switch .form-check-input.form-check-input-lg{width:calc(3rem + (2rem/2));height:2rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-lg+.form-check-label{line-height:2.5rem;vertical-align:middle;padding-left:.75rem}.form-check.form-switch .form-check-input.form-check-input-lg:checked~.form-check-label::after{transform:translateX(calc(3rem - (2rem/2)))}.form-check.form-switch .form-check-input.form-check-input-xl{width:calc(4rem + (2.5rem/2));height:2.5rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-xl+.form-check-label{line-height:3rem;vertical-align:middle;padding-left:.75rem}.form-check.form-switch .form-check-input.form-check-input-xl:checked~.form-check-label::after{transform:translateX(calc(4rem - (2.5rem/2)))}table.table tbody tr.selected{background-color:var(--primary)}tr.table-row-selectable:hover{cursor:pointer}.table-fixed-header{overflow-y:auto}.table-fixed-header>.table{border-collapse:separate;border-spacing:0}.table-fixed-header>.table>thead>tr>th{border-top:none;position:sticky;background:#fff;z-index:10}.table-fixed-header>.table>thead>tr:nth-child(1)>th{top:0}.table-fixed-header>.table-bordered>:not(caption)>*>*{border-width:1px 1px}.overflow-auto-auto{overflow:auto auto !important}.overflow-auto-hidden{overflow:auto hidden !important}.overflow-auto-visible{overflow:auto visible !important}.overflow-auto-scroll{overflow:auto scroll !important}.overflow-hidden-auto{overflow:hidden auto !important}.overflow-hidden-hidden{overflow:hidden hidden !important}.overflow-hidden-visible{overflow:hidden visible !important}.overflow-hidden-scroll{overflow:hidden scroll !important}.overflow-visible-auto{overflow:visible auto !important}.overflow-visible-hidden{overflow:visible hidden !important}.overflow-visible-visible{overflow:visible visible !important}.overflow-visible-scroll{overflow:visible scroll !important}.overflow-scroll-auto{overflow:scroll auto !important}.overflow-scroll-hidden{overflow:scroll hidden !important}.overflow-scroll-visible{overflow:scroll visible !important}.overflow-scroll-scroll{overflow:scroll scroll !important}ol.ordered-list-lower-alpha{list-style-type:lower-alpha}ol.ordered-list-lower-roman{list-style-type:lower-roman}ol.ordered-list-upper-alpha{list-style-type:upper-alpha}ol.ordered-list-upper-roman{list-style-type:upper-roman}.flatpickr-months{margin:.5rem 0}.flatpickr-months .flatpickr-month,.flatpickr-months .flatpickr-next-month,.flatpickr-months .flatpickr-prev-month{height:auto;position:relative}.flatpickr-months .flatpickr-month:hover svg,.flatpickr-months .flatpickr-next-month:hover svg,.flatpickr-months .flatpickr-prev-month:hover svg{fill:#007bff}.flatpickr-months .flatpickr-month{color:#212529}.flatpickr-current-month{padding:13px 0 0 0;font-size:115%}.flatpickr-current-month span.cur-month{font-weight:700}.flatpickr-current-month span.cur-month:hover{background:rgba(0,123,255,.15)}.numInputWrapper:hover{background:rgba(0,123,255,.15)}.flatpickr-day{border-radius:.25rem;font-weight:500;color:#212529}.flatpickr-day.today{border-color:#007bff}.flatpickr-day.today:hover{background:#007bff;border-color:#007bff}.flatpickr-day:hover{background:rgba(0,123,255,.1);border-color:rgba(0,0,0,0)}span.flatpickr-weekday{color:#212529}.flatpickr-day.selected,.flatpickr-day.startRange,.flatpickr-day.endRange,.flatpickr-day.selected.inRange,.flatpickr-day.startRange.inRange,.flatpickr-day.endRange.inRange,.flatpickr-day.selected:focus,.flatpickr-day.startRange:focus,.flatpickr-day.endRange:focus,.flatpickr-day.selected:hover,.flatpickr-day.startRange:hover,.flatpickr-day.endRange:hover,.flatpickr-day.selected.prevMonthDay,.flatpickr-day.startRange.prevMonthDay,.flatpickr-day.endRange.prevMonthDay,.flatpickr-day.selected.nextMonthDay,.flatpickr-day.startRange.nextMonthDay,.flatpickr-day.endRange.nextMonthDay{background:#007bff;border-color:#007bff}.flatpickr-day.selected.startRange+.endRange:not(:nth-child(7n+1)),.flatpickr-day.startRange.startRange+.endRange:not(:nth-child(7n+1)),.flatpickr-day.endRange.startRange+.endRange:not(:nth-child(7n+1)){box-shadow:-10px 0 0 #007bff}.flatpickr-day.selected.startRange,.flatpickr-day.startRange.startRange,.flatpickr-day.endRange.startRange{border-radius:.25rem 0 0 .25rem}.flatpickr-day.selected.endRange,.flatpickr-day.startRange.endRange,.flatpickr-day.endRange.endRange{border-radius:0 .25rem .25rem 0}.flatpickr-monthSelect-month:hover,.flatpickr-monthSelect-month:focus{background:rgba(0,123,255,.1)}.flatpickr-monthSelect-month.selected{background-color:#007bff} +@keyframes fadeIn{0%{opacity:0}100%{opacity:1}0%{opacity:0}}@keyframes slideIn{0%{transform:translateY(1rem);opacity:0}100%{transform:translateY(0);opacity:1}0%{transform:translateY(1rem);opacity:0}}.badge-close{cursor:pointer}.badge-close::before{height:2px;width:50%}.badge-close::after{height:50%;width:2px}.badge-close:hover,.badge-close:focus{background-color:rgba(10,10,10,.3)}.badge-close:active{background-color:rgba(10,10,10,.4)}.navbar-nav .nav-item:hover{cursor:pointer}.navbar-nav .nav-link:hover{cursor:pointer}.nav .nav-link:hover{cursor:pointer}.nav-item{position:relative}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-item{width:100%}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-item::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-item:empty::after{margin-left:0}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-item::after{transform:rotate(-90deg);position:absolute;right:10%;top:45%}.b-bar-horizontal .nav-item.dropdown .dropdown-menu>.dropdown>.dropdown-menu{top:0;left:100%;margin-left:0;margin-right:.1rem}.btn-group>.b-tooltip:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.b-tooltip:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group.btn-group-toggle .btn.active.disabled{opacity:1}.btn-group-vertical>.b-tooltip:not(:last-child)>.btn{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.b-tooltip:not(:first-child)>.btn{border-top-left-radius:0;border-top-right-radius:0}.btn-xs,.btn-group-xs>.btn{padding:.15rem .5rem;font-size:.75rem;line-height:1.5;border-radius:.15rem}.btn-md,.btn-group-md>.btn{padding:.47rem 1rem;font-size:1.125rem;line-height:1.5;border-radius:.25rem}.btn-xl,.btn-group-xl>.btn{padding:.5rem 1rem;font-size:1.5rem;line-height:1.5;border-radius:.4rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.dropdown-toggle.dropdown-toggle-hidden::after{content:none !important}.dropdown-toggle.dropdown-toggle-hidden::before{content:none !important}.dropdown-menu.show{animation-duration:.3s;animation-fill-mode:both;animation-name:fadeIn}.dropdown-menu a:not([href]).dropdown-item:not(.disabled){cursor:pointer}.dropdown-menu.dropdown-menu-scrollable{max-height:var(--dropdown-list-menu-max-height,200px);overflow-y:scroll}.b-is-autocomplete .dropdown-menu{width:100%;max-height:var(--autocomplete-menu-max-height,200px);overflow-y:scroll}.b-is-autocomplete.b-is-autocomplete-multipleselection{max-width:100%;width:100%;cursor:text;height:calc(1.5em + .75rem + 2px);border:1px solid #ced4da;border-radius:.25rem}.b-is-autocomplete.b-is-autocomplete-multipleselection>input.form-control{display:inline-block;border:none;box-shadow:none;outline:none;background-color:transparent;max-width:inherit;width:auto}.b-is-autocomplete.b-is-autocomplete-multipleselection.focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.dropdown.btn-group>.btn.dropdown-toggle-split+.dropdown-menu.show{top:100%}.dropdown>.dropdown-menu>.dropdown{position:relative}.dropdown>.dropdown-menu>.dropdown::after{transform:rotate(-90deg);position:absolute;right:6px;top:.8em}.dropdown>.dropdown-menu>.dropdown>.dropdown-toggle{width:100%}.dropdown>.dropdown-menu>.dropdown>.dropdown-toggle::after{transform:rotate(-90deg);position:absolute;right:10%;top:45%}.dropdown>.dropdown-menu>.dropdown>.dropdown-menu{top:0;left:100%;margin-left:0;margin-right:.1rem}.dropdown-menu-start{right:auto;left:0}.dropdown-menu-end{right:0;left:auto}@media(min-width:576px){.dropdown-menu-sm-start{right:auto;left:0}.dropdown-menu-sm-end{right:0;left:auto}}@media(min-width:768px){.dropdown-menu-md-start{right:auto;left:0}.dropdown-menu-md-end{right:0;left:auto}}@media(min-width:992px){.dropdown-menu-lg-start{right:auto;left:0}.dropdown-menu-lg-end{right:0;left:auto}}@media(min-width:1200px){.dropdown-menu-xl-start{right:auto;left:0}.dropdown-menu-xl-end{right:0;left:auto}}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}hr.divider.divider-text{position:unset}hr.divider.divider-text::before{top:unset}.snackbar{z-index:1060 !important}.figure.figure-is-16x16{height:16px;width:16px}.figure.figure-is-24x24{height:24px;width:24px}.figure.figure-is-32x32{height:32px;width:32px}.figure.figure-is-48x48{height:48px;width:48px}.figure.figure-is-64x64{height:64px;width:64px}.figure.figure-is-96x96{height:96px;width:96px}.figure.figure-is-128x128{height:128px;width:128px}.figure.figure-is-256x256{height:256px;width:256px}.figure.figure-is-512x512{height:512px;width:512px}.form-check>.form-check-input.form-check-input-pointer,.form-check>.form-check-label.form-check-label-pointer,.form-switch>.form-check-input.form-check-input-pointer,.form-switch>.form-check-label.form-check-label-pointer{cursor:pointer}.form-control-plaintext.form-control-xs,.form-control-plaintext.form-control-md,.form-control-plaintext.form-control-xl{padding-right:0;padding-left:0}.form-control-xs{height:calc(1.5em + .3rem + 2px);padding:.15rem .5rem;font-size:.75rem;line-height:1.5;border-radius:.15rem}.form-control-md{height:calc(1.5em + .94rem + 2px);padding:.47rem 1rem;font-size:1.125rem;line-height:1.5;border-radius:.25rem}.form-control-xl{height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.5rem;line-height:1.5;border-radius:.4rem}.form-select-xs{height:calc(1.5em + .3rem + 2px);padding-top:.15rem;padding-bottom:.15rem;padding-left:.5rem;font-size:.75rem}.form-select-md{height:calc(1.5em + .94rem + 2px);padding-top:.47rem;padding-bottom:.47rem;padding-left:1rem;font-size:1.125rem}.form-select-xl{height:calc(1.5em + 1rem + 2px);padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.5rem}.input-group>.b-numeric:not(:last-child)>input{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.b-numeric:not(:first-child)>input{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-xs>.form-control:not(textarea),.input-group-xs>.form-select,.input-group-xs>.b-numeric>input{height:calc(1.5em + .3rem + 2px)}.input-group-xs>.form-control,.input-group-xs>.form-select,.input-group-xs>.input-group-text,.input-group-xs>.btn,.input-group-xs>.b-numeric>input{padding:.15rem .5rem;font-size:.75rem;line-height:1.5;border-radius:.15rem}.input-group-sm>.b-numeric>input{height:calc(1.5em + .5rem + 2px)}.input-group-sm>.b-numeric>input{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-md>.form-control:not(textarea),.input-group-md>.form-select,.input-group-md>.b-numeric>input{height:calc(1.5em + .94rem + 2px)}.input-group-md>.form-control,.input-group-md>.form-select,.input-group-md>.input-group-text,.input-group-md>.btn,.input-group-md>.b-numeric>input{padding:.47rem 1rem;font-size:1.125rem;line-height:1.5;border-radius:.25rem}.input-group-lg>.b-numeric>input{height:calc(1.5em + 1rem + 2px)}.input-group-lg>.b-numeric>input{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-xl>.form-control:not(textarea),.input-group-xl>.form-select,.input-group-xl>.b-numeric>input{height:calc(1.5em + 1rem + 2px)}.input-group-xl>.form-control,.input-group-xl>.form-select,.input-group-xl>.input-group-text,.input-group-xl>.btn,.input-group-xl>.b-numeric>input{padding:.5rem 1rem;font-size:1.5rem;line-height:1.5;border-radius:.4rem}.input-group-xs>.form-select,.input-group-md>.form-select,.input-group-xl>.form-select{padding-right:1.75rem}.input-group:not(.has-validation)>.dropdown:first-child>.btn:not(:last-child).dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown>.btn:not(:last-child).dropdown-toggle,.input-group.has-validation>.dropdown>.btn:not(:last-child):not(.dropdown-toggle){border-top-left-radius:0;border-bottom-left-radius:0}.form-check>.form-check-input.form-check-input-xs{width:.7rem;height:.7rem}.form-check>.form-check-input.form-check-input-xs+.form-check-label{line-height:"normal";padding-left:0}.form-check>.form-check-input.form-check-input-sm{width:.8rem;height:.8rem}.form-check>.form-check-input.form-check-input-sm+.form-check-label{line-height:"normal";padding-left:0}.form-check>.form-check-input.form-check-input-md{width:1.25rem;height:1.25rem}.form-check>.form-check-input.form-check-input-md+.form-check-label{line-height:1.7rem;padding-left:3px}.form-check>.form-check-input.form-check-input-lg{width:1.55rem;height:1.55rem}.form-check>.form-check-input.form-check-input-lg+.form-check-label{line-height:2rem;padding-left:6px}.form-check>.form-check-input.form-check-input-xl{width:1.85rem;height:1.85rem}.form-check>.form-check-input.form-check-input-xl+.form-check-label{line-height:2.5rem;padding-left:10px}select[readonly]{pointer-events:none}select[readonly] option,select[readonly] optgroup{display:none}.b-numeric{position:relative;width:100%}.b-numeric:hover>.b-numeric-handler-wrap{opacity:1}.b-numeric-handler-wrap{position:absolute;top:0;right:0;width:22px;height:100%;background:#fff;border:1px solid #d9d9d9;opacity:0}.input-group .b-numeric{-ms-flex:1 1 auto;flex:1 1 auto;width:1%}.b-numeric-handler-wrap .b-numeric-handler.b-numeric-handler-down{border-top:1px solid #d9d9d9}.b-numeric-handler{position:relative;display:flex;width:100%;height:50%;overflow:hidden;color:rgba(0,0,0,.45);font-weight:700;line-height:0;align-items:center;justify-content:center}.b-numeric-handler.btn{padding:0}.form-control+.b-numeric-handler-wrap{font-size:1rem;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.form-control-xs+.b-numeric-handler-wrap{font-size:.75rem;border-top-right-radius:.15rem;border-bottom-right-radius:.15rem}.form-control-xs+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:.75rem}.form-control-sm+.b-numeric-handler-wrap{font-size:.875rem;border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.form-control-sm+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:.875rem}.form-control-md+.b-numeric-handler-wrap{font-size:1.125rem;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.form-control-md+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:1.125rem}.form-control-lg+.b-numeric-handler-wrap{font-size:1.25rem;border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.form-control-lg+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:1.25rem}.form-control-xl+.b-numeric-handler-wrap{font-size:1.5rem;border-top-right-radius:.4rem;border-bottom-right-radius:.4rem}.form-control-xl+.b-numeric-handler-wrap>.b-numeric-handler.btn{font-size:1.5rem}.custom-file-label{overflow:hidden}input[readonly][type=range],input[readonly=readonly][type=range]{pointer-events:none}input[readonly][type=range]::-webkit-slider-thumb,input[readonly=readonly][type=range]::-webkit-slider-thumb{pointer-events:none}input[readonly][type=range]::-moz-range-thumb,input[readonly=readonly][type=range]::-moz-range-thumb{pointer-events:none}input[readonly][type=range]::-ms-thumb,input[readonly=readonly][type=range]::-ms-thumb{pointer-events:none}.form-group{margin-bottom:1rem}.form-inline{display:flex;flex-flow:row wrap;align-items:center}.form-inline .form-check{width:100%}@media(min-width:576px){.form-inline label{display:flex;align-items:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:flex;flex:0 0 auto;flex-flow:row wrap;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .input-group,.form-inline .custom-select{width:auto}.form-inline .form-check{display:flex;align-items:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;flex-shrink:0;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .form-select{align-items:center;justify-content:center}.form-inline .form-check-label{margin-bottom:0}}.b-input-color-picker{padding:.5rem .6rem}.b-input-color-picker>.b-input-color-picker-preview{height:.55rem}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media(min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.jumbotron.jumbotron-primary{background-color:#007bff;color:#fff}.jumbotron.jumbotron-secondary{background-color:#6c757d;color:#fff}.jumbotron.jumbotron-success{background-color:#28a745;color:#fff}.jumbotron.jumbotron-info{background-color:#17a2b8;color:#fff}.jumbotron.jumbotron-warning{background-color:#ffc107;color:#212529}.jumbotron.jumbotron-danger{background-color:#dc3545;color:#fff}.jumbotron.jumbotron-light{background-color:#f8f9fa;color:#212529}.jumbotron.jumbotron-dark{background-color:#343a40;color:#fff}.jumbotron.jumbotron-link{background-color:#3273dc;color:#fff}.b-layout-header-fixed{z-index:1030}.b-layout-footer-fixed{z-index:1030}.b-layout-sider-content{z-index:1031}li.list-group-item-action{cursor:pointer}.b-list-view{overflow-y:scroll}.media{display:flex;align-items:flex-start}.media-body{flex:1}.modal.show{animation-duration:.25s;animation-fill-mode:both;animation-name:fadeIn}.page-item:not(.disabled) .page-link{cursor:pointer}.pagination-xs .page-link{padding:.125rem .25rem;font-size:.75rem;line-height:1.5}.pagination-xs .page-item:first-child .page-link{border-top-left-radius:.15rem;border-bottom-left-radius:.15rem}.pagination-xs .page-item:last-child .page-link{border-top-right-radius:.15rem;border-bottom-right-radius:.15rem}.pagination-md .page-link{padding:.625rem 1.25rem;font-size:1.125rem;line-height:1.5}.pagination-md .page-item:first-child .page-link{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.pagination-md .page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.pagination-xl .page-link{padding:1rem 2rem;font-size:1.5rem;line-height:1.5}.pagination-xl .page-item:first-child .page-link{border-top-left-radius:.4rem;border-bottom-left-radius:.4rem}.pagination-xl .page-item:last-child .page-link{border-top-right-radius:.4rem;border-bottom-right-radius:.4rem}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-primary{background-color:#007bff}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-secondary{background-color:#6c757d}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-success{background-color:#28a745}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-info{background-color:#17a2b8}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-warning{background-color:#ffc107}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-danger{background-color:#dc3545}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-light{background-color:#f8f9fa}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-dark{background-color:#343a40}.b-page-progress .b-page-progress-indicator.b-page-progress-indicator-link{background-color:#3273dc}.rating:not(.rating-disabled):not(.rating-readonly):hover .rating-item{cursor:pointer}.rating.rating-disabled{opacity:.65}.rating .rating-item.rating-item-primary{color:#007bff}.rating .rating-item.rating-item-secondary{color:#6c757d}.rating .rating-item.rating-item-success{color:#28a745}.rating .rating-item.rating-item-info{color:#17a2b8}.rating .rating-item.rating-item-warning{color:#ffc107}.rating .rating-item.rating-item-danger{color:#dc3545}.rating .rating-item.rating-item-light{color:#f8f9fa}.rating .rating-item.rating-item-dark{color:#343a40}.rating .rating-item.rating-item-link{color:#3273dc}.rating .rating-item.rating-item-hover{opacity:.7}.steps{padding:0;margin:0;list-style:none;display:flex;overflow-x:auto}.steps .step:first-child{margin-left:auto}.steps .step:last-child{margin-right:auto}.step:first-of-type .step-circle::before{display:none}.step:last-of-type .step-container{padding-right:0}.step-container{box-sizing:content-box;display:flex;align-items:center;flex-direction:column;width:5rem;min-width:5rem;max-width:5rem;padding-top:.5rem;padding-right:1rem}.step-circle{position:relative;display:flex;justify-content:center;align-items:center;width:1.5rem;height:1.5rem;color:#adb5bd;border:2px solid #adb5bd;border-radius:100%;background-color:#fff}.step-circle::before{content:"";display:block;position:absolute;top:50%;left:-2px;width:calc(5rem + 1rem - 1.5rem);height:2px;transform:translate(-100%,-50%);color:#adb5bd;background-color:currentColor}.step-text{color:#adb5bd;word-break:break-all;margin-top:.25em}.step-completed .step-circle{color:#fff;background-color:#28a745;border-color:#28a745}.step-completed .step-circle::before{color:#28a745}.step-completed .step-text{color:#28a745}.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-active .step-circle::before{color:#007bff}.step-active .step-text{color:#007bff}.step-primary .step-circle{color:#007bff;border-color:#007bff}.step-primary.step-completed .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-primary.step-completed .step-circle::before{color:#007bff}.step-primary.step-completed .step-text{color:#007bff}.step-primary.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-primary.step-active::before{color:#007bff}.step-primary.step-active .step-text{color:#007bff}.step-secondary .step-circle{color:#6c757d;border-color:#6c757d}.step-secondary.step-completed .step-circle{color:#fff;background-color:#6c757d;border-color:#6c757d}.step-secondary.step-completed .step-circle::before{color:#6c757d}.step-secondary.step-completed .step-text{color:#6c757d}.step-secondary.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-secondary.step-active::before{color:#007bff}.step-secondary.step-active .step-text{color:#007bff}.step-success .step-circle{color:#28a745;border-color:#28a745}.step-success.step-completed .step-circle{color:#fff;background-color:#28a745;border-color:#28a745}.step-success.step-completed .step-circle::before{color:#28a745}.step-success.step-completed .step-text{color:#28a745}.step-success.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-success.step-active::before{color:#007bff}.step-success.step-active .step-text{color:#007bff}.step-info .step-circle{color:#17a2b8;border-color:#17a2b8}.step-info.step-completed .step-circle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.step-info.step-completed .step-circle::before{color:#17a2b8}.step-info.step-completed .step-text{color:#17a2b8}.step-info.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-info.step-active::before{color:#007bff}.step-info.step-active .step-text{color:#007bff}.step-warning .step-circle{color:#ffc107;border-color:#ffc107}.step-warning.step-completed .step-circle{color:#fff;background-color:#ffc107;border-color:#ffc107}.step-warning.step-completed .step-circle::before{color:#ffc107}.step-warning.step-completed .step-text{color:#ffc107}.step-warning.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-warning.step-active::before{color:#007bff}.step-warning.step-active .step-text{color:#007bff}.step-danger .step-circle{color:#dc3545;border-color:#dc3545}.step-danger.step-completed .step-circle{color:#fff;background-color:#dc3545;border-color:#dc3545}.step-danger.step-completed .step-circle::before{color:#dc3545}.step-danger.step-completed .step-text{color:#dc3545}.step-danger.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-danger.step-active::before{color:#007bff}.step-danger.step-active .step-text{color:#007bff}.step-light .step-circle{color:#f8f9fa;border-color:#f8f9fa}.step-light.step-completed .step-circle{color:#fff;background-color:#f8f9fa;border-color:#f8f9fa}.step-light.step-completed .step-circle::before{color:#f8f9fa}.step-light.step-completed .step-text{color:#f8f9fa}.step-light.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-light.step-active::before{color:#007bff}.step-light.step-active .step-text{color:#007bff}.step-dark .step-circle{color:#343a40;border-color:#343a40}.step-dark.step-completed .step-circle{color:#fff;background-color:#343a40;border-color:#343a40}.step-dark.step-completed .step-circle::before{color:#343a40}.step-dark.step-completed .step-text{color:#343a40}.step-dark.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-dark.step-active::before{color:#007bff}.step-dark.step-active .step-text{color:#007bff}.step-link .step-circle{color:#3273dc;border-color:#3273dc}.step-link.step-completed .step-circle{color:#fff;background-color:#3273dc;border-color:#3273dc}.step-link.step-completed .step-circle::before{color:#3273dc}.step-link.step-completed .step-text{color:#3273dc}.step-link.step-active .step-circle{color:#fff;background-color:#007bff;border-color:#007bff}.step-link.step-active::before{color:#007bff}.step-link.step-active .step-text{color:#007bff}.steps-content{margin:1rem 0}.steps-content>.step-panel{display:none}.steps-content>.active{display:block}.form-check.form-switch .form-check-input.form-check-input-primary:checked{background-color:#007bff;border-color:#007bff}.form-check.form-switch .form-check-input.form-check-input-secondary:checked{background-color:#6c757d;border-color:#6c757d}.form-check.form-switch .form-check-input.form-check-input-success:checked{background-color:#28a745;border-color:#28a745}.form-check.form-switch .form-check-input.form-check-input-info:checked{background-color:#17a2b8;border-color:#17a2b8}.form-check.form-switch .form-check-input.form-check-input-warning:checked{background-color:#ffc107;border-color:#ffc107}.form-check.form-switch .form-check-input.form-check-input-danger:checked{background-color:#dc3545;border-color:#dc3545}.form-check.form-switch .form-check-input.form-check-input-light:checked{background-color:#f8f9fa;border-color:#f8f9fa}.form-check.form-switch .form-check-input.form-check-input-dark:checked{background-color:#343a40;border-color:#343a40}.form-check.form-switch .form-check-input.form-check-input-link:checked{background-color:#3273dc;border-color:#3273dc}.form-check.form-switch .form-check-input.form-check-input-xs{width:calc(.75rem + (.5rem/2));height:.5rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-xs+.form-check-label{line-height:1rem;vertical-align:middle;padding-left:0}.form-check.form-switch .form-check-input.form-check-input-xs:checked~.form-check-label::after{transform:translateX(calc(.75rem - (.5rem/2)))}.form-check.form-switch .form-check-input.form-check-input-sm{width:calc(1rem + (.75rem/2));height:.75rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-sm+.form-check-label{line-height:1.25rem;vertical-align:middle;padding-left:.75rem}.form-check.form-switch .form-check-input.form-check-input-sm:checked~.form-check-label::after{transform:translateX(calc(1rem - (.75rem/2)))}.form-check.form-switch .form-check-input.form-check-input-md{width:calc(2rem + (1.5rem/2));height:1.5rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-md+.form-check-label{line-height:2rem;vertical-align:middle;padding-left:.75rem}.form-check.form-switch .form-check-input.form-check-input-md:checked~.form-check-label::after{transform:translateX(calc(2rem - (1.5rem/2)))}.form-check.form-switch .form-check-input.form-check-input-lg{width:calc(3rem + (2rem/2));height:2rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-lg+.form-check-label{line-height:2.5rem;vertical-align:middle;padding-left:.75rem}.form-check.form-switch .form-check-input.form-check-input-lg:checked~.form-check-label::after{transform:translateX(calc(3rem - (2rem/2)))}.form-check.form-switch .form-check-input.form-check-input-xl{width:calc(4rem + (2.5rem/2));height:2.5rem;margin-left:-2.5em}.form-check.form-switch .form-check-input.form-check-input-xl+.form-check-label{line-height:3rem;vertical-align:middle;padding-left:.75rem}.form-check.form-switch .form-check-input.form-check-input-xl:checked~.form-check-label::after{transform:translateX(calc(4rem - (2.5rem/2)))}table.table tbody tr.selected{background-color:var(--primary)}tr.table-row-selectable:hover{cursor:pointer}.table-fixed-header{overflow-y:auto}.table-fixed-header>.table{border-collapse:separate;border-spacing:0}.table-fixed-header>.table>thead>tr>th{border-top:none;position:sticky;background:#fff;z-index:10}.table-fixed-header>.table>thead>tr:nth-child(1)>th{top:0}.table-fixed-header>.table-bordered>:not(caption)>*>*{border-width:1px 1px}.overflow-auto-auto{overflow:auto auto !important}.overflow-auto-hidden{overflow:auto hidden !important}.overflow-auto-visible{overflow:auto visible !important}.overflow-auto-scroll{overflow:auto scroll !important}.overflow-hidden-auto{overflow:hidden auto !important}.overflow-hidden-hidden{overflow:hidden hidden !important}.overflow-hidden-visible{overflow:hidden visible !important}.overflow-hidden-scroll{overflow:hidden scroll !important}.overflow-visible-auto{overflow:visible auto !important}.overflow-visible-hidden{overflow:visible hidden !important}.overflow-visible-visible{overflow:visible visible !important}.overflow-visible-scroll{overflow:visible scroll !important}.overflow-scroll-auto{overflow:scroll auto !important}.overflow-scroll-hidden{overflow:scroll hidden !important}.overflow-scroll-visible{overflow:scroll visible !important}.overflow-scroll-scroll{overflow:scroll scroll !important}ol.ordered-list-lower-alpha{list-style-type:lower-alpha}ol.ordered-list-lower-roman{list-style-type:lower-roman}ol.ordered-list-upper-alpha{list-style-type:upper-alpha}ol.ordered-list-upper-roman{list-style-type:upper-roman}.flatpickr-months{margin:.5rem 0}.flatpickr-months .flatpickr-month,.flatpickr-months .flatpickr-next-month,.flatpickr-months .flatpickr-prev-month{height:auto;position:relative}.flatpickr-months .flatpickr-month:hover svg,.flatpickr-months .flatpickr-next-month:hover svg,.flatpickr-months .flatpickr-prev-month:hover svg{fill:#007bff}.flatpickr-months .flatpickr-month{color:#212529}.flatpickr-current-month{padding:13px 0 0 0;font-size:115%}.flatpickr-current-month span.cur-month{font-weight:700}.flatpickr-current-month span.cur-month:hover{background:rgba(0,123,255,.15)}.numInputWrapper:hover{background:rgba(0,123,255,.15)}.flatpickr-day{border-radius:.25rem;font-weight:500;color:#212529}.flatpickr-day.today{border-color:#007bff}.flatpickr-day.today:hover{background:#007bff;border-color:#007bff}.flatpickr-day:hover{background:rgba(0,123,255,.1);border-color:rgba(0,0,0,0)}span.flatpickr-weekday{color:#212529}.flatpickr-day.selected,.flatpickr-day.startRange,.flatpickr-day.endRange,.flatpickr-day.selected.inRange,.flatpickr-day.startRange.inRange,.flatpickr-day.endRange.inRange,.flatpickr-day.selected:focus,.flatpickr-day.startRange:focus,.flatpickr-day.endRange:focus,.flatpickr-day.selected:hover,.flatpickr-day.startRange:hover,.flatpickr-day.endRange:hover,.flatpickr-day.selected.prevMonthDay,.flatpickr-day.startRange.prevMonthDay,.flatpickr-day.endRange.prevMonthDay,.flatpickr-day.selected.nextMonthDay,.flatpickr-day.startRange.nextMonthDay,.flatpickr-day.endRange.nextMonthDay{background:#007bff;border-color:#007bff}.flatpickr-day.selected.startRange+.endRange:not(:nth-child(7n+1)),.flatpickr-day.startRange.startRange+.endRange:not(:nth-child(7n+1)),.flatpickr-day.endRange.startRange+.endRange:not(:nth-child(7n+1)){box-shadow:-10px 0 0 #007bff}.flatpickr-day.selected.startRange,.flatpickr-day.startRange.startRange,.flatpickr-day.endRange.startRange{border-radius:.25rem 0 0 .25rem}.flatpickr-day.selected.endRange,.flatpickr-day.startRange.endRange,.flatpickr-day.endRange.endRange{border-radius:0 .25rem .25rem 0}.flatpickr-monthSelect-month:hover,.flatpickr-monthSelect-month:focus{background:rgba(0,123,255,.1)}.flatpickr-monthSelect-month.selected{background-color:#007bff} .snackbar{align-items:center;background-color:var(--b-snackbar-background,#323232);color:var(--b-snackbar-text-color,#fff);font-size:.875rem;line-height:1.42857;opacity:0;padding:.875rem 1.5rem;position:fixed;bottom:0;left:0;transform:translateY(100%);transition:opacity 0s .195s,transform .195s cubic-bezier(.4,0,1,1);width:100%;z-index:60}@media(min-width:768px){.snackbar{border-radius:2px;max-width:35.5rem;min-width:18rem;left:50%;transform:translate(-50%,100%);width:auto}}@media(min-width:768px){.snackbar{transition:opacity 0s .2535s,transform .2535s cubic-bezier(.4,0,1,1)}}@media(min-width:1200px){.snackbar{transition:opacity 0s .13s,transform .13s cubic-bezier(.4,0,1,1)}}@media screen and (prefers-reduced-motion:reduce){.snackbar{transition:none}}.snackbar.snackbar-show{transition-duration:.225s;transition-property:transform;transition-timing-function:cubic-bezier(0,0,.2,1);opacity:1;transform:translateY(0)}@media(min-width:768px){.snackbar.snackbar-show{transition-duration:.2925s}}@media(min-width:1200px){.snackbar.snackbar-show{transition-duration:.15s}}@media screen and (prefers-reduced-motion:reduce){.snackbar.snackbar-show{transition:none}}@media(min-width:768px){.snackbar.snackbar-show{transform:translate(-50%,-1.5rem)}}.snackbar-header{display:flex;-ms-flex-pack:justify;justify-content:space-between;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background-color:DARKEN(var(--b-snackbar-background,#323232),30%);margin-right:auto;min-width:0;font-weight:bold;padding-bottom:.875rem}.snackbar-footer{display:flex;-ms-flex-pack:justify;justify-content:space-between;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background-color:DARKEN(var(--b-snackbar-background,#323232),30%);margin-right:auto;min-width:0;padding-top:.875rem}.snackbar-body{display:flex;-ms-flex-pack:justify;justify-content:space-between;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-right:auto;max-height:100%;min-width:0}.snackbar-action-button{transition-duration:.3s;transition-property:background-color,background-image;transition-timing-function:cubic-bezier(.4,0,.2,1);background-color:transparent;background-image:none;border:0;color:var(--b-snackbar-button-color,var(--b-snackbar-button-color,#ff4081));cursor:pointer;display:block;flex-shrink:0;font-size:inherit;font-weight:500;line-height:inherit;padding:0;text-transform:uppercase;white-space:nowrap}@media(min-width:768px){.snackbar-action-button{transition-duration:.39s}}@media(min-width:1200px){.snackbar-action-button{transition-duration:.2s}}@media screen and (prefers-reduced-motion:reduce){.snackbar-action-button{transition:none}}.snackbar-action-button:focus,.snackbar-action-button:hover{color:var(--b-snackbar-button-hover-color,var(--b-snackbar-button-hover-color,#ff80ab));text-decoration:none}@media(min-width:768px){.snackbar-action-button{margin-left:3rem}}.snackbar-action-button:focus{outline:0}@media(min-width:768px){.snackbar-left,.snackbar-right{transform:translateY(100%)}.snackbar-left.snackbar-show,.snackbar-right.snackbar-show{transform:translateY(-1.5rem)}}@media(min-width:768px){.snackbar-left{left:1.5rem}}@media(min-width:768px){.snackbar-right{right:1.5rem;left:auto}}.snackbar-multi-line{padding-top:1.25rem;padding-bottom:1.25rem}.snackbar-multi-line .snackbar-body{white-space:normal}.snackbar-primary{background-color:var(--b-snackbar-background-primary,#cce5ff);color:var(--b-snackbar-text-primary,#004085)}.snackbar-action-button-primary{color:var(--b-snackbar-button-primary,#ff4081)}.snackbar-action-button-primary:focus,.snackbar-action-button-primary:hover{color:var(--b-snackbar-button-hover-primary,#ff80ab)}.snackbar-secondary{background-color:var(--b-snackbar-background-secondary,#e2e3e5);color:var(--b-snackbar-text-secondary,#383d41)}.snackbar-action-button-secondary{color:var(--b-snackbar-button-secondary,#ff4081)}.snackbar-action-button-secondary:focus,.snackbar-action-button-secondary:hover{color:var(--b-snackbar-button-hover-secondary,#ff80ab)}.snackbar-success{background-color:var(--b-snackbar-background-success,#d4edda);color:var(--b-snackbar-text-success,#155724)}.snackbar-action-button-success{color:var(--b-snackbar-button-success,#ff4081)}.snackbar-action-button-success:focus,.snackbar-action-button-success:hover{color:var(--b-snackbar-button-hover-success,#ff80ab)}.snackbar-danger{background-color:var(--b-snackbar-background-danger,#f8d7da);color:var(--b-snackbar-text-danger,#721c24)}.snackbar-action-button-danger{color:var(--b-snackbar-button-danger,#ff4081)}.snackbar-action-button-danger:focus,.snackbar-action-button-danger:hover{color:var(--b-snackbar-button-hover-danger,#ff80ab)}.snackbar-warning{background-color:var(--b-snackbar-background-warning,#fff3cd);color:var(--b-snackbar-text-warning,#856404)}.snackbar-action-button-warning{color:var(--b-snackbar-button-warning,#ff4081)}.snackbar-action-button-warning:focus,.snackbar-action-button-warning:hover{color:var(--b-snackbar-button-hover-warning,#ff80ab)}.snackbar-info{background-color:var(--b-snackbar-background-info,#d1ecf1);color:var(--b-snackbar-text-info,#0c5460)}.snackbar-action-button-info{color:var(--b-snackbar-button-info,#ff4081)}.snackbar-action-button-info:focus,.snackbar-action-button-info:hover{color:var(--b-snackbar-button-hover-info,#ff80ab)}.snackbar-light{background-color:var(--b-snackbar-background-light,#fefefe);color:var(--b-snackbar-text-light,#818182)}.snackbar-action-button-light{color:var(--b-snackbar-button-light,#ff4081)}.snackbar-action-button-light:focus,.snackbar-action-button-light:hover{color:var(--b-snackbar-button-hover-light,#ff80ab)}.snackbar-dark{background-color:var(--b-snackbar-background-dark,#d6d8d9);color:var(--b-snackbar-text-dark,#1b1e21)}.snackbar-action-button-dark{color:var(--b-snackbar-button-dark,#ff4081)}.snackbar-action-button-dark:focus,.snackbar-action-button-dark:hover{color:var(--b-snackbar-button-hover-dark,#ff80ab)}.snackbar-stack{display:flex;flex-direction:column;position:fixed;z-index:60;bottom:0}.snackbar-stack .snackbar{position:relative;flex-direction:row;margin-bottom:0}.snackbar-stack .snackbar:not(:last-child){margin-bottom:1.5rem}@media(min-width:576px){.snackbar-stack-center{left:50%;transform:translate(-50%,0%)}.snackbar-stack-left{left:1.5rem}.snackbar-stack-right{right:1.5rem}} #main-navbar-tools a.dropdown-toggle{text-decoration:none;color:#fff}.navbar .dropdown-submenu{position:relative}.navbar .dropdown-menu{margin:0;padding:0}.navbar .dropdown-menu a{font-size:.9em;padding:10px 15px;display:block;min-width:210px;text-align:left;border-radius:.25rem;min-height:44px}.navbar .dropdown-submenu a::after{transform:rotate(-90deg);position:absolute;right:16px;top:18px}.navbar .dropdown-submenu .dropdown-menu{top:0;left:100%}.card-header .btn{padding:2px 6px}.card-header h5{margin:0}.container>.card{box-shadow:0 .125rem .25rem rgba(0,0,0,.075) !important}@media screen and (min-width:768px){.navbar .dropdown:hover>.dropdown-menu{display:block}.navbar .dropdown-submenu:hover>.dropdown-menu{display:block}}.input-validation-error{border-color:#dc3545}.field-validation-error{font-size:.8em}.dataTables_scrollBody{min-height:248px}div.dataTables_wrapper div.dataTables_info{padding-top:11px;white-space:nowrap}div.dataTables_wrapper div.dataTables_length label{padding-top:10px;margin-bottom:0}.rtl .dropdown-menu-right{right:auto;left:0}.rtl .dropdown-menu-right a{text-align:right}.rtl .navbar .dropdown-menu a{text-align:right}.rtl .navbar .dropdown-submenu .dropdown-menu{top:0;left:auto;right:100%}.navbar-dark .navbar-nav .nav-link{color:#000 !important}.navbar-nav>.nav-item>.nav-link,.navbar-nav>.nav-item>.dropdown>.nav-link{color:#fff !important}.navbar-nav>.nav-item>div>button{color:#fff}.btn span.spinner-border{margin-right:.5rem}.radar-spinner,.radar-spinner *{box-sizing:border-box}.radar-spinner{height:60px;width:60px;position:relative}.radar-spinner .circle{position:absolute;height:100%;width:100%;top:0;left:0;animation:radar-spinner-animation 2s infinite}.radar-spinner .circle:nth-child(1){padding:calc(60px*5*2*0/110);animation-delay:300ms}.radar-spinner .circle:nth-child(2){padding:calc(60px*5*2*1/110);animation-delay:300ms}.radar-spinner .circle:nth-child(3){padding:calc(60px*5*2*2/110);animation-delay:300ms}.radar-spinner .circle:nth-child(4){padding:calc(60px*5*2*3/110);animation-delay:0ms}.radar-spinner .circle-inner,.radar-spinner .circle-inner-container{height:100%;width:100%;border-radius:50%;border:calc(60px*5/110) solid transparent}.radar-spinner .circle-inner{border-left-color:var(--secondary,#ff1d5e);border-right-color:var(--secondary,#ff1d5e)}@keyframes radar-spinner-animation{50%{transform:rotate(180deg)}100%{transform:rotate(0deg)}} diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Host/wwwroot/index.html b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Host/wwwroot/index.html index c79c556930..86693c1b01 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Host/wwwroot/index.html +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Host/wwwroot/index.html @@ -8,7 +8,7 @@ - + @@ -22,7 +22,7 @@ - + diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/MyCompanyName.MyProjectName.Blazor.Server.Host.csproj b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/MyCompanyName.MyProjectName.Blazor.Server.Host.csproj index 9c8b1eeeac..befedf8ea1 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/MyCompanyName.MyProjectName.Blazor.Server.Host.csproj +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/MyCompanyName.MyProjectName.Blazor.Server.Host.csproj @@ -12,8 +12,8 @@ - - + + From cc032b7787a3fb9248475db611cede036310492c Mon Sep 17 00:00:00 2001 From: Hamza Albreem <94292623+braim23@users.noreply.github.com> Date: Thu, 6 Jan 2022 11:35:25 +0300 Subject: [PATCH 46/67] Update Part-3.md applied the usual changes and fixed a few msitakes. --- docs/en/Tutorials/Part-3.md | 86 ++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/docs/en/Tutorials/Part-3.md b/docs/en/Tutorials/Part-3.md index 92e04d0b41..f6a59f1108 100644 --- a/docs/en/Tutorials/Part-3.md +++ b/docs/en/Tutorials/Part-3.md @@ -13,7 +13,7 @@ In this tutorial series, you will build an ABP based web application named `Acme * **{{DB_Value}}** as the ORM provider. * **{{UI_Value}}** as the UI Framework. -This tutorial is organized as the following parts; +This tutorial is organized as the following parts: - [Part 1: Creating the server side](Part-1.md) - [Part 2: The book list page](Part-2.md) @@ -51,19 +51,19 @@ This part is also recorded as a video tutorial and ** ``` -* Added `New book` button to the card header.. +* Added a `New book` button to the card header.. * Added the `abp-modal` which renders a modal to allow user to create a new book. `abp-modal` is a pre-built component to show modals. While you could use another approach to show a modal, `abp-modal` provides additional benefits. -You can open your browser and click **New book** button to see the new modal. +You can open your browser and click the **New book** button to see the new modal. ![Empty modal for new book](images/bookstore-empty-new-book-modal.png) @@ -801,11 +801,11 @@ export class BookComponent implements OnInit { ``` * Imported `FormGroup`, `FormBuilder` and `Validators` from `@angular/forms`. -* Added `form: FormGroup` property. -* Added `bookTypes` property as a list of `BookType` enum members. That will be used in form options. +* Added a `form: FormGroup` property. +* Added a `bookTypes` property as a list of `BookType` enum members. That will be used in form options. * Injected `FormBuilder` into the constructor. [FormBuilder](https://angular.io/api/forms/FormBuilder) provides convenient methods for generating form controls. It reduces the amount of boilerplate needed to build complex forms. -* Added `buildForm` method to the end of the file and executed the `buildForm()` in the `createBook` method. -* Added `save` method. +* Added a `buildForm` method to the end of the file and executed the `buildForm()` in the `createBook` method. +* Added a `save` method. Open `/src/app/book/book.component.html` and replace ` ` with the following code part: @@ -863,7 +863,7 @@ Also replace ` ` with the following code p ### Datepicker -We've used [NgBootstrap datepicker](https://ng-bootstrap.github.io/#/components/datepicker/overview) in this component. So, need to arrange dependencies related to this component. +We've used [NgBootstrap datepicker](https://ng-bootstrap.github.io/#/components/datepicker/overview) in this component. So, we need to arrange the dependencies related to this component. Open `/src/app/book/book.module.ts` and replace the content as below: @@ -959,7 +959,7 @@ export class BookComponent implements OnInit { ``` * Imported ` NgbDateNativeAdapter` and `NgbDateAdapter`. -* We added a new provider `NgbDateAdapter` that converts Datepicker value to `Date` type. See the [datepicker adapters](https://ng-bootstrap.github.io/#/components/datepicker/overview) for more details. +* We added a new provider `NgbDateAdapter` that converts the Datepicker value to `Date` type. Check out the [datepicker adapters](https://ng-bootstrap.github.io/#/components/datepicker/overview) for more details. Now, you can open your browser to see the changes: @@ -1054,14 +1054,14 @@ export class BookComponent implements OnInit { ``` * We declared a variable named `selectedBook` as `BookDto`. -* We added `editBook` method. This method fetches the book with the given `id` and sets it to `selectedBook` object. +* We added an `editBook` method. This method fetches the book with the given `id` and sets it to `selectedBook` object. * We replaced the `buildForm` method so that it creates the form with the `selectedBook` data. * We replaced the `createBook` method so it sets `selectedBook` to an empty object. * We changed the `save` method to handle both of create and update operations. ### Add "Actions" Dropdown to the Table -Open the `/src/app/book/book.component.html`  and add the following `ngx-datatable-column` definition as the first column in the `ngx-datatable`: +Open `/src/app/book/book.component.html`  and add the following `ngx-datatable-column` definition as the first column in the `ngx-datatable`: ```html ``` -This template will show **Edit** text for edit record operation, **New Book** for new record operation in the title. +This template will show the **Edit** text for edit record operation, **New Book** for new record operation in the title. ## Deleting a Book -Open the `/src/app/book/book.component.ts` and inject the `ConfirmationService`. +Open the `/src/app/book/book.component.ts` file and inject the `ConfirmationService`. Replace the constructor as below: @@ -1137,7 +1137,7 @@ delete(id: string) { * We injected `ConfirmationService` to the constructor. * Added a `delete` method. -> See the [Confirmation Popup documentation](../UI/Angular/Confirmation-Service) for more about this service. +> Check out the [Confirmation Popup documentation](../UI/Angular/Confirmation-Service) for more about this service. ### Add a Delete Button @@ -1169,7 +1169,7 @@ Clicking the "Delete" action calls the `delete` method which then shows a confir In this section, you will learn how to create a new modal dialog form to create a new book. Since we've inherited from the `AbpCrudPageBase`, we only need to develop the view part. -### Add "New Button" Button +### Add a "New Button" Button Open the `Books.razor` and replace the `` section with the following code: @@ -1191,7 +1191,7 @@ This will change the card header by adding a "New book" button to the right side ![blazor-add-book-button](images/blazor-add-book-button.png) -Now, we can add a modal that will be opened when we click to the button. +Now, we can add a modal that will be opened when we click the button. ### Book Creation Modal @@ -1259,7 +1259,7 @@ This code requires a service; Inject the `AbpBlazorMessageLocalizerHelper` at ```` * The form implements validation and the `AbpBlazorMessageLocalizerHelper` is used to simply localize the validation messages. -* `CreateModal` object, `CloseCreateModalAsync` and `CreateEntityAsync` method are defined by the base class. See the [Blazorise documentation](https://blazorise.com/docs/) if you want to understand the `Modal` and the other components. +* The `CreateModal` object, `CloseCreateModalAsync` and `CreateEntityAsync` methods are defined by the base class. Check out the [Blazorise documentation](https://blazorise.com/docs/) if you want to understand the `Modal` and the other components. That's all. Run the application and try to add a new book: @@ -1267,7 +1267,7 @@ That's all. Run the application and try to add a new book: ## Updating a Book -Editing a books is similar to the creating a new book. +Editing a book is similar to creating a new book. ### Actions Dropdown @@ -1287,7 +1287,7 @@ Open the `Books.razor` and add the following `DataGridEntityActionsColumn` secti * `OpenEditModalAsync` is defined in the base class which takes the entity (book) to edit. -`DataGridEntityActionsColumn` component is used to show an "Actions" dropdown for each row in the `DataGrid`. `DataGridEntityActionsColumn` shows a **single button** instead of a dropdown if there is only one available action inside it: +The `DataGridEntityActionsColumn` component is used to show an "Actions" dropdown for each row in the `DataGrid`. The `DataGridEntityActionsColumn` shows a **single button** instead of a dropdown if there is only one available action inside it: ![blazor-edit-book-action](images/blazor-edit-book-action-2.png) @@ -1384,7 +1384,7 @@ You can now run the application and try to edit a book. ## Deleting a Book -Open the `Books.razor` page and add the following `EntityAction` under the "Edit" action inside the `EntityActions`: +Open the `Books.razor` page and add the following `EntityAction` code under the "Edit" action inside `EntityActions`: ````xml Date: Thu, 6 Jan 2022 13:40:40 +0300 Subject: [PATCH 47/67] feat: create abstarct menu service --- .../src/lib/services/abstract-menu.service.ts | 60 +++++++++++++++++++ .../src/lib/services/nav-items.service.ts | 48 +-------------- 2 files changed, 63 insertions(+), 45 deletions(-) create mode 100644 npm/ng-packs/packages/theme-shared/src/lib/services/abstract-menu.service.ts diff --git a/npm/ng-packs/packages/theme-shared/src/lib/services/abstract-menu.service.ts b/npm/ng-packs/packages/theme-shared/src/lib/services/abstract-menu.service.ts new file mode 100644 index 0000000000..2c3d904a1b --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/services/abstract-menu.service.ts @@ -0,0 +1,60 @@ +import { BehaviorSubject, Observable } from 'rxjs'; +import { NavItem } from '../models/nav-item'; + +export abstract class AbstractMenuService { + protected abstract baseClass; + + protected _items$ = new BehaviorSubject([]); + + get items(): T[] { + return this._items$.value; + } + + get items$(): Observable { + return this._items$.asObservable(); + } + + addItems(newItems: T[]) { + const items = [...this.items]; + newItems.forEach(item => { + const index = items.findIndex(i => i.id === item.id); + const data = new this.baseClass(item); + + if (index > -1) { + items[index] = data; + return; + } + + items.push(data); + }); + items.sort(this.sortItems); + this._items$.next(items); + } + + removeItem(id: string | number) { + const index = this.items.findIndex(item => item.id === id); + + if (index < 0) return; + + const items = [...this.items.slice(0, index), ...this.items.slice(index + 1)]; + this._items$.next(items); + } + + patchItem(id: string | number, item: Partial>) { + const index = this.items.findIndex(i => i.id === id); + + if (index < 0) return; + + const items = [...this.items]; + items[index] = new this.baseClass({ ...items[index], ...item }); + items.sort(this.sortItems); + this._items$.next(items); + } + + private sortItems(a: T, b: T) { + if (!a.order) return 1; + if (!b.order) return -1; + + return a.order - b.order; + } +} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/services/nav-items.service.ts b/npm/ng-packs/packages/theme-shared/src/lib/services/nav-items.service.ts index ca361a2940..6aacdd279b 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/services/nav-items.service.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/services/nav-items.service.ts @@ -1,50 +1,8 @@ import { Injectable } from '@angular/core'; -import { BehaviorSubject, Observable } from 'rxjs'; import { NavItem } from '../models/nav-item'; +import { AbstractMenuService } from './abstract-menu.service'; @Injectable({ providedIn: 'root' }) -export class NavItemsService { - private _items$ = new BehaviorSubject([]); - - get items(): NavItem[] { - return this._items$.value; - } - - get items$(): Observable { - return this._items$.asObservable(); - } - - addItems(newItems: NavItem[]) { - const items = [...this.items]; - newItems.forEach(item => items.push(new NavItem(item))); - items.sort(sortItems); - this._items$.next(items); - } - - removeItem(id: string | number) { - const index = this.items.findIndex(item => item.id === id); - - if (index < 0) return; - - const items = [...this.items.slice(0, index), ...this.items.slice(index + 1)]; - this._items$.next(items); - } - - patchItem(id: string | number, item: Partial>) { - const index = this.items.findIndex(i => i.id === id); - - if (index < 0) return; - - const items = [...this.items]; - items[index] = new NavItem({ ...items[index], ...item }); - items.sort(sortItems); - this._items$.next(items); - } -} - -function sortItems(a: NavItem, b: NavItem) { - if (!a.order) return 1; - if (!b.order) return -1; - - return a.order - b.order; +export class NavItemsService extends AbstractMenuService { + protected baseClass = NavItem; } From 97b426f8c17bac182fa3a1a846193289bd58e15e Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Thu, 6 Jan 2022 13:40:51 +0300 Subject: [PATCH 48/67] feat: create user-menu.service --- .../packages/theme-shared/src/lib/services/index.ts | 1 + .../theme-shared/src/lib/services/user-menu.service.ts | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 npm/ng-packs/packages/theme-shared/src/lib/services/user-menu.service.ts diff --git a/npm/ng-packs/packages/theme-shared/src/lib/services/index.ts b/npm/ng-packs/packages/theme-shared/src/lib/services/index.ts index 5b97363917..0f98819137 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/services/index.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/services/index.ts @@ -2,3 +2,4 @@ export * from './confirmation.service'; export * from './nav-items.service'; export * from './page-alert.service'; export * from './toaster.service'; +export * from './user-menu.service'; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/services/user-menu.service.ts b/npm/ng-packs/packages/theme-shared/src/lib/services/user-menu.service.ts new file mode 100644 index 0000000000..1d58170084 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/services/user-menu.service.ts @@ -0,0 +1,8 @@ +import { Injectable } from '@angular/core'; +import { UserMenu } from '../models/user-menu'; +import { AbstractMenuService } from './abstract-menu.service'; + +@Injectable({ providedIn: 'root' }) +export class UserMenuService extends AbstractMenuService { + protected baseClass = UserMenu; +} From 3ec9a83acd358fea1f4e533bd8033f771edf46c5 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Thu, 6 Jan 2022 13:41:22 +0300 Subject: [PATCH 49/67] feat: add user-menu.provider --- .../theme-basic/src/lib/enums/index.ts | 1 + .../src/lib/enums/user-menu-items.ts | 4 ++ .../theme-basic/src/lib/providers/index.ts | 1 + .../src/lib/providers/user-menu.provider.ts | 59 +++++++++++++++++++ .../theme-basic/src/lib/theme-basic.module.ts | 2 + .../theme-shared/src/lib/models/index.ts | 3 +- .../theme-shared/src/lib/models/user-menu.ts | 3 + 7 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 npm/ng-packs/packages/theme-basic/src/lib/enums/user-menu-items.ts create mode 100644 npm/ng-packs/packages/theme-basic/src/lib/providers/user-menu.provider.ts create mode 100644 npm/ng-packs/packages/theme-shared/src/lib/models/user-menu.ts diff --git a/npm/ng-packs/packages/theme-basic/src/lib/enums/index.ts b/npm/ng-packs/packages/theme-basic/src/lib/enums/index.ts index 07635cbbc8..3c919aa271 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/enums/index.ts +++ b/npm/ng-packs/packages/theme-basic/src/lib/enums/index.ts @@ -1 +1,2 @@ export * from './components'; +export * from './user-menu-items'; diff --git a/npm/ng-packs/packages/theme-basic/src/lib/enums/user-menu-items.ts b/npm/ng-packs/packages/theme-basic/src/lib/enums/user-menu-items.ts new file mode 100644 index 0000000000..42ab66e802 --- /dev/null +++ b/npm/ng-packs/packages/theme-basic/src/lib/enums/user-menu-items.ts @@ -0,0 +1,4 @@ +export const enum eUserMenuItems { + MyAccount = 'UserMenu.MyAccount', + Logout = 'UserMenu.Logout', +} diff --git a/npm/ng-packs/packages/theme-basic/src/lib/providers/index.ts b/npm/ng-packs/packages/theme-basic/src/lib/providers/index.ts index 8102d94f62..d3028eab68 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/providers/index.ts +++ b/npm/ng-packs/packages/theme-basic/src/lib/providers/index.ts @@ -1,2 +1,3 @@ export * from './nav-item.provider'; export * from './styles.provider'; +export * from './user-menu.provider'; diff --git a/npm/ng-packs/packages/theme-basic/src/lib/providers/user-menu.provider.ts b/npm/ng-packs/packages/theme-basic/src/lib/providers/user-menu.provider.ts new file mode 100644 index 0000000000..5c36cc5347 --- /dev/null +++ b/npm/ng-packs/packages/theme-basic/src/lib/providers/user-menu.provider.ts @@ -0,0 +1,59 @@ +import { + AuthService, + ConfigStateService, + LocalizationService, + NAVIGATE_TO_MANAGE_PROFILE, +} from '@abp/ng.core'; +import { UserMenuService } from '@abp/ng.theme.shared'; +import { APP_INITIALIZER, Injector } from '@angular/core'; +import { filter } from 'rxjs/operators'; +import { eUserMenuItems } from '../enums/user-menu-items'; + +export const BASIC_THEME_USER_MENU_PROVIDERS = [ + { + provide: APP_INITIALIZER, + useFactory: configureUserMenu, + deps: [Injector], + multi: true, + }, +]; + +export function configureUserMenu(injector: Injector) { + const configState = injector.get(ConfigStateService); + const userMenu = injector.get(UserMenuService); + const localization = injector.get(LocalizationService); + const authService = injector.get(AuthService); + const navigateToManageProfile = injector.get(NAVIGATE_TO_MANAGE_PROFILE); + + return () => { + configState + .getAll$() + .pipe(filter(res => !!res?.localization)) + .subscribe(() => { + userMenu.addItems([ + { + id: eUserMenuItems.MyAccount, + order: 100, + html: ` + ${localization.instant('AbpAccount::MyAccount')} + `, + action: () => navigateToManageProfile(), + }, + { + id: eUserMenuItems.Logout, + order: 101, + html: ` + ${localization.instant('AbpUi::Logout')} + `, + action: () => { + authService.logout().subscribe(); + }, + }, + ]); + }); + }; +} diff --git a/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts b/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts index 17ef89338f..a8020e50fe 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts +++ b/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts @@ -23,6 +23,7 @@ import { ValidationErrorComponent } from './components/validation-error/validati import { LazyStyleHandler } from './handlers/lazy-style.handler'; import { BASIC_THEME_NAV_ITEM_PROVIDERS } from './providers/nav-item.provider'; import { BASIC_THEME_STYLES_PROVIDERS } from './providers/styles.provider'; +import { BASIC_THEME_USER_MENU_PROVIDERS } from './providers/user-menu.provider'; export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, EmptyLayoutComponent]; @@ -70,6 +71,7 @@ export class ThemeBasicModule { ngModule: ThemeBasicModule, providers: [ BASIC_THEME_NAV_ITEM_PROVIDERS, + BASIC_THEME_USER_MENU_PROVIDERS, BASIC_THEME_STYLES_PROVIDERS, { provide: VALIDATION_ERROR_TEMPLATE, diff --git a/npm/ng-packs/packages/theme-shared/src/lib/models/index.ts b/npm/ng-packs/packages/theme-shared/src/lib/models/index.ts index d1e2e71c5c..ca6aa74124 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/models/index.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/models/index.ts @@ -1,5 +1,6 @@ export * from './common'; export * from './confirmation'; +export * from './nav-item'; export * from './statistics'; export * from './toaster'; -export * from './nav-item'; +export * from './user-menu'; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/models/user-menu.ts b/npm/ng-packs/packages/theme-shared/src/lib/models/user-menu.ts new file mode 100644 index 0000000000..20b92b8082 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/models/user-menu.ts @@ -0,0 +1,3 @@ +import { NavItem } from './nav-item'; + +export class UserMenu extends NavItem {} From b7e172656f41ff9253990148faeb2eea60f69390 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Thu, 6 Jan 2022 13:41:38 +0300 Subject: [PATCH 50/67] feat: user user-menu.service into the current-user component --- .../theme-basic/src/lib/components/index.ts | 2 +- .../nav-items/current-user.component.html | 20 +++++++++++++------ .../nav-items/current-user.component.ts | 8 ++++++-- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/npm/ng-packs/packages/theme-basic/src/lib/components/index.ts b/npm/ng-packs/packages/theme-basic/src/lib/components/index.ts index 7daf7f2c1a..b5e0d52629 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/components/index.ts +++ b/npm/ng-packs/packages/theme-basic/src/lib/components/index.ts @@ -7,6 +7,6 @@ export * from './logo/logo.component'; export * from './nav-items/current-user.component'; export * from './nav-items/languages.component'; export * from './nav-items/nav-items.component'; +export * from './page-alert-container/page-alert-container.component'; export * from './routes/routes.component'; export * from './validation-error/validation-error.component'; -export * from './page-alert-container/page-alert-container.component'; diff --git a/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.html b/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.html index 64a1bb4d6a..0a1dec59d0 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.html +++ b/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.html @@ -31,11 +31,19 @@ aria-labelledby="dropdownMenuLink" [class.d-block]="smallScreen && currentUserDropdown.isOpen()" > - {{ 'AbpAccount::MyAccount' | abpLocalization }} - {{ 'AbpUi::Logout' | abpLocalization }} + + + + + diff --git a/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.ts b/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.ts index fbfa01882a..9619845837 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.ts +++ b/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.ts @@ -5,7 +5,8 @@ import { NAVIGATE_TO_MANAGE_PROFILE, SessionStateService, } from '@abp/ng.core'; -import { Component, Inject } from '@angular/core'; +import { UserMenu, UserMenuService } from '@abp/ng.theme.shared'; +import { Component, Inject, TrackByFunction } from '@angular/core'; import { Observable } from 'rxjs'; @Component({ @@ -16,12 +17,15 @@ export class CurrentUserComponent { currentUser$: Observable = this.configState.getOne$('currentUser'); selectedTenant$ = this.sessionState.getTenant$(); + trackByFn: TrackByFunction = (_, element) => element.id; + get smallScreen(): boolean { return window.innerWidth < 992; } constructor( - @Inject(NAVIGATE_TO_MANAGE_PROFILE) public navigateToManageProfile: () => void, + @Inject(NAVIGATE_TO_MANAGE_PROFILE) public readonly navigateToManageProfile: () => void, + public readonly userMenu: UserMenuService, private authService: AuthService, private configState: ConfigStateService, private sessionState: SessionStateService, From 1eb3c103854a89a29f53780fce07a91c5a526a34 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Thu, 6 Jan 2022 13:41:46 +0300 Subject: [PATCH 51/67] update yarn.lock --- npm/ng-packs/yarn.lock | 182 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 171 insertions(+), 11 deletions(-) diff --git a/npm/ng-packs/yarn.lock b/npm/ng-packs/yarn.lock index e968d45cba..983efc0350 100644 --- a/npm/ng-packs/yarn.lock +++ b/npm/ng-packs/yarn.lock @@ -2,6 +2,120 @@ # yarn lockfile v1 +"@abp/ng.account.core@~5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@abp/ng.account.core/-/ng.account.core-5.0.1.tgz#ec29ad71cf88c9ac5975e7911e4263efc002d27d" + integrity sha512-h6E8FWE3qJzDObYYtrWEjAqGaoKRhmOERATdndqBElCKWc88BAoO+tCJ67fdi9EGcSyLeYnX2y3fR5QBrThe+g== + dependencies: + tslib "^2.0.0" + +"@abp/ng.account@~5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@abp/ng.account/-/ng.account-5.0.1.tgz#aa428813454dd065edc97be0080ef04c403f2720" + integrity sha512-VeT2zJjB07gFh/wionYiwRbAY+H1ZHf4ueC0xJLP6oADxRf7IZHxFcujsmpv0eB66Zyy3DZ9j6gkx3Kva5B+Rg== + dependencies: + "@abp/ng.account.core" "~5.0.1" + "@abp/ng.theme.shared" "~5.0.1" + tslib "^2.0.0" + +"@abp/ng.components@~5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@abp/ng.components/-/ng.components-5.0.1.tgz#9cd10f91d4da45eb435109fe3c75619f866aad63" + integrity sha512-SZR5+dlWydVJw27un+WFGb1Hnis3Dg+1hZXfHmIuAyX/Mr7l0X0JKKVxfWR+4u/A83xjBxYD4Zo6OaXpEn6cCg== + dependencies: + chart.js "^3.5.1" + ng-zorro-antd "^12.0.1" + tslib "^2.0.0" + +"@abp/ng.core@~5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@abp/ng.core/-/ng.core-5.0.1.tgz#f507075dde476bb32d6b37792bce36443dd2fb83" + integrity sha512-Ta7SqOrrGXeXPM4N2bJuhK9awTHaYSsfE3GTCtOvBn11P/GxfsaUKJ7XFvAd1D/5+3BjF9+LF4EiWYZn1UaWUw== + dependencies: + "@abp/utils" "~5.0.1" + angular-oauth2-oidc "^12.1.0" + just-clone "^3.2.1" + just-compare "^1.4.0" + ts-toolbelt "6.15.4" + tslib "^2.0.0" + +"@abp/ng.feature-management@~5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@abp/ng.feature-management/-/ng.feature-management-5.0.1.tgz#2cbc54f7ca209cc9397394eebabf69a9e5380613" + integrity sha512-evoX1hmFHdKWCW/H409KmXtcg2B9HKXgZTez9/yXV5+eluVm9HY/U/gtTmgMG3vMAfqAJMXQdOEeG/vo5JozsQ== + dependencies: + "@abp/ng.theme.shared" "~5.0.1" + tslib "^2.0.0" + +"@abp/ng.identity@~5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@abp/ng.identity/-/ng.identity-5.0.1.tgz#71e25af3c5fa1f00967b98ec983d013291d76adc" + integrity sha512-AzrGyl88fX+qlZ3DiXqfxG5i4N4Yy6HTiOs6TFNwtEFfNICKXWWOAv6q6w8U50P35WpAytwyTnz9oYeAozn8cg== + dependencies: + "@abp/ng.permission-management" "~5.0.1" + "@abp/ng.theme.shared" "~5.0.1" + tslib "^2.0.0" + +"@abp/ng.permission-management@~5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@abp/ng.permission-management/-/ng.permission-management-5.0.1.tgz#aa712868055ec71b9367b758d899d783df7f7115" + integrity sha512-8ge0TIrdtshEe/hUmmcSBU8T8onKSIBRR3dAkitPJRfU/FSDVB/qM4pOTjWzgL/Rghem+9y9LTV4UXvM3fw8eQ== + dependencies: + "@abp/ng.theme.shared" "~5.0.1" + tslib "^2.0.0" + +"@abp/ng.schematics@~5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@abp/ng.schematics/-/ng.schematics-5.0.1.tgz#f80077c7503789738c9238f4e6f57301a648fc9d" + integrity sha512-dRx1T/I+wAhb1oM+7M0qcnCPn6OPeDcm8NtTmolN8iLkCaMPUh5HkylPNnTvxLcUWXiOFqJtn2HBQn7SBD8Vnw== + dependencies: + "@angular-devkit/core" "~11.0.2" + "@angular-devkit/schematics" "~11.0.2" + got "^11.5.2" + jsonc-parser "^2.3.0" + should-quote "^1.0.0" + typescript "~3.9.2" + +"@abp/ng.setting-management@~5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@abp/ng.setting-management/-/ng.setting-management-5.0.1.tgz#6d32ea9930ac23f56e91306872ce87ab5cc42e54" + integrity sha512-5DhYj14JqT1z2IFnCL4lSOfyK3+ZdJ2y8LOJBROJ9xLnvYUfwFaVcn+V3Iz0kM8v5huWQ+EKgjIZ47qdc/tPCQ== + dependencies: + "@abp/ng.components" "~5.0.1" + "@abp/ng.theme.shared" "~5.0.1" + tslib "^2.0.0" + +"@abp/ng.tenant-management@~5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@abp/ng.tenant-management/-/ng.tenant-management-5.0.1.tgz#592da08b9376c00714bd4dd63f37e752c15de912" + integrity sha512-8m9HuStDWZsLCv6g6vK7l9k6wvK0oamgFuZrac9DjIHsruGdpLFdEeUvqhDhsyulMyk83OUEIi1hRgEX2PdQfg== + dependencies: + "@abp/ng.feature-management" "~5.0.1" + "@abp/ng.theme.shared" "~5.0.1" + tslib "^2.0.0" + +"@abp/ng.theme.basic@~5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@abp/ng.theme.basic/-/ng.theme.basic-5.0.1.tgz#87d4eec12296c6747b5d9d37781c180334e36fbb" + integrity sha512-kzgc2plB9xPTFye8CVlALzCNL/UAAd+jVhl5wz1meau2l7vvnW5sCI6P64y9gpKipQYMSpRhbYYQSBi4JJGNeA== + dependencies: + "@abp/ng.account.core" "~5.0.1" + "@abp/ng.theme.shared" "~5.0.1" + tslib "^2.0.0" + +"@abp/ng.theme.shared@~5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@abp/ng.theme.shared/-/ng.theme.shared-5.0.1.tgz#866e7733619c9c6bcb1d36c827369fff0e97c80b" + integrity sha512-XT1BGJiG9sqZJJGZcCN6+WvlbRdZPRBRnc6NvzZTPXGgnnX107N2lanIShulJiVUX68chkBd4yNuM8tM/hLiOg== + dependencies: + "@abp/ng.core" "~5.0.1" + "@fortawesome/fontawesome-free" "^5.15.4" + "@ng-bootstrap/ng-bootstrap" "11.0.0-beta.2" + "@ngx-validate/core" "^0.1.1" + "@swimlane/ngx-datatable" "^19.0.0" + bootstrap "^5.1.1" + tslib "^2.0.0" + "@abp/utils@~5.0.1": version "5.0.1" resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-5.0.1.tgz#57934383004a21172bf7e08130813c08946894fb" @@ -146,6 +260,17 @@ rxjs "6.6.2" source-map "0.7.3" +"@angular-devkit/core@11.0.7", "@angular-devkit/core@~11.0.2": + version "11.0.7" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-11.0.7.tgz#05b82be7e11ddc2a7836c777297ee45eee20ff55" + integrity sha512-1GKnIT++YSUHpzzRx9QC0+8yOw4wy+ZpiJVDlroPSeK4FGrTCJqJKenkfRjVFRFOSrzTiJds+IU6kI4+bFbw9g== + dependencies: + ajv "6.12.6" + fast-json-stable-stringify "2.1.0" + magic-string "0.25.7" + rxjs "6.6.3" + source-map "0.7.3" + "@angular-devkit/core@12.2.13": version "12.2.13" resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-12.2.13.tgz#db3929d1bfce71010b37fb7c4e6c33ef80a4f35f" @@ -179,6 +304,15 @@ ora "5.4.1" rxjs "6.6.7" +"@angular-devkit/schematics@~11.0.2": + version "11.0.7" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-11.0.7.tgz#7cd2398c98d82f8e5bdc3bb5c70e92d6b1d12a12" + integrity sha512-mKkXWmSTlZYjQO4i7xUX+bG1E9h9Ke3GgGQQouA+kth06IPO+VcywLQNsui4qcyLDUjyo8CaX+44aoSXoX3Tgg== + dependencies: + "@angular-devkit/core" "11.0.7" + ora "5.1.0" + rxjs "6.6.3" + "@angular-eslint/eslint-plugin-template@~12.3.0": version "12.3.1" resolved "https://registry.yarnpkg.com/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-12.3.1.tgz#33260cd5356df5db7e27719443eabcf6c214e32e" @@ -3581,6 +3715,16 @@ ajv@6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@6.12.6, ajv@^6.1.0, ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + ajv@8.6.2: version "8.6.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.6.2.tgz#2fb45e0e5fcbc0813326c1c3da535d1881bb0571" @@ -3591,16 +3735,6 @@ ajv@8.6.2: require-from-string "^2.0.2" uri-js "^4.2.2" -ajv@^6.1.0, ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - ajv@^8.0.0, ajv@^8.0.1: version "8.8.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.8.2.tgz#01b4fef2007a28bf75f0b7fc009f62679de4abbb" @@ -4551,7 +4685,7 @@ cli-cursor@^3.1.0: dependencies: restore-cursor "^3.1.0" -cli-spinners@^2.5.0: +cli-spinners@^2.4.0, cli-spinners@^2.5.0: version "2.6.1" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== @@ -10096,6 +10230,20 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" +ora@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-5.1.0.tgz#b188cf8cd2d4d9b13fd25383bc3e5cba352c94f8" + integrity sha512-9tXIMPvjZ7hPTbk8DFq1f7Kow/HU/pQYB60JbNq+QnGwcyhWVZaQ4hM9zQDEsPxw/muLpgiHSaumUZxCAmod/w== + dependencies: + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.4.0" + is-interactive "^1.0.0" + log-symbols "^4.0.0" + mute-stream "0.0.8" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + ora@5.4.1, ora@^5.1.0, ora@^5.3.0: version "5.4.1" resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" @@ -11838,6 +11986,13 @@ rxjs@6.6.2: dependencies: tslib "^1.9.0" +rxjs@6.6.3: + version "6.6.3" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552" + integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ== + dependencies: + tslib "^1.9.0" + rxjs@6.6.7, rxjs@^6.5.0, rxjs@^6.5.4, rxjs@^6.6.0, rxjs@~6.6.0: version "6.6.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" @@ -13227,6 +13382,11 @@ typescript@4.3.5: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== +typescript@~3.9.2: + version "3.9.10" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8" + integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== + uglify-js@^3.1.4: version "3.14.3" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.14.3.tgz#c0f25dfea1e8e5323eccf59610be08b6043c15cf" From 3dda81f88da0f3f062035cbbe83a308097641377 Mon Sep 17 00:00:00 2001 From: Mehmet Erim <34455572+mehmet-erim@users.noreply.github.com> Date: Thu, 6 Jan 2022 16:10:57 +0300 Subject: [PATCH 52/67] Update Theming.md --- docs/en/UI/Angular/Theming.md | 38 ++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/docs/en/UI/Angular/Theming.md b/docs/en/UI/Angular/Theming.md index 21e28953f8..16bae7aac9 100644 --- a/docs/en/UI/Angular/Theming.md +++ b/docs/en/UI/Angular/Theming.md @@ -204,25 +204,49 @@ constructor(private sessionState: SessionStateService) { } ```` + + ##### User Menu -User menu is a component that can be replaceable. See an example to learn how can you replace it: +`UserMenuService` is used to get the user menu's items and render on the dropdown. You can add/update/remove an item by using the service. + +**Example: Adding/updating/removing an user menu item** ````ts -import { eThemeBasicComponents } from '@abp/ng.theme.basic'; -import { NavItemsService } from '@abp/ng.theme.shared'; +import { eUserMenuItems } from '@abp/ng.theme.basic'; +import { UserMenuService } from '@abp/ng.theme.shared'; import { Component } from '@angular/core'; +import { Router } from '@angular/router'; @Component({/* component metadata */}) export class AppComponent { - constructor(private navItems: NavItemsService) { - this.navItems.patchItem(eThemeBasicComponents.CurrentUser, { component: MyUserMenuComponent }); + constructor(private userMenu: UserMenuService, private router: Router) { + this.userMenu.addItems([ + { + id: 'UserMenu.Reports', + order: 1, + html: `Reports`, + action: () => { + this.router.navigateByUrl('/account/reports'); + }, + }, + ]); + + this.userMenu.patchItem(eUserMenuItems.MyAccount, { + html: `My profile`, + }); + + this.userMenu.removeItem(eUserMenuItems.Logout); } } ```` -[`ConfigStateService`](Config-State-Service.md) service can be used to obtain the `application-configuration` API response (e.g. getting current user or tenant). +In the example above, added a new user menu item labeled "Reports", updated the "My account" item HTML content, and removed the "Logout" item. + +See the result: + +![image](https://user-images.githubusercontent.com/34455572/148387770-5b5e25fb-f855-447c-8ead-c04c69b6d6f7.png) #### Page Alerts -`PageAlertService` service is used to get the current page alerts to render on the layout. See the [Page Alerts](Page-Alerts.md) document to learn more. \ No newline at end of file +`PageAlertService` service is used to get the current page alerts to render on the layout. See the [Page Alerts](Page-Alerts.md) document to learn more. From 081104ea9949a343aa2a9ecef43bd64656d3ef7a Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 7 Jan 2022 11:19:04 +0800 Subject: [PATCH 53/67] Remove Internal method usage. Resolve #11218 --- .../Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs index d5dbbde33a..22325f91c5 100644 --- a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs +++ b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs @@ -1,7 +1,6 @@ using System; using System.Linq; using AutoMapper; -using AutoMapper.Internal; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.DependencyInjection; @@ -19,7 +18,8 @@ namespace Volo.Abp.AutoMapper protected override bool IsConventionalRegistrationDisabled(Type type) { - return !OpenTypes.Any(type.ImplementsGenericInterface) || base.IsConventionalRegistrationDisabled(type); + return type.GetInterfaces().Any(x => x.IsGenericType && OpenTypes.Contains(x.GetGenericTypeDefinition())) || + base.IsConventionalRegistrationDisabled(type); } protected override ServiceLifetime? GetDefaultLifeTimeOrNull(Type type) From d4d507d3eb66f76071ee3cbe030e457660cb076d Mon Sep 17 00:00:00 2001 From: Luke Ni Date: Fri, 7 Jan 2022 13:43:29 +0800 Subject: [PATCH 54/67] translate to zh-Hans --- docs/zh-Hans/Tutorials/Part-9.md | 1250 +++++++++++++++++++++++++++++- 1 file changed, 1249 insertions(+), 1 deletion(-) diff --git a/docs/zh-Hans/Tutorials/Part-9.md b/docs/zh-Hans/Tutorials/Part-9.md index 602306c484..2fbd4dcd55 100644 --- a/docs/zh-Hans/Tutorials/Part-9.md +++ b/docs/zh-Hans/Tutorials/Part-9.md @@ -1 +1,1249 @@ -TODO.. \ No newline at end of file +# Web应用程序开发教程 - 第九章: 作者: 用户页面 +````json +//[doc-params] +{ + "UI": ["MVC","Blazor","BlazorServer","NG"], + "DB": ["EF","Mongo"] +} +```` +## 关于本教程 + +在本系列教程中, 你将构建一个名为 `Acme.BookStore` 的用于管理书籍及其作者列表的基于ABP的应用程序. 它是使用以下技术开发的: + +* **{{DB_Text}}** 做为ORM提供程序. +* **{{UI_Value}}** 做为UI框架. + +本教程分为以下部分: + +- [Part 1: 创建服务端](Part-1.md) +- [Part 2: 图书列表页面](Part-2.md) +- [Part 3: 创建,更新和删除图书](Part-2.md) +- [Part 4: 集成测试](Part-4.md) +- [Part 5: 授权](Part-5.md) +- [Part 6: 作者: 领域层](Part-6.md) +- [Part 7: 作者: 数据库集成](Part-7.md) +- [Part 8: 作者: 应用服务层](Part-8.md) +- [Part 9: 作者: 用户页面](本章) +- [Part 10: 图书到作者的关系](Part-10.md) + +## 下载源码 + +本教程根据你的**UI** 和 **数据库**偏好有多个版本,我们准备了几种可供下载的源码组合: + +* [MVC (Razor Pages) UI 与 EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Mvc-EfCore) +* [Blazor UI 与 EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore) +* [Angular UI 与 MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) + +> 如果你在Windows中遇到 "文件名太长" or "解压错误", 很可能与Windows最大文件路径限制有关. Windows文件路径的最大长度为250字符. 为了解决这个问题,参阅 [在Windows 10中启用长路径](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later). + +> 如果你遇到与Git相关的长路径错误, 尝试使用下面的命令在Windows中启用长路径. 参阅 https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path +> `git config --system core.longpaths true` + +## 简介 + +这章阐述如何为前一章介绍的 `作者` 实体创建CRUD页面. + +{{if UI == "MVC"}} + +## 作者列表页面 + +在 `Acme.BookStore.Web` 项目的 `Pages/Authors` 文件夹下创建一个新的razor页面, `Index.cshtml`, 修改文件内容如下. + +### Index.cshtml + +````html +@page +@using Acme.BookStore.Localization +@using Acme.BookStore.Permissions +@using Acme.BookStore.Web.Pages.Authors +@using Microsoft.AspNetCore.Authorization +@using Microsoft.Extensions.Localization +@inject IStringLocalizer L +@inject IAuthorizationService AuthorizationService +@model IndexModel + +@section scripts +{ + +} + + + + + + @L["Authors"] + + + @if (await AuthorizationService + .IsGrantedAsync(BookStorePermissions.Authors.Create)) + { + + } + + + + + + + +```` + +这是一个简单的页面, 和我们以前创建的图书页面一样. 它导入了一个JavaScript文件, 我们后面会进行介绍这个文件. + +### IndexModel.cshtml.cs + +````csharp +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace Acme.BookStore.Web.Pages.Authors +{ + public class IndexModel : PageModel + { + public void OnGet() + { + + } + } +} +```` + +### Index.js + +````js +$(function () { + var l = abp.localization.getResource('BookStore'); + var createModal = new abp.ModalManager(abp.appPath + 'Authors/CreateModal'); + var editModal = new abp.ModalManager(abp.appPath + 'Authors/EditModal'); + + var dataTable = $('#AuthorsTable').DataTable( + abp.libs.datatables.normalizeConfiguration({ + serverSide: true, + paging: true, + order: [[1, "asc"]], + searching: false, + scrollX: true, + ajax: abp.libs.datatables.createAjax(acme.bookStore.authors.author.getList), + columnDefs: [ + { + title: l('Actions'), + rowAction: { + items: + [ + { + text: l('Edit'), + visible: + abp.auth.isGranted('BookStore.Authors.Edit'), + action: function (data) { + editModal.open({ id: data.record.id }); + } + }, + { + text: l('Delete'), + visible: + abp.auth.isGranted('BookStore.Authors.Delete'), + confirmMessage: function (data) { + return l( + 'AuthorDeletionConfirmationMessage', + data.record.name + ); + }, + action: function (data) { + acme.bookStore.authors.author + .delete(data.record.id) + .then(function() { + abp.notify.info( + l('SuccessfullyDeleted') + ); + dataTable.ajax.reload(); + }); + } + } + ] + } + }, + { + title: l('Name'), + data: "name" + }, + { + title: l('BirthDate'), + data: "birthDate", + render: function (data) { + return luxon + .DateTime + .fromISO(data, { + locale: abp.localization.currentCulture.name + }).toLocaleString(); + } + } + ] + }) + ); + + createModal.onResult(function () { + dataTable.ajax.reload(); + }); + + editModal.onResult(function () { + dataTable.ajax.reload(); + }); + + $('#NewAuthorButton').click(function (e) { + e.preventDefault(); + createModal.open(); + }); +}); +```` + +简单来说, 这个JavaScript页面: + +* 创建了一个具有 `操作`, `姓名` 和 `生日` 列的数据表格. + * `Actions` 列用来添加 *编辑* 和 *删除* 操作. + * `生日` 提供了一个 `render` 函数, 使用 [luxon](https://moment.github.io/luxon/) 库格式化 `DateTime` 值. +* 使用 `abp.ModalManager` 打开 *新建* 和 *编辑* 模态表单. + +这块代码与以前创建的图书页面非常相似, 所以我们不再赘述. + +### 本地化 + +这个页面使用了一些需要声明的本地化键. 打开 `Acme.BookStore.Domain.Shared` 项目中 `Localization/BookStore` 文件夹下的 `en.json` 文件, 加入以下条目: + +````json +"Menu:Authors": "Authors", +"Authors": "Authors", +"AuthorDeletionConfirmationMessage": "Are you sure to delete the author '{0}'?", +"BirthDate": "Birth date", +"NewAuthor": "New author" +```` + +注意我们加入了额外的键. 它们会在下面的小节中被使用. + +### 加入主菜单 + +打开 `Acme.BookStore.Web` 项目的 `Menus` 文件夹中的 `BookStoreMenuContributor.cs` , 在 `ConfigureMainMenuAsync` 方法的结尾加入以下代码: + +````csharp +if (await context.IsGrantedAsync(BookStorePermissions.Authors.Default)) +{ + bookStoreMenu.AddItem(new ApplicationMenuItem( + "BooksStore.Authors", + l["Menu:Authors"], + url: "/Authors" + )); +} +```` + +### 运行应用程序 + +运行并登录应用程序. **因为你还没有权限, 所以不能看见菜单项**. 转到 `Identity/Roles` 页面, 点击 *操作* 按钮并选择**管理员角色**的*权限*操作: + +![bookstore-author-permissions](images/bookstore-author-permissions.png) + +如你所见, 管理员角色还没有*作者管理*权限. 单击复选框并保存, 赋予权限. **刷新页面**后, 你会在主菜单中的*图书商店*下看到*作者*菜单项: + +![bookstore-authors-page](images/bookstore-authors-page.png) + +页面是完全可以工作的, 除了 *新建作者* 和 *操作/编辑*, 因为它们还没有实现 . + +> **提示**: 如果你在定义一个新权限后运行 `.DbMigrator` 控制台程序, 它会自动将这些权限赋予管理员角色, 你不需要手工赋予权限. + +## 新建模态窗口 + +在 `Acme.BookStore.Web` 项目的 `Pages/Authors` 文件夹下创建一个 razor 页面 `CreateModal.cshtml`, 修改它的内容如下: + +### CreateModal.cshtml + +```html +@page +@using Acme.BookStore.Localization +@using Acme.BookStore.Web.Pages.Authors +@using Microsoft.Extensions.Localization +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal +@model CreateModalModel +@inject IStringLocalizer L +@{ + Layout = null; +} +
+ + + + + + + + + +
+``` + +之前我们已经使用ABP框架的 [动态表单](../UI/AspNetCore/Tag-Helpers/Dynamic-Forms.md)开发了图书页面. 这里可以使用相同的方法, 但我们希望展示如何手工完成它. 实际上, 没有那么手工化, 因为在这个例子中我们使用了 `abp-input` 标签简化了表单元素的创建. + +你当然可以使用标准Bootstrap HTML结构, 但是这需要写很多代码. `abp-input` 自动添加验证, 本地化和根据数据类型生成标准元素. + +### CreateModal.cshtml.cs + +```csharp +using System; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using Acme.BookStore.Authors; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; + +namespace Acme.BookStore.Web.Pages.Authors +{ + public class CreateModalModel : BookStorePageModel + { + [BindProperty] + public CreateAuthorViewModel Author { get; set; } + + private readonly IAuthorAppService _authorAppService; + + public CreateModalModel(IAuthorAppService authorAppService) + { + _authorAppService = authorAppService; + } + + public void OnGet() + { + Author = new CreateAuthorViewModel(); + } + + public async Task OnPostAsync() + { + var dto = ObjectMapper.Map(Author); + await _authorAppService.CreateAsync(dto); + return NoContent(); + } + + public class CreateAuthorViewModel + { + [Required] + [StringLength(AuthorConsts.MaxNameLength)] + public string Name { get; set; } + + [Required] + [DataType(DataType.Date)] + public DateTime BirthDate { get; set; } + + [TextArea] + public string ShortBio { get; set; } + } + } +} +``` + +这个页面模型类注入和使用 `IAuthorAppService` 创建新作者. 它和图书创建模型类之间主要的区别是这个模型类为视图模型声明了一个新类 `CreateAuthorViewModel`, 而不是重用 `CreateAuthorDto`. + +这么做的主要原因是展示在页面中如何使用不同的模型. 但还有一个好处: 我们为类成员添加了两个不存在于 `CreateAuthorDto` 中的特性: + +* 为 `BirthDate` 添加 `[DataType(DataType.Date)]` 特性, 这会在UI为这个属性显示一个日期选择控件. +* 为 `ShortBio` 添加 `[TextArea]` 特性, 这会显示一个多行文本框, 而不是标准文本框. + +通过这种方式, 可以根据UI需求定制视图模型类, 而无需修改DTO. 这么做的一个结果是: 使用 `ObjectMapper` 将 `CreateAuthorViewModel` 映射到 `CreateAuthorDto`. 为了完成映射, 需要在 `BookStoreWebAutoMapperProfile` 构造函数中加入新的映射代码: + +````csharp +using Acme.BookStore.Authors; // ADDED NAMESPACE IMPORT +using Acme.BookStore.Books; +using AutoMapper; + +namespace Acme.BookStore.Web +{ + public class BookStoreWebAutoMapperProfile : Profile + { + public BookStoreWebAutoMapperProfile() + { + CreateMap(); + + // ADD a NEW MAPPING + CreateMap(); + } + } +} +```` + +当你重新运行应用程序后, 点击"新建作者" 按钮会打开一个新的模态窗口. + +![bookstore-new-author-modal](images/bookstore-new-author-modal.png) + +## 编辑模态窗口 + +在 `Acme.BookStore.Web` 项目的 `Pages/Authors` 文件夹下创建一个 razor 页面 `EditModal.cshtml`, 修改它的内容如下: + +### EditModal.cshtml + +````html +@page +@using Acme.BookStore.Localization +@using Acme.BookStore.Web.Pages.Authors +@using Microsoft.Extensions.Localization +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal +@model EditModalModel +@inject IStringLocalizer L +@{ + Layout = null; +} +
+ + + + + + + + + + +
+```` + +### EditModal.cshtml.cs + +```csharp +using System; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using Acme.BookStore.Authors; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; + +namespace Acme.BookStore.Web.Pages.Authors +{ + public class EditModalModel : BookStorePageModel + { + [BindProperty] + public EditAuthorViewModel Author { get; set; } + + private readonly IAuthorAppService _authorAppService; + + public EditModalModel(IAuthorAppService authorAppService) + { + _authorAppService = authorAppService; + } + + public async Task OnGetAsync(Guid id) + { + var authorDto = await _authorAppService.GetAsync(id); + Author = ObjectMapper.Map(authorDto); + } + + public async Task OnPostAsync() + { + await _authorAppService.UpdateAsync( + Author.Id, + ObjectMapper.Map(Author) + ); + + return NoContent(); + } + + public class EditAuthorViewModel + { + [HiddenInput] + public Guid Id { get; set; } + + [Required] + [StringLength(AuthorConsts.MaxNameLength)] + public string Name { get; set; } + + [Required] + [DataType(DataType.Date)] + public DateTime BirthDate { get; set; } + + [TextArea] + public string ShortBio { get; set; } + } + } +} +``` + +这个类与 `CreateModal.cshtml.cs` 类似, 主要不同是: + +* 使用 `IAuthorAppService.GetAsync(...)` 方法从应用层获取正在编辑的作者. +* `EditAuthorViewModel` 拥有一个额外的 `Id` 属性, 它被 `[HiddenInput]` 特性标记, 会为这个属性在页面上创建一个隐藏输入框. + +这个类要求在 `BookStoreWebAutoMapperProfile` 类中添加两个对象映射声明: + +```csharp +using Acme.BookStore.Authors; +using Acme.BookStore.Books; +using AutoMapper; + +namespace Acme.BookStore.Web +{ + public class BookStoreWebAutoMapperProfile : Profile + { + public BookStoreWebAutoMapperProfile() + { + CreateMap(); + + CreateMap(); + + // ADD THESE NEW MAPPINGS + CreateMap(); + CreateMap(); + } + } +} +``` + +这就是全部了! 你可以运行应用程序并尝试编辑一个作者. + +{{else if UI == "NG"}} + +## 作者管理页面 + +运行下面的命令行在angular应用程序的根目录创建一个名为 `AuthorModule` 新模块: + +```bash +yarn ng generate module author --module app --routing --route authors +``` + +这上命令应该产生以下输出: + +```bash +> yarn ng generate module author --module app --routing --route authors + +yarn run v1.19.1 +$ ng generate module author --module app --routing --route authors +CREATE src/app/author/author-routing.module.ts (344 bytes) +CREATE src/app/author/author.module.ts (349 bytes) +CREATE src/app/author/author.component.html (21 bytes) +CREATE src/app/author/author.component.spec.ts (628 bytes) +CREATE src/app/author/author.component.ts (276 bytes) +CREATE src/app/author/author.component.scss (0 bytes) +UPDATE src/app/app-routing.module.ts (1396 bytes) +Done in 2.22s. +``` + +### AuthorModule + +打开 `/src/app/author/author.module.ts,` 替换成以下内容: + +```js +import { NgModule } from '@angular/core'; +import { SharedModule } from '../shared/shared.module'; +import { AuthorRoutingModule } from './author-routing.module'; +import { AuthorComponent } from './author.component'; +import { NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap'; + +@NgModule({ + declarations: [AuthorComponent], + imports: [SharedModule, AuthorRoutingModule, NgbDatepickerModule], +}) +export class AuthorModule {} +``` + +- 添加 `SharedModule`. `SharedModule` 导出一些创建用户页面需要的通用模块. +- `SharedModule` 已经导出 `CommonModule`, 所以移除 `CommonModule`. +- 添加 `NgbDatepickerModule`, 后面用于作者创建和编辑表单. + +### 菜单定义 + +打开 `src/app/route.provider.ts` 文件, 加入以下的菜单定义: + +````js +{ + path: '/authors', + name: '::Menu:Authors', + parentName: '::Menu:BookStore', + layout: eLayoutType.application, + requiredPolicy: 'BookStore.Authors', +} +```` + +最终的 `configureRoutes` 函数声明应该如下: + +```js +function configureRoutes(routes: RoutesService) { + return () => { + routes.add([ + { + path: '/', + name: '::Menu:Home', + iconClass: 'fas fa-home', + order: 1, + layout: eLayoutType.application, + }, + { + path: '/book-store', + name: '::Menu:BookStore', + iconClass: 'fas fa-book', + order: 2, + layout: eLayoutType.application, + }, + { + path: '/books', + name: '::Menu:Books', + parentName: '::Menu:BookStore', + layout: eLayoutType.application, + requiredPolicy: 'BookStore.Books', + }, + { + path: '/authors', + name: '::Menu:Authors', + parentName: '::Menu:BookStore', + layout: eLayoutType.application, + requiredPolicy: 'BookStore.Authors', + }, + ]); + }; +} +``` + +### 生成服务代理 + +[ABP CLI](https://docs.abp.io/en/abp/latest/CLI) 提供 `generate-proxy` 命令为HTTP APIs生成客户端代理, 使得使用HTTP APIs更容易. `generate-proxy` 命令运行前, 应用程序必须启动运行. + +在 `angular` 文件夹运行以下命令: + +```bash +abp generate-proxy -t ng +``` + +这个命令为作者服务和相关模型(DTO)类生成服务代理: + +![bookstore-angular-service-proxy-author](images/bookstore-angular-service-proxy-author-2.png) + +### AuthorComponent + +打开 `/src/app/author/author.component.ts` 文件, 替换成以下内容: + +```js +import { Component, OnInit } from '@angular/core'; +import { ListService, PagedResultDto } from '@abp/ng.core'; +import { AuthorService, AuthorDto } from '@proxy/authors'; +import { FormGroup, FormBuilder, Validators } from '@angular/forms'; +import { NgbDateNativeAdapter, NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap'; +import { ConfirmationService, Confirmation } from '@abp/ng.theme.shared'; + +@Component({ + selector: 'app-author', + templateUrl: './author.component.html', + styleUrls: ['./author.component.scss'], + providers: [ListService, { provide: NgbDateAdapter, useClass: NgbDateNativeAdapter }], +}) +export class AuthorComponent implements OnInit { + author = { items: [], totalCount: 0 } as PagedResultDto; + + isModalOpen = false; + + form: FormGroup; + + selectedAuthor = {} as AuthorDto; + + constructor( + public readonly list: ListService, + private authorService: AuthorService, + private fb: FormBuilder, + private confirmation: ConfirmationService + ) {} + + ngOnInit(): void { + const authorStreamCreator = (query) => this.authorService.getList(query); + + this.list.hookToQuery(authorStreamCreator).subscribe((response) => { + this.author = response; + }); + } + + createAuthor() { + this.selectedAuthor = {} as AuthorDto; + this.buildForm(); + this.isModalOpen = true; + } + + editAuthor(id: string) { + this.authorService.get(id).subscribe((author) => { + this.selectedAuthor = author; + this.buildForm(); + this.isModalOpen = true; + }); + } + + buildForm() { + this.form = this.fb.group({ + name: [this.selectedAuthor.name || '', Validators.required], + birthDate: [ + this.selectedAuthor.birthDate ? new Date(this.selectedAuthor.birthDate) : null, + Validators.required, + ], + }); + } + + save() { + if (this.form.invalid) { + return; + } + + if (this.selectedAuthor.id) { + this.authorService + .update(this.selectedAuthor.id, this.form.value) + .subscribe(() => { + this.isModalOpen = false; + this.form.reset(); + this.list.get(); + }); + } else { + this.authorService.create(this.form.value).subscribe(() => { + this.isModalOpen = false; + this.form.reset(); + this.list.get(); + }); + } + } + + delete(id: string) { + this.confirmation.warn('::AreYouSureToDelete', '::AreYouSure') + .subscribe((status) => { + if (status === Confirmation.Status.confirm) { + this.authorService.delete(id).subscribe(() => this.list.get()); + } + }); + } +} +``` + +打开 `/src/app/author/author.component.html` 文件, 替换成以下内容: + +````html +
+
+
+
+
+ {%{{{ '::Menu:Authors' | abpLocalization }}}%} +
+
+
+
+ +
+
+
+
+
+ + + +
+ +
+ + +
+
+
+
+ + + + {%{{{ row.birthDate | date }}}%} + + +
+
+
+ + + +

{%{{{ (selectedAuthor.id ? '::Edit' : '::NewAuthor') | abpLocalization }}}%}

+
+ + +
+
+ * + +
+ +
+ * + +
+
+
+ + + + + + +
+```` + +### 本地化 + +这个页面使用了一些需要声明的本地化键. 打开 `Acme.BookStore.Domain.Shared` 项目中 `Localization/BookStore` 文件夹下的 `en.json` 文件, 加入以下条目: + +````json +"Menu:Authors": "Authors", +"Authors": "Authors", +"AuthorDeletionConfirmationMessage": "Are you sure to delete the author '{0}'?", +"BirthDate": "Birth date", +"NewAuthor": "New author" +```` + +### 运行应用程序 + +运行并登录应用程序. **因为你还没有权限, 所以不能看见菜单项**. 转到 `Identity/Roles` 页面, 点击 *操作* 按钮并选择**管理员角色**的*权限*操作: + +![bookstore-author-permissions](images/bookstore-author-permissions.png) + +如你所见, 管理员角色还没有*作者管理*权限. 单击复选框并保存, 赋予权限. **刷新页面**后, 你会在主菜单中的*图书商店*下看到*作者*菜单项: + +![bookstore-authors-page](images/bookstore-angular-authors-page.png) + +这就是全部了! 这是一个完整的, 可以工作的页面. 你可以新建, 编辑和删除作者. + +> **提示**: 如果你在定义一个新权限后运行 `.DbMigrator` 控制台程序, 它会自动将这些权限赋予管理员角色, 你不需要手工赋予权限. + +{{end}} + +{{if UI == "Blazor" || UI == "BlazorServer"}} + +## 作者管理页面 + +### 作者Razor组件 + +在 `Acme.BookStore.Blazor` 项目中新建一个 Razor组件页面 `/Pages/Authors.razor`, 替换成以下内容: + +````xml +@page "/authors" +@using Acme.BookStore.Authors +@using Acme.BookStore.Localization +@using Volo.Abp.AspNetCore.Components.Web +@inherits BookStoreComponentBase +@inject IAuthorAppService AuthorAppService +@inject AbpBlazorMessageLocalizerHelper LH + + + + +

@L["Authors"]

+
+ + + @if (CanCreateAuthor) + { + + } + + +
+
+ + + + + + + + @L["Actions"] + + + @if (CanEditAuthor) + { + + @L["Edit"] + + } + @if (CanDeleteAuthor) + { + + @L["Delete"] + + } + + + + + + + + @context.BirthDate.ToShortDateString() + + + + + +
+ + + + +
+ + @L["NewAuthor"] + + + + + + + @L["Name"] + + + + + + + + + @L["BirthDate"] + + + + + @L["ShortBio"] + + + + + + + + + + + + + +
+
+
+ + + + +
+ + @EditingAuthor.Name + + + + + + + @L["Name"] + + + + + + + + + @L["BirthDate"] + + + + + @L["ShortBio"] + + + + + + + + + + + + + +
+
+
+```` + +* 这些代码类似 `Books.razor`, 除了不继承自 `AbpCrudPageBase`, 它使用自己的实现. +* 注入 `IAuthorAppService` , 从UI使用服务器端的HTTP APIs . 我们可以直接注入应用服务接口并在 [动态 C# HTTP API 客户端代理系统](../API/Dynamic-CSharp-API-Clients.md)的帮助下像使用普通的方法一样使用它们, 动态 C# HTTP API 客户端代理系统会为我们调用REST API. 参考下面的 `Authors` 类获得使用方法. +* 注入 `IAuthorizationService` 检查 [权限](../Authorization.md). +* 注入 `IObjectMapper` 进行 [对象到对象映射](../Object-To-Object-Mapping.md). + +在 `Pages` 文件夹下新建一个代码后置文件 `Authors.razor.cs`, 使用以下代码: + +````csharp +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Acme.BookStore.Authors; +using Acme.BookStore.Permissions; +using Blazorise; +using Blazorise.DataGrid; +using Microsoft.AspNetCore.Authorization; +using Volo.Abp.Application.Dtos; + +namespace Acme.BookStore.Blazor.Pages +{ + public partial class Authors + { + private IReadOnlyList AuthorList { get; set; } + + private int PageSize { get; } = LimitedResultRequestDto.DefaultMaxResultCount; + private int CurrentPage { get; set; } + private string CurrentSorting { get; set; } + private int TotalCount { get; set; } + + private bool CanCreateAuthor { get; set; } + private bool CanEditAuthor { get; set; } + private bool CanDeleteAuthor { get; set; } + + private CreateAuthorDto NewAuthor { get; set; } + + private Guid EditingAuthorId { get; set; } + private UpdateAuthorDto EditingAuthor { get; set; } + + private Modal CreateAuthorModal { get; set; } + private Modal EditAuthorModal { get; set; } + + private Validations CreateValidationsRef; + + private Validations EditValidationsRef; + + public Authors() + { + NewAuthor = new CreateAuthorDto(); + EditingAuthor = new UpdateAuthorDto(); + } + + protected override async Task OnInitializedAsync() + { + await SetPermissionsAsync(); + await GetAuthorsAsync(); + } + + private async Task SetPermissionsAsync() + { + CanCreateAuthor = await AuthorizationService + .IsGrantedAsync(BookStorePermissions.Authors.Create); + + CanEditAuthor = await AuthorizationService + .IsGrantedAsync(BookStorePermissions.Authors.Edit); + + CanDeleteAuthor = await AuthorizationService + .IsGrantedAsync(BookStorePermissions.Authors.Delete); + } + + private async Task GetAuthorsAsync() + { + var result = await AuthorAppService.GetListAsync( + new GetAuthorListDto + { + MaxResultCount = PageSize, + SkipCount = CurrentPage * PageSize, + Sorting = CurrentSorting + } + ); + + AuthorList = result.Items; + TotalCount = (int)result.TotalCount; + } + + private async Task OnDataGridReadAsync(DataGridReadDataEventArgs e) + { + CurrentSorting = e.Columns + .Where(c => c.Direction != SortDirection.None) + .Select(c => c.Field + (c.Direction == SortDirection.Descending ? " DESC" : "")) + .JoinAsString(","); + CurrentPage = e.Page - 1; + + await GetAuthorsAsync(); + + await InvokeAsync(StateHasChanged); + } + + private void OpenCreateAuthorModal() + { + CreateValidationsRef.ClearAll(); + + NewAuthor = new CreateAuthorDto(); + CreateAuthorModal.Show(); + } + + private void CloseCreateAuthorModal() + { + CreateAuthorModal.Hide(); + } + + private void OpenEditAuthorModal(AuthorDto author) + { + EditValidationsRef.ClearAll(); + + EditingAuthorId = author.Id; + EditingAuthor = ObjectMapper.Map(author); + EditAuthorModal.Show(); + } + + private async Task DeleteAuthorAsync(AuthorDto author) + { + var confirmMessage = L["AuthorDeletionConfirmationMessage", author.Name]; + if (!await Message.Confirm(confirmMessage)) + { + return; + } + + await AuthorAppService.DeleteAsync(author.Id); + await GetAuthorsAsync(); + } + + private void CloseEditAuthorModal() + { + EditAuthorModal.Hide(); + } + + private async Task CreateAuthorAsync() + { + if (CreateValidationsRef.ValidateAll()) + { + await AuthorAppService.CreateAsync(NewAuthor); + await GetAuthorsAsync(); + CreateAuthorModal.Hide(); + } + } + + private async Task UpdateAuthorAsync() + { + if (EditValidationsRef.ValidateAll()) + { + await AuthorAppService.UpdateAsync(EditingAuthorId, EditingAuthor); + await GetAuthorsAsync(); + EditAuthorModal.Hide(); + } + } + } +} +```` + +这个类定义了 `Authors.razor` 页面使用的属性和方法. + +### 对象映射 + +`Authors` 类使用 `OpenEditAuthorModal` 方法中的 `IObjectMapper`. 所以需要定义这个映射. + +打开 `Acme.BookStore.Blazor` 项目中的 `BookStoreBlazorAutoMapperProfile.cs`, 在构造函数中加入一个映射: + +````csharp +CreateMap(); +```` + +你在文件开头需要 `using Acme.BookStore.Authors;` 声明语句. + +### 加入主菜单 + +打开 `Acme.BookStore.Blazor` 项目的 `Menus` 文件夹中的 `BookStoreMenuContributor.cs` , 在 `ConfigureMainMenuAsync` 方法的结尾加入以下代码: + +````csharp +if (await context.IsGrantedAsync(BookStorePermissions.Authors.Default)) +{ + bookStoreMenu.AddItem(new ApplicationMenuItem( + "BooksStore.Authors", + l["Menu:Authors"], + url: "/authors" + )); +} +```` + +### 本地化 + +我们需要本地化上面的代码. 打开 `Acme.BookStore.Domain.Shared` 项目中 `Localization/BookStore` 文件夹下的 `en.json` 文件, 加入以下条目: + +````json +"Menu:Authors": "Authors", +"Authors": "Authors", +"AuthorDeletionConfirmationMessage": "Are you sure to delete the author '{0}'?", +"BirthDate": "Birth date", +"NewAuthor": "New author" +```` + +### 运行应用程序 + +运行并登录应用程序. **因为你还没有权限, 所以不能看见菜单项**. 转到 `Identity/Roles` 页面, 点击 *操作* 按钮并选择**管理员角色**的*权限*操作: + +![bookstore-author-permissions](images/bookstore-author-permissions.png) + +如你所见, 管理员角色还没有*作者管理*权限. 单击复选框并保存, 赋予权限. **刷新页面**后, 你会在主菜单中的*图书商店*下看到*作者*菜单项: + +![bookstore-authors-page](images/bookstore-authors-blazor-ui.png) + +这就是全部了! 这是一个完整的, 可以工作的页面. 你可以新建, 编辑和删除作者. + +> **提示**: 如果你在定义一个新权限后运行 `.DbMigrator` 控制台程序, 它会自动将这些权限赋予管理员角色, 你不需要手工赋予权限. + +{{end}} + +## 下一章 + +查看本教程的[下一章](Part-10.md). From 133a824dcc74e5fa779204e89adadcbc2ef855ca Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 7 Jan 2022 14:23:22 +0800 Subject: [PATCH 55/67] Update AbpAutoMapperConventionalRegistrar.cs --- .../Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs index 22325f91c5..03412e6e30 100644 --- a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs +++ b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs @@ -18,7 +18,7 @@ namespace Volo.Abp.AutoMapper protected override bool IsConventionalRegistrationDisabled(Type type) { - return type.GetInterfaces().Any(x => x.IsGenericType && OpenTypes.Contains(x.GetGenericTypeDefinition())) || + return !type.GetInterfaces().Any(x => x.IsGenericType && OpenTypes.Contains(x.GetGenericTypeDefinition())) || base.IsConventionalRegistrationDisabled(type); } From 0452ff32be20344320b45e55ec872b535a79eb64 Mon Sep 17 00:00:00 2001 From: DongZirun <942217633@qq.com> Date: Fri, 7 Jan 2022 14:24:37 +0800 Subject: [PATCH 56/67] Update Autofac-Integration.md UseAufoFac in ASP.NET Core Application --- docs/zh-Hans/Autofac-Integration.md | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/docs/zh-Hans/Autofac-Integration.md b/docs/zh-Hans/Autofac-Integration.md index 9b1d249e4e..6fd2a91e6f 100644 --- a/docs/zh-Hans/Autofac-Integration.md +++ b/docs/zh-Hans/Autofac-Integration.md @@ -32,26 +32,23 @@ namespace MyCompany.MyProject ### ASP.NET Core 应用程序 -如下所示, 在 **Startup.cs** 文件中调用 `UseAutofac()`: +如下所示, 在 **Program.cs** 文件中调用 `UseAutofac()`: ````csharp -public class Startup +public class Program { - public IServiceProvider ConfigureServices(IServiceCollection services) + public static int Main(string[] args) { - services.AddApplication(options => - { - //Integrate Autofac! - options.UseAutofac(); - }); - - return services.BuildServiceProviderFromFactory(); + CreateHostBuilder(args).Build().Run(); } - public void Configure(IApplicationBuilder app) - { - app.InitializeApplication(); - } + internal static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }) + .UseAutofac(); //Integrate Autofac! } ```` From 51c2b519f1bd006e32f16c11a9f5c3afc6414ee3 Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 7 Jan 2022 15:25:21 +0800 Subject: [PATCH 57/67] Update AbpAutoMapperConventionalRegistrar.cs --- .../Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs index c1fc9cbfde..39c21e2ca7 100644 --- a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs +++ b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs @@ -19,7 +19,7 @@ public class AbpAutoMapperConventionalRegistrar : DefaultConventionalRegistrar protected override bool IsConventionalRegistrationDisabled(Type type) { return !type.GetInterfaces().Any(x => x.IsGenericType && OpenTypes.Contains(x.GetGenericTypeDefinition())) || - base.IsConventionalRegistrationDisabled(type); + base.IsConventionalRegistrationDisabled(type); } protected override ServiceLifetime? GetDefaultLifeTimeOrNull(Type type) From 570646a6365c6729cdb49121cd8af029e8607b11 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 7 Jan 2022 11:05:34 +0300 Subject: [PATCH 58/67] feat: add text property to UserMenu class --- .../components/nav-items/current-user.component.html | 12 +++++++++++- .../theme-shared/src/lib/models/user-menu.ts | 4 +++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.html b/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.html index 0a1dec59d0..9adbde2d55 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.html +++ b/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.html @@ -40,7 +40,17 @@ > -
+
+
+ + + + {{ item.text }} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/models/user-menu.ts b/npm/ng-packs/packages/theme-shared/src/lib/models/user-menu.ts index 20b92b8082..e3b33cb1f2 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/models/user-menu.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/models/user-menu.ts @@ -1,3 +1,5 @@ import { NavItem } from './nav-item'; -export class UserMenu extends NavItem {} +export class UserMenu extends NavItem { + text?: string; +} From 25e23461e15848f7f372a165fe87db41cb1304f9 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 7 Jan 2022 11:29:44 +0300 Subject: [PATCH 59/67] improve the text template of user menu --- .../nav-items/current-user.component.html | 9 ++- .../src/lib/providers/user-menu.provider.ts | 61 +++++++------------ .../theme-shared/src/lib/models/user-menu.ts | 7 ++- 3 files changed, 36 insertions(+), 41 deletions(-) diff --git a/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.html b/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.html index 9adbde2d55..8d76e6cb9c 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.html +++ b/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.html @@ -48,8 +48,13 @@ - - {{ item.text }} + + {{ item.textTemplate.text | abpLocalization }} diff --git a/npm/ng-packs/packages/theme-basic/src/lib/providers/user-menu.provider.ts b/npm/ng-packs/packages/theme-basic/src/lib/providers/user-menu.provider.ts index 5c36cc5347..dbf5815d55 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/providers/user-menu.provider.ts +++ b/npm/ng-packs/packages/theme-basic/src/lib/providers/user-menu.provider.ts @@ -1,12 +1,6 @@ -import { - AuthService, - ConfigStateService, - LocalizationService, - NAVIGATE_TO_MANAGE_PROFILE, -} from '@abp/ng.core'; +import { AuthService, NAVIGATE_TO_MANAGE_PROFILE } from '@abp/ng.core'; import { UserMenuService } from '@abp/ng.theme.shared'; import { APP_INITIALIZER, Injector } from '@angular/core'; -import { filter } from 'rxjs/operators'; import { eUserMenuItems } from '../enums/user-menu-items'; export const BASIC_THEME_USER_MENU_PROVIDERS = [ @@ -19,41 +13,32 @@ export const BASIC_THEME_USER_MENU_PROVIDERS = [ ]; export function configureUserMenu(injector: Injector) { - const configState = injector.get(ConfigStateService); const userMenu = injector.get(UserMenuService); - const localization = injector.get(LocalizationService); const authService = injector.get(AuthService); const navigateToManageProfile = injector.get(NAVIGATE_TO_MANAGE_PROFILE); return () => { - configState - .getAll$() - .pipe(filter(res => !!res?.localization)) - .subscribe(() => { - userMenu.addItems([ - { - id: eUserMenuItems.MyAccount, - order: 100, - html: ` - ${localization.instant('AbpAccount::MyAccount')} - `, - action: () => navigateToManageProfile(), - }, - { - id: eUserMenuItems.Logout, - order: 101, - html: ` - ${localization.instant('AbpUi::Logout')} - `, - action: () => { - authService.logout().subscribe(); - }, - }, - ]); - }); + userMenu.addItems([ + { + id: eUserMenuItems.MyAccount, + order: 100, + textTemplate: { + text: 'AbpAccount::MyAccount', + icon: 'fa fa-cog', + }, + action: () => navigateToManageProfile(), + }, + { + id: eUserMenuItems.Logout, + order: 101, + textTemplate: { + text: 'AbpUi::Logout', + icon: 'fa fa-power-off', + }, + action: () => { + authService.logout().subscribe(); + }, + }, + ]); }; } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/models/user-menu.ts b/npm/ng-packs/packages/theme-shared/src/lib/models/user-menu.ts index e3b33cb1f2..c45ea84396 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/models/user-menu.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/models/user-menu.ts @@ -1,5 +1,10 @@ import { NavItem } from './nav-item'; export class UserMenu extends NavItem { - text?: string; + textTemplate?: UserMenuTextTemplate; +} + +export interface UserMenuTextTemplate { + text: string; + icon?: string; } From b8eafdd722435e46c23c2f3808017d37d6b29ec0 Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Fri, 7 Jan 2022 12:31:53 +0300 Subject: [PATCH 60/67] Update Oracle version --- .../Volo.Abp.EntityFrameworkCore.Oracle.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo.Abp.EntityFrameworkCore.Oracle.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo.Abp.EntityFrameworkCore.Oracle.csproj index 7d99c2035b..5a0a11b6ad 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo.Abp.EntityFrameworkCore.Oracle.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo.Abp.EntityFrameworkCore.Oracle.csproj @@ -19,7 +19,7 @@
- + From 6fa437f6870c216ad08a4594313b7275c6bf12cd Mon Sep 17 00:00:00 2001 From: bnymncoskuner Date: Fri, 7 Jan 2022 14:38:31 +0300 Subject: [PATCH 61/67] feat: add to-injector pipe in core package --- .../packages/core/src/lib/core.module.ts | 3 ++ .../packages/core/src/lib/pipes/index.ts | 1 + .../core/src/lib/pipes/to-injector.pipe.ts | 28 +++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 npm/ng-packs/packages/core/src/lib/pipes/to-injector.pipe.ts diff --git a/npm/ng-packs/packages/core/src/lib/core.module.ts b/npm/ng-packs/packages/core/src/lib/core.module.ts index c34b4a2fab..270ab7dcbd 100644 --- a/npm/ng-packs/packages/core/src/lib/core.module.ts +++ b/npm/ng-packs/packages/core/src/lib/core.module.ts @@ -23,6 +23,7 @@ import { LocalizationModule } from './localization.module'; import { ABP } from './models/common'; import { LocalizationPipe } from './pipes/localization.pipe'; import { SortPipe } from './pipes/sort.pipe'; +import { ToInjectorPipe } from './pipes/to-injector.pipe'; import { CookieLanguageProvider } from './providers/cookie-language.provider'; import { LocaleProvider } from './providers/locale.provider'; import { LocalizationService } from './services/localization.service'; @@ -65,6 +66,7 @@ export function storageFactory(): OAuthStorage { RouterOutletComponent, SortPipe, StopPropagationDirective, + ToInjectorPipe, ], imports: [ OAuthModule, @@ -89,6 +91,7 @@ export function storageFactory(): OAuthStorage { RouterOutletComponent, SortPipe, StopPropagationDirective, + ToInjectorPipe, ], providers: [LocalizationPipe], entryComponents: [ diff --git a/npm/ng-packs/packages/core/src/lib/pipes/index.ts b/npm/ng-packs/packages/core/src/lib/pipes/index.ts index eb028eee4f..31e0a76593 100644 --- a/npm/ng-packs/packages/core/src/lib/pipes/index.ts +++ b/npm/ng-packs/packages/core/src/lib/pipes/index.ts @@ -1,2 +1,3 @@ export * from './localization.pipe'; export * from './sort.pipe'; +export * from './to-injector.pipe'; diff --git a/npm/ng-packs/packages/core/src/lib/pipes/to-injector.pipe.ts b/npm/ng-packs/packages/core/src/lib/pipes/to-injector.pipe.ts new file mode 100644 index 0000000000..5a1ac4df29 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/pipes/to-injector.pipe.ts @@ -0,0 +1,28 @@ +import { InjectionToken, Injector, Pipe, PipeTransform } from '@angular/core'; + +export const INJECTOR_PIPE_DATA_TOKEN = new InjectionToken( + 'INJECTOR_PIPE_DATA_TOKEN', +); + +@Pipe({ + name: 'toInjector', +}) +export class ToInjectorPipe implements PipeTransform { + constructor(private injector: Injector) {} + transform( + value: any, + token: InjectionToken = INJECTOR_PIPE_DATA_TOKEN, + name = 'ToInjectorPipe', + ): Injector { + return Injector.create({ + providers: [ + { + provide: token, + useValue: value, + }, + ], + parent: this.injector, + name, + }); + } +} From 80f7dae23b0b17a35f5dfde9bc7d5aa69e1ba5cd Mon Sep 17 00:00:00 2001 From: bnymncoskuner Date: Fri, 7 Jan 2022 14:38:51 +0300 Subject: [PATCH 62/67] feat: use toInjector in nav-items and current-user --- .../src/lib/components/nav-items/current-user.component.html | 1 + .../src/lib/components/nav-items/nav-items.component.html | 1 + 2 files changed, 2 insertions(+) diff --git a/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.html b/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.html index 8d76e6cb9c..3484c452a0 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.html +++ b/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.html @@ -37,6 +37,7 @@ diff --git a/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/nav-items.component.html b/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/nav-items.component.html index ac571d7680..2b1949a0eb 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/nav-items.component.html +++ b/npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/nav-items.component.html @@ -5,6 +5,7 @@ From fa229efee1c4fbbf51473a6daf01b3de0fb8c03b Mon Sep 17 00:00:00 2001 From: bnymncoskuner Date: Fri, 7 Jan 2022 14:39:28 +0300 Subject: [PATCH 63/67] docs: update theming with new options of user menu --- docs/en/UI/Angular/Theming.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/en/UI/Angular/Theming.md b/docs/en/UI/Angular/Theming.md index 16bae7aac9..74cf3b08cb 100644 --- a/docs/en/UI/Angular/Theming.md +++ b/docs/en/UI/Angular/Theming.md @@ -210,6 +210,9 @@ constructor(private sessionState: SessionStateService) { `UserMenuService` is used to get the user menu's items and render on the dropdown. You can add/update/remove an item by using the service. +You can either pass a `component`, a piece of `html` or a `textTemplate` to render an item. +All of the options are shown below. You can choose either of them. + **Example: Adding/updating/removing an user menu item** ````ts @@ -218,6 +221,21 @@ import { UserMenuService } from '@abp/ng.theme.shared'; import { Component } from '@angular/core'; import { Router } from '@angular/router'; +// make sure that you import this component in a NgModule +@Component({ + selector: 'abp-current-user-test', + template: ` + + + {{ data.textTemplate.text | abpLocalization }} + + `, +}) +export class UserMenuItemComponent { + // you can inject the data through `INJECTOR_PIPE_DATA_TOKEN` token + constructor(@Inject(INJECTOR_PIPE_DATA_TOKEN) public data: UserMenu) {} +} + @Component({/* component metadata */}) export class AppComponent { constructor(private userMenu: UserMenuService, private router: Router) { @@ -225,7 +243,18 @@ export class AppComponent { { id: 'UserMenu.Reports', order: 1, + + // HTML example html: `Reports`, + + // text template example + textTemplate: { + text: 'AbpAccount::MyAccount', + icon: 'fa fa-cog', + }, + // component example + component: UserMenuItemComponent, + action: () => { this.router.navigateByUrl('/account/reports'); }, From 0f52f4ee8f36567fe331335d0068fc4c72109858 Mon Sep 17 00:00:00 2001 From: bnymncoskuner Date: Fri, 7 Jan 2022 14:45:13 +0300 Subject: [PATCH 64/67] docs: update the example in theming --- docs/en/UI/Angular/Theming.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/en/UI/Angular/Theming.md b/docs/en/UI/Angular/Theming.md index 74cf3b08cb..3b7e3d1afd 100644 --- a/docs/en/UI/Angular/Theming.md +++ b/docs/en/UI/Angular/Theming.md @@ -241,11 +241,11 @@ export class AppComponent { constructor(private userMenu: UserMenuService, private router: Router) { this.userMenu.addItems([ { - id: 'UserMenu.Reports', + id: 'UserMenu.MyAccount', order: 1, // HTML example - html: `Reports`, + html: `My account`, // text template example textTemplate: { @@ -256,7 +256,7 @@ export class AppComponent { component: UserMenuItemComponent, action: () => { - this.router.navigateByUrl('/account/reports'); + this.router.navigateByUrl('/account/manage'); }, }, ]); From 52573ade748e62183aa8ba327316b1faf7dc0d55 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 7 Jan 2022 16:07:56 +0300 Subject: [PATCH 65/67] fix nightly publish script --- npm/preview-publish.ps1 | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/npm/preview-publish.ps1 b/npm/preview-publish.ps1 index 61c68e10b0..cdf8a5478c 100644 --- a/npm/preview-publish.ps1 +++ b/npm/preview-publish.ps1 @@ -1,12 +1,9 @@ param( [string]$Version, - [string]$User, - [string]$Pass, - [string]$Email, [string]$Registry ) -npm install +yarn install $NextVersion = $(node publish-utils.js --nextVersion) $RootFolder = (Get-Item -Path "./" -Verbose).FullName @@ -21,8 +18,8 @@ exit $commands = ( "cd ng-packs\scripts", - "npm install", - "npm run publish-packages -- --nextVersion $Version --preview --registry $Registry", + "yarn", + "npm run publish-packages -- --nextVersion $Version --preview --registry $Registry --skipVersionValidation", "cd ../../", "npm run lerna -- version $Version --yes --no-commit-hooks --skip-git --force-publish", "npm run replace-with-tilde", From fd6078182b35a3b51963f596b72c43be48f0806f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 9 Jan 2022 15:09:26 +0300 Subject: [PATCH 66/67] Improved the connstring document --- docs/en/Connection-Strings.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/en/Connection-Strings.md b/docs/en/Connection-Strings.md index c5a70174bf..e73f0ca38b 100644 --- a/docs/en/Connection-Strings.md +++ b/docs/en/Connection-Strings.md @@ -1,15 +1,17 @@ # Connection Strings -ABP Framework is designed to be [modular](Module-Development-Basics.md), [microservice compatible](Microservice-Architecture.md) and [multi-tenancy](Multi-Tenancy.md) aware. Connection string management is also designed to support these scenarios; +> Connection string system is especially needed when you want to create or use a modular system. If you have a monolithic application with a single database, you can go with the [ABP startup solution template](Startup-Templates/Application.md), which is properly configured for you. -* Allows to set separate connection strings for every module, so every module can have its own physical database. Modules even might be configured to use different DBMSs. +ABP Framework is designed to be [modular](Module-Development-Basics.md) and [multi-tenancy](Multi-Tenancy.md) aware. Connection string management is also designed to support these scenarios; + +* Allows to set separate connection strings for every module, so every module can have its own physical database. Modules even might be configured to use different database providers. * Allows to set separate connection string and use a separate database per tenant (in a SaaS application). It also supports hybrid scenarios; -* Allows to group modules into databases (all modules into a single shared database, 2 modules to database A, 3 modules to database B, 1 module to database C and rest of the modules to database D... etc.) +* Allows to group modules into databases (e.g., all modules into a single shared database or two modules to database A, three modules to database B, one module to database C and rest of the modules to database D) * Allows to group tenants into databases, just like the modules. -* Allows to separate databases per tenant per module (which might be harder to maintain for you because of too many databases, but the ABP framework supports it). +* Allows to separate databases per tenant per module (which might be hard to maintain for you because of too many databases, but the ABP framework supports it). All the [pre-built application modules](Modules/Index.md) are designed to be compatible these scenarios. @@ -29,15 +31,15 @@ See the following configuration: This configuration defines three different connection strings: -* `MyMainDb` (the `Default` connection string) is the main connection string of the application. If you don't specify a connection string for a module, it fallbacks to the `Default` connection string. The [application startup template](Startup-Templates/Application.md) is configured to use a single connection string, so all the modules uses a single shared database. -* `MyIdsDb` is used by the [IdentityServer](Modules/IdentityServer.md) module. -* `MyPermissionDb` is used by the [Permission Management](Modules/Permission-Management.md) module. +* `MyMainDb` (the `Default` connection string) is the main connection string of the application. If you don't specify a connection string for a module, it fallbacks to the `Default` connection string. The [application startup template](Startup-Templates/Application.md) is configured to use a single connection string, so all the modules uses a single, shared database. +* `MyIdsDb` (the `AbpIdentityServer` connection string) is used by the [IdentityServer](Modules/IdentityServer.md) module. +* `MyPermissionDb` (the `AbpPermissionManagement` connection string) is used by the [Permission Management](Modules/Permission-Management.md) module. -[Pre-built application modules](Modules/Index.md) define constants for the connection string names. For example, the IdentityServer module defines a ` ConnectionStringName ` constant in the ` AbpIdentityServerDbProperties ` class (located in the ` Volo.Abp.IdentityServer ` namespace). Other modules similarly define constants, so you can investigate the connection string name. +[Pre-built application modules](Modules/Index.md) define constants for the connection string names. For example, the [IdentityServer module](Modules/IdentityServer.md) defines a ` ConnectionStringName ` constant in the ` AbpIdentityServerDbProperties ` class (located in the ` Volo.Abp.IdentityServer ` namespace). Other modules similarly define constants, so you can investigate the connection string name. ### AbpDbConnectionOptions -ABP actually uses the `AbpDbConnectionOptions` to get the connection strings. If you set the connection strings as explained above, `AbpDbConnectionOptions` is automatically filled. However, you can set or override the connection strings using [the options pattern](Options.md). You can configure the `AbpDbConnectionOptions` in the `ConfigureServices` method of your [module](Module-Development-Basics.md) as shown below: +ABP uses the `AbpDbConnectionOptions` to get the connection strings. If you configure the connection strings as explained above, `AbpDbConnectionOptions` is automatically filled. However, you can set or override the connection strings using [the options pattern](Options.md). You can configure the `AbpDbConnectionOptions` in the `ConfigureServices` method of your [module](Module-Development-Basics.md) as shown below: ````csharp public override void ConfigureServices(ServiceConfigurationContext context) @@ -64,13 +66,11 @@ public class IdentityServerDbContext For [Entity Framework Core](Entity-Framework-Core.md) and [MongoDB](MongoDB.md), write this to your `DbContext` class (and the interface if it has). -> If you are developing a reusable, database provider independent module see also [the best practices guide](Best-Practices/Index.md). - ## Database Migrations for the Entity Framework Core Relational databases require to create the database and the database schema (tables, views... etc.) before using it. -The startup template (with EF Core ORM) comes with a single database and a `.EntityFrameworkCore` project that contains related classes and the migration files for that database. This project mainly defines a *YourProjectName*DbContext that calls the `Configure...()` methods of the used modules, like `builder.ConfigurePermissionManagement()`. +The startup template (with EF Core ORM) comes with a single database and a `.EntityFrameworkCore` project that contains related classes and the migration files for that database. This project mainly defines a `YourProjectNameDbContext` class that calls the `Configure...()` methods of the used modules, like `builder.ConfigurePermissionManagement()`. Once you want to separate a module's database, you typically will need to create a second migration path. See the [EF Core Migrations](Entity-Framework-Core-Migrations.md) document to learn how to create and use a different database for a desired module. From a1aa065f207351584e947adf20ab6ac7a206d15b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 9 Jan 2022 15:38:54 +0300 Subject: [PATCH 67/67] Added "Configuring the database structures" section to the connection strings documentation. --- docs/en/Connection-Strings.md | 52 ++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/docs/en/Connection-Strings.md b/docs/en/Connection-Strings.md index e73f0ca38b..76e535a960 100644 --- a/docs/en/Connection-Strings.md +++ b/docs/en/Connection-Strings.md @@ -39,6 +39,10 @@ This configuration defines three different connection strings: ### AbpDbConnectionOptions +`AbpDbConnectionOptions` is the options class that is used to set the connection strings and configure database structures. + +#### Setting the connection strings + ABP uses the `AbpDbConnectionOptions` to get the connection strings. If you configure the connection strings as explained above, `AbpDbConnectionOptions` is automatically filled. However, you can set or override the connection strings using [the options pattern](Options.md). You can configure the `AbpDbConnectionOptions` in the `ConfigureServices` method of your [module](Module-Development-Basics.md) as shown below: ````csharp @@ -52,6 +56,52 @@ public override void ConfigureServices(ServiceConfigurationContext context) } ```` +#### Configuring the database structures + +`Databases` property of the `AbpDbConnectionOptions` class is used to group multiple connection strings (of multiple modules) to a single connection string. + +See the following connection strings: + +````json +"ConnectionStrings": { + "Default": "Server=localhost;Database=MyMainDb;Trusted_Connection=True;", + "AbpIdentity": "Server=localhost;Database=MySecondaryDb;Trusted_Connection=True;", + "AbpIdentityServer": "Server=localhost;Database=MySecondaryDb;Trusted_Connection=True;", + "AbpPermissionManagement": "Server=localhost;Database=MySecondaryDb;Trusted_Connection=True;" +} +```` + +In this example, we've defined four connection strings, but the last three of them are the same; `AbpIdentity`, `AbpIdentityServer` and `AbpPermissionManagement` uses the same database, named `MySecondaryDb`. The main application and the other modules use the `Default` connection string, hence the `MyMainDb` database. + +What we want to do here is to group three modules (`AbpIdentity`, `AbpIdentityServer` and `AbpPermissionManagement`) in a single database, but we needed to specify each one manually. Because the fallback connection string is the `Default` one, if we don't specify it for a module. + +To eliminate the repetitive connection string definition, we can configure the `AbpDbConnectionOptions.Databases` property to group these connection strings, as shown in the following code (we place that in the `ConfigureServices` method of our [module class](Module-Development-Basics.md)): + +````csharp +Configure(options => +{ + options.Databases.Configure("MySecondaryDb", db => + { + db.MappedConnections.Add("AbpIdentity"); + db.MappedConnections.Add("AbpIdentityServer"); + db.MappedConnections.Add("AbpPermissionManagement"); + }); +}); +```` + +Then we can change the `appsettings.json` file as shown in the following code block: + +````json +"ConnectionStrings": { + "Default": "Server=localhost;Database=MyMainDb;Trusted_Connection=True;", + "MySecondaryDb": "Server=localhost;Database=MySecondaryDb;Trusted_Connection=True;" +} +```` + +`MySecondaryDb` becomes the new connection string for the mapped connections. + +> ABP first looks for the module-specific connection string, then looks if a database mapping is available, finally fallbacks to the `Default` connection string. + ## Set the Connection String Name A module typically has a unique connection string name associated to its `DbContext` class using the `ConnectionStringName` attribute. Example: @@ -64,7 +114,7 @@ public class IdentityServerDbContext } ```` -For [Entity Framework Core](Entity-Framework-Core.md) and [MongoDB](MongoDB.md), write this to your `DbContext` class (and the interface if it has). +For [Entity Framework Core](Entity-Framework-Core.md) and [MongoDB](MongoDB.md), write this to your `DbContext` class (and the interface if it has). In this way, ABP uses the specified connection string for the related `DbContext` instances. ## Database Migrations for the Entity Framework Core