From 6e8aac61d19d8c15ff225fce6e6e105767643f4a Mon Sep 17 00:00:00 2001 From: Olmo del Corral Date: Mon, 3 Feb 2020 22:17:30 +0100 Subject: [PATCH] many changes to support --- Signum.Entities/EnumMessages.cs | 8 ++ Signum.React/Facades/ReflectionServer.cs | 106 +++++++++------ Signum.React/Facades/SignumServer.cs | 3 + Signum.React/Scripts/Constructor.tsx | 5 +- Signum.React/Scripts/Finder.tsx | 10 +- Signum.React/Scripts/Frames/FrameModal.tsx | 10 +- Signum.React/Scripts/Frames/FramePage.tsx | 5 +- .../Scripts/Lines/DynamicComponent.tsx | 4 +- Signum.React/Scripts/Lines/EntityBase.tsx | 12 +- Signum.React/Scripts/Lines/EntityRepeater.tsx | 4 +- Signum.React/Scripts/Lines/RenderEntity.tsx | 4 +- Signum.React/Scripts/Lines/ValueLine.tsx | 14 +- Signum.React/Scripts/Navigator.tsx | 126 ++++++++++-------- .../Operations/ContextualOperations.tsx | 4 +- .../Scripts/Operations/EntityOperations.tsx | 8 +- Signum.React/Scripts/Reflection.ts | 77 ++++++----- .../Scripts/SearchControl/EntityLink.tsx | 2 +- .../Scripts/SearchControl/FilterBuilder.tsx | 4 +- .../SearchControl/MultipliedMessage.tsx | 2 +- .../SearchControl/PinnedFilterBuilder.tsx | 2 +- .../Scripts/SearchControl/SearchControl.tsx | 6 +- .../SearchControl/SearchControlLoaded.tsx | 6 +- .../SearchControl/ValueSearchControlLine.tsx | 4 +- Signum.React/Scripts/Signum.Entities.t4s | 10 +- Signum.React/Scripts/Signum.Entities.ts | 10 +- 25 files changed, 261 insertions(+), 185 deletions(-) diff --git a/Signum.Entities/EnumMessages.cs b/Signum.Entities/EnumMessages.cs index 48c8e5b084..33fb733f5e 100644 --- a/Signum.Entities/EnumMessages.cs +++ b/Signum.Entities/EnumMessages.cs @@ -1,10 +1,17 @@ using Signum.Utilities; +using System; using System.ComponentModel; namespace Signum.Entities { + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] + public sealed class AllowUnathenticatedAttribute : Attribute + { + + } + public enum OperationMessage { [Description("Create...")] @@ -264,6 +271,7 @@ public enum CalendarMessage Today, } + [AllowUnathenticated] public enum JavascriptMessage { [Description("Choose a type")] diff --git a/Signum.React/Facades/ReflectionServer.cs b/Signum.React/Facades/ReflectionServer.cs index 686a48b598..9467982af5 100644 --- a/Signum.React/Facades/ReflectionServer.cs +++ b/Signum.React/Facades/ReflectionServer.cs @@ -42,10 +42,13 @@ public static object GetCurrentValidCulture() t.IsEnum && !t.Name.EndsWith("Query") && !t.Name.EndsWith("Message")) .ToDictionaryEx(GetTypeName, "Types")); - public static void RegisterLike(Type type) + public static Dictionary> OverrideIsNamespaceAllowed = new Dictionary>(); + + public static void RegisterLike(Type type, Func allowed) { TypesByName.Reset(); EntityAssemblies.GetOrCreate(type.Assembly).Add(type.Namespace!); + OverrideIsNamespaceAllowed[type.Namespace!] = allowed; } internal static void Start() @@ -64,54 +67,68 @@ internal static void Start() const BindingFlags instanceFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; const BindingFlags staticFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly; - public static event Action? AddTypeExtension; - static TypeInfoTS OnAddTypeExtension(TypeInfoTS ti, Type t) + public static event Func? TypeExtension; + static TypeInfoTS? OnTypeExtension(TypeInfoTS ti, Type t) { - foreach (var a in AddTypeExtension.GetInvocationListTyped()) - a(ti, t); + foreach (var a in TypeExtension.GetInvocationListTyped()) + { + ti = a(ti, t)!; + if (ti == null) + return null; + } return ti; } - public static event Action? AddPropertyRouteExtension; - static MemberInfoTS OnAddPropertyRouteExtension(MemberInfoTS mi, PropertyRoute m) + public static event Func? PropertyRouteExtension; + static MemberInfoTS? OnPropertyRouteExtension(MemberInfoTS mi, PropertyRoute m) { - if (AddPropertyRouteExtension == null) + if (PropertyRouteExtension == null) return mi; - foreach (var a in AddPropertyRouteExtension.GetInvocationListTyped()) - a(mi, m); + foreach (var a in PropertyRouteExtension.GetInvocationListTyped()) + { + mi = a(mi, m)!; + if (mi == null) + return null; + } return mi; } - public static event Action? AddFieldInfoExtension; - static MemberInfoTS OnAddFieldInfoExtension(MemberInfoTS mi, FieldInfo m) + public static event Func? FieldInfoExtension; + static MemberInfoTS? OnFieldInfoExtension(MemberInfoTS mi, FieldInfo m) { - if (AddFieldInfoExtension == null) + if (FieldInfoExtension == null) return mi; - foreach (var a in AddFieldInfoExtension.GetInvocationListTyped()) - a(mi, m); + foreach (var a in FieldInfoExtension.GetInvocationListTyped()) + { + mi = a(mi, m)!; + if (mi == null) + return null; + } return mi; } - public static event Action? AddOperationExtension; - static OperationInfoTS OnAddOperationExtension(OperationInfoTS oi, OperationInfo o, Type type) + public static event Func? OperationExtension; + static OperationInfoTS? OnOperationExtension(OperationInfoTS oi, OperationInfo o, Type type) { - if (AddOperationExtension == null) + if (OperationExtension == null) return oi; - foreach (var a in AddOperationExtension.GetInvocationListTyped()) - a(oi, o, type); + foreach (var a in OperationExtension.GetInvocationListTyped()) + { + oi = a(oi, o, type)!; + if (oi == null) + return null; + } return oi; } - - public static HashSet ExcludeTypes = new HashSet(); internal static Dictionary GetTypeInfoTS() @@ -167,7 +184,7 @@ where typeof(ModelEntity).IsAssignableFrom(type) && !type.IsAbstract where !type.IsEnumEntity() && !ReflectionServer.ExcludeTypes.Contains(type) let descOptions = LocalizedAssembly.GetDescriptionOptions(type) let allOperations = !type.IsEntity() ? null : OperationLogic.GetAllOperationInfos(type) - select KeyValuePair.Create(GetTypeName(type), OnAddTypeExtension(new TypeInfoTS + select KeyValuePair.Create(GetTypeName(type), OnTypeExtension(new TypeInfoTS { Kind = KindOfType.Entity, FullName = type.FullName!, @@ -182,7 +199,7 @@ select KeyValuePair.Create(GetTypeName(type), OnAddTypeExtension(new TypeInfoTS QueryDefined = queries.QueryDefined(type), Members = PropertyRoute.GenerateRoutes(type) .Where(pr => InTypeScript(pr)) - .ToDictionary(p => p.PropertyString(), p => + .Select(p => { var validators = Validator.TryGetPropertyValidator(p)?.Validators; @@ -196,19 +213,24 @@ select KeyValuePair.Create(GetTypeName(type), OnAddTypeExtension(new TypeInfoTS Unit = UnitAttribute.GetTranslation(p.PropertyInfo?.GetCustomAttribute()?.UnitName), Type = new TypeReferenceTS(IsId(p) ? PrimaryKey.Type(type).Nullify() : p.PropertyInfo!.PropertyType, p.Type.IsMList() ? p.Add("Item").TryGetImplementations() : p.TryGetImplementations()), IsMultiline = validators?.OfType().FirstOrDefault()?.MultiLine ?? false, - IsVirtualMList = p.IsVirtualMList(), + IsVirtualMList = p.IsVirtualMList(), MaxLength = validators?.OfType().FirstOrDefault()?.Max.DefaultToNull(-1), PreserveOrder = settings.FieldAttributes(p)?.OfType().Any() ?? false, }; - return OnAddPropertyRouteExtension(mi, p); - }), + return KeyValuePair.Create(p.PropertyString(), OnPropertyRouteExtension(mi, p)!); + }) + .Where(kvp => kvp.Value != null) + .ToDictionaryEx("properties"), - Operations = allOperations == null ? null : allOperations.ToDictionary(oi => oi.OperationSymbol.Key, oi => OnAddOperationExtension(new OperationInfoTS(oi), oi, type)), + HasConstructorOperation = allOperations != null && allOperations.Any(oi => oi.OperationType == OperationType.Constructor), + Operations = allOperations == null ? null : allOperations.Select(oi => KeyValuePair.Create(oi.OperationSymbol.Key, OnOperationExtension(new OperationInfoTS(oi), oi, type)!)).Where(kvp => kvp.Value != null).ToDictionaryEx("operations"), RequiresEntityPack = allOperations != null && allOperations.Any(oi => oi.HasCanExecute != null), - }, type))).ToDictionaryEx("entities"); + }, type))) + .Where(kvp => kvp.Value != null) + .ToDictionaryEx("entities"); return result; } @@ -248,19 +270,23 @@ where type.IsEnum where descOptions != DescriptionOptions.None let kind = type.Name.EndsWith("Query") ? KindOfType.Query : type.Name.EndsWith("Message") ? KindOfType.Message : KindOfType.Enum - select KeyValuePair.Create(GetTypeName(type), OnAddTypeExtension(new TypeInfoTS + select KeyValuePair.Create(GetTypeName(type), OnTypeExtension(new TypeInfoTS { Kind = kind, FullName = type.FullName!, NiceName = descOptions.HasFlag(DescriptionOptions.Description) ? type.NiceName() : null, Members = type.GetFields(staticFlags) .Where(fi => kind != KindOfType.Query || queries.QueryDefined(fi.GetValue(null)!)) - .ToDictionary(fi => fi.Name, fi => OnAddFieldInfoExtension(new MemberInfoTS + .Select(fi => KeyValuePair.Create(fi.Name, OnFieldInfoExtension(new MemberInfoTS { NiceName = fi.NiceName(), IsIgnoredEnum = kind == KindOfType.Enum && fi.HasAttribute() - }, fi)), - }, type))).ToDictionaryEx("enums"); + }, fi)!)) + .Where(a=>a.Value != null) + .ToDictionaryEx("query"), + }, type))) + .Where(a => a.Value != null) + .ToDictionaryEx("enums"); return result; } @@ -271,7 +297,7 @@ public static Dictionary GetSymbolContainers(IEnumerable() - select KeyValuePair.Create(GetTypeName(type), OnAddTypeExtension(new TypeInfoTS + select KeyValuePair.Create(GetTypeName(type), OnTypeExtension(new TypeInfoTS { Kind = KindOfType.SymbolContainer, FullName = type.FullName!, @@ -280,13 +306,15 @@ select KeyValuePair.Create(GetTypeName(type), OnAddTypeExtension(new TypeInfoTS .Where(s => s.FieldInfo != null && /*Duplicated like in Dynamic*/ s.IdOrNull.HasValue /*Not registered*/) - .ToDictionary(s => s.FieldInfo.Name, s => OnAddFieldInfoExtension(new MemberInfoTS + .Select(s => KeyValuePair.Create(s.FieldInfo.Name, OnFieldInfoExtension(new MemberInfoTS { NiceName = s.FieldInfo.NiceName(), Id = s.IdOrNull!.Value.Object - }, s.FieldInfo)) + }, s.FieldInfo)!)) + .Where(a => a.Value != null) + .ToDictionaryEx("fields"), }, type))) - .Where(a => a.Value.Members.Any()) + .Where(a => a.Value != null && a.Value.Members.Any()) .ToDictionaryEx("symbols"); return result; @@ -340,9 +368,11 @@ public class TypeInfoTS [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "toStringFunction")] public string? ToStringFunction { get; set; } [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, PropertyName = "queryDefined")] - public bool QueryDefined { get; internal set; } + public bool QueryDefined { get; set; } [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "members")] public Dictionary Members { get; set; } = null!; + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, PropertyName = "hasConstructorOperation")] + public bool HasConstructorOperation { get; set; } [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "operations")] public Dictionary? Operations { get; set; } [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, PropertyName = "requiresEntityPack")] diff --git a/Signum.React/Facades/SignumServer.cs b/Signum.React/Facades/SignumServer.cs index d260dfbb46..0b6575ba2f 100644 --- a/Signum.React/Facades/SignumServer.cs +++ b/Signum.React/Facades/SignumServer.cs @@ -11,6 +11,7 @@ using Signum.Engine.Maps; using Signum.Engine.Operations; using Signum.Entities; +using Signum.Entities.Basics; using Signum.React.ApiControllers; using Signum.React.Filters; using Signum.React.Json; @@ -85,6 +86,8 @@ public static void Start(IApplicationBuilder app, IWebHostEnvironment hostingEnv SignumControllerFactory.RegisterArea(MethodInfo.GetCurrentMethod()!); ReflectionServer.Start(); + ReflectionServer.OverrideIsNamespaceAllowed.Add(typeof(DayOfWeek).Namespace!, () => UserHolder.Current != null); + ReflectionServer.OverrideIsNamespaceAllowed.Add(typeof(CollectionMessage).Namespace!, () => UserHolder.Current != null); } public static EntityPackTS GetEntityPack(Entity entity) diff --git a/Signum.React/Scripts/Constructor.tsx b/Signum.React/Scripts/Constructor.tsx index f3f416c6d2..faefa3f25b 100644 --- a/Signum.React/Scripts/Constructor.tsx +++ b/Signum.React/Scripts/Constructor.tsx @@ -1,6 +1,6 @@ import { Dic } from './Globals'; import { Entity, ModifiableEntity, SelectorMessage, EntityPack } from './Signum.Entities'; -import { Type, getTypeInfo, OperationType, New, OperationInfo, PropertyRoute } from './Reflection'; +import { Type, getTypeInfo, OperationType, New, OperationInfo, PropertyRoute, tryGetTypeInfo } from './Reflection'; import SelectorModal from './SelectorModal'; import * as Operations from './Operations'; import * as Navigator from './Navigator'; @@ -20,10 +20,9 @@ export function constructPack(type: string | Type, props?: any, pr?: Proper const typeName = (type as Type).typeName ?? type as string; - const ti = getTypeInfo(typeName); + const ti = tryGetTypeInfo(typeName); if (ti) pr = PropertyRoute.root(ti); - const c = customConstructors[typeName]; if (c) diff --git a/Signum.React/Scripts/Finder.tsx b/Signum.React/Scripts/Finder.tsx index da4f9a281e..9f72a07368 100644 --- a/Signum.React/Scripts/Finder.tsx +++ b/Signum.React/Scripts/Finder.tsx @@ -21,8 +21,8 @@ import { TypeEntity, QueryEntity } from './Signum.Entities.Basics'; import { Type, IType, EntityKind, QueryKey, getQueryNiceName, getQueryKey, isQueryDefined, TypeReference, - getTypeInfo, getTypeInfos, getEnumInfo, toMomentFormat, toNumbroFormat, PseudoType, EntityData, - TypeInfo, PropertyRoute, QueryTokenString + getTypeInfo, tryGetTypeInfos, getEnumInfo, toMomentFormat, toNumbroFormat, PseudoType, EntityData, + TypeInfo, PropertyRoute, QueryTokenString, getTypeInfos } from './Reflection'; import SearchModal from './SearchControl/SearchModal'; @@ -223,7 +223,7 @@ export function findOptionsPathQuery(fo: FindOptions, extra?: any): any { export function getTypeNiceName(tr: TypeReference) { const niceName = tr.typeNiceName ?? - getTypeInfos(tr) + tryGetTypeInfos(tr) .map(ti => ti == undefined ? getSimpleTypeNiceName(tr.name) : (ti.niceName ?? ti.name)) .joinComma(External.CollectionMessage.Or.niceToString()); @@ -581,7 +581,7 @@ export function parseFindOptions(findOptions: FindOptions, qd: QueryDescription, fo.columnOptions = mergeColumns(Dic.getValues(qd.columns), fo.columnOptionsMode ?? "Add", fo.columnOptions ?? []); var qs: QuerySettings | undefined = querySettings[qd.queryKey]; - const tis = getTypeInfos(qd.columns["Entity"].type); + const tis = tryGetTypeInfos(qd.columns["Entity"].type); if (!fo.groupResults && (!fo.orderOptions || fo.orderOptions.length == 0)) { @@ -1515,7 +1515,7 @@ export const entityFormatRules: EntityFormatRule[] = [ { name: "View", isApplicable: row => true, - formatter: (row, columns, sc) => !row.entity || !Navigator.isNavigable(row.entity.EntityType, undefined, true) ? undefined : + formatter: (row, columns, sc) => !row.entity || !Navigator.isNavigable(row.entity.EntityType, { isSearch: true }) ? undefined : { @@ -214,7 +214,7 @@ export const FrameModal = React.forwardRef(function FrameModal(p: FrameModalProp }; const styleOptions: StyleOptions = { - readOnly: p.readOnly != undefined ? p.readOnly : Navigator.isReadOnly(pc.pack), + readOnly: p.readOnly != undefined ? p.readOnly : Navigator.isReadOnly(pc.pack, { isEmbedded: p.propertyRoute?.member?.type.isEmbedded }), frame: frame, }; @@ -316,9 +316,9 @@ export function FrameModalTitle({ pack, pr, title, getViewPromise }: { pack?: En if (entity == undefined || entity.isNew) return undefined; - const ti = getTypeInfo(entity.Type); + const ti = tryGetTypeInfo(entity.Type); - if (ti == undefined || !Navigator.isNavigable(ti, false)) //Embedded + if (ti == undefined || !Navigator.isNavigable(ti)) //Embedded return undefined; return ( diff --git a/Signum.React/Scripts/Frames/FramePage.tsx b/Signum.React/Scripts/Frames/FramePage.tsx index dfc8fc1fd9..8160d873bb 100644 --- a/Signum.React/Scripts/Frames/FramePage.tsx +++ b/Signum.React/Scripts/Frames/FramePage.tsx @@ -35,11 +35,10 @@ export default function FramePage(p: FramePageProps) { const mounted = useMounted(); const forceUpdate = useForceUpdate(); - const type = getTypeInfo(p.match.params.type).name; + const ti = getTypeInfo(p.match.params.type); + const type = ti.name; const id = p.match.params.id; - const ti = getTypeInfo(type); - useTitle(state?.pack.entity.toStr ?? "", [state?.pack.entity]); React.useEffect(() => { diff --git a/Signum.React/Scripts/Lines/DynamicComponent.tsx b/Signum.React/Scripts/Lines/DynamicComponent.tsx index 598a9741ed..7936c3d730 100644 --- a/Signum.React/Scripts/Lines/DynamicComponent.tsx +++ b/Signum.React/Scripts/Lines/DynamicComponent.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { Dic } from '../Globals' -import { getTypeInfos, TypeReference } from '../Reflection' +import { tryGetTypeInfos, TypeReference, TypeInfo } from '../Reflection' import { ModifiableEntity } from '../Signum.Entities' import * as Navigator from '../Navigator' import { ViewReplacer } from '../Frames/ReactVisitor' @@ -75,7 +75,7 @@ export function getAppropiateComponentFactory(pr: PropertyRoute): (ctx: TypeCont } export function getAppropiateComponentFactoryBasic(tr: TypeReference): (ctx: TypeContext) => React.ReactElement | undefined { - let tis = getTypeInfos(tr); + let tis = tryGetTypeInfos(tr) as TypeInfo[]; if (tis.length == 1 && tis[0] == undefined) tis = []; diff --git a/Signum.React/Scripts/Lines/EntityBase.tsx b/Signum.React/Scripts/Lines/EntityBase.tsx index 3740c8448b..a9e269d64c 100644 --- a/Signum.React/Scripts/Lines/EntityBase.tsx +++ b/Signum.React/Scripts/Lines/EntityBase.tsx @@ -5,7 +5,7 @@ import * as Constructor from '../Constructor' import * as Finder from '../Finder' import { FindOptions } from '../FindOptions' import { TypeContext } from '../TypeContext' -import { PropertyRoute, getTypeInfos, TypeInfo, IsByAll, TypeReference, getTypeInfo } from '../Reflection' +import { PropertyRoute, tryGetTypeInfos, TypeInfo, IsByAll, TypeReference, getTypeInfo, getTypeInfos } from '../Reflection' import { ModifiableEntity, Lite, Entity, EntityControlMessage, toLiteFat, is, entityInfo, SelectorMessage, toLite } from '../Signum.Entities' import { LineBaseController, LineBaseProps } from './LineBase' import SelectorModal from '../SelectorModal' @@ -48,15 +48,15 @@ export class EntityBaseController

extends LineBaseCon } static defaultIsCreable(type: TypeReference, customComponent: boolean) { - return type.isEmbedded ? Navigator.isCreable(type.name, customComponent, false) : + return type.isEmbedded ? Navigator.isCreable(type.name, { customComponent, isEmbedded: type.isEmbedded }) : type.name == IsByAll ? false : - getTypeInfos(type).some(ti => Navigator.isCreable(ti, customComponent, false)); + getTypeInfos(type).some(ti => Navigator.isCreable(ti, { customComponent })); } static defaultIsViewable(type: TypeReference, customComponent: boolean) { - return type.isEmbedded ? Navigator.isViewable(type.name, customComponent) : + return type.isEmbedded ? Navigator.isViewable(type.name, { customComponent, isEmbedded: type.isEmbedded }) : type.name == IsByAll ? true : - getTypeInfos(type).some(ti => Navigator.isViewable(ti, customComponent)); + getTypeInfos(type).some(ti => Navigator.isViewable(ti, { customComponent })); } static defaultIsFindable(type: TypeReference) { @@ -211,7 +211,7 @@ export class EntityBaseController

extends LineBaseCon defaultCreate(pr: PropertyRoute): Promise | undefined> { - return this.chooseType(t => this.props.create /*Hack?*/ || Navigator.isCreable(t, !!this.props.getComponent || !!this.props.getViewPromise, false)) + return this.chooseType(t => this.props.create /*Hack?*/ || Navigator.isCreable(t, { customComponent: !!this.props.getComponent || !!this.props.getViewPromise, isEmbedded: pr.member!.type.isEmbedded })) .then(typeName => { if (!typeName) return Promise.resolve(undefined); diff --git a/Signum.React/Scripts/Lines/EntityRepeater.tsx b/Signum.React/Scripts/Lines/EntityRepeater.tsx index c291bcd701..b428c9300b 100644 --- a/Signum.React/Scripts/Lines/EntityRepeater.tsx +++ b/Signum.React/Scripts/Lines/EntityRepeater.tsx @@ -7,7 +7,7 @@ import { EntityBaseController } from './EntityBase' import { EntityListBaseController, EntityListBaseProps, DragConfig } from './EntityListBase' import { RenderEntity } from './RenderEntity' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { getTypeInfos, getTypeInfo } from '../Reflection'; +import { tryGetTypeInfos, getTypeInfo } from '../Reflection'; import { useController } from './LineBase' export interface EntityRepeaterProps extends EntityListBaseProps { @@ -72,7 +72,7 @@ export const EntityRepeater = React.forwardRef(function EntityRepeater(props: En function renderElements() { const readOnly = ctx.readOnly; - const showType = getTypeInfos(ctx.propertyRoute.typeReference().name).length > 1; + const showType = tryGetTypeInfos(ctx.propertyRoute.typeReference().name).length > 1; return (

{ diff --git a/Signum.React/Scripts/Lines/RenderEntity.tsx b/Signum.React/Scripts/Lines/RenderEntity.tsx index 9c5c6fb937..ffb6f14c49 100644 --- a/Signum.React/Scripts/Lines/RenderEntity.tsx +++ b/Signum.React/Scripts/Lines/RenderEntity.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import * as Navigator from '../Navigator' import { TypeContext, EntityFrame } from '../TypeContext' -import { PropertyRoute, getTypeInfo, ReadonlyBinding } from '../Reflection' +import { PropertyRoute, getTypeInfo, ReadonlyBinding, tryGetTypeInfo } from '../Reflection' import { ModifiableEntity, Lite, Entity, isLite, isModifiableEntity } from '../Signum.Entities' import { ViewPromise } from "../Navigator"; import { ErrorBoundary } from '../Components'; @@ -44,7 +44,7 @@ export function RenderEntity(p: RenderEntityProps) { if (componentBox == null) return null; - const ti = getTypeInfo(entity.Type); + const ti = tryGetTypeInfo(entity.Type); const ctx = p.ctx; diff --git a/Signum.React/Scripts/Lines/ValueLine.tsx b/Signum.React/Scripts/Lines/ValueLine.tsx index 20e037368a..d7910dd31b 100644 --- a/Signum.React/Scripts/Lines/ValueLine.tsx +++ b/Signum.React/Scripts/Lines/ValueLine.tsx @@ -3,7 +3,7 @@ import * as moment from 'moment' import numbro from 'numbro' import * as DateTimePicker from 'react-widgets/lib/DateTimePicker' import { Dic, addClass, classes } from '../Globals' -import { MemberInfo, getTypeInfo, TypeReference, toMomentFormat, toDurationFormat, toNumbroFormat, isTypeEnum, durationToString } from '../Reflection' +import { MemberInfo, getTypeInfo, TypeReference, toMomentFormat, toDurationFormat, toNumbroFormat, isTypeEnum, durationToString, TypeInfo } from '../Reflection' import { LineBaseController, LineBaseProps, useController } from '../Lines/LineBase' import { FormGroup } from '../Lines/FormGroup' import { FormControlReadonly } from '../Lines/FormControlReadonly' @@ -246,13 +246,15 @@ ValueLineRenderers.renderers["ComboBox"] = (vl) => { return internalComboBox(vl); }; - - function getOptionsItems(vl: ValueLineController): OptionItem[] { - var ti = getTypeInfo(vl.props.type!.name); + var ti: TypeInfo; + function getTi() { + return ti ?? (ti = getTypeInfo(vl.props.type!.name)); + } + if (vl.props.comboBoxItems) return vl.props.comboBoxItems.map(a => - typeof a == "string" ? ti.members[a] && toOptionItem(ti.members[a]) : + typeof a == "string" ? getTi().members[a] && toOptionItem(getTi().members[a]) : toOptionItem(a)).filter(a => !!a); if (vl.props.type!.name == "boolean") @@ -261,7 +263,7 @@ function getOptionsItems(vl: ValueLineController): OptionItem[] { { label: BooleanEnum.niceToString("True")!, value: true } ]); - return Dic.getValues(ti.members).map(m => toOptionItem(m)); + return Dic.getValues(getTi().members).map(m => toOptionItem(m)); } function toOptionItem(m: MemberInfo | OptionItem): OptionItem { diff --git a/Signum.React/Scripts/Navigator.tsx b/Signum.React/Scripts/Navigator.tsx index 3e89afc0f6..e6a5db8984 100644 --- a/Signum.React/Scripts/Navigator.tsx +++ b/Signum.React/Scripts/Navigator.tsx @@ -5,7 +5,7 @@ import { Dic, classes, } from './Globals'; import { ajaxGet, ajaxPost } from './Services'; import { Lite, Entity, ModifiableEntity, EntityPack, isEntity, isLite, isEntityPack, toLite, liteKey } from './Signum.Entities'; import { IUserEntity, TypeEntity } from './Signum.Entities.Basics'; -import { PropertyRoute, PseudoType, Type, getTypeInfo, getTypeInfos, getTypeName, isTypeEmbeddedOrValue, isTypeModel, OperationType, TypeReference, IsByAll } from './Reflection'; +import { PropertyRoute, PseudoType, Type, getTypeInfo, tryGetTypeInfos, getTypeName, isTypeModel, OperationType, TypeReference, IsByAll, isTypeEntity, tryGetTypeInfo, getTypeInfos } from './Reflection'; import { TypeContext } from './TypeContext'; import * as Finder from './Finder'; import * as Operations from './Operations'; @@ -84,25 +84,25 @@ export function start(options: { routes: JSX.Element[] }) { export function getTypeTitle(entity: ModifiableEntity, pr: PropertyRoute | undefined) { - if (isTypeEmbeddedOrValue(entity.Type)) { - - return pr!.typeReference().typeNiceName; - - } else if (isTypeModel(entity.Type)) { + if (isTypeEntity(entity.Type)) { const typeInfo = getTypeInfo(entity.Type); - return typeInfo.niceName; + if (entity.isNew) + return NormalWindowMessage.New0_G.niceToString().forGenderAndNumber(typeInfo.gender).formatWith(typeInfo.niceName); + + return NormalWindowMessage.Type0Id1.niceToString().formatHtml(typeInfo.niceName, renderId(entity as Entity)); } - else { + else if (isTypeModel(entity.Type)) { const typeInfo = getTypeInfo(entity.Type); + return typeInfo.niceName; - if (entity.isNew) - return NormalWindowMessage.New0_G.niceToString().forGenderAndNumber(typeInfo.gender).formatWith(typeInfo.niceName); + } else { + + return pr!.typeReference().typeNiceName; - return NormalWindowMessage.Type0Id1.niceToString().formatHtml(typeInfo.niceName, renderId(entity as Entity)); } } @@ -118,6 +118,7 @@ export function navigateRoute(entityOrLite: Entity | Lite, viewName?: st let typeName: string; let id: number | string | undefined; if (isEntity(entityOrLite)) { + typeName = entityOrLite.Type; id = entityOrLite.id; } @@ -287,47 +288,51 @@ export function getViewPromise(entity: T, viewName?: return viewDispatcher.getViewPromise(entity, viewName); } -export const isCreableEvent: Array<(typeName: string) => boolean> = []; +export const isCreableEvent: Array<(typeName: string, options: IsCreableOptions | undefined) => boolean> = []; + +export interface IsCreableOptions { + customComponent?: boolean; + isSearch?: boolean; + isEmbedded?: boolean; +} -export function isCreable(type: PseudoType, customView = false, isSearch = false) { +export function isCreable(type: PseudoType, options?: IsCreableOptions) { const typeName = getTypeName(type); - const baseIsCreable = checkFlag(typeIsCreable(typeName), isSearch); + const baseIsCreable = checkFlag(typeIsCreable(typeName, options?.isEmbedded), options?.isSearch); - const hasView = customView || viewDispatcher.hasDefaultView(typeName); + const hasView = options?.customComponent || viewDispatcher.hasDefaultView(typeName); const hasConstructor = hasAllowedConstructor(typeName); - return baseIsCreable && hasView && hasConstructor && isCreableEvent.every(f => f(typeName)); + return baseIsCreable && hasView && hasConstructor && isCreableEvent.every(f => f(typeName, options)); } function hasAllowedConstructor(typeName: string) { - const ti = getTypeInfo(typeName); + const ti = tryGetTypeInfo(typeName); if (ti == undefined || ti.operations == undefined) return true; - const constructOperations = Dic.getValues(ti.operations).filter(a => a.operationType == OperationType.Constructor); - - if (!constructOperations.length) + if (!ti.hasConstructorOperation) return true; - const allowed = constructOperations.filter(oi => Operations.isOperationInfoAllowed(oi)); + const allowed = Dic.getValues(ti.operations).some(oi => oi.operationType == OperationType.Constructor && Operations.isOperationInfoAllowed(oi)); - return allowed.length > 0; + return allowed; } -function typeIsCreable(typeName: string): EntityWhen { +function typeIsCreable(typeName: string, isEmbedded?: boolean): EntityWhen { const es = entitySettings[typeName]; if (es != undefined && es.isCreable != undefined) return es.isCreable; - const typeInfo = getTypeInfo(typeName); - if (typeInfo == undefined) + if (isEmbedded) return "IsLine"; + const typeInfo = getTypeInfo(typeName); if (typeInfo.kind == "Enum") return "Never"; @@ -347,13 +352,18 @@ function typeIsCreable(typeName: string): EntityWhen { export const isReadonlyEvent: Array<(typeName: string, entity?: EntityPack) => boolean> = []; -export function isReadOnly(typeOrEntity: PseudoType | EntityPack, ignoreTypeIsReadonly: boolean = false) { +export interface IsReadonlyOptions { + ignoreTypeIsReadonly?: boolean; + isEmbedded?: boolean; +} + +export function isReadOnly(typeOrEntity: PseudoType | EntityPack, options?: IsReadonlyOptions) { const entityPack = isEntityPack(typeOrEntity) ? typeOrEntity : undefined; const typeName = isEntityPack(typeOrEntity) ? typeOrEntity.entity.Type : getTypeName(typeOrEntity as PseudoType); - const baseIsReadOnly = ignoreTypeIsReadonly ? false : typeIsReadOnly(typeName); + const baseIsReadOnly = options?.ignoreTypeIsReadonly ? false : typeIsReadOnly(typeName); return baseIsReadOnly || isReadonlyEvent.some(f => f(typeName, entityPack)); } @@ -364,7 +374,7 @@ function typeIsReadOnly(typeName: string): boolean { if (es != undefined && es.isReadOnly != undefined) return es.isReadOnly; - const typeInfo = getTypeInfo(typeName); + const typeInfo = tryGetTypeInfo(typeName); if (typeInfo == undefined) return false; @@ -386,7 +396,7 @@ function typeIsReadOnly(typeName: string): boolean { export function typeRequiresSaveOperation(typeName: string): boolean { - const typeInfo = getTypeInfo(typeName); + const typeInfo = tryGetTypeInfo(typeName); if (typeInfo == undefined) return false; @@ -403,28 +413,31 @@ export function typeRequiresSaveOperation(typeName: string): boolean { } } -export const isFindableEvent: Array<(typeName: string) => boolean> = []; +export interface IsFindableOptions { + isSearch?: boolean; + isEmbedded?: boolean; +} -export function isFindable(type: PseudoType, isSearch?: boolean) { +export function isFindable(type: PseudoType, options?: IsFindableOptions) { const typeName = getTypeName(type); - const baseIsReadOnly = typeIsFindable(typeName); + const baseIsReadOnly = typeIsFindable(typeName, options?.isEmbedded); return baseIsReadOnly && Finder.isFindable(typeName, true); } -function typeIsFindable(typeName: string) { +function typeIsFindable(typeName: string, isEmbedded: boolean | undefined) { const es = entitySettings[typeName]; if (es != undefined && es.isFindable != undefined) return es.isFindable; - const typeInfo = getTypeInfo(typeName); - if (typeInfo == undefined) + if (isEmbedded) return false; + const typeInfo = getTypeInfo(typeName); if (typeInfo.kind == "Enum") return true; @@ -441,33 +454,38 @@ function typeIsFindable(typeName: string) { } } -export const isViewableEvent: Array<(typeName: string, entityPack?: EntityPack) => boolean> = []; +export const isViewableEvent: Array<(typeName: string, entityPack: EntityPack | undefined, options: IsViewableOptions | undefined) => boolean> = []; -export function isViewable(typeOrEntity: PseudoType | EntityPack, customView = false): boolean { +export interface IsViewableOptions { + customComponent?: boolean; + isSearch?: boolean; + isEmbedded?: boolean; +} + +export function isViewable(typeOrEntity: TypeReference | PseudoType | EntityPack, options?: IsViewableOptions): boolean { const entityPack = isEntityPack(typeOrEntity) ? typeOrEntity : undefined; const typeName = isEntityPack(typeOrEntity) ? typeOrEntity.entity.Type : getTypeName(typeOrEntity as PseudoType); - const baseIsViewable = typeIsViewable(typeName); + const baseIsViewable = typeIsViewable(typeName, options?.isEmbedded); - const hasView = customView || viewDispatcher.hasDefaultView(typeName); + const hasView = options?.customComponent || viewDispatcher.hasDefaultView(typeName); - return baseIsViewable && hasView && isViewableEvent.every(f => f(typeName, entityPack)); + return baseIsViewable && hasView && isViewableEvent.every(f => f(typeName, entityPack, options)); } - -function typeIsViewable(typeName: string): boolean { +function typeIsViewable(typeName: string, isEmbedded: boolean | undefined): boolean { const es = entitySettings[typeName]; if (es != undefined && es.isViewable != undefined) return es.isViewable; - const typeInfo = getTypeInfo(typeName); - if (typeInfo == undefined) + if (isEmbedded) return true; + const typeInfo = getTypeInfo(typeName); if (typeInfo.kind == "Enum") return false; @@ -484,30 +502,30 @@ function typeIsViewable(typeName: string): boolean { } } -export function isNavigable(typeOrEntity: PseudoType | EntityPack, customComponent = false, isSearch = false): boolean { +export function isNavigable(typeOrEntity: PseudoType | EntityPack, options?: IsViewableOptions): boolean { const entityPack = isEntityPack(typeOrEntity) ? typeOrEntity : undefined; const typeName = isEntityPack(typeOrEntity) ? typeOrEntity.entity.Type : getTypeName(typeOrEntity as PseudoType); - const baseTypeName = checkFlag(typeIsNavigable(typeName), isSearch); + const baseTypeName = checkFlag(typeIsNavigable(typeName, options?.isEmbedded), options?.isSearch); - const hasView = customComponent || viewDispatcher.hasDefaultView(typeName); + const hasView = options?.customComponent || viewDispatcher.hasDefaultView(typeName); - return baseTypeName && hasView && isViewableEvent.every(f => f(typeName, entityPack)); + return baseTypeName && hasView && isViewableEvent.every(f => f(typeName, entityPack, options)); } -function typeIsNavigable(typeName: string): EntityWhen { +function typeIsNavigable(typeName: string, isEmbedded: boolean | undefined): EntityWhen { const es = entitySettings[typeName]; if (es != undefined && es.isNavigable != undefined) return es.isNavigable; - const typeInfo = getTypeInfo(typeName); - if (typeInfo == undefined) + if (isEmbedded) return "Never"; + const typeInfo = getTypeInfo(typeName); if (typeInfo.kind == "Enum") return "Never"; @@ -685,7 +703,7 @@ export function toEntityPack(entityOrEntityPack: Lite | ModifiableEntity if (entity == undefined) return API.fetchEntityPack(entityOrEntityPack as Lite); - let ti = getTypeInfo(entity.Type); + let ti = tryGetTypeInfo(entity.Type); if (ti == null || !ti.requiresEntityPack) return Promise.resolve({ entity: cloneEntity(entity), canExecute: {} }); @@ -988,7 +1006,7 @@ export function surroundFunctionComponent(functionCo return result; } -export function checkFlag(entityWhen: EntityWhen, isSearch: boolean) { +export function checkFlag(entityWhen: EntityWhen, isSearch: boolean | undefined) { return entityWhen == "Always" || entityWhen == (isSearch ? "IsSearch" : "IsLine"); } @@ -1073,7 +1091,7 @@ export function tryConvert(value: any, type: TypeReference): Promise | unde return undefined; } - const ti = getTypeInfo(type.name); + const ti = tryGetTypeInfo(type.name); if (ti?.kind == "Entity") { diff --git a/Signum.React/Scripts/Operations/ContextualOperations.tsx b/Signum.React/Scripts/Operations/ContextualOperations.tsx index 78ab0d8cec..1866747e1f 100644 --- a/Signum.React/Scripts/Operations/ContextualOperations.tsx +++ b/Signum.React/Scripts/Operations/ContextualOperations.tsx @@ -112,7 +112,7 @@ export function getEntityOperationsContextualItems(ctx: ContextualItemsContext { contexts.forEach(coc => { coc.canExecute = ep.canExecute[coc.operationInfo.key]; - coc.isReadonly = Navigator.isReadOnly(ep, true); + coc.isReadonly = Navigator.isReadOnly(ep, { ignoreTypeIsReadonly: true }); }); return contexts; }); @@ -128,7 +128,7 @@ export function getEntityOperationsContextualItems(ctx: ContextualItemsContext a.isReadonly = true); } diff --git a/Signum.React/Scripts/Operations/EntityOperations.tsx b/Signum.React/Scripts/Operations/EntityOperations.tsx index 1bf68b1b4c..7031df123f 100644 --- a/Signum.React/Scripts/Operations/EntityOperations.tsx +++ b/Signum.React/Scripts/Operations/EntityOperations.tsx @@ -1,6 +1,6 @@ import * as React from "react" import { Entity, toLite, JavascriptMessage, OperationMessage, getToString, NormalControlMessage, NormalWindowMessage, EntityPack, ModifiableEntity } from '../Signum.Entities'; -import { getTypeInfo, OperationType, GraphExplorer } from '../Reflection'; +import { getTypeInfo, OperationType, GraphExplorer, tryGetTypeInfo } from '../Reflection'; import { classes, ifError } from '../Globals'; import { ButtonsContext, IOperationVisible, ButtonBarElement } from '../TypeContext'; import * as Navigator from '../Navigator'; @@ -21,7 +21,7 @@ import { notifySuccess } from "../Operations"; export function getEntityOperationButtons(ctx: ButtonsContext): Array | undefined { - const ti = getTypeInfo(ctx.pack.entity.Type); + const ti = tryGetTypeInfo(ctx.pack.entity.Type); if (ti == undefined) return undefined; @@ -53,7 +53,7 @@ export function getEntityOperationButtons(ctx: ButtonsContext): Array(eoc: EntityOperationContext, inDropd text: () => OperationMessage._0AndNew.niceToString(eoc.textOrNiceName()), icon: "plus", keyboardShortcut: eoc.keyboardShortcut && { altKey: true, ...eoc.keyboardShortcut }, - isVisible: eoc.frame!.allowChangeEntity && Navigator.isCreable(eoc.entity.Type, true, true), + isVisible: eoc.frame!.allowChangeEntity && Navigator.isCreable(eoc.entity.Type, { customComponent: true, isSearch: true }), inDropdown: inDropdown, onClick: () => { eoc.onExecuteSuccess = pack => { diff --git a/Signum.React/Scripts/Reflection.ts b/Signum.React/Scripts/Reflection.ts index 48ee97ff90..67911c1012 100644 --- a/Signum.React/Scripts/Reflection.ts +++ b/Signum.React/Scripts/Reflection.ts @@ -7,9 +7,9 @@ import { MList } from "./Signum.Entities"; import QueryTokenBuilder from './SearchControl/QueryTokenBuilder'; import { AggregateType } from './FindOptions'; -export function getEnumInfo(enumTypeName: string, enumId: number) { +export function getEnumInfo(enumTypeName: string, enumId: number): MemberInfo { - const ti = getTypeInfo(enumTypeName); + const ti = tryGetTypeInfo(enumTypeName); if (!ti || ti.kind != "Enum") throw new Error(`${enumTypeName} is not an Enum`); @@ -34,7 +34,7 @@ export interface TypeInfo { requiresEntityPack?: boolean; members: { [name: string]: MemberInfo }; membersById?: { [name: string]: MemberInfo }; - + hasConstructorOperation?: boolean; operations?: { [name: string]: OperationInfo }; } @@ -250,42 +250,46 @@ export function getTypeName(pseudoType: IType | TypeInfo | string | Lite } export function isTypeEntity(type: PseudoType): boolean { - const ti = getTypeInfo(type); - return ti && ti.kind == "Entity" && !!ti.members["Id"]; + const ti = tryGetTypeInfo(type); + return ti != null && ti.kind == "Entity" && !!ti.members["Id"]; } export function isTypeEnum(type: PseudoType): boolean { - const ti = getTypeInfo(type); - return ti && ti.kind == "Enum"; + const ti = tryGetTypeInfo(type); + return ti != null && ti.kind == "Enum"; } export function isTypeModel(type: PseudoType): boolean { - const ti = getTypeInfo(type); - return ti && ti.kind == "Entity" && !ti.members["Id"]; -} - -export function isTypeEmbeddedOrValue(type: PseudoType): boolean { - const ti = getTypeInfo(type); - return !ti; + const ti = tryGetTypeInfo(type); + return ti != null && ti.kind == "Entity" && !ti.members["Id"]; } export function isTypeModifiableEntity(type: TypeReference): boolean { - return type.isEmbedded == true || getTypeInfos(type).every(ti => ti != undefined && (isTypeEntity(ti) || isTypeModel(ti))); + return type.isEmbedded == true || tryGetTypeInfos(type).every(ti => ti != undefined && (isTypeEntity(ti) || isTypeModel(ti))); } - export function getTypeInfo(type: PseudoType): TypeInfo { - if ((type as TypeInfo).kind != undefined) - return type as TypeInfo; + const typeName = getTypeName(type); + + const ti = _types[typeName.toLowerCase()]; + + if (ti == null) + throw new Error(`Type not found: ${typeName}`); + + return ti; +} + +export function tryGetTypeInfo(type: PseudoType): TypeInfo | undefined { - if ((type as IType).typeName) - return _types[((type as IType).typeName).toLowerCase()]; + const typeName = getTypeName(type); - if (typeof type == "string") - return _types[(type as string).toLowerCase()]; + if (typeName == null) + throw new Error("Unexpected type: " + type); - throw new Error("Unexpected type: " + type); + const ti: TypeInfo | undefined = _types[typeName.toLowerCase()]; + + return ti; } export function isLowPopulationSymbol(type: PseudoType) { @@ -308,7 +312,16 @@ export function getTypeInfos(typeReference: TypeReference | string): TypeInfo[] return []; return name.split(", ").map(getTypeInfo); +} + +export function tryGetTypeInfos(typeReference: TypeReference | string): (TypeInfo | undefined)[] { + + const name = typeof typeReference == "string" ? typeReference : typeReference.name; + if (name == IsByAll || name == "") + return []; + + return name.split(", ").map(tryGetTypeInfo); } export function getQueryNiceName(queryName: PseudoType | QueryKey): string { @@ -345,7 +358,7 @@ export function getQueryInfo(queryName: PseudoType | QueryKey): MemberInfo | Typ return queryName.memberInfo(); } else { - const ti = getTypeInfo(queryName); + const ti = tryGetTypeInfo(queryName); if (ti) return ti; @@ -751,7 +764,7 @@ export type MemberType = "Member" | "Mixin" | "Indexer"; export function New(type: PseudoType, props?: any, propertyRoute?: PropertyRoute): ModifiableEntity { - const ti = getTypeInfo(type); + const ti = tryGetTypeInfo(type); const result = { Type: getTypeName(type), isNew: true, modified: true } as any as ModifiableEntity; @@ -804,7 +817,7 @@ function initializeCollections(m: ModifiableEntity, pr: PropertyRoute) { export function clone(original: ModifiableEntity, propertyRoute?: PropertyRoute) { - const ti = getTypeInfo(original.Type); + const ti = tryGetTypeInfo(original.Type); const result = { Type: original.Type, isNew: true, modified: true } as any as ModifiableEntity; @@ -877,7 +890,7 @@ function cloneIfNeeded(original: any, pr: PropertyRoute) { if (tr.isEmbedded) return clone(original, pr); - if (tr.name == IsByAll || getTypeInfos(tr.name).length > 0) + if (tr.name == IsByAll || tryGetTypeInfos(tr.name).length > 0) return JSON.parse(JSON.stringify(original)); return original; //string, number, boolean, etc... @@ -905,7 +918,7 @@ export class Type implements IType { New(props?: Partial, propertyRoute?: PropertyRoute): T { - if (props && props.Type && (propertyRoute|| getTypeInfo(props.Type))) { + if (props && props.Type && (propertyRoute || tryGetTypeInfo(props.Type))) { if (props.Type != this.typeName) throw new Error("Cloning with another type"); return clone(props as ModifiableEntity, propertyRoute) as T; @@ -1430,7 +1443,7 @@ export class PropertyRoute { return PropertyRoute.liteEntity(this); } - const ti = getTypeInfos(ref).single("Ambiguity due to multiple Implementations" + getErrorContext()); //[undefined] + const ti = tryGetTypeInfos(ref).single("Ambiguity due to multiple Implementations" + getErrorContext()); //[undefined] if (ti) { const m = ti.members[memberName]; @@ -1526,7 +1539,11 @@ export class PropertyRoute { case "Field": case "MListItem": { - const ti = getTypeInfos(this.typeReference()).single("Ambiguity due to multiple Implementations"); //[undefined] + var tr = this.typeReference(); + if (tr.name == IsByAll) + return {}; + + const ti = tryGetTypeInfos(this.typeReference()).single("Ambiguity due to multiple Implementations"); //[undefined] if (ti && isTypeEntity(ti)) return simpleMembersAfter(ti, ""); else diff --git a/Signum.React/Scripts/SearchControl/EntityLink.tsx b/Signum.React/Scripts/SearchControl/EntityLink.tsx index 16714ab763..4a542b0728 100644 --- a/Signum.React/Scripts/SearchControl/EntityLink.tsx +++ b/Signum.React/Scripts/SearchControl/EntityLink.tsx @@ -17,7 +17,7 @@ export default function EntityLink(p: EntityLinkProps) { const { lite, inSearch, children, onNavigated, getViewPromise, inPlaceNavigation, ...htmlAtts } = p; - if (!Navigator.isNavigable(lite.EntityType, undefined, p.inSearch || false)) + if (!Navigator.isNavigable(lite.EntityType, { isSearch: p.inSearch || false })) return {p.children ?? getToString(lite)}; diff --git a/Signum.React/Scripts/SearchControl/FilterBuilder.tsx b/Signum.React/Scripts/SearchControl/FilterBuilder.tsx index 33a7aab2ac..a3453d77e4 100644 --- a/Signum.React/Scripts/SearchControl/FilterBuilder.tsx +++ b/Signum.React/Scripts/SearchControl/FilterBuilder.tsx @@ -5,7 +5,7 @@ import { FilterOptionParsed, QueryDescription, QueryToken, SubTokensOptions, fil import { SearchMessage } from '../Signum.Entities' import { isNumber} from '../Lines/ValueLine' import { ValueLine, EntityLine, EntityCombo, StyleContext, FormControlReadonly } from '../Lines' -import { Binding, IsByAll, getTypeInfos, toMomentFormat } from '../Reflection' +import { Binding, IsByAll, tryGetTypeInfos, toMomentFormat, getTypeInfos } from '../Reflection' import { TypeContext } from '../TypeContext' import QueryTokenBuilder from './QueryTokenBuilder' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -606,7 +606,7 @@ export function createFilterValueControl(ctx: TypeContext, token: QueryToke case "Embedded": return ; case "Enum": - const ti = getTypeInfos(tokenType).single(); + const ti = tryGetTypeInfos(tokenType).single(); if (!ti) throw new Error(`EnumType ${tokenType.name} not found`); const members = Dic.getValues(ti.members).filter(a => !a.isIgnoredEnum); diff --git a/Signum.React/Scripts/SearchControl/MultipliedMessage.tsx b/Signum.React/Scripts/SearchControl/MultipliedMessage.tsx index a287f8e9dc..7ca1cd501f 100644 --- a/Signum.React/Scripts/SearchControl/MultipliedMessage.tsx +++ b/Signum.React/Scripts/SearchControl/MultipliedMessage.tsx @@ -3,7 +3,7 @@ import * as React from 'react' import { Dic } from '../Globals' import { FindOptionsParsed, QueryToken, getTokenParents, isFilterGroupOptionParsed } from '../FindOptions' import { ValidationMessage, External } from '../Signum.Entities' -import { getTypeInfos, TypeReference } from '../Reflection' +import { tryGetTypeInfos, TypeReference, getTypeInfos } from '../Reflection' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FilterOptionParsed } from '../Search'; diff --git a/Signum.React/Scripts/SearchControl/PinnedFilterBuilder.tsx b/Signum.React/Scripts/SearchControl/PinnedFilterBuilder.tsx index 387861e96d..75e9acdbde 100644 --- a/Signum.React/Scripts/SearchControl/PinnedFilterBuilder.tsx +++ b/Signum.React/Scripts/SearchControl/PinnedFilterBuilder.tsx @@ -4,7 +4,7 @@ import { isList, isFilterGroupOptionParsed } from '../FindOptions' import { ValueLine, FormGroup } from '../Lines' -import { Binding, IsByAll, getTypeInfos, toMomentFormat } from '../Reflection' +import { Binding, IsByAll, tryGetTypeInfos, toMomentFormat } from '../Reflection' import { TypeContext } from '../TypeContext' import "./FilterBuilder.css" import { createFilterValueControl, MultiValue } from './FilterBuilder'; diff --git a/Signum.React/Scripts/SearchControl/SearchControl.tsx b/Signum.React/Scripts/SearchControl/SearchControl.tsx index eaf2bbfada..7a7e8e0b67 100644 --- a/Signum.React/Scripts/SearchControl/SearchControl.tsx +++ b/Signum.React/Scripts/SearchControl/SearchControl.tsx @@ -3,7 +3,7 @@ import * as Finder from '../Finder' import { CellFormatter, EntityFormatter } from '../Finder' import { ResultTable, ResultRow, FindOptions, FindOptionsParsed, FilterOptionParsed, FilterOption, QueryDescription } from '../FindOptions' import { Lite, Entity } from '../Signum.Entities' -import { getTypeInfos, getQueryKey } from '../Reflection' +import { tryGetTypeInfos, getQueryKey, getTypeInfos } from '../Reflection' import * as Navigator from '../Navigator' import SearchControlLoaded, { ShowBarExtensionOption } from './SearchControlLoaded' import { ErrorBoundary } from '../Components'; @@ -185,8 +185,8 @@ const SearchControl = React.forwardRef(function SearchControl(p: SearchControlPr showFooter={p.showFooter != null ? p.showFooter : true} allowChangeColumns={p.allowChangeColumns != null ? p.allowChangeColumns : true} allowChangeOrder={p.allowChangeOrder != null ? p.allowChangeOrder : true} - create={p.create != null ? p.create : tis.some(ti => Navigator.isCreable(ti, false, true))} - navigate={p.navigate != null ? p.navigate : tis.some(ti => Navigator.isNavigable(ti, undefined, true))} + create={p.create != null ? p.create : tis.some(ti => Navigator.isCreable(ti, { isSearch: true }))} + navigate={p.navigate != null ? p.navigate : tis.some(ti => Navigator.isNavigable(ti, { isSearch: true}))} allowSelection={p.allowSelection != null ? p.allowSelection : qs && qs.allowSelection != null ? qs!.allowSelection : true} diff --git a/Signum.React/Scripts/SearchControl/SearchControlLoaded.tsx b/Signum.React/Scripts/SearchControl/SearchControlLoaded.tsx index 6f8e069905..aac9d7152c 100644 --- a/Signum.React/Scripts/SearchControl/SearchControlLoaded.tsx +++ b/Signum.React/Scripts/SearchControl/SearchControlLoaded.tsx @@ -8,7 +8,7 @@ import { toQueryToken, Pagination, OrderOptionParsed, SubTokensOptions, filterOperations, QueryToken, QueryRequest } from '../FindOptions' import { SearchMessage, JavascriptMessage, Lite, liteKey, Entity, ModifiableEntity } from '../Signum.Entities' -import { getTypeInfos, TypeInfo, isTypeModel } from '../Reflection' +import { tryGetTypeInfos, TypeInfo, isTypeModel, getTypeInfos } from '../Reflection' import * as Navigator from '../Navigator' import { AbortableRequest } from '../Services' import * as Constructor from '../Constructor' @@ -619,7 +619,7 @@ export default class SearchControlLoaded extends React.Component { const tis = getTypeInfos(this.props.queryDescription.columns["Entity"].type) - .filter(ti => Navigator.isCreable(ti, false, true)); + .filter(ti => Navigator.isCreable(ti, { isSearch: true })); return SelectorModal.chooseType(tis) .then(ti => ti ? ti.name : undefined); @@ -1179,7 +1179,7 @@ export default class SearchControlLoaded extends React.Component { const tis = getTypeInfos(qd.columns["Entity"].type) - .filter(ti => Navigator.isCreable(ti, false, true)); + .filter(ti => Navigator.isCreable(ti, { isSearch: true })); return SelectorModal.chooseType(tis) .then(ti => ti ? ti.name : undefined); diff --git a/Signum.React/Scripts/Signum.Entities.t4s b/Signum.React/Scripts/Signum.Entities.t4s index cabf2a60fb..f5bad4b067 100644 --- a/Signum.React/Scripts/Signum.Entities.t4s +++ b/Signum.React/Scripts/Signum.Entities.t4s @@ -83,7 +83,7 @@ function getOrCreateToStringFunction(type: string) { if (f || f === null) return f; - const ti = Reflection.getTypeInfo(type); + const ti = Reflection.tryGetTypeInfo(type); const getToString2 = getToString; @@ -209,10 +209,10 @@ return obj != null && (obj as ModifiableEntity).Type != undefined; } export function isEntity(obj: any): obj is Entity { -if(!isModifiableEntity(obj)) -return false; -const ti = Reflection.getTypeInfo(obj.Type); -return ti != null && ti.entityKind != null; + if(!isModifiableEntity(obj)) + return false; + const ti = Reflection.tryGetTypeInfo(obj.Type); + return ti != null && ti.entityKind != null; } export function isEntityPack(obj: any): obj is EntityPack { diff --git a/Signum.React/Scripts/Signum.Entities.ts b/Signum.React/Scripts/Signum.Entities.ts index 21e244bbcc..40e07f0650 100644 --- a/Signum.React/Scripts/Signum.Entities.ts +++ b/Signum.React/Scripts/Signum.Entities.ts @@ -90,7 +90,7 @@ function getOrCreateToStringFunction(type: string) { if (f || f === null) return f; - const ti = Reflection.getTypeInfo(type); + const ti = Reflection.tryGetTypeInfo(type); const getToString2 = getToString; @@ -216,10 +216,10 @@ return obj != null && (obj as ModifiableEntity).Type != undefined; } export function isEntity(obj: any): obj is Entity { -if(!isModifiableEntity(obj)) -return false; -const ti = Reflection.getTypeInfo(obj.Type); -return ti != null && ti.entityKind != null; + if(!isModifiableEntity(obj)) + return false; + const ti = Reflection.tryGetTypeInfo(obj.Type); + return ti != null && ti.entityKind != null; } export function isEntityPack(obj: any): obj is EntityPack {