Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Mimeo.DynamicUI.Blazor/FormFields/DynamicField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class DynamicField : ComponentBase
private static readonly Dictionary<FormFieldType, Type> formFieldTypeMap = new()
{
{ FormFieldType.Text, typeof(TextField) },
{ FormFieldType.Combobox, typeof(TextField) },
{ FormFieldType.Checkbox, typeof(CheckboxField) },
{ FormFieldType.SingleSelect, typeof(SingleSelectField) },
{ FormFieldType.MultiSelect, typeof(MultiSelectField) },
Expand All @@ -22,7 +23,12 @@ public class DynamicField : ComponentBase
{ FormFieldType.DateTime, typeof(DateTimeField) },
{ FormFieldType.Integer, typeof(IntegerField) },
{ FormFieldType.Decimal, typeof(DecimalField) },
#pragma warning disable CS0618 // Type or member is obsolete (Justification: Backwards compatibility)
{ FormFieldType.List, typeof(ListField<>) },
#pragma warning restore CS0618 // Type or member is obsolete
{ FormFieldType.Table, typeof(ListField<>) },
{ FormFieldType.SectionList, typeof(ListField<>) },
{ FormFieldType.ReorderableSectionList, typeof(ListField<>) },
{ FormFieldType.Nullable, typeof(NullableFormField) },
{ FormFieldType.Guid, typeof(GuidFormField) }
};
Expand Down Expand Up @@ -118,7 +124,7 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)
builder.CloseComponent();
}

private bool InheritsFormFieldBase(Type type)
private static bool InheritsFormFieldBase(Type type)
{
// The built-in methods don't support unbound generics (or I haven't found the correct one yet)

Expand Down
4 changes: 2 additions & 2 deletions Mimeo.DynamicUI.Blazor/FormFields/ListField.razor
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
@typeparam T
@inherits FormFieldBase<List<T>>

@if (!wrapInViewModel && ListDefinition?.PresentationMode == ListFieldPresentationMode.SectionList)
@if (!wrapInViewModel && ListDefinition?.Type == FormFieldType.SectionList)
{
if (ReadOnly)
{
Expand Down Expand Up @@ -56,7 +56,7 @@
<RadzenButton Icon="add_circle_outline" style="margin-top:1em;margin-bottom:1em;" Text="@lang.GetValueOrDefault("add")" Click="() => OnCreate(CreateViewModel())" />
}
}
else if (!wrapInViewModel && ListDefinition?.PresentationMode == ListFieldPresentationMode.ReorderableSectionList)
else if (!wrapInViewModel && ListDefinition?.Type == FormFieldType.ReorderableSectionList)
{
if (ReadOnly)
{
Expand Down
2 changes: 1 addition & 1 deletion Mimeo.DynamicUI.Blazor/Forms/ODataGrid.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ private void ShowTooltip(ElementReference element, string languageKey)
}
private bool GetActionsMenuVisibility()
{
return CanCopy || CanUpdate || CanView || CanDelete;
return CanCopy || CanUpdate || CanView || CanDelete || CustomRowActions.Any();
}

private GridItem CreateGridItem(ViewModel listModel)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ protected override IEnumerable<FormFieldDefinition> GetListFormFields()
yield return FormField(() => Number);
yield return FormField(() => Decimal);
yield return FormField(() => DateTimeUtc, dateDisplayMode: DateDisplayMode.UserLocal);
yield return FormField(() => StringList);
yield return Table(() => StringList);
}

protected override IEnumerable<FormFieldDefinition> GetDropDownListFormFields()
Expand Down Expand Up @@ -185,13 +185,13 @@ protected override IEnumerable<FormFieldDefinition> GetEditFormFields()
yield return FormField(() => ComboBox, textType: TextType.SingleLine, items: ["Option 1", "option2languagekey", "Option 3"]);
yield return new FormFieldDefinition(FormFieldType.Color, () => Color);
yield return FormField(() => Section);
yield return FormField(() => StringList);
yield return Table(() => StringList);

// Depending on the structure of the view model, sometimes a table is more appropriate
yield return FormField(() => SimpleModelList, mode: ListFieldPresentationMode.Table);
yield return Table(() => SimpleModelList);

// but for sufficiently large view models, a section list is easier on the user
yield return FormField(() => AdvancedModelList, m => m.FormField(() => m.Property1), mode: ListFieldPresentationMode.SectionList);
yield return SectionList(() => AdvancedModelList, m => m.FormField(() => m.Property1));

yield return new SingleSelectDropDownFormFieldDefinition(() => RelatedModelId, relatedModelsSource, FormField(() => Name), idField);
yield return new MultiSelectDropDownFormFieldDefinition(() => RelatedModelIds, relatedModelsSource, FormField(() => Name), idField);
Expand Down Expand Up @@ -233,9 +233,9 @@ protected override IEnumerable<FormFieldDefinition> GetSearchFormFields()
yield return FormField(() => ComboBox, textType: TextType.SingleLine, items: ["Option 1", "option2languagekey", "Option 3"]);
yield return new FormFieldDefinition(FormFieldType.Color, () => Color);
yield return FormField(() => Section);
yield return FormField(() => StringList);
yield return FormField(() => SimpleModelList);
yield return FormField(() => AdvancedModelList);
yield return Table(() => StringList);
yield return Table(() => SimpleModelList);
yield return SectionList(() => AdvancedModelList);
yield return FormField(() => Enabled);
yield return new NullableFormFieldDefinition(() => NullableStringEnabled, FormField(() => NullableStringValue));
yield return new FormFieldDefinition(FormFieldType.Checkbox, () => EnableHiddenProperties)
Expand All @@ -249,15 +249,15 @@ protected override IEnumerable<FormFieldDefinition> GetSearchFormFields()

}

public class SimpleSubViewModel : ViewModel, INotifyPropertyChanged
public class SimpleSubViewModel : ViewModel
{
public string? Property1
{
get => _property1;
set
{
_property1 = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Property1)));
RaisePropertyChanged(nameof(Property1));
}
}
private string? _property1;
Expand All @@ -268,30 +268,27 @@ public int Property2
set
{
_property2 = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Property2)));
RaisePropertyChanged(nameof(Property2));
}
}
private int _property2;

// INotifyPropertyChanged is partially supported by the UI, and is generally not required, but can be useful in niche situations
public event PropertyChangedEventHandler? PropertyChanged;

protected override IEnumerable<FormFieldDefinition> GetEditFormFields()
{
yield return FormField(() => Property1);
yield return FormField(() => Property2);
}
}

public class AdvancedSubViewModel : ViewModel, INotifyPropertyChanged
public class AdvancedSubViewModel : ViewModel
{
public string? Property1
{
get => _property1;
set
{
_property1 = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Property1)));
RaisePropertyChanged(nameof(Property1));
}
}
private string? _property1;
Expand All @@ -302,21 +299,18 @@ public int Property2
set
{
_property2 = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Property2)));
RaisePropertyChanged(nameof(Property2));
}
}
private int _property2;

public List<string> SubList { get; set; } = [];

// INotifyPropertyChanged is partially supported by the UI, and is generally not required, but can be useful in niche situations
public event PropertyChangedEventHandler? PropertyChanged;

protected override IEnumerable<FormFieldDefinition> GetEditFormFields()
{
yield return FormField(() => Property1);
yield return FormField(() => Property2);
yield return FormField(() => SubList);
yield return Table(() => SubList);
}
}

Expand Down
5 changes: 5 additions & 0 deletions Mimeo.DynamicUI/Data/OData/ODataExpressionGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,12 @@ public IEnumerable<DataFilterOperator> GetSupportedFilterOperators(DataFieldDefi
DataFilterOperator.GreaterThan,
DataFilterOperator.GreaterThanOrEquals
};
#pragma warning disable CS0618 // Type or member is obsolete (Justification: Backwards compatibility)
case FormFieldType.List:
#pragma warning restore CS0618 // Type or member is obsolete
case FormFieldType.Table:
case FormFieldType.SectionList:
case FormFieldType.ReorderableSectionList:
var sampleItem = (filter.FormFieldDefinition as IListFieldDefinition)?.CreateNewItem();
if (sampleItem is ViewModel)
{
Expand Down
2 changes: 2 additions & 0 deletions Mimeo.DynamicUI/FormFieldDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ public string FilterPropertyName

public string LanguageKey { get; set; }

public string DescriptionLanguageKey => LanguageKey + "_desc";

public Type PropertyType { get; set; }

public Type? FilterType { get; set; }
Expand Down
61 changes: 59 additions & 2 deletions Mimeo.DynamicUI/FormFieldType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,79 @@
public enum FormFieldType
{
Hidden = 0,
Text,

/// <summary>
/// A field that accepts user-entered text
/// </summary>
Text,

/// <summary>
/// A field that accepts user-entered text but presents some pre-defined values
/// </summary>
Combobox,

Checkbox,

/// <summary>
/// A field that presents the user with pre-defined value and allows selection of a single value
/// </summary>
SingleSelect,

/// <summary>
/// A field that presents the user with a dropdown to select a single pre-defined value
/// </summary>
SingleSelectDropdown,

/// <summary>
/// A field that presents the user with a dropdown to select a single value from a data source
/// </summary>
SingleSelectDataSourceDropdown,

/// <summary>
/// A field that presents the user with pre-defined value and allows selection of multiple values
/// </summary>
MultiSelect,

/// <summary>
/// A field that presents the user with a dropdown to select one or more pre-defined values
/// </summary>
MultiSelectDropdown,

/// <summary>
/// A field that presents the user with values that come from a data source and allows selection of multiple values
/// </summary>
MultiSelectDataSourceDropdown,

Date,
Time,
DateTime,
Color,
Integer,
Decimal,
Decimal,

[Obsolete("Use Table, SectionList, or ReorderableSectionList instead")]
List,

/// <summary>
/// Presents a list of items or view models in a table
/// </summary>
Table,

/// <summary>
/// Presents a list of items or view models as a sequential list of sub-editors
/// </summary>
SectionList,

/// <summary>
/// Presents a list of items or view models as a sequential list of sub-editors, with the ability to reorder items
/// </summary>
ReorderableSectionList,

/// <summary>
/// Presents another form field, wrapped with a checkbox that is meant to indicate whether the value is null
/// </summary>
Nullable,

Guid,
Section,
Custom
Expand Down
41 changes: 40 additions & 1 deletion Mimeo.DynamicUI/ListFieldDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,54 @@ public interface IListFieldDefinition

public class ListFieldDefinition<T> : FormFieldDefinition, IListFieldDefinition
{
[Obsolete("Use overload with FormFieldType instead")]
public ListFieldDefinition(Expression<Func<List<T>>> @for)
: base(FormFieldType.List, LinqExtensions.Cast<List<T>, object?>(@for))
{
}

public ListFieldDefinition(FormFieldType formFieldType, Expression<Func<List<T>>> @for)
: base(formFieldType, LinqExtensions.Cast<List<T>, object?>(@for))
{
switch (formFieldType)
{
case FormFieldType.Table:
case FormFieldType.SectionList:
case FormFieldType.ReorderableSectionList:
break;
default:
throw new ArgumentException("formFieldType must be Table, SectionList, or ReorderableSectionList", nameof(formFieldType));
}
}

public FormFieldType? ItemFormFieldType { get; set; }

public Func<T>? NewItemCreator { get; set; }

public ListFieldPresentationMode PresentationMode { get; set; } = ListFieldPresentationMode.Table;
[Obsolete("Differentiate using FormFieldType instead")]
public ListFieldPresentationMode PresentationMode
{
get => _presentationMode;
set
{
_presentationMode = value;
if (_presentationMode == ListFieldPresentationMode.Table)
{
this.Type = FormFieldType.Table;
}
else if (_presentationMode == ListFieldPresentationMode.SectionList)
{
this.Type = FormFieldType.SectionList;
}
else if (_presentationMode == ListFieldPresentationMode.ReorderableSectionList)
{
this.Type = FormFieldType.ReorderableSectionList;
}
}
}

[Obsolete("Differentiate using FormFieldType instead")]
private ListFieldPresentationMode _presentationMode = ListFieldPresentationMode.Table;

/// <summary>
/// For use with <see cref="PresentationMode"/> equal to <see cref="ListFieldPresentationMode.SectionList"/> or <see cref="ListFieldPresentationMode.ReorderableSectionList"/>,
Expand Down Expand Up @@ -50,6 +88,7 @@ public T CreateNewItem()
object? IListFieldDefinition.CreateNewItem() => CreateNewItem();
}

[Obsolete("Differentiate using FormFieldType instead")]
public enum ListFieldPresentationMode
{
Table,
Expand Down
18 changes: 17 additions & 1 deletion Mimeo.DynamicUI/TextFieldDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,22 @@ public TextType TextType
/// <summary>
/// An optional set of values that can be selected as a combobox. Requires <see cref="TextType"/> to be <see cref="DynamicUI.TextType.SingleLine"/>.
/// </summary>
public List<string>? Items { get; set; }
public List<string>? Items
{
get => _items;
set
{
_items = value;

if (value != null && value.Count > 0)
{
// Backwards compatibility for when Items was just an option under a Text form field type
Type = FormFieldType.Combobox;
}
}
}
private List<string>? _items;

public bool MultiLine => TextType != TextType.SingleLine;
}
}
Loading