From e11a04d81947b89e1b732f4f88f350cbf690010f Mon Sep 17 00:00:00 2001 From: Olmo del Corral Date: Wed, 16 Sep 2020 00:05:14 +0200 Subject: [PATCH] more on MultiPropertySetter --- Signum.Entities/DynamicQuery/QueryUtils.cs | 12 ++- Signum.Entities/EnumMessages.cs | 2 + .../ApiControllers/OperationController.cs | 13 +-- .../JsonConverters/EntityJsonConverter.cs | 11 +++ Signum.React/Scripts/FindOptions.ts | 30 +++++- Signum.React/Scripts/Lines.tsx | 12 ++- Signum.React/Scripts/Operations.tsx | 13 ++- .../Operations/ContextualOperations.tsx | 6 +- .../Operations/MultiPropertySetter.tsx | 95 +++++++++++++------ Signum.React/Scripts/Reflection.ts | 22 ++++- Signum.React/Scripts/Signum.Entities.ts | 2 + 11 files changed, 168 insertions(+), 50 deletions(-) diff --git a/Signum.Entities/DynamicQuery/QueryUtils.cs b/Signum.Entities/DynamicQuery/QueryUtils.cs index c6a2ac7dd2..c727e737a0 100644 --- a/Signum.Entities/DynamicQuery/QueryUtils.cs +++ b/Signum.Entities/DynamicQuery/QueryUtils.cs @@ -500,14 +500,24 @@ internal static Type BuildLite(this Type type) static readonly MethodInfo miLike = ReflectionTools.GetMethodInfo((string s) => s.Like(s)); static readonly MethodInfo miDistinctNullable = ReflectionTools.GetMethodInfo((string s) => LinqHints.DistinctNull(null, null)).GetGenericMethodDefinition(); static readonly MethodInfo miDistinct = ReflectionTools.GetMethodInfo((string s) => LinqHints.DistinctNull(null, null)).GetGenericMethodDefinition(); + static readonly MethodInfo miEquals = ReflectionTools.GetMethodInfo(() => object.Equals(null, null)); public static Expression GetCompareExpression(FilterOperation operation, Expression left, Expression right, bool inMemory = false) { switch (operation) { - case FilterOperation.EqualTo: return Expression.Equal(left, right); + case FilterOperation.EqualTo: + { + if (inMemory) + return Expression.Call(null, miEquals, left, right); + + return Expression.Equal(left, right); + } case FilterOperation.DistinctTo: { + if (inMemory) + return Expression.Not(Expression.Call(null, miEquals, left, right)); + var t = left.Type.UnNullify(); var mi = t.IsValueType ? miDistinctNullable : miDistinct; return Expression.Call(mi.MakeGenericMethod(t), left.Nullify(), right.Nullify()); diff --git a/Signum.Entities/EnumMessages.cs b/Signum.Entities/EnumMessages.cs index 17434e58ca..5911d9fb31 100644 --- a/Signum.Entities/EnumMessages.cs +++ b/Signum.Entities/EnumMessages.cs @@ -42,6 +42,8 @@ public enum OperationMessage Predictate, Setters, + [Description("Add setter")] + AddSetter, } public enum SynchronizerMessage diff --git a/Signum.React/ApiControllers/OperationController.cs b/Signum.React/ApiControllers/OperationController.cs index 15b809509a..187578480f 100644 --- a/Signum.React/ApiControllers/OperationController.cs +++ b/Signum.React/ApiControllers/OperationController.cs @@ -6,6 +6,7 @@ using Signum.Engine.Maps; using Signum.Engine.Operations; using Signum.Entities; +using Signum.Entities.DynamicQuery; using Signum.Entities.Reflection; using Signum.React.Facades; using Signum.React.Filters; @@ -258,7 +259,8 @@ public class MultiOperationRequest : BaseOperationRequest public class PropertySetter { public string Property; - public PropertyOperation Operation; + public PropertyOperation? Operation; + public FilterOperation? FilterOperation; public object? Value; public string? EntityType; public List? Predicate; @@ -338,8 +340,8 @@ public static void SetSetters(ModifiableEntity entity, List sett { case PropertyOperation.AddElement: { - var item = (ModifiableEntity)Activator.CreateInstance(pr.Type.ElementType()!)!; - SetSetters(item, setter.Setters!, pr); + var item = (ModifiableEntity)Activator.CreateInstance(elementPr.Type)!; + SetSetters(item, setter.Setters!, elementPr); ((IList)mlist).Add(item); } break; @@ -359,7 +361,7 @@ public static void SetSetters(ModifiableEntity entity, List sett var toRemove = ((IEnumerable)mlist).Where(predicate.Compile()).ToList(); foreach (var item in toRemove) { - ((IList)mlist).Add(item); + ((IList)mlist).Remove(item); } } break; @@ -407,7 +409,6 @@ private static void SetProperty(ModifiableEntity entity, PropertyRoute pr, Prope return pr.PropertyInfo!.GetValue(subEntity); } - static MethodInfo miEquals = ReflectionTools.GetMethodInfo(() => object.Equals(null, null)); static Expression> GetPredicate(List predicate, PropertyRoute mainRoute, JsonSerializer serializer) { @@ -422,7 +423,7 @@ static Expression> GetPredicate(List predicat var left = Expression.Invoke(lambda, param); object? objClean = ConvertObject(p.Value, pr, serializer); - return (Expression)Expression.Call(null, miEquals, left, Expression.Constant(objClean)); + return (Expression)QueryUtils.GetCompareExpression(p.FilterOperation!.Value, left, Expression.Constant(objClean), inMemory: true); }).Aggregate((a, b) => Expression.AndAlso(a, b)); diff --git a/Signum.React/JsonConverters/EntityJsonConverter.cs b/Signum.React/JsonConverters/EntityJsonConverter.cs index c976aadaa2..99dacd6f40 100644 --- a/Signum.React/JsonConverters/EntityJsonConverter.cs +++ b/Signum.React/JsonConverters/EntityJsonConverter.cs @@ -182,6 +182,17 @@ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer WriteJsonProperty(writer, serializer, mod, kvp.Key, kvp.Value, tup.pr); } + var readonlyProps = PropertyConverter.GetPropertyConverters(value!.GetType()) + .Where(kvp => kvp.Value.PropertyValidator?.IsPropertyReadonly(mod) == true) + .Select(a => a.Key) + .ToList(); + + if (readonlyProps.Any()) + { + writer.WritePropertyName("readonlyProperties"); + serializer.Serialize(writer, readonlyProps); + } + if (mod.Mixins.Any()) { writer.WritePropertyName("mixins"); diff --git a/Signum.React/Scripts/FindOptions.ts b/Signum.React/Scripts/FindOptions.ts index ae7c6ccfca..19a63a00d1 100644 --- a/Signum.React/Scripts/FindOptions.ts +++ b/Signum.React/Scripts/FindOptions.ts @@ -1,4 +1,4 @@ -import { TypeReference, PseudoType, QueryKey, getLambdaMembers, QueryTokenString } from './Reflection'; +import { TypeReference, PseudoType, QueryKey, getLambdaMembers, QueryTokenString, tryGetTypeInfos } from './Reflection'; import { Lite, Entity } from './Signum.Entities'; import { PaginationMode, OrderType, FilterOperation, FilterType, ColumnOptionsMode, UniqueType, SystemTimeMode, FilterGroupOperation, PinnedFilterActive } from './Signum.Entities.DynamicQuery'; import { SearchControlProps, SearchControlLoaded } from "./Search"; @@ -421,6 +421,34 @@ export function isList(fo: FilterOperation) { } +export function getFilterType(tr: TypeReference): FilterType | null { + if (tr.name == "number") + return "Integer"; + + if (tr.name == "decmial") + return "Decimal"; + + if (tr.name == "boolean") + return "Boolean"; + + if (tr.name == "string") + return "String"; + + if (tr.name == "dateTime") + return "DateTime"; + + if (tr.name == "Guid") + return "Guid"; + + if (tr.isEmbedded) + return "Embedded"; + + if (tr.isLite || tryGetTypeInfos(tr)[0]?.name) + return "Lite"; + + return null; +} + export const filterOperations: { [a: string /*FilterType*/]: FilterOperation[] } = {}; filterOperations["String"] = [ "Contains", diff --git a/Signum.React/Scripts/Lines.tsx b/Signum.React/Scripts/Lines.tsx index ba854851db..c3638b3a92 100644 --- a/Signum.React/Scripts/Lines.tsx +++ b/Signum.React/Scripts/Lines.tsx @@ -98,8 +98,8 @@ export function taskSetFormat(lineBase: LineBaseController, state: LineBase } } -tasks.push(taskSetReadOnly); -export function taskSetReadOnly(lineBase: LineBaseController, state: LineBaseProps) { +tasks.push(taskSetReadOnlyProperty); +export function taskSetReadOnlyProperty(lineBase: LineBaseController, state: LineBaseProps) { if (!state.ctx.readOnly && state.ctx.propertyRoute && state.ctx.propertyRoute.propertyRouteType == "Field" && @@ -108,6 +108,14 @@ export function taskSetReadOnly(lineBase: LineBaseController, state: LineBa } } +tasks.push(taskSetReadOnly); +export function taskSetReadOnly(lineBase: LineBaseController, state: LineBaseProps) { + if (!state.ctx.readOnly && + state.ctx.binding.getIsReadonly()) { + state.ctx.readOnly = true; + } +} + tasks.push(taskSetMandatory); export function taskSetMandatory(lineBase: LineBaseController, state: LineBaseProps) { if (state.ctx.propertyRoute && state.mandatory == undefined && diff --git a/Signum.React/Scripts/Operations.tsx b/Signum.React/Scripts/Operations.tsx index eae56bdef8..bbdccc537b 100644 --- a/Signum.React/Scripts/Operations.tsx +++ b/Signum.React/Scripts/Operations.tsx @@ -19,6 +19,7 @@ import { ContextualItemsContext } from './SearchControl/ContextualItems'; import { BsColor, KeyCodes } from "./Components/Basic"; import { IconProp } from "@fortawesome/fontawesome-svg-core"; import Notify from './Frames/Notify'; +import { FilterOperation } from "./Signum.Entities.DynamicQuery"; export namespace Options { export function maybeReadonly(ti: TypeInfo) { @@ -454,11 +455,14 @@ export namespace Defaults { return oi.key.endsWith(".Save"); } - export function defaultSetterConfig(oi: OperationInfo): SettersConfig { - if (!oi.canBeModified) + export function defaultSetterConfig(coc: ContextualOperationContext): SettersConfig { + if (!coc.operationInfo.canBeModified) return "No"; - return isSave(oi) ? "Mandatory" : "Optional"; + if (coc.context.lites.length == 1) //Will create too much noise + return "No"; + + return isSave(coc.operationInfo) ? "Mandatory" : "Optional"; } export function getColor(oi: OperationInfo): BsColor { @@ -580,7 +584,8 @@ export namespace API { export interface PropertySetter { property: string; - operation: PropertyOperation; + operation?: PropertyOperation; + filterOperation?: FilterOperation; value?: any; entityType?: string; predicate?: PropertySetter[]; diff --git a/Signum.React/Scripts/Operations/ContextualOperations.tsx b/Signum.React/Scripts/Operations/ContextualOperations.tsx index 70bb6b70f7..9d5ba58219 100644 --- a/Signum.React/Scripts/Operations/ContextualOperations.tsx +++ b/Signum.React/Scripts/Operations/ContextualOperations.tsx @@ -88,7 +88,7 @@ export function getEntityOperationsContextualItems(ctx: ContextualItemsContext, ... if (!coc.operationInfo.canBeModified) return Promise.resolve([]); - var settersConfig = coc.settings?.settersConfig ?? Defaults.defaultSetterConfig(coc.operationInfo); + var settersConfig = coc.settings?.settersConfig ?? Defaults.defaultSetterConfig(coc); if (settersConfig == "No") return Promise.resolve([]); @@ -345,7 +345,7 @@ export function defaultContextualClick(coc: ContextualOperationContext, ... if (!onlyType) return Promise.resolve([]); - return MultiPropertySetterModal.show(getTypeInfo(onlyType), coc.context.lites, coc.operationInfo); + return MultiPropertySetterModal.show(getTypeInfo(onlyType), coc.context.lites, coc.operationInfo, settersConfig == "Mandatory"); } } diff --git a/Signum.React/Scripts/Operations/MultiPropertySetter.tsx b/Signum.React/Scripts/Operations/MultiPropertySetter.tsx index d8fde43dd9..c2da30ab5a 100644 --- a/Signum.React/Scripts/Operations/MultiPropertySetter.tsx +++ b/Signum.React/Scripts/Operations/MultiPropertySetter.tsx @@ -20,6 +20,7 @@ import { Modal } from 'react-bootstrap' import { ErrorBoundary } from '../Components' import './MultiPropertySetter.css'; import SelectorModal from '../SelectorModal' +import { FilterOperation, filterOperations, getFilterType } from '../FindOptions' @@ -28,6 +29,7 @@ interface MultiPropertySetterModalProps extends IModalProps lites: Lite[]; operationInfo: OperationInfo; setters: API.PropertySetter[]; + mandatory: boolean; } export function MultiPropertySetterModal(p: MultiPropertySetterModalProps) { @@ -59,7 +61,7 @@ export function MultiPropertySetterModal(p: MultiPropertySetterModalProps) {
- +
@@ -71,7 +73,7 @@ export function MultiPropertySetterModal(p: MultiPropertySetterModalProps) { )}


-