GetRollbackVersions(int contentId, string culture = null)
{
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js
index a836f8db3d7b..b6f45ead0e1e 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js
@@ -1234,6 +1234,186 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
),
"Failed to roll back content item with id " + contentId
);
+ },
+
+ /**
+ * @ngdoc method
+ * @name umbraco.resources.contentResource#getPublicAccess
+ * @methodOf umbraco.resources.contentResource
+ *
+ * @description
+ * Returns the public access protection for a content item
+ *
+ * ##usage
+ *
+ * contentResource.getPublicAccess(contentId)
+ * .then(function(publicAccess) {
+ * // do your thing
+ * });
+ *
+ *
+ * @param {Int} contentId The content Id
+ * @returns {Promise} resourcePromise object containing the public access protection
+ *
+ */
+ getPublicAccess: function (contentId) {
+ return umbRequestHelper.resourcePromise(
+ $http.get(
+ umbRequestHelper.getApiUrl("contentApiBaseUrl", "GetPublicAccess", {
+ contentId: contentId
+ })
+ ),
+ "Failed to get public access for content item with id " + contentId
+ );
+ },
+
+ /**
+ * @ngdoc method
+ * @name umbraco.resources.contentResource#updatePublicAccess
+ * @methodOf umbraco.resources.contentResource
+ *
+ * @description
+ * Sets or updates the public access protection for a content item
+ *
+ * ##usage
+ *
+ * contentResource.updatePublicAccess(contentId, userName, password, roles, loginPageId, errorPageId)
+ * .then(function() {
+ * // do your thing
+ * });
+ *
+ *
+ * @param {Int} contentId The content Id
+ * @param {Array} groups The names of the groups that should have access (if using group based protection)
+ * @param {Array} usernames The usernames of the members that should have access (if using member based protection)
+ * @param {Int} loginPageId The Id of the login page
+ * @param {Int} errorPageId The Id of the error page
+ * @returns {Promise} resourcePromise object containing the public access protection
+ *
+ */
+ updatePublicAccess: function (contentId, groups, usernames, loginPageId, errorPageId) {
+ var publicAccess = {
+ contentId: contentId,
+ loginPageId: loginPageId,
+ errorPageId: errorPageId
+ };
+ if (Utilities.isArray(groups) && groups.length) {
+ publicAccess.groups = groups;
+ }
+ else if (Utilities.isArray(usernames) && usernames.length) {
+ publicAccess.usernames = usernames;
+ }
+ else {
+ throw "must supply either userName/password or roles";
+ }
+ return umbRequestHelper.resourcePromise(
+ $http.post(
+ umbRequestHelper.getApiUrl("contentApiBaseUrl", "PostPublicAccess", publicAccess)
+ ),
+ "Failed to update public access for content item with id " + contentId
+ );
+ },
+
+ /**
+ * @ngdoc method
+ * @name umbraco.resources.contentResource#removePublicAccess
+ * @methodOf umbraco.resources.contentResource
+ *
+ * @description
+ * Removes the public access protection for a content item
+ *
+ * ##usage
+ *
+ * contentResource.removePublicAccess(contentId)
+ * .then(function() {
+ * // do your thing
+ * });
+ *
+ *
+ * @param {Int} contentId The content Id
+ * @returns {Promise} resourcePromise object that's resolved once the public access has been removed
+ *
+ */
+ removePublicAccess: function (contentId) {
+ return umbRequestHelper.resourcePromise(
+ $http.post(
+ umbRequestHelper.getApiUrl("contentApiBaseUrl", "RemovePublicAccess", {
+ contentId: contentId
+ })
+ ),
+ "Failed to remove public access for content item with id " + contentId
+ );
+ },
+
+ /**
+ * @ngdoc method
+ * @name umbraco.resources.contentResource#getPagedContentVersions
+ * @methodOf umbraco.resources.contentResource
+ *
+ * @description
+ * Returns a paged array of previous version id's, given a node id, pageNumber, pageSize and a culture
+ *
+ * ##usage
+ *
+ * contentResource.getPagedContentVersions(id, pageNumber, pageSize, culture)
+ * .then(function(versions) {
+ * alert('its here!');
+ * });
+ *
+ *
+ * @param {Int} id Id of node
+ * @param {Int} pageNumber page number
+ * @param {Int} pageSize page size
+ * @param {Int} culture if provided, the results will be for this specific culture/variant
+ * @returns {Promise} resourcePromise object containing the versions
+ *
+ */
+ getPagedContentVersions: function (contentId, pageNumber, pageSize, culture) {
+ return umbRequestHelper.resourcePromise(
+ $http.get(
+ umbRequestHelper.getApiUrl("contentApiBaseUrl", "GetPagedContentVersions", {
+ contentId: contentId,
+ pageNumber: pageNumber,
+ pageSize: pageSize,
+ culture: culture
+ })
+ ),
+ "Failed to get versions for content item with id " + contentId
+ );
+ },
+
+ /**
+ * @ngdoc method
+ * @name umbraco.resources.contentResource#contentVersionPreventCleanup
+ * @methodOf umbraco.resources.contentResource
+ *
+ * @description
+ * Enables or disabled clean up of a version
+ *
+ * ##usage
+ *
+ * contentResource.contentVersionPreventCleanup(contentId, versionId, preventCleanup)
+ * .then(function() {
+ * // do your thing
+ * });
+ *
+ *
+ * @param {Int} contentId Id of node
+ * @param {Int} versionId Id of version
+ * @param {Int} preventCleanup Boolean to toggle clean up prevention
+ *
+ */
+ contentVersionPreventCleanup: function (contentId, versionId, preventCleanup) {
+ return umbRequestHelper.resourcePromise(
+ $http.post(
+ umbRequestHelper.getApiUrl("contentApiBaseUrl", "PostSetContentVersionPreventCleanup", {
+ contentId: contentId,
+ versionId: versionId,
+ preventCleanup: preventCleanup
+ })
+ ),
+ "Failed to toggle prevent cleanup of version with id " + versionId
+ );
}
};
}
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js
index 1f65bd7cea01..b146f471e0d8 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js
@@ -527,7 +527,7 @@ When building a custom infinite editor view you can use the same components as a
*/
function rollback(editor) {
editor.view = "views/common/infiniteeditors/rollback/rollback.html";
- if (!editor.size) editor.size = "medium";
+ if (!editor.size) editor.size = "";
open(editor);
}
diff --git a/src/Umbraco.Web.UI.Client/src/less/belle.less b/src/Umbraco.Web.UI.Client/src/less/belle.less
index 6f95608d7a8d..ba4df33aa0b3 100644
--- a/src/Umbraco.Web.UI.Client/src/less/belle.less
+++ b/src/Umbraco.Web.UI.Client/src/less/belle.less
@@ -203,6 +203,8 @@
@import "components/umbemailmarketing.less";
+// Editors
+@import "../views/common/infiniteeditors/rollback/rollback.less";
// Property Editors
@import "../views/components/blockcard/umb-block-card-grid.less";
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button.less b/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button.less
index b6800aba65fc..88e172db0ced 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button.less
@@ -91,6 +91,11 @@
color: @white;
}
+.umb-button__success.-black,
+.umb-button__error.-black {
+ color: @black;
+}
+
.umb-button__overlay {
position: absolute;
width: 100%;
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.controller.js
index 4b0dfcb8b47a..7f1dbad69153 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.controller.js
@@ -1,7 +1,7 @@
(function () {
"use strict";
- function RollbackController($scope, contentResource, localizationService, assetsService, dateHelper, userService) {
+ function RollbackController($scope, contentResource, localizationService, assetsService, dateHelper, userService, notificationsService) {
var vm = this;
@@ -10,6 +10,9 @@
vm.changeVersion = changeVersion;
vm.submit = submit;
vm.close = close;
+ vm.pinVersion = pinVersion;
+ vm.goToPage = goToPage;
+ vm.paginationCount = { from: 0, to: 0, total: 0 };
//////////
@@ -22,6 +25,11 @@
vm.rollbackButtonDisabled = true;
vm.labels = {};
+ vm.pageSize = 15;
+ vm.pageNumber = 1;
+ vm.totalPages = 1;
+ vm.totalItems = 0;
+
// find the current version for invariant nodes
if($scope.model.node.variants.length === 1) {
vm.currentVersion = $scope.model.node.variants[0];
@@ -61,27 +69,40 @@
function changeLanguage(language) {
vm.currentVersion = language;
+ vm.pageNumber = 1;
getVersions();
}
function changeVersion(version) {
- if(version && version.versionId) {
+ const canRollback = !version.currentDraftVersion && !version.currentPublishedVersion;
- vm.loading = true;
+ if (canRollback === false) {
+ return;
+ }
+ if (vm.previousVersion && version && vm.previousVersion.versionId === version.versionId) {
+ vm.previousVersion = null;
+ vm.diff = null;
+ vm.rollbackButtonDisabled = true;
+ return;
+ }
+
+ if (version && version.versionId) {
+ vm.loadingDiff = true;
const culture = $scope.model.node.variants.length > 1 ? vm.currentVersion.language.culture : null;
contentResource.getRollbackVersion(version.versionId, culture)
.then(function(data) {
vm.previousVersion = data;
vm.previousVersion.versionId = version.versionId;
+ vm.previousVersion.displayValue = version.displayValue + ' - ' + version.username;
createDiff(vm.currentVersion, vm.previousVersion);
- vm.loading = false;
+ vm.loadingDiff = false;
vm.rollbackButtonDisabled = false;
}, function () {
- vm.loading = false;
+ vm.loadingDiff = false;
});
} else {
@@ -93,15 +114,26 @@
function getVersions() {
const nodeId = $scope.model.node.id;
- const culture = $scope.model.node.variants.length > 1 ? vm.currentVersion.language.culture : null;
+ const culture = vm.currentVersion.language ? vm.currentVersion.language.culture : null;
- return contentResource.getRollbackVersions(nodeId, culture)
+ return contentResource.getPagedContentVersions(nodeId, vm.pageNumber, vm.pageSize, culture)
.then(function (data) {
+ vm.totalPages = data.totalPages;
+ vm.totalItems = data.totalItems;
+
+ const possibleTotalItems = vm.pageNumber * vm.pageSize;
+
+ vm.paginationCount = {
+ from: (vm.pageNumber * vm.pageSize - vm.pageSize) + 1,
+ to: vm.totalItems < possibleTotalItems ? vm.totalItems : possibleTotalItems,
+ total: vm.totalItems
+ };
+
// get current backoffice user and format dates
userService.getCurrentUser().then(function (currentUser) {
- vm.previousVersions = data.map(version => {
+ vm.previousVersions = data.items.map(version => {
var timestampFormatted = dateHelper.getLocalDate(version.versionDate, currentUser.locale, 'LLL');
- version.displayValue = timestampFormatted + ' - ' + version.versionAuthorName;
+ version.displayValue = timestampFormatted;
return version;
});
});
@@ -200,6 +232,39 @@
}
}
+ function pinVersion (version, event) {
+ if (!version) {
+ return;
+ }
+
+ version.pinningState = 'busy';
+
+ const nodeId = $scope.model.node.id;
+ const versionId = version.versionId;
+ const preventCleanup = !version.preventCleanup;
+
+ contentResource.contentVersionPreventCleanup(nodeId, versionId, preventCleanup)
+ .then(() => {
+ version.pinningState = 'success';
+ version.preventCleanup = preventCleanup;
+ }, () => {
+ version.pinningState = 'error';
+
+ const localizationKey = preventCleanup ? 'speechBubbles_preventCleanupEnableError' : 'speechBubbles_preventCleanupDisableError';
+
+ localizationService.localize(localizationKey).then(value => {
+ notificationsService.error(value);
+ });
+ });
+
+ event.stopPropagation();
+ }
+
+ function goToPage (pageNumber) {
+ vm.pageNumber = pageNumber;
+ getVersions();
+ }
+
onInit();
}
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.html
index e48b5991f602..a5ac2ea6cb4c 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.html
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.html
@@ -1,4 +1,4 @@
-
+
@@ -16,75 +16,138 @@
ng-if="vm.loading">
-
-
-
-
-
Language
-
-
-
-
-
-
-
Current version
-
{{vm.currentVersion.name}} (Created : {{vm.currentVersion.createDate}})
-
-
Rollback to
-
- {{vm.labels.choose}}...
-
-
-
-
-
-
Changes
-
-
- This shows the differences between the current version and the selected versionRed text will be
- removed in the selected version, green text will be added
+
+
+
+
+
+
-
-
-
-
-
- Name
-
-
-
- {{part.value}}
- {{part.value}}
- {{part.value}}
-
-
-
-
- {{property.label}}
-
-
- {{part.value}}
- {{part.value}}
- {{part.value}}
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
Language
+
+
+
+
+
+
+ Current version :
+ {{vm.currentVersion.name}} (Created : {{vm.currentVersion.createDate}})
+
+
+
+
+
+
+
+
+
+
{{ version.displayValue }}
+
{{version.username}}
+
+ Current version
+ Current version
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This shows the differences between the current version and the selected versionRed text will be
+ removed in the selected version, green text will be added
+
+
+
+
+
+
+
+ Name
+
+
+
+ {{part.value}}
+ {{part.value}}
+ {{part.value}}
+
+
+
+
+ {{property.label}}
+
+
+ {{part.value}}
+ {{part.value}}
+ {{part.value}}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.less b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.less
new file mode 100644
index 000000000000..e7953a4feada
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.less
@@ -0,0 +1,32 @@
+.editor-rollback {
+
+ .main-content {
+ display: flex;
+ gap: 20px;
+ }
+
+ .side-panel {
+ flex: 0 0 33%;
+ }
+
+ .compare-panel {
+ flex: 1 1 auto;
+ position: relative;
+ }
+
+ .current-version {
+ background: @gray-10;
+ padding: 15px;
+ margin-bottom: 12px;
+ }
+
+ .culture-select {
+ margin-bottom: 12px;
+ }
+
+ .version-details {
+ color: @gray-5;
+ font-size: 13px;
+ }
+
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-button.html b/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-button.html
index 552d0ffdb578..365aad38171a 100644
--- a/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-button.html
+++ b/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-button.html
@@ -1,9 +1,9 @@