From 91548e2cd01ef589dd59ed1eeb0898e7ebf05f00 Mon Sep 17 00:00:00 2001 From: Tobias Klika Date: Mon, 17 Aug 2020 14:46:13 +0200 Subject: [PATCH] output revisions for pages --- zero.Core/Api/PagesApi.cs | 17 --- zero.Core/Api/RevisionsApi.cs | 77 ++++++++++++ zero.Core/Entities/Revision.cs | 43 +++---- .../RavenDocumentSessionExtensions.cs | 49 ++++++++ ...ons.cs => RavenDocumentStoreExtensions.cs} | 2 +- zero.Web.UI/App/components/date.vue | 22 +++- zero.Web.UI/App/components/revisions.vue | 112 ++++++++++++++++++ zero.Web.UI/App/pages/pages/page-info.vue | 33 +++++- zero.Web.UI/App/pages/pages/page.vue | 7 +- zero.Web.UI/App/services/strings.js | 7 +- zero.Web.UI/Sass/Modules/Buttons/_button.scss | 6 + zero.Web.UI/Sass/Modules/_box.scss | 16 +-- zero.Web.UI/Sass/Modules/_link.scss | 3 +- zero.Web/Controllers/PagesController.cs | 6 +- zero.Web/Defaults/ZeroBackofficePlugin.cs | 1 + 15 files changed, 330 insertions(+), 71 deletions(-) create mode 100644 zero.Core/Api/RevisionsApi.cs create mode 100644 zero.Core/Extensions/RavenDocumentSessionExtensions.cs rename zero.Core/Extensions/{DocumentStoreExtensions.cs => RavenDocumentStoreExtensions.cs} (98%) create mode 100644 zero.Web.UI/App/components/revisions.vue diff --git a/zero.Core/Api/PagesApi.cs b/zero.Core/Api/PagesApi.cs index cb44b008..52c7e49f 100644 --- a/zero.Core/Api/PagesApi.cs +++ b/zero.Core/Api/PagesApi.cs @@ -71,18 +71,6 @@ namespace zero.Core.Api } - /// - public async Task> GetRevisions(string id, int pageNumber = 1, int pageSize = 30) - { - using (IAsyncDocumentSession session = Raven.OpenAsyncSession()) - { - - List revisions = await session.Advanced.Revisions.GetForAsync(id, pageNumber - 1, pageSize); - return new ListResult(revisions, revisions.Count, pageNumber, pageSize); - } - } - - /// public async Task> Save(T model) { @@ -310,11 +298,6 @@ namespace zero.Core.Api /// PageType GetPageType(string alias); - /// - /// Get revisions of a page (if activated in RavenDB configuration) - /// - Task> GetRevisions(string id, int pageNumber = 1, int pageSize = 30); - /// /// Creates or updates a page /// diff --git a/zero.Core/Api/RevisionsApi.cs b/zero.Core/Api/RevisionsApi.cs new file mode 100644 index 00000000..f0672fcb --- /dev/null +++ b/zero.Core/Api/RevisionsApi.cs @@ -0,0 +1,77 @@ +using Newtonsoft.Json; +using Raven.Client.Documents; +using Raven.Client.Documents.Session; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using zero.Core.Entities; +using zero.Core.Extensions; +using zero.Core.Options; + +namespace zero.Core.Api +{ + public class RevisionsApi : IRevisionsApi + { + protected IZeroOptions Options { get; set; } + + protected IDocumentStore Raven { get; set; } + + + public RevisionsApi(IZeroOptions options, IDocumentStore raven) + { + Options = options; + Raven = raven; + } + + + /// + /// Get revision list for an entity + /// + public async Task> GetPaged(string id, int pageNumber = 1, int pageSize = 30, bool includeContent = false) where T : IZeroEntity + { + using IAsyncDocumentSession session = Raven.OpenAsyncSession(); + + List items = await session.Advanced.Revisions.GetForAsync(id, pageNumber - 1, pageSize); + List revisions = new List(); + + string[] userIds = items.Select(x => x.LastModifiedById).Distinct().ToArray(); + Dictionary users = await session.LoadAsync(userIds); + + foreach (T item in items) + { + DateTime? date = session.Advanced.GetLastModifiedFor(item); + + Revision revision = new Revision() + { + ChangeVector = session.Advanced.GetChangeVectorFor(item), + Date = date.HasValue ? new DateTimeOffset(date.Value) : item.CreatedDate, + Json = includeContent ? JsonConvert.SerializeObject(item) : null + }; + + if (!item.LastModifiedById.IsNullOrEmpty() && users.TryGetValue(item.LastModifiedById, out User user)) + { + revision.User = new RevisionUser() + { + AvatarId = user.AvatarId, + Id = user.Id, + Name = user.Name + }; + } + + revisions.Add(revision); + } + + return new ListResult(revisions, revisions.Count, pageNumber, pageSize); + } + } + + + public interface IRevisionsApi + { + /// + /// Get revision list (without content JSON) for an entity + /// + Task> GetPaged(string id, int pageNumber = 1, int pageSize = 30, bool includeContent = false) where T : IZeroEntity; + } +} diff --git a/zero.Core/Entities/Revision.cs b/zero.Core/Entities/Revision.cs index 4b34b46e..884e2fc7 100644 --- a/zero.Core/Entities/Revision.cs +++ b/zero.Core/Entities/Revision.cs @@ -1,29 +1,24 @@ -//using System; +using System; -//namespace zero.Core.Entities -//{ -// public class Revision : ZeroEntity, IRevision -// { -// /// -// public string Content { get; set; } -// } +namespace zero.Core.Entities +{ + public class Revision + { + public RevisionUser User { get; set; } + public DateTimeOffset Date { get; set; } -// public interface IRevision : IZeroEntity, IZeroDbConventions -// { -// /// -// /// Id of the affected entity -// /// -// string EntityId { get; set; } + public string ChangeVector { get; set; } -// /// -// /// Id of the affected entity -// /// -// string EntityId { get; set; } + public string Json { get; set; } + } -// /// -// /// Contains the content as JSON -// /// -// string Content { get; set; } -// } -//} + public class RevisionUser + { + public string Id { get; set; } + + public string Name { get; set; } + + public string AvatarId { get; set; } + } +} diff --git a/zero.Core/Extensions/RavenDocumentSessionExtensions.cs b/zero.Core/Extensions/RavenDocumentSessionExtensions.cs new file mode 100644 index 00000000..04b08ada --- /dev/null +++ b/zero.Core/Extensions/RavenDocumentSessionExtensions.cs @@ -0,0 +1,49 @@ +using Raven.Client.Documents.Session; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using zero.Core.Entities; + +namespace zero.Core.Extensions +{ + public static class RavenDocumentSessionExtensions + { + /// + /// Get revision list (without content JSON) for an entity + /// + public static async Task> GetRevisions(this IAsyncDocumentSession session, string id, int pageNumber = 1, int pageSize = 30) where T : IZeroEntity + { + List items = await session.Advanced.Revisions.GetForAsync(id, pageNumber - 1, pageSize); + List revisions = new List(); + + string[] userIds = items.Select(x => x.LastModifiedById).Distinct().ToArray(); + Dictionary users = await session.LoadAsync(userIds); + + foreach (T item in items) + { + DateTime? date = session.Advanced.GetLastModifiedFor(item); + + Revision revision = new Revision() + { + ChangeVector = session.Advanced.GetChangeVectorFor(item), + Date = date.HasValue ? new DateTimeOffset(date.Value) : item.CreatedDate + }; + + if (!item.LastModifiedById.IsNullOrEmpty() && users.TryGetValue(item.LastModifiedById, out User user)) + { + revision.User = new RevisionUser() + { + AvatarId = user.AvatarId, + Id = user.Id, + Name = user.Name + }; + } + + revisions.Add(revision); + } + + return new ListResult(revisions, revisions.Count, pageNumber, pageSize); + } + } +} diff --git a/zero.Core/Extensions/DocumentStoreExtensions.cs b/zero.Core/Extensions/RavenDocumentStoreExtensions.cs similarity index 98% rename from zero.Core/Extensions/DocumentStoreExtensions.cs rename to zero.Core/Extensions/RavenDocumentStoreExtensions.cs index 123576f6..4e0c2772 100644 --- a/zero.Core/Extensions/DocumentStoreExtensions.cs +++ b/zero.Core/Extensions/RavenDocumentStoreExtensions.cs @@ -12,7 +12,7 @@ using zero.Core.Utils; namespace zero.Core.Extensions { - public static class DocumentStoreExtensions + public static class RavenDocumentStoreExtensions { /// /// Setup conventions for the document store diff --git a/zero.Web.UI/App/components/date.vue b/zero.Web.UI/App/components/date.vue index 2dc7664c..03f9879a 100644 --- a/zero.Web.UI/App/components/date.vue +++ b/zero.Web.UI/App/components/date.vue @@ -18,6 +18,10 @@ format: { type: String, default: null + }, + split: { + type: Boolean, + default: false } }, @@ -47,10 +51,24 @@ return; } - this.output = Strings.date(this.value, this.format); + if (!this.split) + { + this.output = Strings.date(this.value, this.format); + } + else + { + this.output = Strings.date(this.value, 'short') + ' ' + Strings.date(this.value, 'time') + ''; + } } } } - \ No newline at end of file + + + \ No newline at end of file diff --git a/zero.Web.UI/App/components/revisions.vue b/zero.Web.UI/App/components/revisions.vue new file mode 100644 index 00000000..c343aedf --- /dev/null +++ b/zero.Web.UI/App/components/revisions.vue @@ -0,0 +1,112 @@ + + + + + + + \ No newline at end of file diff --git a/zero.Web.UI/App/pages/pages/page-info.vue b/zero.Web.UI/App/pages/pages/page-info.vue index 1dc1626d..7420a481 100644 --- a/zero.Web.UI/App/pages/pages/page-info.vue +++ b/zero.Web.UI/App/pages/pages/page-info.vue @@ -1,7 +1,11 @@  - + @@ -82,11 +82,6 @@ onLoad(form) { - PagesApi.getRevisions(this.id).then(response => - { - console.info(response); - }); - form.load(!this.id ? PagesApi.getEmpty(this.type, this.parent) : PagesApi.getById(this.id)).then(response => { this.renderer = 'page.' + response.entity.pageTypeAlias; diff --git a/zero.Web.UI/App/services/strings.js b/zero.Web.UI/App/services/strings.js index 1e06c5b3..b3e5abdf 100644 --- a/zero.Web.UI/App/services/strings.js +++ b/zero.Web.UI/App/services/strings.js @@ -2,8 +2,9 @@ import dayjs from 'dayjs'; const BYTE_UNIT = 'B'; const UNITS = ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; -const DATETIME_FORMAT = 'DD.MM.YY HH:mm'; const DATE_FORMAT = 'DD.MM.YY'; +const TIME_FORMAT = 'HH:mm'; +const DATETIME_FORMAT = DATE_FORMAT + ' ' + TIME_FORMAT; export default { /// @@ -59,6 +60,10 @@ export default { { format = DATE_FORMAT; } + else if (format === 'time') + { + format = TIME_FORMAT; + } return dayjs(value).format(format); }, diff --git a/zero.Web.UI/Sass/Modules/Buttons/_button.scss b/zero.Web.UI/Sass/Modules/Buttons/_button.scss index 6a90bce2..5eb6406c 100644 --- a/zero.Web.UI/Sass/Modules/Buttons/_button.scss +++ b/zero.Web.UI/Sass/Modules/Buttons/_button.scss @@ -99,6 +99,12 @@ button::-moz-focus-inner padding: 0 30px; } + &.type-small + { + height: 32px; + padding: 0 12px; + } + &.type-light { background: var(--color-bg-bright-two); diff --git a/zero.Web.UI/Sass/Modules/_box.scss b/zero.Web.UI/Sass/Modules/_box.scss index 1f682b5a..f4d0b099 100644 --- a/zero.Web.UI/Sass/Modules/_box.scss +++ b/zero.Web.UI/Sass/Modules/_box.scss @@ -9,19 +9,11 @@ border-radius: var(--radius); box-shadow: var(--color-shadow-short); /*max-width: 1104px;*/ - - h2 + + h2, h3 { - margin: -5px -32px var(--padding); - padding: 0 var(--padding) 25px; - //border-bottom: 1px solid var(--color-line-light); - } - - h3 - { - margin: -5px -32px var(--padding); - padding: 0 var(--padding) 25px; - //border-bottom: 1px solid var(--color-line-light); + margin: -5px 0 25px; + padding: 0; } .ui-property-content & diff --git a/zero.Web.UI/Sass/Modules/_link.scss b/zero.Web.UI/Sass/Modules/_link.scss index 9a75fb3f..305995f3 100644 --- a/zero.Web.UI/Sass/Modules/_link.scss +++ b/zero.Web.UI/Sass/Modules/_link.scss @@ -3,5 +3,6 @@ .ui-link { color: var(--color-primary); - text-decoration: underline dotted; + text-decoration: underline dotted var(--color-fg-dim-two); + text-underline-offset: 3px; } \ No newline at end of file diff --git a/zero.Web/Controllers/PagesController.cs b/zero.Web/Controllers/PagesController.cs index e8929233..1e716bba 100644 --- a/zero.Web/Controllers/PagesController.cs +++ b/zero.Web/Controllers/PagesController.cs @@ -8,10 +8,12 @@ namespace zero.Web.Controllers public class PagesController : BackofficeController where T : IPage, new() { IPagesApi Api; + IRevisionsApi RevisionsApi; - public PagesController(IPagesApi api) + public PagesController(IPagesApi api, IRevisionsApi revisionsApi) { Api = api; + RevisionsApi = revisionsApi; } @@ -28,7 +30,7 @@ namespace zero.Web.Controllers ParentId = parent }); - public async Task GetRevisions([FromQuery] string id) => Json(await Api.GetRevisions(id)); + public async Task GetRevisions([FromQuery] string id) => Json(await RevisionsApi.GetPaged(id)); public async Task Save([FromBody] T model) => Json(await Api.Save(model)); diff --git a/zero.Web/Defaults/ZeroBackofficePlugin.cs b/zero.Web/Defaults/ZeroBackofficePlugin.cs index 9ae07630..cbe875bb 100644 --- a/zero.Web/Defaults/ZeroBackofficePlugin.cs +++ b/zero.Web/Defaults/ZeroBackofficePlugin.cs @@ -43,6 +43,7 @@ namespace zero.Web.Defaults services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient();