Displays the date, time, and username of the most recent save and publish
Conflicts: cms/djangoapps/contentstore/views/item.py
This commit is contained in:
@@ -566,8 +566,10 @@ def create_xblock_info(usage_key, xblock, data=None, metadata=None):
|
||||
"category": xblock.category,
|
||||
"has_changes": modulestore().has_changes(usage_key),
|
||||
"published": publish_state in (PublishState.public, PublishState.draft),
|
||||
"edited_on": get_default_time_display(xblock.edited_on) if xblock.edited_on else None,
|
||||
"edited_by": safe_get_username(xblock.edited_by)
|
||||
"edited_on": get_default_time_display(xblock.subtree_edited_on) if xblock.subtree_edited_on else None,
|
||||
"edited_by": safe_get_username(xblock.subtree_edited_by),
|
||||
"published_on": get_default_time_display(xblock.published_date) if xblock.published_date else None,
|
||||
"published_by": safe_get_username(xblock.published_by),
|
||||
}
|
||||
if data is not None:
|
||||
xblock_info["data"] = data
|
||||
|
||||
@@ -32,14 +32,21 @@ define(["backbone", "js/utils/module"], function(Backbone, ModuleUtils) {
|
||||
*/
|
||||
"locked": null,
|
||||
/**
|
||||
* Date of last edit to this xblock. Will be the latest change to either the draft
|
||||
* or the published version.
|
||||
* Date of the last edit to this xblock or any of its descendants.
|
||||
*/
|
||||
"edited_on":null,
|
||||
/**
|
||||
* User who last edited the xblock.
|
||||
* User who last edited the xblock or any of its descendants.
|
||||
*/
|
||||
"edited_by":null,
|
||||
/**
|
||||
* Date of the last publish of this xblock, or null if never published.
|
||||
*/
|
||||
"published_on": null,
|
||||
/**
|
||||
* User who last published the xblock, or null if never published.
|
||||
*/
|
||||
"published_by": null,
|
||||
/**
|
||||
* If the xblock is published, the date on which it will be released to students.
|
||||
*/
|
||||
|
||||
@@ -12,6 +12,7 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin
|
||||
beforeEach(function () {
|
||||
edit_helpers.installTemplate('xblock-string-field-editor');
|
||||
edit_helpers.installTemplate('publish-xblock');
|
||||
edit_helpers.installTemplate('publish-history');
|
||||
appendSetFixtures(mockContainerPage);
|
||||
|
||||
model = new XBlockInfo({
|
||||
@@ -130,6 +131,7 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin
|
||||
draftBit = "draft",
|
||||
publishButtonCss = ".action-publish",
|
||||
discardChangesButtonCss = ".action-discard",
|
||||
lastDraftCss = ".wrapper-last-draft",
|
||||
request, lastRequest, promptSpies, sendDiscardChangesToServer;
|
||||
|
||||
lastRequest = function() { return requests[requests.length - 1]; };
|
||||
@@ -280,6 +282,49 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin
|
||||
expect(requests.length).toEqual(numRequests);
|
||||
expect(containerPage.$(discardChangesButtonCss)).not.toHaveClass('is-disabled');
|
||||
});
|
||||
|
||||
it('renders the last published date and user when there are no changes', function () {
|
||||
renderContainerPage(mockContainerXBlockHtml, this);
|
||||
fetch({ "id": "locator-container", "has_changes": false,
|
||||
"edited_on": "Jun 30, 2014 at 14:20 UTC", "edited_by": "joe",
|
||||
"published_on": "Jul 01, 2014 at 12:45 UTC", "published_by": "amako"});
|
||||
expect(containerPage.$(lastDraftCss).text()).
|
||||
toContain("Last published Jul 01, 2014 at 12:45 UTC by amako");
|
||||
});
|
||||
|
||||
it('renders the last saved date and user when there are changes', function () {
|
||||
renderContainerPage(mockContainerXBlockHtml, this);
|
||||
fetch({ "id": "locator-container", "has_changes": true,
|
||||
"edited_on": "Jul 02, 2014 at 14:20 UTC", "edited_by": "joe",
|
||||
"published_on": "Jul 01, 2014 at 12:45 UTC", "published_by": "amako"});
|
||||
expect(containerPage.$(lastDraftCss).text()).
|
||||
toContain("Draft saved on Jul 02, 2014 at 14:20 UTC by joe");
|
||||
});
|
||||
});
|
||||
|
||||
describe("PublishHistory", function () {
|
||||
var lastPublishCss = ".wrapper-last-publish";
|
||||
|
||||
it('renders the last published date and user when the block is published', function () {
|
||||
renderContainerPage(mockContainerXBlockHtml, this);
|
||||
fetch({ "id": "locator-container", "published": true,
|
||||
"published_on": "Jul 01, 2014 at 12:45 UTC", "published_by": "amako" });
|
||||
expect(containerPage.$(lastPublishCss).text()).
|
||||
toContain("Last published Jul 01, 2014 at 12:45 UTC by amako");
|
||||
});
|
||||
|
||||
it('renders never published when the block is unpublished', function () {
|
||||
renderContainerPage(mockContainerXBlockHtml, this);
|
||||
fetch({ "id": "locator-container", "published": false,
|
||||
"published_on": "Jul 01, 2014 at 12:45 UTC", "published_by": "amako" });
|
||||
expect(containerPage.$(lastPublishCss).text()).toContain("Never published");
|
||||
});
|
||||
|
||||
it('renders correctly when the block is published without publish info', function () {
|
||||
renderContainerPage(mockContainerXBlockHtml, this);
|
||||
fetch({ "id": "locator-container", "published": true, "published_on": null, "published_by": null});
|
||||
expect(containerPage.$(lastPublishCss).text()).toContain("Previously published");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -34,6 +34,12 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/contai
|
||||
});
|
||||
this.xblockPublisher.render();
|
||||
|
||||
this.publishHistory = new ContainerSubviews.PublishHistory({
|
||||
el: this.$('#publish-history'),
|
||||
model: this.model
|
||||
});
|
||||
this.publishHistory.render();
|
||||
|
||||
// No need to render initially. This is only used for updating state
|
||||
// when the unit changes visibility.
|
||||
this.visibilityState = new ContainerSubviews.VisibilityStateController({
|
||||
|
||||
@@ -108,7 +108,9 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/feedba
|
||||
has_changes: this.model.get('has_changes'),
|
||||
published: this.model.get('published'),
|
||||
edited_on: this.model.get('edited_on'),
|
||||
edited_by: this.model.get('edited_by')
|
||||
edited_by: this.model.get('edited_by'),
|
||||
published_on: this.model.get('published_on'),
|
||||
published_by: this.model.get('published_by')
|
||||
}));
|
||||
|
||||
return this;
|
||||
@@ -174,9 +176,40 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/feedba
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* PublishHistory displays when and by whom the xblock was last published, if it ever was.
|
||||
*/
|
||||
var PublishHistory = BaseView.extend({
|
||||
// takes XBlockInfo as a model
|
||||
|
||||
initialize: function () {
|
||||
BaseView.prototype.initialize.call(this);
|
||||
this.template = this.loadTemplate('publish-history');
|
||||
this.model.on('sync', this.onSync, this);
|
||||
},
|
||||
|
||||
onSync: function(e) {
|
||||
if (e.changedAttributes() && (('published' in e.changedAttributes()) ||
|
||||
('published_on' in e.changedAttributes()) || ('published_by' in e.changedAttributes()))) {
|
||||
this.render();
|
||||
}
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.html(this.template({
|
||||
published: this.model.get('published'),
|
||||
published_on: this.model.get('published_on'),
|
||||
published_by: this.model.get('published_by')
|
||||
}));
|
||||
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
'VisibilityStateController': VisibilityStateController,
|
||||
'PreviewActionController': PreviewActionController,
|
||||
'Publisher': Publisher
|
||||
'Publisher': Publisher,
|
||||
'PublishHistory': PublishHistory
|
||||
};
|
||||
}); // end define();
|
||||
|
||||
@@ -139,6 +139,11 @@
|
||||
|
||||
.wrapper-last-draft {
|
||||
padding: ($baseline*.75) ($baseline*.75) ($baseline/4) ($baseline*.75);
|
||||
|
||||
.date,
|
||||
.user {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper-release {
|
||||
@@ -184,6 +189,26 @@
|
||||
|
||||
}
|
||||
|
||||
// versioning widget
|
||||
.unit-publish-history {
|
||||
|
||||
.wrapper-last-publish {
|
||||
margin-bottom: $baseline;
|
||||
padding: ($baseline*.75);
|
||||
background-color: $white;
|
||||
|
||||
.copy {
|
||||
@extend %t-copy-sub2;
|
||||
color: $gray;
|
||||
}
|
||||
|
||||
.date,
|
||||
.user {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// location widget
|
||||
.unit-location {
|
||||
@extend %bar-module;
|
||||
|
||||
@@ -24,7 +24,7 @@ from django.utils.translation import ugettext as _
|
||||
templates = ["basic-modal", "modal-button", "edit-xblock-modal",
|
||||
"editor-mode-button", "upload-dialog", "image-modal",
|
||||
"add-xblock-component", "add-xblock-component-button", "add-xblock-component-menu",
|
||||
"add-xblock-component-menu-problem", "xblock-string-field-editor", "publish-xblock"]
|
||||
"add-xblock-component-menu-problem", "xblock-string-field-editor", "publish-xblock", "publish-history"]
|
||||
%>
|
||||
<%block name="header_extras">
|
||||
% for template_name in templates:
|
||||
@@ -142,6 +142,7 @@ templates = ["basic-modal", "modal-button", "edit-xblock-modal",
|
||||
% endif
|
||||
% if is_unit_page:
|
||||
<div id="publish-unit"></div>
|
||||
<div id="publish-history" class="unit-publish-history"></div>
|
||||
<div class="unit-location is-hidden">
|
||||
<h4 class="bar-mod-title">${_("Unit Location")}</h4>
|
||||
<div class="wrapper-unit-id bar-mod-content">
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
</article>
|
||||
<aside class="content-supplementary" role="complimentary">
|
||||
<div id="publish-unit" class="window"></div>
|
||||
<div id="publish-history"></div>
|
||||
</aside>
|
||||
<div class="unit-location">
|
||||
<h4 class="header">${_("Unit Location")}</h4>
|
||||
|
||||
16
cms/templates/js/publish-history.underscore
Normal file
16
cms/templates/js/publish-history.underscore
Normal file
@@ -0,0 +1,16 @@
|
||||
<div class="wrapper-last-publish">
|
||||
<p class="copy">
|
||||
<% if (published) {
|
||||
if (published_on && published_by) {
|
||||
var message = gettext("Last published %(last_published_date)s by %(publish_username)s"); %>
|
||||
<%= interpolate(message, {
|
||||
last_published_date: '<span class="date">' + published_on + '</span>',
|
||||
publish_username: '<span class="user">' + published_by + '</span>' }, true) %>
|
||||
<% } else { %>
|
||||
<%= gettext("Previously published") %>
|
||||
<% } %>
|
||||
<% } else { %>
|
||||
<%= gettext("Never published") %>
|
||||
<% } %>
|
||||
</p>
|
||||
</div>
|
||||
@@ -7,12 +7,23 @@
|
||||
<% } %>
|
||||
</h3>
|
||||
|
||||
<!--To be added in STUDIO-1826-->
|
||||
<!--<div class="wrapper-last-draft bar-mod-content">-->
|
||||
<!--<p class="copy meta">-->
|
||||
<!--Draft saved on 6/15/2014 at 12:45pm by amako-->
|
||||
<!--</p>-->
|
||||
<!--</div>-->
|
||||
<div class="wrapper-last-draft bar-mod-content">
|
||||
<p class="copy meta">
|
||||
<% if (has_changes && edited_on && edited_by) {
|
||||
var message = gettext("Draft saved on %(last_saved_date)s by %(edit_username)s") %>
|
||||
<%= interpolate(message, {
|
||||
last_saved_date: '<span class="date">' + edited_on + '</span>',
|
||||
edit_username: '<span class="user">' + edited_by + '</span>' }, true) %>
|
||||
<% } else if (published_on && published_by) {
|
||||
var message = gettext("Last published %(last_published_date)s by %(publish_username)s"); %>
|
||||
<%= interpolate(message, {
|
||||
last_published_date: '<span class="date">' + published_on + '</span>',
|
||||
publish_username: '<span class="user">' + published_by + '</span>' }, true) %>
|
||||
<% } else { %>
|
||||
<%= gettext("Previously published") %>
|
||||
<% } %>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!--To be added in STUD-1829-->
|
||||
<!--<div class="wrapper-release bar-mod-content">-->
|
||||
|
||||
Reference in New Issue
Block a user