Merge pull request #3312 from umbraco/temp8-3298-move-rollback

Temp8 3298 move rollback
This commit is contained in:
Warren Buckley
2018-10-23 09:28:41 +01:00
committed by GitHub
28 changed files with 733 additions and 751 deletions
@@ -19,6 +19,12 @@ namespace Umbraco.Core.Persistence.Repositories
/// <remarks>Current version is first, and then versions are ordered with most recent first.</remarks>
IEnumerable<TEntity> GetAllVersions(int nodeId);
/// <summary>
/// Gets versions.
/// </summary>
/// <remarks>Current version is first, and then versions are ordered with most recent first.</remarks>
IEnumerable<TEntity> GetAllVersionsSlim(int nodeId, int skip, int take);
/// <summary>
/// Gets version identifiers.
/// </summary>
@@ -53,6 +53,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// gets all versions, current first
public abstract IEnumerable<TEntity> GetAllVersions(int nodeId);
// gets all versions, current first
public virtual IEnumerable<TEntity> GetAllVersionsSlim(int nodeId, int skip, int take)
=> GetAllVersions(nodeId).Skip(skip).Take(take);
// gets all version ids, current first
public virtual IEnumerable<int> GetVersionIds(int nodeId, int maxRows)
{
@@ -220,6 +220,16 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return MapDtosToContent(Database.Fetch<DocumentDto>(sql), true);
}
public override IEnumerable<IContent> GetAllVersionsSlim(int nodeId, int skip, int take)
{
var sql = GetBaseQuery(QueryType.Many, false)
.Where<NodeDto>(x => x.NodeId == nodeId)
.OrderByDescending<ContentVersionDto>(x => x.Current)
.AndByDescending<ContentVersionDto>(x => x.VersionDate);
return MapDtosToContent(Database.Fetch<DocumentDto>(sql), true, true);
}
public override IContent GetVersion(int versionId)
{
var sql = GetBaseQuery(QueryType.Single, false)
@@ -911,7 +921,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return base.ApplySystemOrdering(ref sql, ordering);
}
private IEnumerable<IContent> MapDtosToContent(List<DocumentDto> dtos, bool withCache = false)
private IEnumerable<IContent> MapDtosToContent(List<DocumentDto> dtos, bool withCache = false, bool slim = false)
{
var temps = new List<TempContent<Content>>();
var contentTypes = new Dictionary<int, IContentType>();
@@ -944,18 +954,21 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
var c = content[i] = ContentBaseFactory.BuildEntity(dto, contentType);
// need templates
var templateId = dto.DocumentVersionDto.TemplateId;
if (templateId.HasValue && templateId.Value > 0)
templateIds.Add(templateId.Value);
if (dto.Published)
if (!slim)
{
templateId = dto.PublishedVersionDto.TemplateId;
// need templates
var templateId = dto.DocumentVersionDto.TemplateId;
if (templateId.HasValue && templateId.Value > 0)
templateIds.Add(templateId.Value);
if (dto.Published)
{
templateId = dto.PublishedVersionDto.TemplateId;
if (templateId.HasValue && templateId.Value > 0)
templateIds.Add(templateId.Value);
}
}
// need properties
// need temps, for properties, templates and variations
var versionId = dto.DocumentVersionDto.Id;
var publishedVersionId = dto.Published ? dto.PublishedVersionDto.Id : 0;
var temp = new TempContent<Content>(dto.NodeId, versionId, publishedVersionId, contentType, c)
@@ -966,25 +979,28 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
temps.Add(temp);
}
// load all required templates in 1 query, and index
var templates = _templateRepository.GetMany(templateIds.ToArray())
.ToDictionary(x => x.Id, x => x);
// load all properties for all documents from database in 1 query - indexed by version id
var properties = GetPropertyCollections(temps);
// assign templates and properties
foreach (var temp in temps)
if (!slim)
{
// complete the item
if (temp.Template1Id.HasValue && templates.TryGetValue(temp.Template1Id.Value, out var template))
temp.Content.Template = template;
if (temp.Template2Id.HasValue && templates.TryGetValue(temp.Template2Id.Value, out template))
temp.Content.PublishTemplate = template;
temp.Content.Properties = properties[temp.VersionId];
// load all required templates in 1 query, and index
var templates = _templateRepository.GetMany(templateIds.ToArray())
.ToDictionary(x => x.Id, x => x);
// reset dirty initial properties (U4-1946)
temp.Content.ResetDirtyProperties(false);
// load all properties for all documents from database in 1 query - indexed by version id
var properties = GetPropertyCollections(temps);
// assign templates and properties
foreach (var temp in temps)
{
// complete the item
if (temp.Template1Id.HasValue && templates.TryGetValue(temp.Template1Id.Value, out var template))
temp.Content.Template = template;
if (temp.Template2Id.HasValue && templates.TryGetValue(temp.Template2Id.Value, out template))
temp.Content.PublishTemplate = template;
temp.Content.Properties = properties[temp.VersionId];
// reset dirty initial properties (U4-1946)
temp.Content.ResetDirtyProperties(false);
}
}
// set variations, if varying
@@ -134,6 +134,12 @@ namespace Umbraco.Core.Services
/// <remarks>Versions are ordered with current first, then most recent first.</remarks>
IEnumerable<IContent> GetVersions(int id);
/// <summary>
/// Gets all versions of a document.
/// </summary>
/// <remarks>Versions are ordered with current first, then most recent first.</remarks>
IEnumerable<IContent> GetVersionsSlim(int id, int skip, int take);
/// <summary>
/// Gets top versions of a document.
/// </summary>
@@ -461,5 +467,21 @@ namespace Umbraco.Core.Services
IContent CreateAndSave(string name, IContent parent, string contentTypeAlias, int userId = 0);
#endregion
#region Rollback
/// <summary>
/// Rolls back the content to a specific version.
/// </summary>
/// <param name="id">The id of the content node.</param>
/// <param name="versionId">The version id to roll back to.</param>
/// <param name="culture">An optional culture to roll back.</param>
/// <param name="userId">The identifier of the user who is performing the roll back.</param>
/// <remarks>
/// <para>When no culture is specified, all cultures are rolled back.</para>
/// </remarks>
OperationResult Rollback(int id, int versionId, string culture = "*", int userId = 0);
#endregion
}
}
@@ -474,6 +474,19 @@ namespace Umbraco.Core.Services.Implement
}
}
/// <summary>
/// Gets a collection of an <see cref="IContent"/> objects versions by Id
/// </summary>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IContent> GetVersionsSlim(int id, int skip, int take)
{
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
scope.ReadLock(Constants.Locks.ContentTree);
return _documentRepository.GetAllVersionsSlim(id, skip, take);
}
}
/// <summary>
/// Gets a list of all version Ids for the given content item ordered so latest is first
/// </summary>
@@ -2490,5 +2503,68 @@ namespace Umbraco.Core.Services.Implement
}
#endregion
#region Rollback
public OperationResult Rollback(int id, int versionId, string culture = "*", int userId = 0)
{
var evtMsgs = EventMessagesFactory.Get();
//Get the current copy of the node
var content = GetById(id);
//Get the version
var version = GetVersion(versionId);
//Good ole null checks
if (content == null || version == null)
{
return new OperationResult(OperationResultType.FailedCannot, evtMsgs);
}
//Store the result of doing the save of content for the rollback
OperationResult rollbackSaveResult;
using (var scope = ScopeProvider.CreateScope())
{
var rollbackEventArgs = new RollbackEventArgs<IContent>(content);
//Emit RollingBack event aka before
if (scope.Events.DispatchCancelable(RollingBack, this, rollbackEventArgs))
{
scope.Complete();
return OperationResult.Cancel(evtMsgs);
}
//Copy the changes from the version
content.CopyFrom(version, culture);
//Save the content for the rollback
rollbackSaveResult = Save(content, userId);
//Depending on the save result - is what we log & audit along with what we return
if (rollbackSaveResult.Success == false)
{
//Log the error/warning
Logger.Error<ContentService>("User '{UserId}' was unable to rollback content '{ContentId}' to version '{VersionId}'", userId, id, versionId);
}
else
{
//Emit RolledBack event aka after
rollbackEventArgs.CanCancel = false;
scope.Events.Dispatch(RolledBack, this, rollbackEventArgs);
//Logging & Audit message
Logger.Info<ContentService>("User '{UserId}' rolled back content '{ContentId}' to version '{VersionId}'", userId, id, versionId);
Audit(AuditType.RollBack, $"Content '{content.Name}' was rolled back to version '{versionId}'", userId, id);
}
scope.Complete();
}
return rollbackSaveResult;
}
#endregion
}
}
@@ -2330,6 +2330,22 @@ namespace Umbraco.Tests.Services
}
Console.WriteLine("-");
var versionsSlim = ServiceContext.ContentService.GetVersionsSlim(page.Id, 0, 50).ToArray();
Assert.AreEqual(5, versionsSlim.Length);
for (var i = 0; i < 5; i++)
{
Console.Write("[{0}] ", i);
Console.WriteLine(versionsSlim[i].UpdateDate.ToString("O").Substring(11));
Console.WriteLine(" fr: {0}", versionsSlim[i].GetUpdateDate("fr")?.ToString("O").Substring(11));
Console.WriteLine(" da: {0}", versionsSlim[i].GetUpdateDate("da")?.ToString("O").Substring(11));
}
Console.WriteLine("-");
// what we do in the controller to get rollback versions
var versionsSlimFr = versionsSlim.Where(x => x.UpdateDate == x.GetUpdateDate("fr")).ToArray();
Assert.AreEqual(3, versionsSlimFr.Length);
// alas, at the moment we do *not* properly track 'dirty' for cultures, meaning
// that we cannot synchronize dates the way we do with publish dates - and so this
// would fail - the version UpdateDate is greater than the cultures'.
@@ -103,6 +103,17 @@
loadContent();
}
}));
evts.push(eventsService.on("editors.content.reload", function (name, args) {
// if this content item uses the updated doc type we need to reload the content item
if(args && args.node && args.node.key === $scope.content.key) {
$scope.page.loading = true;
loadContent().then(function() {
$scope.page.loading = false;
});
}
}));
}
/**
@@ -101,6 +101,22 @@
scope.node.template = templateAlias;
};
scope.openRollback = function() {
var rollback = {
node: scope.node,
submit: function(model) {
const args = { node: scope.node };
eventsService.emit("editors.content.reload", args);
editorService.close();
},
close: function() {
editorService.close();
}
};
editorService.rollback(rollback);
};
function loadAuditTrail() {
scope.loadingAuditTrail = true;
@@ -808,8 +808,106 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
),
"Failed to create blueprint from content with id " + contentId
);
}
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#getRollbackVersions
* @methodOf umbraco.resources.contentResource
*
* @description
* Returns an array of previous version id's, given a node id and a culture
*
* ##usage
* <pre>
* contentResource.getRollbackVersions(id, culture)
* .then(function(versions) {
* alert('its here!');
* });
* </pre>
*
* @param {Int} id Id of node
* @param {Int} culture if provided, the results will be for this specific culture/variant
* @returns {Promise} resourcePromise object containing the versions
*
*/
getRollbackVersions: function (contentId, culture) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl("contentApiBaseUrl", "GetRollbackVersions", {
contentId: contentId,
culture: culture
})
),
"Failed to get rollback versions for content item with id " + contentId
);
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#getRollbackVersion
* @methodOf umbraco.resources.contentResource
*
* @description
* Returns a previous version of a content item
*
* ##usage
* <pre>
* contentResource.getRollbackVersion(versionId, culture)
* .then(function(version) {
* alert('its here!');
* });
* </pre>
*
* @param {Int} versionId The version Id
* @param {Int} culture if provided, the results will be for this specific culture/variant
* @returns {Promise} resourcePromise object containing the version
*
*/
getRollbackVersion: function (versionId, culture) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl("contentApiBaseUrl", "GetRollbackVersion", {
versionId: versionId,
culture: culture
})
),
"Failed to get version for content item with id " + versionId
);
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#rollback
* @methodOf umbraco.resources.contentResource
*
* @description
* Roll backs a content item to a previous version
*
* ##usage
* <pre>
* contentResource.rollback(contentId, versionId, culture)
* .then(function() {
* alert('its here!');
* });
* </pre>
*
* @param {Int} id Id of node
* @param {Int} versionId The version Id
* @param {Int} culture if provided, the results will be for this specific culture/variant
* @returns {Promise} resourcePromise object
*
*/
rollback: function (contentId, versionId, culture) {
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl("contentApiBaseUrl", "PostRollbackContent", {
contentId: contentId, versionId:versionId, culture:culture
})
),
"Failed to roll back content item with id " + contentId
);
}
};
}
@@ -180,6 +180,25 @@
open(editor);
}
/**
* @ngdoc method
* @name umbraco.services.editorService#rollback
* @methodOf umbraco.services.editorService
*
* @description
* Opens a rollback editor in infinite editing.
* @param {String} editor.node The node to rollback
* @param {Callback} editor.submit Saves, submits, and closes the editor
* @param {Callback} editor.close Closes the editor
* @returns {Object} editor object
*/
function rollback(editor) {
editor.view = "views/common/infiniteeditors/rollback/rollback.html";
editor.size = "small";
open(editor);
}
/**
* @ngdoc method
* @name umbraco.services.editorService#linkPicker
@@ -481,6 +500,7 @@
copy: copy,
move: move,
embed: embed,
rollback: rollback,
linkPicker: linkPicker,
mediaPicker: mediaPicker,
iconPicker: iconPicker,
@@ -104,7 +104,7 @@
}
.umb-button--xs {
padding: 5px 16px;
padding: 5px 13px;
font-size: 14px;
}
@@ -8,6 +8,9 @@
.umb-box-header {
padding: 10px 20px;
border-bottom: 1px solid @gray-9;
display: flex;
align-items: center;
justify-content: space-between;
}
.umb-box-header-title {
@@ -7,6 +7,8 @@
.ws-normal { white-space: normal; }
.nowrap { white-space: nowrap; }
.pre { white-space: pre; }
.pre-wrap { white-space: pre-wrap; }
.pre-line { white-space: pre-line; }
.truncate {
white-space: nowrap;
@@ -0,0 +1,177 @@
(function () {
"use strict";
function RollbackController($scope, contentResource, localizationService, assetsService) {
var vm = this;
vm.rollback = rollback;
vm.changeLanguage = changeLanguage;
vm.changeVersion = changeVersion;
vm.submit = submit;
vm.close = close;
//////////
function onInit() {
vm.loading = true;
vm.variantVersions = [];
vm.diff = null;
vm.currentVersion = null;
vm.rollbackButtonDisabled = true;
// find the current version for invariant nodes
if($scope.model.node.variants.length === 1) {
vm.currentVersion = $scope.model.node.variants[0];
}
// find the current version for nodes with variants
if($scope.model.node.variants.length > 1) {
var active = _.find($scope.model.node.variants, function (v) {
return v.active;
});
// preselect the language in the dropdown
if(active) {
vm.selectedLanguage = active;
vm.currentVersion = active;
}
}
// set default title
if(!$scope.model.title) {
localizationService.localize("actions_rollback").then(function(value){
$scope.model.title = value;
});
}
// Load in diff library
assetsService.loadJs('lib/jsdiff/diff.min.js', $scope).then(function () {
getVersions().then(function(){
vm.loading = false;
});
});
}
function changeLanguage(language) {
vm.currentVersion = language;
getVersions();
}
function changeVersion(version) {
if(version && version.versionId) {
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;
createDiff(vm.currentVersion, vm.previousVersion);
vm.rollbackButtonDisabled = false;
});
} else {
vm.diff = null;
vm.rollbackButtonDisabled = true;
}
}
function getVersions() {
const nodeId = $scope.model.node.id;
const culture = $scope.model.node.variants.length > 1 ? vm.currentVersion.language.culture : null;
return contentResource.getRollbackVersions(nodeId, culture)
.then(function(data){
vm.previousVersions = data.map(version => {
version.displayValue = version.versionDate + " - " + version.versionAuthorName;
return version;
});
});
}
/**
* This will load in a new version
*/
function createDiff(currentVersion, previousVersion) {
vm.diff = {};
vm.diff.properties = [];
// find diff in name
vm.diff.name = JsDiff.diffWords(currentVersion.name, previousVersion.name);
// extract all properties from the tabs and create new object for the diff
currentVersion.tabs.forEach((tab, tabIndex) => {
tab.properties.forEach((property, propertyIndex) => {
var oldProperty = previousVersion.tabs[tabIndex].properties[propertyIndex];
// we have to make properties storing values as object into strings (Grid, nested content, etc.)
if(property.value instanceof Object) {
property.value = JSON.stringify(property.value, null, 1);
property.isObject = true;
}
if(oldProperty.value instanceof Object) {
oldProperty.value = JSON.stringify(oldProperty.value, null, 1);
oldProperty.isObject = true;
}
// create new property object used in the diff table
var diffProperty = {
"alias": property.alias,
"label": property.label,
"diff": (property.value || oldProperty.value) ? JsDiff.diffWords(property.value, oldProperty.value) : "",
"isObject": (property.isObject || oldProperty.isObject) ? true : false
};
vm.diff.properties.push(diffProperty);
});
});
}
function rollback() {
vm.rollbackButtonState = "busy";
const nodeId = $scope.model.node.id;
const versionId = vm.previousVersion.versionId;
const culture = $scope.model.node.variants.length > 1 ? vm.currentVersion.language.culture : null;
return contentResource.rollback(nodeId, versionId, culture)
.then(data => {
vm.rollbackButtonState = "success";
submit();
}, error => {
vm.rollbackButtonState = "error";
});
}
function submit() {
if($scope.model.submit) {
$scope.model.submit($scope.model.submit);
}
}
function close() {
if($scope.model.close) {
$scope.model.close();
}
}
onInit();
}
angular.module("umbraco").controller("Umbraco.Editors.RollbackController", RollbackController);
})();
@@ -0,0 +1,104 @@
<div ng-controller="Umbraco.Editors.RollbackController as vm">
<umb-editor-view>
<umb-editor-header
name="model.title"
name-locked="true"
hide-alias="true"
hide-icon="true"
hide-description="true">
</umb-editor-header>
<umb-editor-container>
<umb-load-indicator
ng-if="vm.loading">
</umb-load-indicator>
<umb-box>
<umb-box-content>
<div ng-if="model.node.variants.length > 1">
<h5><localize key="general_language"></localize></h5>
<select
class="input-block-level"
ng-model="vm.selectedLanguage"
ng-options="variant as variant.language.name for variant in model.node.variants track by variant.language.culture"
ng-change="vm.changeLanguage(vm.selectedLanguage)">
</select>
</div>
<div>
<h5><localize key="rollback_currentVersion"></localize></h5>
<p>{{vm.currentVersion.name}} (Created: {{vm.currentVersion.createDate}})</p>
<h5><localize key="rollback_rollbackTo"></localize></h5>
<select
class="input-block-level"
ng-model="vm.selectedVersion"
ng-options="version.displayValue for version in vm.previousVersions track by version.versionId"
ng-change="vm.changeVersion(vm.selectedVersion)">
<option value=""><localize key="general_choose">Choose</localize>...</option>
</select>
</div>
<div ng-if="vm.diff" class="diff" style="border-top: 1px solid #e9e9eb; margin-top: 30px;">
<h5>Changes</h5>
<small style="margin-bottom: 15px; display: block;"><localize key="rollback_diffHelp"></localize></small>
<table class="table table-condensed table-bordered">
<tbody>
<tr>
<td class="bold">Name</td>
<td>
<span ng-repeat="part in vm.diff.name">
<ins ng-if="part.added">{{part.value}}</ins>
<del ng-if="part.removed">{{part.value}}</del>
<span ng-if="!part.added && !part.removed">{{part.value}}</span>
</span>
</td>
</tr>
<tr ng-repeat="property in vm.diff.properties track by property.alias">
<td class="bold">{{property.label}}</td>
<td ng-class="{'pre-line': property.isObject}">
<span ng-repeat="part in property.diff">
<ins ng-if="part.added">{{part.value}}</ins>
<del ng-if="part.removed">{{part.value}}</del>
<span ng-if="!part.added && !part.removed">{{part.value}}</span>
</span>
</td>
</tr>
</tbody>
</table>
</div>
</umb-box-content>
</umb-box>
</umb-editor-container>
<umb-editor-footer>
<umb-editor-footer-content-right>
<umb-button
type="button"
button-style="link"
label-key="general_close"
action="vm.close()">
</umb-button>
<umb-button
type="button"
button-style="success"
state="vm.rollbackButtonState"
label-key="actions_rollback"
disabled="vm.rollbackButtonDisabled"
action="vm.rollback()">
</umb-button>
</umb-editor-footer-content-right>
</umb-editor-footer>
</umb-editor-view>
</div>
@@ -41,7 +41,19 @@
</umb-box>
<umb-box data-element="node-info-history">
<umb-box-header title-key="general_history"></umb-box-header>
<umb-box-header
title-key="general_history">
<umb-button
type="button"
button-style="outline"
action="openRollback()"
label-key="actions_rollback"
size="xs"
add-ellipsis="true">
</umb-button>
</umb-box-header>
<umb-box-content class="block-form">
<div style="position: relative;">
@@ -1,10 +1,13 @@
<div class="umb-box-header" ng-transclude>
<div class="umb-box-header-title" ng-if="title || titleKey">
<localize ng-if="titleKey" key="{{titleKey}}"></localize>
<span ng-if="title">{{title}}</span>
</div>
<div class="umb-box-header-description" ng-if="description || descriptionKey">
<localize ng-if="descriptionKey" key="{{descriptionKey}}"></localize>
<span ng-if="description">{{description}}</span>
<div class="umb-box-header">
<div>
<div class="umb-box-header-title" ng-if="title || titleKey">
<localize ng-if="titleKey" key="{{titleKey}}"></localize>
<span ng-if="title">{{title}}</span>
</div>
<div class="umb-box-header-description" ng-if="description || descriptionKey">
<localize ng-if="descriptionKey" key="{{descriptionKey}}"></localize>
<span ng-if="description">{{description}}</span>
</div>
</div>
<ng-transclude></ng-transclude>
</div>
@@ -1,117 +0,0 @@
(function () {
"use strict";
function ContentRollbackController($scope, assetsService) {
var vm = this;
vm.rollback = rollback;
vm.loadVersion = loadVersion;
vm.closeDialog = closeDialog;
function onInit() {
vm.loading = true;
vm.variantVersions = [];
vm.diff = null;
// Load in diff library
assetsService.loadJs('lib/jsdiff/diff.min.js', $scope).then(function () {
var currentLanguage = $scope.currentNode.metaData.culture;
vm.currentVersion = {
"id": 1,
"createDate": "22/08/2018 13.32",
"name": "Forside",
"properties": [
{
"alias": "headline",
"label": "Headline",
"value": "Velkommen"
},
{
"alias": "text",
"label": "Text",
"value": "This is my danish Content"
}
]
};
vm.previousVersions = [
{
"id": 2,
"name": "Forside",
"createDate": "21/08/2018 19.25"
}
];
vm.loading = false;
});
}
function rollback() {
console.log("rollback");
}
/**
* This will load in a new version
*/
function loadVersion(id) {
// fake load version
var currentLanguage = $scope.currentNode.metaData.culture;
vm.diff = {};
vm.diff.properties = [];
var oldVersion = {
"id": 2,
"name": "Foride",
"properties": [
{
"alias": "headline",
"label": "Headline",
"value": ""
},
{
"alias": "text",
"label": "Text",
"value": "This is my danish Content Test"
}
]
};
// find diff in name
vm.diff.name = JsDiff.diffWords(vm.currentVersion.name, oldVersion.name);
// find diff in properties
angular.forEach(vm.currentVersion.properties,
function(newProperty, index){
var oldProperty = oldVersion.properties[index];
var diffProperty = {
"alias": newProperty.alias,
"label": newProperty.label,
"diff": JsDiff.diffWords(newProperty.value, oldProperty.value)
};
vm.diff.properties.push(diffProperty);
});
}
/**
* This will close the dialog
*/
function closeDialog() {
$scope.nav.hideDialog();
}
onInit();
}
angular.module("umbraco").controller("Umbraco.Editors.Content.RollbackController", ContentRollbackController);
})();
@@ -1,80 +0,0 @@
<div ng-controller="Umbraco.Editors.Content.RollbackController as vm">
<div class="umb-dialog-body" ng-cloak>
<umb-load-indicator ng-if="vm.loading"></umb-load-indicator>
<div class="umb-pane" ng-show="!vm.loading">
<div>
<h5>Rollback {{ currentNode.name }}</h5>
<h5><localize key="rollback_currentVersion"></localize></h5>
<p>{{vm.currentVersion.name}} (Created: {{vm.currentVersion.createDate}})</p>
<h5><localize key="rollback_rollbackTo"></localize></h5>
<select
class="input-block-level"
ng-model="vm.selectedVersion"
ng-options="version.createDate for version in vm.previousVersions track by version.id"
ng-change="vm.loadVersion(vm.selectedVersion.id)">
<option value=""><localize key="general_choose">Choose</localize>...</option>
</select>
</div>
<div ng-if="vm.diff" class="diff" style="border-top: 1px solid #e9e9eb; margin-top: 30px;">
<h5>Changes</h5>
<small style="margin-bottom: 15px; display: block;"><localize key="rollback_diffHelp"></localize></small>
<table class="table table-condensed table-bordered">
<tbody>
<tr>
<td class="bold">Name</td>
<td>
<span ng-repeat="part in vm.diff.name">
<ins ng-if="part.added">{{part.value}}</ins>
<del ng-if="part.removed">{{part.value}}</del>
<span ng-if="!part.added && !part.removed">{{part.value}}</span>
</span>
</td>
</tr>
<tr ng-repeat="property in vm.diff.properties track by property.alias">
<td class="bold">{{property.label}}</td>
<td>
<span ng-repeat="part in property.diff">
<ins ng-if="part.added">{{part.value}}</ins>
<del ng-if="part.removed">{{part.value}}</del>
<span ng-if="!part.added && !part.removed">{{part.value}}</span>
</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar">
<umb-button
label-key="general_close"
disabled="vm.saveState === 'busy'"
action="vm.closeDialog()"
type="button"
button-style="link">
</umb-button>
<umb-button
label-key="buttons_rollback"
disabled="vm.saveState === 'busy'"
state="vm.saveState"
action="vm.rollback()"
type="button"
button-style="success">
</umb-button>
</div>
</div>
-1
View File
@@ -348,7 +348,6 @@
<Content Include="Umbraco\Developer\Packages\directoryBrowser.aspx" />
<Content Include="Umbraco\Developer\Packages\editPackage.aspx" />
<Content Include="Umbraco\Dialogs\protectPage.aspx" />
<Content Include="Umbraco\Dialogs\rollBack.aspx" />
<Content Include="Umbraco\Dialogs\sendToTranslation.aspx" />
<Content Include="Umbraco\Config\Create\UI.xml" />
<Content Include="Umbraco\Config\Lang\en.xml">
@@ -1,98 +0,0 @@
<%@ Page Language="c#" MasterPageFile="../masterpages/umbracoDialog.Master"AutoEventWireup="True" Inherits="umbraco.presentation.dialogs.rollBack" %>
<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %>
<%@ Register TagPrefix="cc1" Namespace="Umbraco.Web._Legacy.Controls" Assembly="Umbraco.Web" %>
<asp:Content ContentPlaceHolderID="head" runat="server">
<script type="text/javascript">
function doSubmit() { document.Form1["ok"].click() }
var functionsFrame = this;
var tabFrame = this;
var isDialog = true;
var submitOnEnter = true;
</script>
<style type="text/css">
.propertyItemheader {
width: 140px !Important;
}
.diff {
margin-top: 10px;
height: 100%;
overflow: auto;
border-top: 1px solid #efefef;
padding: 5px;
}
.diff table td {
border-bottom: 1px solid #ccc;
padding: 3px;
}
.diff del {
background: rgb(255, 230, 230) none repeat scroll 0%;
-moz-background-clip: -moz-initial;
-moz-background-origin: -moz-initial;
-moz-background-inline-policy: -moz-initial;
}
.diff ins {
background: rgb(230, 255, 230) none repeat scroll 0%;
-moz-background-clip: -moz-initial;
-moz-background-origin: -moz-initial;
-moz-background-inline-policy: -moz-initial;
}
.diff .diffnotice {
text-align: center;
margin-bottom: 10px;
}
</style>
</asp:Content>
<asp:Content ContentPlaceHolderID="body" runat="server">
<div class="umb-dialog-body">
<umb:JsInclude ID="JsInclude1" runat="server" FilePath="js/umbracoCheckKeys.js" PathNameAlias="UmbracoRoot" />
<cc1:Feedback ID="feedBackMsg" runat="server" />
<cc1:Pane ID="pp_selectVersion" runat="server" Text="Select a version to compare with the current version">
<cc1:PropertyPanel id="pp_currentVersion" Text="Current version" runat="server">
<asp:Literal ID="currentVersionTitle" runat="server" />
<small>(<asp:Literal ID="currentVersionMeta" runat="server" />)</small></cc1:PropertyPanel>
<cc1:PropertyPanel ID="pp_rollBackTo" Text="Rollback to" runat="server">
<asp:DropDownList OnSelectedIndexChanged="version_load" ID="allVersions" runat="server" Width="400px" AutoPostBack="True" CssClass="guiInputTextTiny" />
</cc1:PropertyPanel>
<cc1:PropertyPanel id="pp_view" Text="View" runat="server">
<small>
<asp:RadioButtonList ID="rbl_mode" runat="server" OnSelectedIndexChanged="version_load" RepeatDirection="Horizontal">
<asp:ListItem Selected="True" Value="diff">Diff</asp:ListItem>
<asp:ListItem Value="html">Html</asp:ListItem>
</asp:RadioButtonList>
</small>
</cc1:PropertyPanel>
</cc1:Pane>
<asp:Panel ID="diffPanel" Visible="false" runat="server" Height="300px">
<div class="diff">
<div class="diffnotice">
<p>
<asp:Literal ID="lt_notice" runat="server" />
</p>
</div>
<table border="0" style="width: 95%;">
<asp:Literal ID="propertiesCompare" runat="server"></asp:Literal>
</table>
</div>
</asp:Panel>
</div>
<div runat="server" id="pl_buttons" class="umb-dialog-footer btn-toolbar umb-btn-toolbar">
<a href="#" class="btn btn-link" onclick="UmbClientMgr.closeModalWindow()"><%=Services.TextService.Localize("general/cancel")%></a>
<asp:Button ID="Button1" runat="server" visible="false" CssClass="btn btn-primary" OnClick="doRollback_Click"></asp:Button>
</div>
</asp:Content>
@@ -1702,5 +1702,93 @@ namespace Umbraco.Web.Editors
Services.NotificationService.SetNotifications(Security.CurrentUser, content, notifyOptions);
}
[HttpGet]
public IEnumerable<RollbackVersion> GetRollbackVersions(int contentId, string culture = null)
{
var rollbackVersions = new List<RollbackVersion>();
var writerIds = new HashSet<int>();
//Return a list of all versions of a specific content node
// fixme - cap at 50 versions for now?
var versions = Services.ContentService.GetVersionsSlim(contentId, 0, 50);
//Not all nodes are variants & thus culture can be null
if (culture != null)
{
//Get cultures that were published with the version = their update date is equal to the version's
versions = versions.Where(x => x.UpdateDate == x.GetUpdateDate(culture));
}
//First item is our current item/state (cant rollback to ourselves)
versions = versions.Skip(1);
foreach (var version in versions)
{
var rollbackVersion = new RollbackVersion
{
VersionId = version.VersionId,
VersionDate = version.UpdateDate,
VersionAuthorId = version.WriterId
};
rollbackVersions.Add(rollbackVersion);
writerIds.Add(version.WriterId);
}
var users = Services.UserService
.GetUsersById(writerIds.ToArray())
.ToDictionary(x => x.Id, x => x.Name);
foreach (var rollbackVersion in rollbackVersions)
{
if (users.TryGetValue(rollbackVersion.VersionAuthorId, out var userName))
rollbackVersion.VersionAuthorName = userName;
}
return rollbackVersions;
}
[HttpGet]
public ContentVariantDisplay GetRollbackVersion(int versionId, string culture = null)
{
var version = Services.ContentService.GetVersion(versionId);
var content = MapToDisplay(version);
return culture == null
? content.Variants.FirstOrDefault() //No culture set - so this is an invariant node - so just list me the first item in here
: content.Variants.FirstOrDefault(x => x.Language.IsoCode == culture);
}
[HttpPost]
public HttpResponseMessage PostRollbackContent(int contentId, int versionId, string culture = "*")
{
var rollbackResult = Services.ContentService.Rollback(contentId, versionId, culture, Security.GetUserId().ResultOr(0));
if (rollbackResult.Success)
return Request.CreateResponse(HttpStatusCode.OK);
var notificationModel = new SimpleNotificationModel();
switch (rollbackResult.Result)
{
case OperationResultType.Failed:
case OperationResultType.FailedCannot:
case OperationResultType.FailedExceptionThrown:
case OperationResultType.NoOperation:
default:
notificationModel.AddErrorNotification(
Services.TextService.Localize("speechBubbles/operationFailedHeader"),
null); //TODO: There is no specific failed to save error message AFAIK
break;
case OperationResultType.FailedCancelledByEvent:
notificationModel.AddErrorNotification(
Services.TextService.Localize("speechBubbles/operationCancelledHeader"),
Services.TextService.Localize("speechBubbles/operationCancelledText"));
break;
}
return Request.CreateValidationErrorResponse(notificationModel);
}
}
}
@@ -0,0 +1,21 @@
using System;
using System.Runtime.Serialization;
namespace Umbraco.Web.Models.ContentEditing
{
[DataContract(Name = "rollbackVersion", Namespace = "")]
public class RollbackVersion
{
[DataMember(Name = "versionId")]
public int VersionId { get; set; }
[DataMember(Name = "versionDate")]
public DateTime VersionDate { get; set; }
[DataMember(Name = "versionAuthorId")]
public int VersionAuthorId { get; set; }
[DataMember(Name = "versionAuthorName")]
public string VersionAuthorName { get; set; }
}
}
@@ -238,7 +238,6 @@ namespace Umbraco.Web.Trees
AddActionNode<ActionSort>(item, menu, true);
AddActionNode<ActionRollback>(item, menu);
AddActionNode<ActionToPublish>(item, menu, convert: true);
AddActionNode<ActionAssignDomain>(item, menu);
AddActionNode<ActionRights>(item, menu, convert: true);
+2 -13
View File
@@ -147,6 +147,7 @@
<Compile Include="Media\TypeDetector\SvgDetector.cs" />
<Compile Include="Media\TypeDetector\TIFFDetector.cs" />
<Compile Include="Media\UploadAutoFillProperties.cs" />
<Compile Include="Models\ContentEditing\RollbackVersion.cs" />
<Compile Include="Models\ContentEditing\UnpublishContent.cs" />
<Compile Include="Models\Mapping\MappingOperationOptionsExtensions.cs" />
<Compile Include="ContentApps\ContentAppDefinitionCollection.cs" />
@@ -1311,12 +1312,6 @@
<Compile Include="umbraco.presentation\umbraco\developer\Packages\editPackage.aspx.designer.cs">
<DependentUpon>editPackage.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\dialogs\rollBack.aspx.cs">
<DependentUpon>rollBack.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\dialogs\rollBack.aspx.designer.cs">
<DependentUpon>rollBack.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\templateControls\DisableEventValidation.cs" />
<Compile Include="umbraco.presentation\umbraco\templateControls\Item.cs" />
<Compile Include="umbraco.presentation\umbraco\templateControls\ItemRenderer.cs" />
@@ -1401,9 +1396,6 @@
<Content Include="umbraco.presentation\umbraco\developer\Packages\editPackage.aspx">
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\dialogs\rollBack.aspx">
<SubType>ASPXCodeBehind</SubType>
</Content>
</ItemGroup>
<ItemGroup>
<None Include="Web References\org.umbraco.update\checkforupgrade.disco" />
@@ -1457,10 +1449,7 @@
<CachedSettingsPropName>umbraco_org_umbraco_update_CheckForUpgrade</CachedSettingsPropName>
</WebReferenceUrl>
</ItemGroup>
<ItemGroup>
<Folder Include="umbraco.presentation\umbraco\settings\" />
<Folder Include="umbraco.presentation\umbraco\translation\" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!--
copied from Microsoft.CSharp.targets
@@ -1,99 +0,0 @@
<%@ Page Language="c#" CodeBehind="rollBack.aspx.cs" MasterPageFile="../masterpages/umbracoDialog.Master" AutoEventWireup="True" Inherits="umbraco.presentation.dialogs.rollBack" %>
<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %>
<%@ Register TagPrefix="cc1" Namespace="Umbraco.Web._Legacy.Controls" %>
<asp:Content ContentPlaceHolderID="head" runat="server">
<script type="text/javascript">
function doSubmit() { document.Form1["ok"].click() }
var functionsFrame = this;
var tabFrame = this;
var isDialog = true;
var submitOnEnter = true;
</script>
<style type="text/css">
.propertyItemheader {
width: 140px !Important;
}
.diff {
margin-top: 10px;
height: 100%;
overflow: auto;
border-top: 1px solid #ccc;
border-top: 1px solid #ccc;
padding: 5px;
}
.diff table td {
border-bottom: 1px solid #ccc;
padding: 3px;
}
.diff del {
background: rgb(255, 230, 230) none repeat scroll 0%;
-moz-background-clip: -moz-initial;
-moz-background-origin: -moz-initial;
-moz-background-inline-policy: -moz-initial;
}
.diff ins {
background: rgb(230, 255, 230) none repeat scroll 0%;
-moz-background-clip: -moz-initial;
-moz-background-origin: -moz-initial;
-moz-background-inline-policy: -moz-initial;
}
.diff .diffnotice {
text-align: center;
margin-bottom: 10px;
}
</style>
</asp:Content>
<asp:Content ContentPlaceHolderID="body" runat="server">
<div class="umb-dialog-body">
<umb:JsInclude ID="JsInclude1" runat="server" FilePath="js/umbracoCheckKeys.js" PathNameAlias="UmbracoRoot" />
<cc1:Feedback ID="feedBackMsg" runat="server" />
<cc1:Pane ID="pp_selectVersion" runat="server" Text="Select a version to compare with the current version">
<cc1:PropertyPanel id="pp_currentVersion" Text="Current version" runat="server">
<asp:Literal ID="currentVersionTitle" runat="server" />
<small>(<asp:Literal ID="currentVersionMeta" runat="server" />)</small></cc1:PropertyPanel>
<cc1:PropertyPanel ID="pp_rollBackTo" Text="Rollback to" runat="server">
<asp:DropDownList OnSelectedIndexChanged="version_load" ID="allVersions" runat="server" Width="400px" AutoPostBack="True" CssClass="guiInputTextTiny" />
</cc1:PropertyPanel>
<cc1:PropertyPanel id="pp_view" Text="View" runat="server">
<small>
<asp:RadioButtonList ID="rbl_mode" runat="server" OnSelectedIndexChanged="version_load" RepeatDirection="Horizontal">
<asp:ListItem Selected="True" Value="diff">Diff</asp:ListItem>
<asp:ListItem Value="html">Html</asp:ListItem>
</asp:RadioButtonList>
</small>
</cc1:PropertyPanel>
</cc1:Pane>
<asp:Panel ID="diffPanel" Visible="false" runat="server" Height="300px">
<div class="diff">
<div class="diffnotice">
<p>
<asp:Literal ID="lt_notice" runat="server" />
</p>
</div>
<table border="0" style="width: 95%;">
<asp:Literal ID="propertiesCompare" runat="server"></asp:Literal>
</table>
</div>
</asp:Panel>
</div>
<div runat="server" id="pl_buttons" class="umb-dialog-footer btn-toolbar umb-btn-toolbar">
<a href="#" class="btn btn-link" onclick="UmbClientMgr.closeModalWindow()"><%=Services.TextService.Localize("general/cancel")%></a>
<asp:Button ID="Button1" runat="server" Visible="false" CssClass="btn btn-primary" OnClick="doRollback_Click"></asp:Button>
</div>
</asp:Content>
@@ -1,156 +0,0 @@
//TODO: REbuild this in angular and then remove
//using System;
//using System.Collections;
//using System.ComponentModel;
//using System.Data;
//using System.Drawing;
//using System.Linq;
//using System.Web;
//using System.Web.SessionState;
//using System.Web.UI;
//using System.Web.UI.WebControls;
//using System.Web.UI.HtmlControls;
//
//using umbraco.cms.businesslogic.web;
//using umbraco.cms.businesslogic.property;
//namespace umbraco.presentation.dialogs
//{
// /// <summary>
// /// Summary description for rollBack.
// /// </summary>
// public partial class rollBack : UmbracoEnsuredPage
// {
// public rollBack()
// {
// CurrentApp = Constants.Applications.Content.ToString();
// }
// private Document currentDoc = new Document(int.Parse(helper.Request("nodeId")));
// protected void version_load(object sender, EventArgs e) {
// if (allVersions.SelectedValue != "")
// {
// diffPanel.Visible = true;
// Document rollback = new Document(currentDoc.Id, new Guid(allVersions.SelectedValue));
// propertiesCompare.Text = "<tr><th style='width: 25%;' valign='top'>" + Services.TextService.Localize("general/name") + ":</th><td>" + rollback.Text + "</td></tr>";
// propertiesCompare.Text += "<tr><th style='width: 25%;' valign='top'>" + Services.TextService.Localize("content/createDate") + ":</th><td>" + rollback.VersionDate.ToLongDateString() + " " + rollback.VersionDate.ToLongTimeString() + " " + Services.TextService.Localize("general/by") + ": " + rollback.User.Name + "</td></tr>";
// if (rbl_mode.SelectedValue == "diff")
// lt_notice.Text = Services.TextService.Localize("rollback/diffHelp");
// else
// lt_notice.Text = Services.TextService.Localize("rollback/htmlHelp");
// var props = rollback.GenericProperties;
// foreach (Property p in props)
// {
// try
// {
// if (p.Value != null)
// {
// //new property value...
// string thevalue = p.Value.ToString();
// if (rbl_mode.SelectedValue == "diff")
// {
// //if display mode is set to diff...
// thevalue = library.StripHtml(p.Value.ToString());
// Property cP = currentDoc.getProperty(p.PropertyType);
// if (cP != null && cP.Value != null)
// {
// string cThevalue = library.StripHtml(cP.Value.ToString());
// propertiesCompare.Text += "<tr><th style='width: 25%;' valign='top'>" + p.PropertyType.Name + ":</th><td>" + library.ReplaceLineBreaks(cms.businesslogic.utilities.Diff.Diff2Html(cThevalue, thevalue)) + "</td></tr>";
// }
// else
// {
// //If no current version of the value... display with no diff.
// propertiesCompare.Text += "<tr><th style='width: 25%;' valign='top'>" + p.PropertyType.Name + ":</th><td>" + thevalue + "</td></tr>";
// }
// }
// else
// {
// //If display mode is html
// propertiesCompare.Text += "<tr><th style='width: 25%;' valign='top'>" + p.PropertyType.Name + ":</th><td>" + thevalue + "</td></tr>";
// }
// //previewVersionContent.Controls.Add(new LiteralControl("<div style=\"margin-top: 4px; border: 1px solid #DEDEDE; padding: 4px;\"><p style=\"padding: 0px; margin: 0px;\" class=\"guiDialogNormal\"><b>" + p.PropertyType.Name + "</b><br/>"));
// //previewVersionContent.Controls.Add(new LiteralControl(thevalue));
// }
// //previewVersionContent.Controls.Add(new LiteralControl("</p></div>"));
// }
// catch { }
// }
// Button1.Visible = true;
// }
// else
// {
// diffPanel.Visible = false;
// Button1.Visible = false;
// }
// }
// protected void Page_Load(object sender, System.EventArgs e)
// {
// if (String.IsNullOrEmpty(allVersions.SelectedValue))
// rbl_mode.AutoPostBack = false;
// else
// rbl_mode.AutoPostBack = true;
// currentVersionTitle.Text = currentDoc.Text;
// currentVersionMeta.Text = Services.TextService.Localize("content/createDate") + ": " + currentDoc.VersionDate.ToShortDateString() + " " + currentDoc.VersionDate.ToShortTimeString();
// if (!IsPostBack) {
// allVersions.Items.Add(new ListItem(Services.TextService.Localize("rollback/selectVersion")+ "...", ""));
// foreach (DocumentVersionList dl in currentDoc.GetVersions())
// {
// //we don't need to show the current version
// if (dl.Version == currentDoc.Version)
// continue;
//
// allVersions.Items.Add(new ListItem(dl.Text + " (" + Services.TextService.Localize("content/createDate") + ": " + dl.Date.ToShortDateString() + " " + dl.Date.ToShortTimeString() + ")", dl.Version.ToString()));
// }
// Button1.Text = Services.TextService.Localize("actions/rollback");
// }
// }
// protected void doRollback_Click(object sender, System.EventArgs e)
// {
// if (allVersions.SelectedValue.Trim() != "")
// {
// Document d = new Document(int.Parse(helper.Request("nodeId")));
// d.RollBack(new Guid(allVersions.SelectedValue), Security.CurrentUser);
// BusinessLogic.Log.Add(BusinessLogic.LogTypes.RollBack, Security.CurrentUser, d.Id, "Version rolled back to revision '" + allVersions.SelectedValue + "'");
// Document rollback = new Document(d.Id, new Guid(allVersions.SelectedValue));
// feedBackMsg.type = global::Umbraco.Web._Legacy.Controls.Feedback.feedbacktype.success;
// string[] vars = {rollback.Text, rollback.VersionDate.ToLongDateString()};
// feedBackMsg.Text = ui.Text("rollback", "documentRolledBack", vars, new global::umbraco.BusinessLogic.User(0)) + "</p><p><a href='#' onclick='" + ClientTools.Scripts.CloseModalWindow() + "'>" + Services.TextService.Localize("closeThisWindow") + "</a>";
// diffPanel.Visible = false;
// pl_buttons.Visible = false;
//
// ClientTools.ReloadLocationIfMatched(string.Format("/content/content/edit/{0}", d.Id));
// }
// }
// }
//}
@@ -1,150 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace umbraco.presentation.dialogs {
public partial class rollBack {
/// <summary>
/// JsInclude1 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::ClientDependency.Core.Controls.JsInclude JsInclude1;
/// <summary>
/// feedBackMsg control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::Umbraco.Web._Legacy.Controls.Feedback feedBackMsg;
/// <summary>
/// pp_selectVersion control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::Umbraco.Web._Legacy.Controls.Pane pp_selectVersion;
/// <summary>
/// pp_currentVersion control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::Umbraco.Web._Legacy.Controls.PropertyPanel pp_currentVersion;
/// <summary>
/// currentVersionTitle control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Literal currentVersionTitle;
/// <summary>
/// currentVersionMeta control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Literal currentVersionMeta;
/// <summary>
/// pp_rollBackTo control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::Umbraco.Web._Legacy.Controls.PropertyPanel pp_rollBackTo;
/// <summary>
/// allVersions control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.DropDownList allVersions;
/// <summary>
/// pp_view control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::Umbraco.Web._Legacy.Controls.PropertyPanel pp_view;
/// <summary>
/// rbl_mode control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.RadioButtonList rbl_mode;
/// <summary>
/// diffPanel control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Panel diffPanel;
/// <summary>
/// lt_notice control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Literal lt_notice;
/// <summary>
/// propertiesCompare control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Literal propertiesCompare;
/// <summary>
/// pl_buttons control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.HtmlControls.HtmlGenericControl pl_buttons;
/// <summary>
/// Button1 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Button Button1;
}
}