Skip to content

Commit

Permalink
Add NumberBox, Toggle, TimePicker, and ColorPicker.
Browse files Browse the repository at this point in the history
  • Loading branch information
gdlcf88 committed Aug 22, 2024
1 parent ac46af2 commit 12e4850
Show file tree
Hide file tree
Showing 32 changed files with 1,000 additions and 207 deletions.
7 changes: 0 additions & 7 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,6 @@ An ABP module helps users to define and use dynamic forms at runtime.
{
options.AddOrUpdateFormDefinition(new FormDefinition("InternalForm", "Internal Form"));
});

Configure<DynamicFormCoreOptions>(options =>
{
options.AddTextBoxFormItemType();
options.AddOptionButtonsFormItemType();
// Add any type you want, including your custom types....
});
```

2. (Optional) Create a custom `FormTemplateOperationAuthorizationHandler` to determine who can create/read/update/delete
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,6 @@ public override void ConfigureServices(ServiceConfigurationContext context)
options.AddOrUpdateFormDefinition(new FormDefinition("InternalForm", "Internal Form"));
});

Configure<DynamicFormCoreOptions>(options =>
{
options.AddTextBoxFormItemType();
options.AddOptionButtonsFormItemType();
options.AddFileBoxFormItemType();
});

Configure<AbpDbContextOptions>(options =>
{
options.UseSqlServer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,6 @@ public override void ConfigureServices(ServiceConfigurationContext context)
options.AddOrUpdateFormDefinition(new FormDefinition("InternalForm", "Internal Form"));
});

Configure<DynamicFormCoreOptions>(options =>
{
options.AddTextBoxFormItemType();
options.AddOptionButtonsFormItemType();
options.AddFileBoxFormItemType();
});

Configure<AbpDbContextOptions>(options =>
{
options.UseSqlServer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,6 @@ public override void ConfigureServices(ServiceConfigurationContext context)
options.AddOrUpdateFormDefinition(new FormDefinition("InternalForm", "Internal Form"));
});

Configure<DynamicFormCoreOptions>(options =>
{
options.AddTextBoxFormItemType();
options.AddOptionButtonsFormItemType();
options.AddFileBoxFormItemType();
});

Configure<AbpDbContextOptions>(options =>
{
options.UseSqlServer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@ public static class DynamicFormCoreErrorCodes
public const string InvalidFormItemValue = "EasyAbp.DynamicForm:InvalidFormItemValue";
public const string FormItemValueIsRequired = "EasyAbp.DynamicForm:FormItemValueIsRequired";
public const string TextBoxInvalidMaxLength = "EasyAbp.DynamicForm:TextBoxInvalidMaxLength";
public const string TextBoxInvalidRegexPattern = "EasyAbp.DynamicForm:TextBoxInvalidRegexPattern";
public const string InvalidRegexPattern = "EasyAbp.DynamicForm:InvalidRegexPattern";
public const string TextBoxInvalidValueLength = "EasyAbp.DynamicForm:TextBoxInvalidValueLength";
public const string NumberBoxInvalidValue = "EasyAbp.DynamicForm:NumberBoxInvalidValue";
public const string NumberBoxInvalidMaxValue = "EasyAbp.DynamicForm:NumberBoxInvalidMaxValue";
public const string NumberBoxInvalidNumericValue = "EasyAbp.DynamicForm:NumberBoxInvalidNumericValue";
public const string OptionButtonsInvalidMaxSelection = "EasyAbp.DynamicForm:OptionButtonsInvalidMaxSelection";
public const string OptionButtonsInvalidOptionQuantitySelected = "EasyAbp.DynamicForm:OptionButtonsInvalidOptionQuantitySelected";
public const string FileBoxInvalidUrls = "EasyAbp.DynamicForm:FileBoxInvalidUrls";
public const string ToggleIsOptional = "EasyAbp.DynamicForm:ToggleIsOptional";
public const string TimePickerInvalidDateTime = "EasyAbp.DynamicForm:TimePickerInvalidDateTime";
public const string ColorPickerInvalidHexValue = "EasyAbp.DynamicForm:ColorPickerInvalidHexValue";
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Volo.Abp.Json;
using EasyAbp.DynamicForm.Options;
using Volo.Abp.Json;
using Volo.Abp.Modularity;

namespace EasyAbp.DynamicForm;
Expand All @@ -9,4 +10,8 @@ namespace EasyAbp.DynamicForm;
)]
public class DynamicFormDomainCoreModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<DynamicFormCoreOptions>(options => { options.AddBuiltInFormItemTypes(); });
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using JetBrains.Annotations;

namespace EasyAbp.DynamicForm.FormItemTypes.ColorPicker;

public class ColorPickerFormItemConfigurations
{
[CanBeNull]
public string RegexPattern { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using EasyAbp.DynamicForm.Shared;
using Volo.Abp;
using Volo.Abp.DependencyInjection;

namespace EasyAbp.DynamicForm.FormItemTypes.ColorPicker;

public partial class ColorPickerFormItemProvider : FormItemProviderBase, IScopedDependency
{
public static string Name { get; set; } = "ColorPicker";
public static string LocalizationItemKey { get; set; } = "FormItemType.ColorPicker";

public override Task ValidateTemplateAsync(IFormItemMetadata metadata)
{
var configurations = GetConfigurations<ColorPickerFormItemConfigurations>(metadata);

if (!configurations.RegexPattern.IsNullOrWhiteSpace())
{
try
{
_ = Regex.Match(string.Empty, configurations.RegexPattern!);
}
catch
{
throw new BusinessException(DynamicFormCoreErrorCodes.InvalidRegexPattern)
.WithData("item", metadata.Name);
}
}

if (metadata.AvailableValues.Any(x => !HexRegex().IsMatch(x)))
{
throw new BusinessException(DynamicFormCoreErrorCodes.ColorPickerInvalidHexValue)
.WithData("item", metadata.Name);
}

return Task.CompletedTask;
}

public override Task ValidateValueAsync(IFormItemMetadata metadata, string value)
{
var isEmptyValue = value.IsNullOrWhiteSpace();
var configurations = GetConfigurations<ColorPickerFormItemConfigurations>(metadata);

if (!metadata.Optional && isEmptyValue)
{
throw new BusinessException(DynamicFormCoreErrorCodes.FormItemValueIsRequired)
.WithData("item", metadata.Name);
}

if (isEmptyValue)
{
return Task.CompletedTask;
}

if (!HexRegex().IsMatch(value))
{
throw new BusinessException(DynamicFormCoreErrorCodes.ColorPickerInvalidHexValue)
.WithData("item", metadata.Name);
}

if (!configurations.RegexPattern.IsNullOrWhiteSpace() && !Regex.IsMatch(value!, configurations.RegexPattern!))
{
throw new BusinessException(DynamicFormCoreErrorCodes.InvalidFormItemValue)
.WithData("item", metadata.Name);
}

if (metadata.AvailableValues.Any() &&
!metadata.AvailableValues.Contains(value, StringComparer.InvariantCultureIgnoreCase))
{
throw new BusinessException(DynamicFormCoreErrorCodes.InvalidFormItemValue)
.WithData("item", metadata.Name);
}

return Task.CompletedTask;
}

public override Task<object> CreateConfigurationsObjectOrNullAsync()
{
return Task.FromResult<object>(new ColorPickerFormItemConfigurations());
}

[GeneratedRegex("^#(?:[0-9a-fA-F]{3,4}){1,2}$")]
private static partial Regex HexRegex();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Threading.Tasks;
using EasyAbp.DynamicForm.Shared;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;

namespace EasyAbp.DynamicForm.FormItemTypes.FileBox;

Expand All @@ -13,9 +12,7 @@ public class FileBoxFormItemProvider : FormItemProviderBase, IScopedDependency

protected IEnumerable<IFileBoxValueValidator> ValueValidators { get; }

public FileBoxFormItemProvider(
IJsonSerializer jsonSerializer,
IEnumerable<IFileBoxValueValidator> valueValidators) : base(jsonSerializer)
public FileBoxFormItemProvider(IEnumerable<IFileBoxValueValidator> valueValidators)
{
ValueValidators = valueValidators;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
using System;
using System.Threading.Tasks;
using EasyAbp.DynamicForm.Shared;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;

namespace EasyAbp.DynamicForm.FormItemTypes;

public abstract class FormItemProviderBase : IFormItemProvider
{
protected IJsonSerializer JsonSerializer { get; }
public IAbpLazyServiceProvider LazyServiceProvider { get; set; }

public FormItemProviderBase(IJsonSerializer jsonSerializer)
{
JsonSerializer = jsonSerializer;
}
protected IJsonSerializer JsonSerializer => LazyServiceProvider.LazyGetRequiredService<IJsonSerializer>();

public abstract Task ValidateTemplateAsync(IFormItemMetadata metadata);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace EasyAbp.DynamicForm.FormItemTypes.NumberBox;

public class NumberBoxFormItemConfigurations
{
public byte DecimalPlaces { get; set; }

public long? MaxValue { get; set; }

public long? MinValue { get; set; }

public NumberUi NumberUi { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using EasyAbp.DynamicForm.Shared;
using Volo.Abp;
using Volo.Abp.DependencyInjection;

namespace EasyAbp.DynamicForm.FormItemTypes.NumberBox;

public class NumberBoxFormItemProvider : FormItemProviderBase, IScopedDependency
{
public static string Name { get; set; } = "NumberBox";
public static string LocalizationItemKey { get; set; } = "FormItemType.NumberBox";

public override Task ValidateTemplateAsync(IFormItemMetadata metadata)
{
var configurations = GetConfigurations<NumberBoxFormItemConfigurations>(metadata);

if (configurations.MinValue.HasValue && configurations.MaxValue.HasValue &&
configurations.MinValue > configurations.MaxValue)
{
throw new BusinessException(DynamicFormCoreErrorCodes.NumberBoxInvalidMaxValue)
.WithData("item", metadata.Name);
}

if (metadata.AvailableValues.Any(x => !decimal.TryParse(x, out _)))
{
throw new BusinessException(DynamicFormCoreErrorCodes.InvalidFormItemValue)
.WithData("item", metadata.Name);
}

return Task.CompletedTask;
}

public override Task ValidateValueAsync(IFormItemMetadata metadata, string value)
{
var isEmptyValue = value.IsNullOrWhiteSpace();

if (!metadata.Optional && isEmptyValue)
{
throw new BusinessException(DynamicFormCoreErrorCodes.FormItemValueIsRequired)
.WithData("item", metadata.Name);
}

if (isEmptyValue)
{
return Task.CompletedTask;
}

if (!decimal.TryParse(value, out var numericValue))
{
throw new BusinessException(DynamicFormCoreErrorCodes.NumberBoxInvalidNumericValue)
.WithData("item", metadata.Name);
}

var configurations = GetConfigurations<NumberBoxFormItemConfigurations>(metadata);

int decimalPlaces = BitConverter.GetBytes(decimal.GetBits(numericValue)[3])[2];

if (configurations.DecimalPlaces < decimalPlaces ||
configurations.MinValue.HasValue && numericValue < configurations.MinValue ||
(configurations.MaxValue.HasValue && numericValue > configurations.MaxValue))
{
throw new BusinessException(DynamicFormCoreErrorCodes.NumberBoxInvalidValue)
.WithData("item", metadata.Name)
.WithData("decimalPlaces", configurations.DecimalPlaces)
.WithData("min", configurations.MinValue.HasValue ? configurations.MinValue.Value : "-∞")
.WithData("max", configurations.MaxValue.HasValue ? configurations.MaxValue.Value : "");
}

if (metadata.AvailableValues.Any() && !metadata.AvailableValues.Select(decimal.Parse).Contains(numericValue))
{
throw new BusinessException(DynamicFormCoreErrorCodes.InvalidFormItemValue)
.WithData("item", metadata.Name);
}

return Task.CompletedTask;
}

public override Task<object> CreateConfigurationsObjectOrNullAsync()
{
return Task.FromResult<object>(new NumberBoxFormItemConfigurations());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace EasyAbp.DynamicForm.FormItemTypes.NumberBox;

public enum NumberUi
{
Default = 0,

/// <summary>
/// Normal numerical input box.
/// </summary>
NumberInput = 1,

/// <summary>
/// The <see cref="Slider"/> provides a ranged number selection.
/// High-precision decimals or a wider range of numbers may not be well-supported.
/// </summary>
Slider = 2,

/// <summary>
/// The <see cref="Rating"/> provides a simple stars selection, usually integers like 1 to 5.
/// High-precision decimals or a wider range of numbers may not be well-supported.
/// </summary>
Rating = 3
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using EasyAbp.DynamicForm.Shared;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;

namespace EasyAbp.DynamicForm.FormItemTypes.OptionButtons;

Expand All @@ -14,10 +13,6 @@ public class OptionButtonsFormItemProvider : FormItemProviderBase, IScopedDepend
public static string LocalizationItemKey { get; set; } = "FormItemType.OptionButtons";
public static string SelectionSeparator { get; set; } = ",";

public OptionButtonsFormItemProvider(IJsonSerializer jsonSerializer) : base(jsonSerializer)
{
}

public override Task ValidateTemplateAsync(IFormItemMetadata metadata)
{
var configurations = GetConfigurations<OptionButtonsFormItemConfigurations>(metadata);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,18 @@ namespace EasyAbp.DynamicForm.FormItemTypes.TextBox;

public class TextBoxFormItemConfigurations
{
public int TextBoxRows { get; set; } = 1;
public int Rows { get; set; } = 1;

public int? MaxLength { get; set; }
/// <summary>
/// This option works when `<see cref="Rows"/> == 1` and `<see cref="TextFormat"/> == <see cref="TextFormat.PlainText"/>`.
/// </summary>
public bool IsSecret { get; set; }

public int? MinLength { get; set; }
public uint? MaxLength { get; set; }

public uint? MinLength { get; set; }

public TextFormat TextFormat { get; set; }

[CanBeNull]
public string RegexPattern { get; set; }
Expand Down
Loading

0 comments on commit 12e4850

Please sign in to comment.