Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions cms/djangoapps/contentstore/features/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,17 @@ def save_button_disabled(step):
assert world.css_has_class(button_css, disabled)


@step('I confirm the prompt')
def confirm_the_prompt(step):
prompt_css = 'a.button.action-primary'
world.css_click(prompt_css)


@step(u'I am shown a (.*)$')
def i_am_shown_a_notification(step, notification_type):
assert world.is_css_present('.wrapper-%s' % notification_type)


def type_in_codemirror(index, text):
world.css_click(".CodeMirror", index=index)
g = world.css_find("div.CodeMirror.CodeMirror-focused > div > textarea")
Expand Down
18 changes: 18 additions & 0 deletions cms/djangoapps/contentstore/features/component.feature
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,21 @@ Feature: Component Adding
When I will confirm all alerts
And I delete all components
Then I see no components

Scenario: I see a prompt on delete
Given I have opened a new course in studio
And I am editing a new unit
And I add the following components:
| Component |
| Discussion |
And I delete a component
Then I am shown a prompt

Scenario: I see a notification on save
Given I have opened a new course in studio
And I am editing a new unit
And I add the following components:
| Component |
| Discussion |
And I edit and save a component
Then I am shown a notification
11 changes: 11 additions & 0 deletions cms/djangoapps/contentstore/features/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ def see_no_components(steps):
assert world.is_css_not_present('li.component')


@step(u'I delete a component')
def delete_one_component(step):
world.css_click('a.delete-button')


@step(u'I edit and save a component')
def edit_and_save_component(step):
world.css_click('.edit-button')
world.css_click('.save-button')


def step_selector_list(data_type, path, index=1):
selector_list = ['a[data-type="{}"]'.format(data_type)]
if index != 1:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Feature: Overview Toggle Section
In order to quickly view the details of a course's section or to scan the inventory of sections
Feature: Course Overview
In order to quickly view the details of a course's section and set release dates and grading
As a course author
I want to toggle the visibility of each section's subsection details in the overview listing
I want to use the course overview page

Scenario: The default layout for the overview page is to show sections in expanded view
Given I have a course with multiple sections
Expand Down Expand Up @@ -57,3 +57,9 @@ Feature: Overview Toggle Section
And I click the "Expand All Sections" link
Then I see the "Collapse All Sections" link
And all sections are expanded

Scenario: Notification is shown on grading status changes
Given I have a course with 1 section
When I navigate to the course overview page
And I change an assignment's grading status
Then I am shown a notification
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,9 @@ def all_sections_are_collapsed(step):
subsections = world.css_find(subsection_locator)
for index in range(len(subsections)):
assert_false(world.css_visible(subsection_locator, index=index))


@step(u"I change an assignment's grading status")
def change_grading_status(step):
world.css_find('a.menu-toggle').click()
world.css_find('.menu li').first.click()
1 change: 1 addition & 0 deletions cms/djangoapps/contentstore/features/section.feature
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@ Feature: Create Section
And I have added a new section
When I will confirm all alerts
And I press the "section" delete icon
And I confirm the prompt
Then the section does not exist
1 change: 1 addition & 0 deletions cms/djangoapps/contentstore/features/subsection.feature
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ Feature: Create Subsection
And I see my subsection on the Courseware page
When I will confirm all alerts
And I press the "subsection" delete icon
And I confirm the prompt
Then the subsection does not exist
33 changes: 32 additions & 1 deletion cms/static/coffee/spec/views/overview_spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,30 @@ describe "Course Overview", ->
</div>
"""#"

appendSetFixtures """
<section class="courseware-section branch" data-id="a-location-goes-here">
<li class="branch collapsed id-holder" data-id="an-id-goes-here">
<a href="#" class="delete-section-button"></a>
</li>
</section>
"""#"

spyOn(window, 'saveSetSectionScheduleDate').andCallThrough()
# Have to do this here, as it normally gets bound in document.ready()
$('a.save-button').click(saveSetSectionScheduleDate)
$('a.delete-section-button').click(deleteSection)

@notificationSpy = spyOn(CMS.Views.Notification.Mini.prototype, 'show').andCallThrough()
window.analytics = jasmine.createSpyObj('analytics', ['track'])
window.course_location_analytics = jasmine.createSpy()
sinon.useFakeXMLHttpRequest()
@xhr = sinon.useFakeXMLHttpRequest()
requests = @requests = []
@xhr.onCreate = (req) -> requests.push(req)

afterEach ->
delete window.analytics
delete window.course_location_analytics
@notificationSpy.reset()

it "should save model when save is clicked", ->
$('a.edit-button').click()
Expand All @@ -61,3 +74,21 @@ describe "Course Overview", ->
$('a.edit-button').click()
$('a.save-button').click()
expect(@notificationSpy).toHaveBeenCalled()

it "should delete model when delete is clicked", ->

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to add a test for cancelling the delete confirmation.

deleteSpy = spyOn(window, '_deleteItem').andCallThrough()
$('a.delete-section-button').click()
$('a.action-primary').click()
expect(deleteSpy).toHaveBeenCalled()
expect(@requests[0].url).toEqual('/delete_item')

it "should not delete model when cancel is clicked", ->
deleteSpy = spyOn(window, '_deleteItem').andCallThrough()
$('a.delete-section-button').click()
$('a.action-secondary').click()
expect(@requests.length).toEqual(0)

it "should show a confirmation on delete", ->
$('a.delete-section-button').click()
$('a.action-primary').click()
expect(@notificationSpy).toHaveBeenCalled()
4 changes: 4 additions & 0 deletions cms/static/coffee/src/views/module_edit.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,15 @@ class CMS.Views.ModuleEdit extends Backbone.View

data.metadata = _.extend(data.metadata || {}, @changedMetadata())
@hideModal()
saving = new CMS.Views.Notification.Mini
title: gettext('Saving') + '&hellip;'
saving.show()
@model.save(data).done( =>
# # showToastMessage("Your changes have been saved.", null, 3)
@module = null
@render()
@$el.removeClass('editing')
saving.hide()
).fail( ->
showToastMessage(gettext("There was an error saving your changes. Please try again."), null, 3)
)
Expand Down
62 changes: 39 additions & 23 deletions cms/static/coffee/src/views/unit.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ class CMS.Views.UnitEdit extends Backbone.View
type = $(event.currentTarget).data('type')
@$newComponentTypePicker.slideUp(250)
@$(".new-component-#{type}").slideDown(250)
$('html, body').animate({
scrollTop: @$(".new-component-#{type}").offset().top
$('html, body').animate({
scrollTop: @$(".new-component-#{type}").offset().top
}, 500)

closeNewComponent: (event) =>
Expand Down Expand Up @@ -115,27 +115,43 @@ class CMS.Views.UnitEdit extends Backbone.View
@model.save()

deleteComponent: (event) =>
if not confirm 'Are you sure you want to delete this component? This action cannot be undone.'
return
$component = $(event.currentTarget).parents('.component')
$.post('/delete_item', {
id: $component.data('id')
}, =>
analytics.track "Deleted a Component",
course: course_location_analytics
unit_id: unit_location_analytics
id: $component.data('id')

$component.remove()
# b/c we don't vigilantly keep children up to date
# get rid of it before it hurts someone
# sorry for the js, i couldn't figure out the coffee equivalent
`_this.model.save({children: _this.components()},
{success: function(model) {
model.unset('children');
}}
);`
msg = new CMS.Views.Prompt.Warning(
title: gettext('Delete this component?'),
message: gettext('Deleting this component is permanent and cannot be undone.'),
actions:
primary:
text: gettext('Yes, delete this component'),
click: (view) =>
view.hide()
deleting = new CMS.Views.Notification.Mini
title: gettext('Deleting') + '&hellip;',
deleting.show()
$component = $(event.currentTarget).parents('.component')
$.post('/delete_item', {
id: $component.data('id')
}, =>
deleting.hide()
analytics.track "Deleted a Component",
course: course_location_analytics
unit_id: unit_location_analytics
id: $component.data('id')

$component.remove()
# b/c we don't vigilantly keep children up to date
# get rid of it before it hurts someone
# sorry for the js, i couldn't figure out the coffee equivalent
`_this.model.save({children: _this.components()},
{success: function(model) {
model.unset('children');
}}
);`
)
secondary:
text: gettext('Cancel'),
click: (view) ->
view.hide()
)
msg.show()

deleteDraft: (event) ->
@wait(true)
Expand Down Expand Up @@ -236,7 +252,7 @@ class CMS.Views.UnitEdit.NameEdit extends Backbone.View
class CMS.Views.UnitEdit.LocationState extends Backbone.View
initialize: =>
@model.on('change:state', @render)

render: =>
@$el.toggleClass("#{@model.previous('state')}-item #{@model.get('state')}-item")

Expand Down
70 changes: 46 additions & 24 deletions cms/static/js/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -356,39 +356,61 @@ function createNewUnit(e) {

function deleteUnit(e) {
e.preventDefault();
_deleteItem($(this).parents('li.leaf'));
_deleteItem($(this).parents('li.leaf'), 'Unit');
}

function deleteSubsection(e) {
e.preventDefault();
_deleteItem($(this).parents('li.branch'));
_deleteItem($(this).parents('li.branch'), 'Subsection');
}

function deleteSection(e) {
e.preventDefault();
_deleteItem($(this).parents('section.branch'));
}

function _deleteItem($el) {
if (!confirm(gettext('Are you sure you wish to delete this item. It cannot be reversed!'))) return;

var id = $el.data('id');

analytics.track('Deleted an Item', {
'course': course_location_analytics,
'id': id
});


$.post('/delete_item', {
'id': id,
'delete_children': true,
'delete_all_versions': true
},

function(data) {
$el.remove();
_deleteItem($(this).parents('section.branch'), 'Section');
}

function _deleteItem($el, type) {
var confirm = new CMS.Views.Prompt.Warning({
title: gettext('Delete this ' + type + '?'),
message: gettext('Deleting this ' + type + ' is permanent and cannot be undone.'),
actions: {
primary: {
text: gettext('Yes, delete this ' + type),
click: function(view) {
view.hide();

var id = $el.data('id');

analytics.track('Deleted an Item', {
'course': course_location_analytics,
'id': id
});

var deleting = new CMS.Views.Notification.Mini({
title: gettext('Deleting') + '&hellip;'
});
deleting.show();

$.post('/delete_item',
{'id': id,
'delete_children': true,
'delete_all_versions': true},
function(data) {
$el.remove();
deleting.hide();
}
);
}
},
secondary: {
text: gettext('Cancel'),
click: function(view) {
view.hide();
}
}
}
});
confirm.show();
}

function markAsLoaded() {
Expand Down
11 changes: 10 additions & 1 deletion cms/static/js/views/grader-select-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,18 @@ CMS.Views.OverviewAssignmentGrader = Backbone.View.extend({

this.removeMenu(e);

var saving = new CMS.Views.Notification.Mini({
title: gettext('Saving') + '&hellip;'
});
saving.show();

// TODO I'm not happy with this string fetch via the html for what should be an id. I'd rather use the id attr
// of the CourseGradingPolicy model or null for Not Graded (NOTE, change template's if check for is-selected accordingly)
this.assignmentGrade.save('graderType', $(e.target).text());
this.assignmentGrade.save(
'graderType',
$(e.target).text(),
{success: function () { saving.hide(); }}
);

this.render();
}
Expand Down