private async Task <IResolvedSetup <CollectionSetup> > ConvertConfigAsync(CollectionConfig config) { var repositoryAlias = _repositoryTypeResolver.GetAlias(config.RepositoryType); var collection = new CollectionSetup( config.Icon, config.Color, config.Name, config.Alias, repositoryAlias) { DataViews = config.DataViews, DataViewBuilder = config.DataViewBuilder, UsageType = GetCollectionUsage(config), Validators = config.Validators.ToList(x => new ValidationSetup(x.Type, x.Configuration)) }; if (!_cmsConfig.Advanced.RemoveDataAnnotationEntityValidator) { collection.Validators.Insert(0, new ValidationSetup(typeof(DataAnnotationEntityValidator), default)); } var cacheable = true; if (!string.IsNullOrWhiteSpace(config.ParentAlias) && _collectionMap.TryGetValue(config.ParentAlias, out var collectionConfig)) { collection.Parent = new TreeElementSetup(collectionConfig.Alias, collectionConfig.Name, PageType.Collection); // TODO: this assumes nesting is always with collections } collection.Collections = (await _treeElementResolver.ResolveSetupAsync(config.CollectionsAndPages, collection)).CheckIfCachable(ref cacheable).ToList(); collection.EntityVariant = (await _entityVariantResolver.ResolveSetupAsync(config.EntityVariant, collection)).CheckIfCachable(ref cacheable); if (config.SubEntityVariants.Any()) { collection.SubEntityVariants = (await _entityVariantResolver.ResolveSetupAsync(config.SubEntityVariants, collection)).CheckIfCachable(ref cacheable).ToList(); } collection.TreeView = config.TreeView == null ? null : (await _treeViewResolver.ResolveSetupAsync(config.TreeView, collection)).CheckIfCachable(ref cacheable); collection.ElementSetup = config.ElementConfig == null ? null : (await _elementResolver.ResolveSetupAsync(config.ElementConfig, collection)).CheckIfCachable(ref cacheable); collection.ListView = config.ListView == null ? null : (await _listResolver.ResolveSetupAsync(config.ListView, collection)).CheckIfCachable(ref cacheable); collection.ListEditor = config.ListEditor == null ? null : (await _listResolver.ResolveSetupAsync(config.ListEditor, collection)).CheckIfCachable(ref cacheable); collection.NodeView = config.NodeView == null ? null : (await _nodeResolver.ResolveSetupAsync(config.NodeView, collection)).CheckIfCachable(ref cacheable); collection.NodeEditor = config.NodeEditor == null ? null : (await _nodeResolver.ResolveSetupAsync(config.NodeEditor, collection)).CheckIfCachable(ref cacheable); return(new ResolvedSetup <CollectionSetup>(collection, cacheable)); }
public async Task <IReadOnlyList <IElement> > GetAvailableElementsAsync(IView view) { if (_editContext?.Parent?.Entity is ModelEntity modelEntity) { var collection = await _collectionSetupResolver.ResolveSetupAsync(modelEntity.Alias); var relatedCollectionAlias = _property?.Details.SelectNotNull(x => x.Config?.RelatedCollectionAlias).FirstOrDefault(); if (relatedCollectionAlias is string alias) { var model = await _modelResolver.HandleAsync(new GetByIdRequest <ModelEntity>(alias)); if (model.Entity != null) { var possibleProperties = model.Entity.Properties.Where(x => (x.IsRelationToMany || x.IsRelationToOne) && x.Type == collection.EntityVariant.Type.FullName); return(possibleProperties.Select(x => new Element { Id = x.Name, Labels = new[] { x.Name } }).ToList()); } } } return(new List <IElement>()); }
public async Task <IResolvedSetup <PaneSetup> > ResolveSetupAsync(PaneConfig config, CollectionSetup?collection = default) { if (collection == null) { throw new ArgumentNullException(nameof(collection)); } var cacheable = true; var buttons = (await _buttonSetupResolver.ResolveSetupAsync(config.Buttons, collection)).CheckIfCachable(ref cacheable).ToList(); var fields = (await _fieldSetupResolver.ResolveSetupAsync(config.Fields, collection)).CheckIfCachable(ref cacheable).ToList(); var subCollectionLists = (await _subCollectionSetupResolver.ResolveSetupAsync(config.SubCollectionLists, collection)).CheckIfCachable(ref cacheable).ToList(); var relatedCollectionLists = (await _relatedCollectionSetupResolver.ResolveSetupAsync(config.RelatedCollectionLists, collection)).CheckIfCachable(ref cacheable).ToList(); return(new ResolvedSetup <PaneSetup>(new PaneSetup( config.CustomType, config.Label, config.IsVisible, config.VariantType, buttons, fields, subCollectionLists, relatedCollectionLists), cacheable)); }
public override async Task <CrudType> ButtonClickBeforeRepositoryActionAsync(ButtonSetup button, FormEditContext editContext, ButtonContext context) { var request = await _navigationHandler.CreateNavigationRequestAsync(button, editContext); if (request != null) { var collection = request.IsPage ? null : await _collectionResolver.ResolveSetupAsync(request.CollectionAlias); var usageType = request.IsNew ? UsageType.New : request.IsEdit ? UsageType.Edit : UsageType.View; NavigationState navigationState; if (request.IsPage) { navigationState = new NavigationState(request.CollectionAlias, usageType); } else if (request.IsList) { navigationState = new NavigationState(request.CollectionAlias, request.ParentPath, usageType); } else { navigationState = new NavigationState(request.CollectionAlias, request.ParentPath, request.VariantAlias ?? collection !.EntityVariant.Alias, request.Id, usageType); } _navigationStateProvider.AppendNavigationState(navigationState); } return(CrudType.None); }
public async Task <IResolvedSetup <ListSetup> > ResolveSetupAsync(ListConfig config, CollectionSetup?collection = default) { if (collection == null) { throw new ArgumentNullException(nameof(collection)); } if (config is IIsConventionBased isConventionBasedConfig) { config = await _conventionListConfigResolver.ResolveByConventionAsync(config.BaseType, isConventionBasedConfig.GetFeatures(), collection); } var cacheable = true; var panes = (await _paneSetupResolver.ResolveSetupAsync(config.Panes, collection)).CheckIfCachable(ref cacheable).ToList(); var buttons = (await _buttonSetupResolver.ResolveSetupAsync(config.Buttons, collection)).CheckIfCachable(ref cacheable).ToList(); return(new ResolvedSetup <ListSetup>(new ListSetup( config.PageSize, config.SearchBarVisible, config.ReorderingAllowed, config.ListEditorType, config.EmptyVariantColumnVisibility, panes, buttons), cacheable)); }
async Task <PageSetup> ISetupResolver <PageSetup> .ResolveSetupAsync(string alias) { if (_cache.TryGetValue(alias, out var pageSetup)) { return(pageSetup); } var config = _cmsConfig.CollectionsAndPages.SelectNotNull(x => x as IPageConfig).FirstOrDefault(x => x.Alias == alias); if (config == null) { throw new InvalidOperationException($"Cannot find page with alias {alias}."); } var cacheable = true; pageSetup = new PageSetup { Name = config.Name, Alias = config.Alias, Icon = config.Icon, Color = config.Color, Sections = (await _typeRegistrationSetupResolver.ResolveSetupAsync(config.SectionRegistrations)).CheckIfCachable(ref cacheable).ToList() }; if (cacheable) { _cache[alias] = pageSetup; } return(pageSetup); }
public async Task <INodeUIResolver> GetNodeUIResolverAsync(NavigationState navigationState) { var collection = await _collectionResolver.ResolveSetupAsync(navigationState.CollectionAlias); var node = navigationState.UsageType.HasFlag(UsageType.View) ? collection.NodeView ?? collection.NodeEditor : collection.NodeEditor ?? collection.NodeView; if (node == null) { throw new InvalidOperationException($"Failed to get UI configuration from collection {navigationState.CollectionAlias} for action {navigationState.UsageType}"); } INodeUIResolver nodeUI = new NodeUIResolver(node, _dataProviderResolver, _buttonActionHandlerResolver, _navigationStateProvider, _authService); return(nodeUI); }
public static async Task <IResolvedSetup <IEnumerable <TSetup> > > ResolveSetupAsync <TSetup, TConfig>(this ISetupResolver <TSetup, TConfig> resolver, IEnumerable <TConfig> configs, CollectionSetup?collection = default) where TConfig : notnull { var allCachable = true; return(new ResolvedSetup <IEnumerable <TSetup> >( await configs.ToListAsync(async config => (await resolver.ResolveSetupAsync(config, collection)).CheckIfCachable(ref allCachable)), allCachable)); }
public async Task <NodeSetup> ResolveByConventionAsync(Type subject, Features features, CollectionSetup?collection) { var node = await _nodeResolver.ResolveByConventionAsync(subject, features, collection); var pane = await _nodeSetupResolver.ResolveSetupAsync(node, collection); return(pane.Setup); }
public async Task <IEditContext> GetEditContextWrapperAsync(FormEditContext editContext) { var collection = await _collectionResolver.ResolveSetupAsync(editContext.CollectionAlias); var contextType = typeof(FormEditContextWrapper <>).MakeGenericType(collection.EntityVariant.Type); var instance = Activator.CreateInstance(contextType, editContext); return(instance as IEditContext ?? throw new InvalidOperationException("Cannot create FormEditContextWrapper")); }
public async Task <TreePageUI?> GetPageAsync(string alias) { var page = await _pageResolver.ResolveSetupAsync(alias); if (page == null) { throw new InvalidOperationException($"Failed to get page for given alias ({alias})."); } return(new TreePageUI(page.Name, page.Icon, page.Color, new NavigationState(page.Alias, UsageType.View))); }
public async Task <ListContext> GetAsync(GetEntitiesRequestModel request) { var collection = await _collectionResolver.ResolveSetupAsync(request.CollectionAlias); var variant = collection.GetEntityVariant(request.VariantAlias); var repository = _repositoryResolver.GetRepository(collection); var requestedEntityVariantIsDefaultVariant = variant.Alias == collection.EntityVariant.Alias; var parent = request is GetEntitiesOfParentRequestModel parentRequest ? await _parentService.GetParentAsync(parentRequest.ParentPath) : default; var relatedEntity = (request as GetEntitiesOfRelationRequestModel)?.Related; var protoEntity = await _concurrencyService.EnsureCorrectConcurrencyAsync(() => repository.NewAsync(new ViewContext(collection.Alias, parent), collection.EntityVariant.Type)); var newEntity = requestedEntityVariantIsDefaultVariant ? protoEntity : await _concurrencyService.EnsureCorrectConcurrencyAsync(() => repository.NewAsync(new ViewContext(collection.Alias, parent), variant.Type)); await _authService.EnsureAuthorizedUserAsync(request.UsageType, protoEntity); await _dataViewResolver.ApplyDataViewToViewAsync(request.View); var action = (request.UsageType & ~(UsageType.List)) switch { UsageType.Add when relatedEntity != null => () => repository.GetAllNonRelatedAsync(new RelatedViewContext(relatedEntity !, collection.Alias, parent), request.View), _ when relatedEntity != null => () => repository.GetAllRelatedAsync(new RelatedViewContext(relatedEntity !, collection.Alias, parent), request.View), _ when relatedEntity == null => () => repository.GetAllAsync(new ViewContext(collection.Alias, parent), request.View), _ => default(Func <Task <IEnumerable <IEntity> > >) }; if (action == default) { throw new InvalidOperationException($"UsageType {request.UsageType} is invalid for this method"); } var isRoot = parent == null || request.IsEmbedded; var protoEditContextUsage = request.UsageType | (isRoot ? UsageType.Root : UsageType.NotRoot); var protoEditContext = new FormEditContext(request.CollectionAlias, collection.RepositoryAlias, collection.EntityVariant.Alias, protoEntity, parent, protoEditContextUsage | UsageType.List, collection.Validators, _serviceProvider); var newEditContext = new FormEditContext(request.CollectionAlias, collection.RepositoryAlias, variant.Alias, newEntity, parent, request.UsageType | UsageType.Node, collection.Validators, _serviceProvider); var existingEntities = await _concurrencyService.EnsureCorrectConcurrencyAsync(action); return(new ListContext( request.CollectionAlias, protoEditContext, parent, request.UsageType, ConvertEditContexts(request, protoEditContext, newEditContext, existingEntities), _serviceProvider)); }
public async Task ApplyDataViewToViewAsync(IView view) { if (string.IsNullOrEmpty(view.CollectionAlias)) { throw new ArgumentNullException($"{nameof(view)}.{nameof(view.CollectionAlias)}"); } var collection = await _collectionResolver.ResolveSetupAsync(view.CollectionAlias); if (collection.DataViewBuilder != null || collection.DataViews?.Count > 0) { var dataViews = await GetDataViewsAsync(collection); var dataView = dataViews.FirstOrDefault(x => x.Id == view.ActiveTab) ?? dataViews.FirstOrDefault(); if (dataView != null) { view.SetDataView(dataView); } } }
private async Task <(IButtonActionHandler handler, ButtonSetup button)> FindButtonHandlerAsync(string collectionAlias, string buttonId) { var collection = await _collectionResolver.ResolveSetupAsync(collectionAlias); var button = collection.FindButton(buttonId); if (button == null) { throw new Exception($"Cannot determine which button triggered action for collection {collectionAlias}"); } return(_buttonActionHandlerResolver.GetButtonActionHandler(button), button); }
public async Task <IReadOnlyList <IElement> > GetAvailableElementsAsync(IView view) { var treeElements = await _setupResolver.ResolveSetupAsync(); return(treeElements .Where(treeElement => treeElement.Type == PageType.Collection) .Where(treeElement => treeElement.Alias != Constants.ModelMakerAdminCollectionAlias) .Select(treeElement => new Element { Id = treeElement.Alias, Labels = new[] { treeElement.Name } }) .ToList()); }
async Task <IEnumerable <TreeElementSetup> > ISetupResolver <IEnumerable <TreeElementSetup> > .ResolveSetupAsync() { var results = new List <TreeElementSetup>(); foreach (var plugin in _plugins) { var treeElements = await _pluginTreeElementResolver.ResolveSetupAsync(plugin); results.AddRange(treeElements.Setup); } results.AddRange((await _treeElementResolver.ResolveSetupAsync(_cmsConfig.CollectionsAndPages?.Skip(1) ?? Enumerable.Empty <ITreeElementConfig>())).Setup); return(results); }
private async Task <T> InvokeAsync <T>(PersistEntityRequestModel request, T response) where T : ViewCommandResponseModel { var collection = await _collectionResolver.ResolveSetupAsync(request.EditContext.CollectionAlias); var repository = _repositoryResolver.GetRepository(collection); var entityVariant = collection.GetEntityVariant(request.EditContext.Entity); var crudType = await _buttonInteraction.ValidateButtonInteractionAsync(request); switch (crudType) { case CrudType.View: _navigationStateProvider.AppendNavigationState(request.NavigationState, new NavigationState( request.EditContext.CollectionAlias, request.EditContext.Parent?.GetParentPath(), entityVariant.Alias, request.EditContext.Entity.Id, UsageType.View)); break; case CrudType.Edit: _navigationStateProvider.AppendNavigationState(request.NavigationState, new NavigationState( request.EditContext.CollectionAlias, request.EditContext.Parent?.GetParentPath(), entityVariant.Alias, request.EditContext.Entity.Id, UsageType.Edit)); break; case CrudType.Update: var updateContext = await _editContextFactory.GetEditContextWrapperAsync(request.EditContext); if (!await updateContext.IsValidAsync()) { throw new InvalidEntityException(); } await _concurrencyService.EnsureCorrectConcurrencyAsync(() => repository.UpdateAsync(updateContext)); if (request.EditContext.IsReordered()) { await _concurrencyService.EnsureCorrectConcurrencyAsync( () => repository.ReorderAsync(request.EditContext.ReorderedBeforeId, request.EditContext.Entity.Id !, new ViewContext(collection.Alias, request.EditContext.Parent))); } response.RefreshIds = new[] { request.EditContext.Entity.Id ! };
public async Task <FormEditContext> GetAsync(GetEntityRequestModel request) { if (string.IsNullOrWhiteSpace(request.Id) && (request.UsageType.HasFlag(UsageType.View) || request.UsageType.HasFlag(UsageType.Edit))) { throw new InvalidOperationException($"Cannot View/Edit Node when id is null"); } if (!string.IsNullOrWhiteSpace(request.Id) && request.UsageType.HasFlag(UsageType.New)) { throw new InvalidOperationException($"Cannot New Node when id is not null"); } var collection = await _collectionResolver.ResolveSetupAsync(request.CollectionAlias); var variant = request.VariantAlias == null ? collection.EntityVariant : collection.GetEntityVariant(request.VariantAlias); var repository = _repositoryResolver.GetRepository(collection); var parent = await _parentService.GetParentAsync(request.ParentPath); var action = (request.UsageType & ~(UsageType.Node)) switch { UsageType.View => () => repository.GetByIdAsync(request.Id !, new ViewContext(collection.Alias, parent)), UsageType.Edit => () => repository.GetByIdAsync(request.Id !, new ViewContext(collection.Alias, parent)), UsageType.New => () => repository.NewAsync(new ViewContext(collection.Alias, parent), variant.Type) !, _ => default(Func <Task <IEntity?> >) }; if (action == default) { throw new InvalidOperationException($"UsageType {request.UsageType} is invalid for this method"); } var entity = await _concurrencyService.EnsureCorrectConcurrencyAsync(action); if (entity == null) { throw new Exception("Failed to get entity for given id(s)"); } await _authService.EnsureAuthorizedUserAsync(request.UsageType, entity); return(new FormEditContext(request.CollectionAlias, collection.RepositoryAlias, variant.Alias, entity, parent, request.UsageType | UsageType.Node, collection.Validators, _serviceProvider)); } }
public async Task <IEnumerable <TypeRegistrationSetup> > GetAsync(string request) { var currentNavigationState = _navigationStateProvider.GetCurrentState(); var configuredSections = (await _pageResolver.ResolveSetupAsync(request)).Sections; var sections = new List <TypeRegistrationSetup>(); var isAuthorized = default(bool?); foreach (var section in configuredSections) { if (section.Type == typeof(ICollectionConfig) && section.Parameters != null && section.Parameters.TryGetValue("InitialState", out var obj) && obj is NavigationState state) { _navigationStateProvider.NestNavigationState(currentNavigationState, state); var collection = await _collectionResolver.ResolveSetupAsync(state.CollectionAlias); var repository = _repositoryResolver.GetRepository(collection); var entity = await repository.NewAsync(new ViewContext(section.Alias, default), default);
public async Task <IResolvedSetup <NodeSetup> > ResolveSetupAsync(NodeConfig config, CollectionSetup?collection = default) { if (collection == null) { throw new ArgumentNullException(nameof(collection)); } if (config is IIsConventionBased isConventionBasedConfig) { config = await _conventionNodeConfigResolver.ResolveByConventionAsync(config.BaseType, isConventionBasedConfig.GetFeatures(), collection); } var cacheable = true; var panes = (await _paneSetupResolver.ResolveSetupAsync(config.Panes, collection)).CheckIfCachable(ref cacheable).ToList(); var buttons = (await _buttonSetupResolver.ResolveSetupAsync(config.Buttons, collection)).CheckIfCachable(ref cacheable).ToList(); return(new ResolvedSetup <NodeSetup>(new NodeSetup( config.BaseType, panes, buttons), cacheable)); }
private async Task <T> InvokeAsync <T>(PersistEntitiesRequestModel request, T response) where T : ViewCommandResponseModel { var collection = await _collectionResolver.ResolveSetupAsync(request.ListContext.CollectionAlias); var repository = _repositoryResolver.GetRepository(collection); var(crudType, entityVariant) = await _buttonInteraction.ValidateButtonInteractionAsync(request); switch (crudType) { case CrudType.Create: if (entityVariant == null) { throw new InvalidOperationException($"Button of type {CrudType.Create} must have an EntityVariant."); } if (response is ListViewCommandResponseModel || ShouldFallbackToNavigatingToNodeEditor(collection)) { _navigationStateProvider.AppendNavigationState( request.NavigationState, new NavigationState( request.ListContext.CollectionAlias, request.ListContext.Parent?.GetParentPath(), entityVariant.Alias, request.Related, UsageType.New)); } else { _navigationStateProvider.AppendNavigationState( request.NavigationState, new NavigationState( request.ListContext.CollectionAlias, request.ListContext.Parent?.GetParentPath(), request.Related, UsageType.New, PageType.Collection) { CollectionState = request.NavigationState.CollectionState }); } break; case CrudType.Update: var affectedEntities = new List <IEntity>(); foreach (var editContext in request.ListContext.EditContexts.Where(f => f.IsModified() || f.IsReordered())) { var innerRequest = new PersistEntityCollectionRequestModel { ActionId = request.ActionId, CustomData = request.CustomData, EditContext = editContext, ListContext = request.ListContext }; if (!await editContext.IsValidAsync()) { throw new InvalidEntityException(); } await _buttonInteraction.ValidateButtonInteractionAsync(innerRequest); if (editContext.IsModified()) { var wrapper = await _editContextFactory.GetEditContextWrapperAsync(editContext); await _concurrencyService.EnsureCorrectConcurrencyAsync(() => repository.UpdateAsync(wrapper)); } if (editContext.IsReordered()) { await _concurrencyService.EnsureCorrectConcurrencyAsync( () => repository.ReorderAsync(editContext.ReorderedBeforeId, editContext.Entity.Id !, new ViewContext(null, editContext.Parent))); } affectedEntities.Add(editContext.Entity); } response.RefreshIds = affectedEntities.SelectNotNull(x => x.Id); _mediator.NotifyEvent(this, new CollectionRepositoryEventArgs( collection.Alias, collection.RepositoryAlias, request.ListContext.ProtoEditContext.Parent?.GetParentPath(), response.RefreshIds, CrudType.Update)); break; case CrudType.None: response.NoOp = true; break; case CrudType.Refresh: break; case CrudType.Return: if (!_navigationStateProvider.RemoveNavigationState(request.NavigationState)) { var parentPath = request.ListContext.Parent?.GetParentPath(); _navigationStateProvider.AppendNavigationState( request.NavigationState, new NavigationState( request.ListContext.CollectionAlias, parentPath, request.Related, collection.ListEditor == null ? UsageType.View : UsageType.Edit, PageType.Collection)); } break; case CrudType.Up: var(newParentPath, repositoryAlias, parentId) = ParentPath.RemoveLevel(request.ListContext.Parent?.GetParentPath()); if (repositoryAlias == null) { break; } var parentCollection = collection.Parent != null && collection.Parent.Type == PageType.Collection ? await _collectionResolver.ResolveSetupAsync(collection.Parent.Alias) : default; if (parentCollection == null) { throw new InvalidOperationException("Cannot go Up on collection that is root."); } _navigationStateProvider.AppendNavigationState( request.NavigationState, new NavigationState( request.ListContext.CollectionAlias, newParentPath, parentCollection.EntityVariant.Alias, parentId, collection.ListEditor == null ? UsageType.View : UsageType.Edit)); break; case CrudType.Add when request.Related != null: _navigationStateProvider.AppendNavigationState( request.NavigationState, new NavigationState( request.ListContext.CollectionAlias, request.Related, UsageType.Add)); break; default: throw new InvalidOperationException(); } await _buttonInteraction.CompleteButtonInteractionAsync(request); return(response); }
public async Task <IEntity> GetAsync(GetEntityRequestModel request) { if (string.IsNullOrWhiteSpace(request.Subject.Id) && (request.UsageType.HasFlag(UsageType.View) || request.UsageType.HasFlag(UsageType.Edit))) { throw new InvalidOperationException($"Cannot View/Edit Node when id is null"); } if (!string.IsNullOrWhiteSpace(request.Subject.Id) && request.UsageType.HasFlag(UsageType.New)) { throw new InvalidOperationException($"Cannot New Node when id is not null"); } var repository = _repositoryResolver.GetRepository(request.Subject.RepositoryAlias ?? throw new ArgumentNullException()); var parent = await _parentService.GetParentAsync(ParentPath.TryParse(request.Subject.ParentPath)); var entityVariant = request.Subject.VariantAlias == null ? default : await _entityVariantResolver.ResolveSetupAsync(request.Subject.VariantAlias); var action = (request.UsageType & ~(UsageType.Node)) switch { UsageType.View => () => repository.GetByIdAsync(request.Subject.Id !, new ViewContext(null, parent)), UsageType.Edit => () => repository.GetByIdAsync(request.Subject.Id !, new ViewContext(null, parent)), UsageType.New => () => repository.NewAsync(new ViewContext(null, parent), entityVariant?.Type) !, _ => default(Func <Task <IEntity?> >) }; if (action == default) { throw new InvalidOperationException($"UsageType {request.UsageType} is invalid for this method"); } var entity = await action.Invoke(); if (entity == null) { throw new NotFoundException("Failed to get entity for given id"); } await _authService.EnsureAuthorizedUserAsync(request.UsageType, entity); return(entity); } }
public async Task <FormDataProvider?> GetDataProviderAsync(FieldSetup field) { if (!(field is PropertyFieldSetup propertyField && propertyField.Relation != null)) { return(null); } switch (propertyField.Relation) { case RepositoryRelationSetup collectionRelation: var collectionSetup = collectionRelation.CollectionAlias == null ? default : await _collectionSetupResolver.ResolveSetupAsync(collectionRelation.CollectionAlias); var repo = collectionRelation.RepositoryAlias != null ? _repositoryResolver.GetRepository(collectionRelation.RepositoryAlias) : collectionSetup != null ? _repositoryResolver.GetRepository(collectionSetup) : default; if (repo == null) { throw new InvalidOperationException($"Field {propertyField.Property!.PropertyName} has incorrectly configure relation, cannot find repository for alias {(collectionRelation.CollectionAlias ?? collectionRelation.RepositoryAlias)}."); } // TODO: investigate whether this can be moved to Setup to allow for better caching var idProperty = collectionRelation.IdProperty ?? collectionSetup?.ElementSetup?.IdProperty ?? throw new InvalidOperationException($"Field {propertyField.Property!.PropertyName} has incorrect Id property metadata."); var displayProperties = collectionRelation.DisplayProperties ?? collectionSetup?.ElementSetup?.DisplayProperties ?? throw new InvalidOperationException($"Field {propertyField.Property!.PropertyName} has incorrect display properties metadata."); var relatedElementGetter = collectionRelation.RelatedElementsGetter ?? ((collectionRelation.IsRelationToMany && propertyField.Property != null && propertyField.Property.PropertyType.IsAssignableTo(typeof(IEnumerable <IEntity>))) ? PropertyMetadataHelper.GetPropertyMetadata <IEnumerable <IEntity>, IEnumerable <object?> >(x => x.Select(idProperty.Getter)) : default); var provider = new CollectionDataProvider( repo, _concurrencyService, collectionRelation.RepositoryAlias, collectionRelation.CollectionAlias, relatedElementGetter, collectionRelation.EntityAsParent, collectionRelation.RepositoryParentSelector, idProperty, displayProperties, collectionRelation.RelatedEntityType ?? collectionSetup?.EntityVariant.Type ?? typeof(object), propertyField.Property !, _mediator); return(new FormDataProvider( propertyField.Property !, provider)); case DataProviderRelationSetup dataProviderRelation: var dataCollection = _serviceProvider.GetService <IDataCollection>(dataProviderRelation.DataCollectionType); if (dataProviderRelation.Configuration != null) { dataCollection.Configure(dataProviderRelation.Configuration); } return(new FormDataProvider(propertyField.Property !, dataCollection)); case ConcreteDataProviderRelationSetup concreteDataProvider: return(new FormDataProvider(propertyField.Property !, concreteDataProvider.DataCollection)); default: throw new InvalidOperationException(); } ; }
public async Task <TreeCollectionUI?> GetCollectionAsync(string alias, ParentPath?parentPath) { var collection = await _collectionResolver.ResolveSetupAsync(alias); if (collection == null) { throw new InvalidOperationException($"Failed to get collection for given alias ({alias})."); } var parent = await _parentService.GetParentAsync(parentPath); var isList = collection.UsageType.HasFlag(UsageType.List); var isListEditor = collection.ListEditor != null; var isListView = collection.ListView != null; var isDetails = collection.UsageType.HasFlag(UsageType.Details) && parent?.Entity != null; var respository = _repositoryResolver.GetRepository(collection); var entity = await _concurrencyService.EnsureCorrectConcurrencyAsync(async() => isList ?await respository.NewAsync(new ViewContext(collection.Alias, parent), collection.EntityVariant.Type) : await respository.GetByIdAsync(parent !.Entity.Id !, new ViewContext(collection.Alias, parent)) ?? throw new InvalidOperationException($"Failed to get detail entity for given alias ({alias}) -- a detail entity should always exist.")); var canEdit = (isList && isListEditor && await _authService.IsUserAuthorizedAsync(Operations.Update, entity)) || (isDetails && await _authService.IsUserAuthorizedAsync(Operations.Update, parent !.Entity)); var canView = isList && isListView && await _authService.IsUserAuthorizedAsync(Operations.Read, entity); if (!canEdit && !canView) { return(TreeCollectionUI.None); } var tree = new TreeCollectionUI(collection.Alias, collection.RepositoryAlias, collection.Name) { EntitiesVisible = collection.TreeView?.EntityVisibility == EntityVisibilty.Visible, RootVisible = collection.TreeView?.RootVisibility == CollectionRootVisibility.Visible, Icon = collection.Icon ?? "Database", Color = collection.Color, DefaultOpenEntities = collection.TreeView?.DefaultOpenEntities ?? false }; if (canEdit) { if (isList) { tree.NavigateTo = new NavigationState( collection.Alias, parentPath, UsageType.Edit); } else if (isDetails) { var entityVariant = collection.GetEntityVariant(entity); tree.NavigateTo = new NavigationState( collection.Alias, parentPath, entityVariant.Alias, parent !.Entity.Id, UsageType.Edit); } } else if (canView) { tree.NavigateTo = new NavigationState( collection.Alias, parentPath, UsageType.View); } return(tree); }