From ca6d2957eaa7e4813c0ea7ec0caa6f0996787a77 Mon Sep 17 00:00:00 2001 From: Tobias Klika Date: Fri, 29 May 2020 15:46:03 +0200 Subject: [PATCH] create and load nested media --- zero.Core/Api/MediaFolderApi.cs | 61 ++++++++++++++++--- .../Indexes/MediaFolders_WithChildren.cs | 48 +++++++++++++++ zero.Web.UI/App/pages/media/folder.vue | 2 - zero.Web.UI/App/pages/media/media.vue | 9 +-- zero.Web.UI/App/resources/media-folder.js | 9 ++- zero.Web/Controllers/MediaFolderController.cs | 4 +- 6 files changed, 113 insertions(+), 20 deletions(-) create mode 100644 zero.Core/Database/Indexes/MediaFolders_WithChildren.cs diff --git a/zero.Core/Api/MediaFolderApi.cs b/zero.Core/Api/MediaFolderApi.cs index dc5c4845..b24d0ead 100644 --- a/zero.Core/Api/MediaFolderApi.cs +++ b/zero.Core/Api/MediaFolderApi.cs @@ -1,4 +1,5 @@ using Raven.Client.Documents; +using Raven.Client.Documents.Linq; using Raven.Client.Documents.Session; using System.Collections.Generic; using System.Linq; @@ -37,35 +38,74 @@ namespace zero.Core.Api /// - public async Task> GetAllAsTree(string parentId = null) + public async Task> GetAllAsTree(string parentId = null, string activeId = null) { - List result = new List(); + List items = new List(); + string[] openIds = new string[0] { }; using (IAsyncDocumentSession session = Raven.OpenAsyncSession()) { - IList items = await session.Query() + IList folders = await session.Query() .Scope(Scope) .WhereIf(x => x.ParentId == parentId, !parentId.IsNullOrEmpty(), x => x.ParentId == null) .OrderByDescending(x => x.Name) .ToListAsync(); - foreach (MediaFolder folder in items) + + // get hierarchy so we know if we should set the folder to open + if (!activeId.IsNullOrEmpty()) { - result.Add(new TreeItem() + MediaFolder_ByHierarchy.Result result = await session.Query() + .ProjectInto() + .Include(x => x.Path.Select(p => p.Id)) + .Scope(Scope) + .FirstOrDefaultAsync(x => x.Id == activeId); + + if (result != null) + { + openIds = result.Path.Select(x => x.Id).ToArray(); + } + } + + + // get children for all folders + string[] folderIds = folders.Select(x => x.Id).ToArray(); + + IList children = await session.Query() + .ProjectInto() + .Scope(Scope) + .Where(x => x.Id.In(folderIds)) + .ToListAsync(); + + + foreach (MediaFolder folder in folders) + { + int childCount = children.Count(x => x.Id == folder.Id); + + items.Add(new TreeItem() { Id = folder.Id, Name = folder.Name, - HasChildren = true, + HasChildren = childCount > 0, + ChildCount = childCount, ParentId = folder.ParentId, Sort = folder.Sort, - Icon = "fth-folder" + Icon = "fth-folder", + IsOpen = openIds.Contains(folder.Id), + IsInactive = !folder.IsActive, + HasActions = true, + Modifier = !folder.IsActive ? new TreeItemModifier() + { + Icon = "fth-minus-circle color-red", + Name = "Inactive" + } : null }); } } if (parentId.IsNullOrEmpty()) { - result.Add(new TreeItem() + items.Add(new TreeItem() { Id = "recyclebin", ParentId = null, @@ -76,7 +116,7 @@ namespace zero.Core.Api }); } - return result; + return items; } @@ -104,6 +144,7 @@ namespace zero.Core.Api /// public async Task> Save(MediaFolder model) { + model.IsActive = true; return await SaveModel(model, new MediaFolderValidator()); } @@ -136,7 +177,7 @@ namespace zero.Core.Api /// /// Get all folders with the specified parent or on root for tree output /// - Task> GetAllAsTree(string parentId = null); + Task> GetAllAsTree(string parentId = null, string activeId = null); /// /// Creates or updates a folder diff --git a/zero.Core/Database/Indexes/MediaFolders_WithChildren.cs b/zero.Core/Database/Indexes/MediaFolders_WithChildren.cs new file mode 100644 index 00000000..7f396a42 --- /dev/null +++ b/zero.Core/Database/Indexes/MediaFolders_WithChildren.cs @@ -0,0 +1,48 @@ +using Raven.Client.Documents.Indexes; +using System; +using System.Linq; +using zero.Core.Entities; + +namespace zero.Core.Database.Indexes +{ + public class MediaFolders_WithChildren : AbstractIndexCreationTask + { + public class Result : IZeroIdEntity, IAppAwareEntity, IZeroDbConventions + { + public string Id { get; set; } + + public string ParentId { get; set; } + + public string AppId { get; set; } + + public string Name { get; set; } + + public string[] ChildrenIds { get; set; } + } + + + public MediaFolders_WithChildren() + { + Map = items => items.Where(x => x.ParentId != null).Select(item => new Result + { + Id = item.Id, + ParentId = item.ParentId, + Name = item.Name, + AppId = item.AppId, + ChildrenIds = new string[] { } + }); + + Reduce = results => results.GroupBy(x => new { x.ParentId, x.AppId }).Select(group => new Result() + { + Id = group.Key.ParentId, + ParentId = group.Key.ParentId, + Name = String.Empty, + AppId = group.Key.AppId, + ChildrenIds = group.Select(x => x.Id).ToArray() + }); + + StoreAllFields(FieldStorage.Yes); + //Index(x => x.ChannelId, FieldIndexing.Exact); + } + } +} diff --git a/zero.Web.UI/App/pages/media/folder.vue b/zero.Web.UI/App/pages/media/folder.vue index 639b29bf..6439c236 100644 --- a/zero.Web.UI/App/pages/media/folder.vue +++ b/zero.Web.UI/App/pages/media/folder.vue @@ -37,8 +37,6 @@ onLoad(form) { - console.info(JSON.parse(JSON.stringify(this.model))); - form.load(!this.model.id ? MediaFolderApi.getEmpty() : MediaFolderApi.getById(this.model.id)).then(response => { this.disabled = !response.canEdit; diff --git a/zero.Web.UI/App/pages/media/media.vue b/zero.Web.UI/App/pages/media/media.vue index 97e77808..cc1c4f7f 100644 --- a/zero.Web.UI/App/pages/media/media.vue +++ b/zero.Web.UI/App/pages/media/media.vue @@ -138,6 +138,7 @@ watch: { '$route'() { + this.cache = {}; this.getItems(); } }, @@ -177,7 +178,7 @@ return Promise.resolve(this.cache[key]); } - return MediaFolderApi.getAllAsTree(parent).then(response => + return MediaFolderApi.getAllAsTree(parent, this.id).then(response => { response.forEach(item => { @@ -211,10 +212,10 @@ { setTimeout(() => { - this.cache = {}; this.$refs.tree.refresh(); - this.getItems(); - }, 1000); + this.$router.push({ name: 'mediafolder', params: { id: item.model.id } }); + //this.getItems(); + }, 500); }, () => { }); }, diff --git a/zero.Web.UI/App/resources/media-folder.js b/zero.Web.UI/App/resources/media-folder.js index da501e23..71333d62 100644 --- a/zero.Web.UI/App/resources/media-folder.js +++ b/zero.Web.UI/App/resources/media-folder.js @@ -17,9 +17,14 @@ export default { }, // get all folder with a certain parent (can be empty) as tree - getAllAsTree(parent) + getAllAsTree(parent, active) { - return Axios.get(base + 'getAllAsTree', { params: { parent } }).then(res => Promise.resolve(res.data)); + return Axios.get(base + 'getAllAsTree', { + params: { + parent: parent, + active: active + } + }).then(res => Promise.resolve(res.data)); }, // save a media folder diff --git a/zero.Web/Controllers/MediaFolderController.cs b/zero.Web/Controllers/MediaFolderController.cs index fab0e7d3..dfd92555 100644 --- a/zero.Web/Controllers/MediaFolderController.cs +++ b/zero.Web/Controllers/MediaFolderController.cs @@ -41,9 +41,9 @@ namespace zero.Web.Controllers /// /// Get all folders with a specific parent as tree /// - public async Task GetAllAsTree([FromQuery] string parent = null) + public async Task GetAllAsTree([FromQuery] string parent = null, [FromQuery] string active = null) { - return Json(await Api.GetAllAsTree(parent)); + return Json(await Api.GetAllAsTree(parent, active)); }