diff --git a/zero.Core/Api/MediaApi.cs b/zero.Core/Api/MediaApi.cs
index b1a463e9..759875ee 100644
--- a/zero.Core/Api/MediaApi.cs
+++ b/zero.Core/Api/MediaApi.cs
@@ -57,55 +57,6 @@ namespace zero.Core.Api
}
- ///
- public async Task> GetFolders(string parentId = null)
- {
- using (IAsyncDocumentSession session = Backoffice.Raven.OpenAsyncSession())
- {
- return await session.Query()
- .ForApp(Backoffice.AppId)
- .WhereIf(x => x.ParentId == parentId, !parentId.IsNullOrEmpty(), x => x.ParentId == null)
- .OrderByDescending(x => x.Name)
- .ToListAsync();
- }
- }
-
-
- ///
- public async Task> GetFolderHierarchy(string id)
- {
- using (IAsyncDocumentSession session = Backoffice.Raven.OpenAsyncSession())
- {
- MediaFolder_ByHierarchy.Result result = await session.Query()
- .ProjectInto()
- .Include(x => x.Path.Select(p => p.Id))
- .ForApp(Backoffice.AppId)
- .FirstOrDefaultAsync(x => x.Id == id);
-
- if (result == null)
- {
- return new List();
- }
-
- return (await session.LoadAsync(result.Path.Select(x => x.Id))).Select(x => x.Value).ToList();
- }
- }
-
-
- ///
- public async Task> SaveFolder(MediaFolder model)
- {
- return await Backoffice.Save(model, new MediaFolderValidator());
- }
-
-
- ///
- public async Task> DeleteFolder(string id)
- {
- return await Backoffice.DeleteById(id);
- }
-
-
///
public async Task Cleanup()
{
@@ -136,26 +87,6 @@ namespace zero.Core.Api
///
Task> Delete(string id);
- ///
- /// Get hierarchy for a folder
- ///
- Task> GetFolderHierarchy(string id);
-
- ///
- /// Get all folders with the specified parent or on root
- ///
- Task> GetFolders(string parentId = null);
-
- ///
- /// Creates or updates a folder
- ///
- Task> SaveFolder(MediaFolder model);
-
- ///
- /// Deletes a folder
- ///
- Task> DeleteFolder(string id);
-
///
/// Clean-up all media based on stored database information
///
diff --git a/zero.Core/Api/MediaFolderApi.cs b/zero.Core/Api/MediaFolderApi.cs
new file mode 100644
index 00000000..003458db
--- /dev/null
+++ b/zero.Core/Api/MediaFolderApi.cs
@@ -0,0 +1,157 @@
+using Raven.Client.Documents;
+using Raven.Client.Documents.Session;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using zero.Core.Database.Indexes;
+using zero.Core.Entities;
+using zero.Core.Extensions;
+using zero.Core.Validation;
+
+namespace zero.Core.Api
+{
+ public class MediaFolderApi : IMediaFolderApi
+ {
+ protected IAppAwareBackofficeStore Backoffice { get; private set; }
+
+
+ public MediaFolderApi(IAppAwareBackofficeStore backoffice)
+ {
+ Backoffice = backoffice;
+ }
+
+
+ ///
+ public async Task GetById(string id)
+ {
+ return await Backoffice.GetById(id);
+ }
+
+
+ ///
+ public async Task> GetAll(string parentId = null)
+ {
+ using (IAsyncDocumentSession session = Backoffice.Raven.OpenAsyncSession())
+ {
+ return await session.Query()
+ .ForApp(Backoffice.AppId)
+ .WhereIf(x => x.ParentId == parentId, !parentId.IsNullOrEmpty(), x => x.ParentId == null)
+ .OrderByDescending(x => x.Name)
+ .ToListAsync();
+ }
+ }
+
+
+ ///
+ public async Task> GetAllAsTree(string parentId = null)
+ {
+ List result = new List();
+
+ using (IAsyncDocumentSession session = Backoffice.Raven.OpenAsyncSession())
+ {
+ IList items = await session.Query()
+ .ForApp(Backoffice.AppId)
+ .WhereIf(x => x.ParentId == parentId, !parentId.IsNullOrEmpty(), x => x.ParentId == null)
+ .OrderByDescending(x => x.Name)
+ .ToListAsync();
+
+ foreach (MediaFolder folder in items)
+ {
+ result.Add(new TreeItem()
+ {
+ Id = folder.Id,
+ Name = folder.Name,
+ HasChildren = true,
+ ParentId = folder.ParentId,
+ Sort = folder.Sort,
+ Icon = "fth-folder"
+ });
+ }
+ }
+
+ if (parentId.IsNullOrEmpty())
+ {
+ result.Add(new TreeItem()
+ {
+ Id = "recyclebin",
+ ParentId = null,
+ Sort = 99999,
+ Name = "@page.recyclebin.name",
+ Icon = "fth-trash",
+ HasChildren = false
+ });
+ }
+
+ return result;
+ }
+
+
+ ///
+ public async Task> GetHierarchy(string id)
+ {
+ using (IAsyncDocumentSession session = Backoffice.Raven.OpenAsyncSession())
+ {
+ MediaFolder_ByHierarchy.Result result = await session.Query()
+ .ProjectInto()
+ .Include(x => x.Path.Select(p => p.Id))
+ .ForApp(Backoffice.AppId)
+ .FirstOrDefaultAsync(x => x.Id == id);
+
+ if (result == null)
+ {
+ return new List();
+ }
+
+ return (await session.LoadAsync(result.Path.Select(x => x.Id))).Select(x => x.Value).ToList();
+ }
+ }
+
+
+ ///
+ public async Task> Save(MediaFolder model)
+ {
+ return await Backoffice.Save(model, new MediaFolderValidator());
+ }
+
+
+ ///
+ public async Task> Delete(string id)
+ {
+ return await Backoffice.DeleteById(id);
+ }
+ }
+
+
+ public interface IMediaFolderApi
+ {
+ ///
+ /// Get application by Id
+ ///
+ Task GetById(string id);
+
+ ///
+ /// Get hierarchy for a folder
+ ///
+ Task> GetHierarchy(string id);
+
+ ///
+ /// Get all folders with the specified parent or on root
+ ///
+ Task> GetAll(string parentId = null);
+
+ ///
+ /// Get all folders with the specified parent or on root for tree output
+ ///
+ Task> GetAllAsTree(string parentId = null);
+
+ ///
+ /// Creates or updates a folder
+ ///
+ Task> Save(MediaFolder model);
+
+ ///
+ /// Deletes a folder
+ ///
+ Task> Delete(string id);
+ }
+}
diff --git a/zero.Core/Entities/Tree/TreeItem.cs b/zero.Core/Entities/Tree/TreeItem.cs
index 7bf558ce..f912ba02 100644
--- a/zero.Core/Entities/Tree/TreeItem.cs
+++ b/zero.Core/Entities/Tree/TreeItem.cs
@@ -18,7 +18,7 @@
///
/// Sort order
///
- public int Sort { get; set; }
+ public uint Sort { get; set; }
///
/// Name of the item
diff --git a/zero.Web.UI/App/pages/media/folder.vue b/zero.Web.UI/App/pages/media/folder.vue
new file mode 100644
index 00000000..4234979f
--- /dev/null
+++ b/zero.Web.UI/App/pages/media/folder.vue
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/zero.Web.UI/App/pages/media/media.vue b/zero.Web.UI/App/pages/media/media.vue
index bd39c618..9c535777 100644
--- a/zero.Web.UI/App/pages/media/media.vue
+++ b/zero.Web.UI/App/pages/media/media.vue
@@ -2,13 +2,14 @@