Studio support for cohorted courseware

TNL-652
This commit is contained in:
Andy Armstrong
2014-12-11 10:05:00 -05:00
parent 206ea8caeb
commit 4fa33e25ed
47 changed files with 1121 additions and 255 deletions

View File

@@ -144,8 +144,3 @@ from django.utils.translation import ugettext as _
</div>
</div>
</%block>
<!-- NOTE: remove this HTML if you want to not see the fake visibility modal -->
<%block name="modal_placeholder">
<%include file="ux/reference/modal_access-component.html" />
</%block>

View File

@@ -47,17 +47,9 @@
<div class="wrapper-content wrapper">
<section class="content">
<article class="content-primary" role="main">
% if configurations is None:
<div class="notice notice-incontext notice-moduledisabled">
<p class="copy">
${_("This module is disabled at the moment.")}
</p>
</div>
% else:
<div class="ui-loading">
<p><span class="spin"><i class="icon fa fa-refresh"></i></span> <span class="copy">${_("Loading")}</span></p>
</div>
% endif
</article>
<aside class="content-supplementary" role="complementary">
<div class="bit">

View File

@@ -46,6 +46,9 @@
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-visibility">
<a href="#" class="visibility-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>
@@ -71,6 +74,9 @@
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-visibility">
<a href="#" class="visibility-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>
@@ -96,6 +102,9 @@
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-visibility">
<a href="#" class="visibility-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>
@@ -151,6 +160,9 @@
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-visibility">
<a href="#" class="visibility-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>
@@ -176,6 +188,9 @@
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-visibility">
<a href="#" class="visibility-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>
@@ -201,6 +216,9 @@
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-visibility">
<a href="#" class="visibility-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>

View File

@@ -0,0 +1,3 @@
<div class="xblock xblock-visibility_view" data-runtime-version="1" data-usage-id="i4x:;_;_edX;_mock"
data-init="MockXBlock" data-runtime-class="StudioRuntime" tabindex="0">
</div>

View File

@@ -77,13 +77,12 @@ var visibleToStaffOnly = visibilityState === 'staff_only';
<% } else { %>
<p class="visbility-copy copy"><%= gettext("Staff and Students") %></p>
<% } %>
<!-- NOTE: @andyarmstrong, here's the new copy we're adding to the visibility summary UI to make sure we're as accurate as we can be at the final state of the unit/container's visibility -->
<p class="note-visibility">
<i class="icon icon-eye-open"></i>
<span class="note-copy"><%= gettext("Some content in this unit is only visible to particular groups") %></span>
</p>
<% if (hasContentGroupComponents) { %>
<p class="note-visibility">
<i class="icon icon-eye-open"></i>
<span class="note-copy"><%= gettext("Some content in this unit is only visible to particular groups") %></span>
</p>
<% } %>
<ul class="actions-inline">
<li class="action-inline">
<a href="" class="action-staff-lock" role="button" aria-pressed="<%= hasExplicitStaffLock %>">

View File

@@ -7,7 +7,6 @@
<%!
from django.utils.translation import ugettext as _
from contentstore import utils
from contentstore.views.course import should_show_group_configurations_page
import urllib
%>
@@ -333,9 +332,7 @@ CMS.URL.UPLOAD_ASSET = '${upload_asset_url}';
<ul>
<li class="nav-item"><a href="${grading_config_url}">${_("Grading")}</a></li>
<li class="nav-item"><a href="${course_team_url}">${_("Course Team")}</a></li>
% if should_show_group_configurations_page(context_course):
<li class="nav-item"><a href="${utils.reverse_course_url('group_configurations_list_handler', context_course.id)}">${_("Group Configurations")}</a></li>
% endif
<li class="nav-item"><a href="${utils.reverse_course_url('group_configurations_list_handler', context_course.id)}">${_("Group Configurations")}</a></li>
<li class="nav-item"><a href="${advanced_config_url}">${_("Advanced Settings")}</a></li>
</ul>
</nav>

View File

@@ -4,7 +4,6 @@
<%!
from django.utils.translation import ugettext as _
from contentstore import utils
from contentstore.views.course import should_show_group_configurations_page
from django.utils.html import escapejs
%>
<%block name="title">${_("Advanced Settings")}</%block>
@@ -92,9 +91,7 @@
<li class="nav-item"><a href="${details_url}">${_("Details &amp; Schedule")}</a></li>
<li class="nav-item"><a href="${grading_url}">${_("Grading")}</a></li>
<li class="nav-item"><a href="${course_team_url}">${_("Course Team")}</a></li>
% if should_show_group_configurations_page(context_course):
<li class="nav-item"><a href="${utils.reverse_course_url('group_configurations_list_handler', context_course.id)}">${_("Group Configurations")}</a></li>
% endif
<li class="nav-item"><a href="${utils.reverse_course_url('group_configurations_list_handler', context_course.id)}">${_("Group Configurations")}</a></li>
</ul>
</nav>
% endif

View File

@@ -6,7 +6,6 @@
<%namespace name='static' file='static_content.html'/>
<%!
from contentstore import utils
from contentstore.views.course import should_show_group_configurations_page
from django.utils.translation import ugettext as _
%>
@@ -135,9 +134,7 @@
<ul>
<li class="nav-item"><a href="${detailed_settings_url}">${_("Details &amp; Schedule")}</a></li>
<li class="nav-item"><a href="${course_team_url}">${_("Course Team")}</a></li>
% if should_show_group_configurations_page(context_course):
<li class="nav-item"><a href="${utils.reverse_course_url('group_configurations_list_handler', context_course.id)}">${_("Group Configurations")}</a></li>
% endif
<li class="nav-item"><a href="${utils.reverse_course_url('group_configurations_list_handler', context_course.id)}">${_("Group Configurations")}</a></li>
<li class="nav-item"><a href="${advanced_settings_url}">${_("Advanced Settings")}</a></li>
</ul>
</nav>

View File

@@ -1,6 +1,7 @@
<%!
from django.utils.translation import ugettext as _
from contentstore.views.helpers import xblock_studio_url
from contentstore.utils import is_visible_to_specific_content_groups
import json
%>
<%
@@ -38,8 +39,11 @@ messages = json.dumps(xblock.validate().to_json())
<div class="studio-xblock-wrapper" data-locator="${xblock.location | h}" data-course-key="${xblock.location.course_key | h}">
% endif
<!-- NOTE: @andyarmstrong, in order to style the case when an access level is set, we need to add a class to each xblock's wrapper. How does .has-visiblity-set sound? -->
<section class="wrapper-xblock ${section_class} ${collapsible_class} has-visibility-set">
<section class="wrapper-xblock ${section_class} ${collapsible_class}
% if is_visible_to_specific_content_groups(xblock):
has-group-visibility-set
% endif
">
% endif
<header class="xblock-header xblock-header-${xblock.category}">
@@ -77,7 +81,6 @@ messages = json.dumps(xblock.validate().to_json())
<span class="sr">${_("Delete")}</span>
</a>
</li>
<!-- NOTE: @andyarmstrong, here's a static version of the new access control we're adding. Remember we wanted to update the tooltip if particular groups were set on a component -->
<li class="action-item action-visibility">
<a href="#" data-tooltip="${_("Visibility Settings")}" class="visibility-button action-button">
<i class="icon-eye-open"></i>

View File

@@ -0,0 +1,94 @@
<%
from django.utils.translation import ugettext as _
from openedx.core.djangoapps.course_groups.partition_scheme import get_cohorted_user_partition
from contentstore.utils import ancestor_has_staff_lock
cohorted_user_partition = get_cohorted_user_partition(xblock.location.course_key)
unsorted_groups = cohorted_user_partition.groups if cohorted_user_partition else []
groups = sorted(unsorted_groups, key=lambda group: group.name)
selected_group_ids = xblock.group_access.get(cohorted_user_partition.id, []) if cohorted_user_partition else []
has_selected_groups = len(selected_group_ids) > 0
is_staff_locked = ancestor_has_staff_lock(xblock)
%>
<div class="modal-section visibility-summary">
% if len(groups) == 0:
<div class="is-not-configured has-actions">
<h4 class="title">${_('You have not set up any groups to manage visibility with.')}</h4>
<div class="copy">
<p>${_('Groups are a way for you to organize content in your course with a particular student experience in mind. They are commonly used to facilitate content and pedagogical experiments as well as provide different tracks of content.')}</p>
</div>
<div class="actions">
<a href="${manage_groups_url}" class="action action-primary action-settings">${_('Manage groups in this course')}</a>
</div>
</div>
% elif is_staff_locked:
<div class="summary-message summary-message-warning visibility-summary-message">
<i class="icon icon-warning-sign"></i>
<p class="copy">${_('The Unit this component is contained in is hidden from students. Visibility settings here will be trumped by this.')}</p>
</div>
% endif
</div>
% if len(groups) > 0:
<form class="visibility-controls-form" method="post" action="">
<div class="modal-section visibility-controls">
<h3 class="modal-section-title">${_('Set visibility to:')}</h3>
<div class="modal-section-content">
<section class="visibility-controls-primary">
<ul class="list-fields list-radio">
<li class="field field-radio field-visibility-level">
<input type="radio" id="visibility-level-all" name="visibility-level" value="" class="input input-radio visibility-level-all" ${'checked="checked"' if not has_selected_groups else ''} />
<label for="visibility-level-all" class="label">${_('All Students and Staff')}</label>
</li>
<li class="field field-radio field-visibility-level">
<input type="radio" id="visibility-level-specific" name="visibility-level" value="" class="input input-radio visibility-level-specific" ${'checked="checked"' if has_selected_groups else ''} />
<label for="visibility-level-specific" class="label">${_('Specific Content Groups')}</label>
</li>
</ul>
</section>
<div class="wrapper-visibility-specific" data-user-partition-id="${cohorted_user_partition.id}">
<section class="visibility-controls-secondary">
<div class="visibility-controls-group">
<h4 class="visibility-controls-title modal-subsection-title sr">${_('Content Groups')}</h4>
<ul class="list-fields list-checkbox">
<%
missing_group_ids = set(selected_group_ids)
%>
% for group in groups:
<%
is_group_selected = group.id in selected_group_ids
if is_group_selected:
missing_group_ids.remove(group.id)
%>
<li class="field field-checkbox field-visibility-content-group">
<input type="checkbox" id="visibility-content-group-${group.id}" name="visibility-content-group" value="${group.id}" class="input input-checkbox" ${'checked="checked"' if group.id in selected_group_ids else ''}/>
<label for="visibility-content-group-${group.id}" class="label">${group.name | h}</label>
</li>
% endfor
% for group_id in missing_group_ids:
<li class="field field-checkbox field-visibility-content-group was-removed">
<input type="checkbox" id="visibility-content-group-${group_id}" name="visibility-content-group" value="${group_id}" class="input input-checkbox" checked="checked" />
<label for="visibility-content-group-${group_id}" class="label">
${_('Deleted Content Group')}
<span class="note">${_('Content group no longer exists. Please choose another or allow access to All Students and staff')}</span>
</label>
</li>
% endfor
</ul>
</div>
</section>
</div>
</div>
</div>
</form>
% endif

View File

@@ -3,7 +3,6 @@
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext as _
from contentstore.context_processors import doc_url
from contentstore.views.course import should_show_group_configurations_page
%>
<%page args="online_help_token"/>
@@ -93,11 +92,9 @@
<li class="nav-item nav-course-settings-team">
<a href="${course_team_url}">${_("Course Team")}</a>
</li>
% if should_show_group_configurations_page(context_course):
<li class="nav-item nav-course-settings-group-configurations">
<a href="${reverse('contentstore.views.group_configurations_list_handler', kwargs={'course_key_string': unicode(course_key)})}">${_("Group Configurations")}</a>
</li>
% endif
<li class="nav-item nav-course-settings-group-configurations">
<a href="${reverse('contentstore.views.group_configurations_list_handler', kwargs={'course_key_string': unicode(course_key)})}">${_("Group Configurations")}</a>
</li>
<li class="nav-item nav-course-settings-advanced">
<a href="${advanced_settings_url}">${_("Advanced Settings")}</a>
</li>