Files
edx-platform/cms/templates/js/course-outline.underscore
Michael Terry 74887aa216 feat: turn on schedule creation by default
This commit removes several waffle toggles that have been enabled
on edx.org for years. It's time to remove the rollout gating for
these features and enable them by default.

This doesn't directly change any behavior. But it does create new
database objects by default now and allows for enabling other
schedule based features more easily.

Specifically, the following toggles were affected.

schedules.create_schedules_for_course
- Waffle flag removed as always-enabled
- We now always create a schedule when an enrollment is created

schedules.send_updates_for_course
- Waffle flag removed as always-enabled
- Course update emails are sent as long as the ScheduleConfig
  allows it.
- This is not a change in default behavior, because ScheduleConfig
  is off by default.

dynamic_pacing.studio_course_update
- Waffle switch removed as always-enabled
- Course teams can now always edit course updates directly in Studio

ScheduleConfig.create_schedules
ScheduleConfig.hold_back_ratio
- Model fields for rolling out the schedules feature
- Schedules are now always created
- This commit only removes references to these fields, they still
  exist in the database. A future commit will remove them entirely

This commit also adds a new has_highlights field to CourseOverview.
This is used to cache whether a course has highlights, used to
decide which course update email behavior they get. Previously every
enrollment had to dig into the modulestore to determine that.
2021-02-23 12:34:02 -05:00

320 lines
16 KiB
Plaintext

<%
var releasedToStudents = xblockInfo.get('released_to_students');
var visibilityState = xblockInfo.get('visibility_state');
var published = xblockInfo.get('published');
var prereq = xblockInfo.get('prereq');
var hasPartitionGroups = xblockInfo.get('has_partition_group_components');
var userPartitionInfo = xblockInfo.get('user_partition_info');
var selectedGroupsLabel = userPartitionInfo['selected_groups_label'];
var selectedPartitionIndex = userPartitionInfo['selected_partition_index'];
var statusMessages = [];
var messageType;
var messageText;
var statusType = null;
var addStatusMessage = function (statusType, message) {
var statusIconClass = '';
if (statusType === 'warning') {
statusIconClass = 'fa-file-o';
} else if (statusType === 'error') {
statusIconClass = 'fa-warning';
} else if (statusType === 'staff-only' || statusType === 'gated') {
statusIconClass = 'fa-lock';
} else if (statusType === 'partition-groups') {
statusIconClass = 'fa-eye';
}
statusMessages.push({iconClass: statusIconClass, text: message});
};
if (prereq) {
var prereqDisplayName = '';
_.each(xblockInfo.get('prereqs'), function (p) {
if (p.block_usage_key == prereq) {
prereqDisplayName = p.block_display_name;
return false;
}
});
messageType = 'gated';
messageText = interpolate(
gettext('Prerequisite: %(prereq_display_name)s'),
{prereq_display_name: prereqDisplayName},
true
);
addStatusMessage(messageType, messageText);
}
if (staffOnlyMessage) {
messageType = 'staff-only';
messageText = gettext('Contains staff only content');
addStatusMessage(messageType, messageText);
} else {
if (visibilityState === 'needs_attention' && xblockInfo.isVertical()) {
messageType = 'warning';
if (published && releasedToStudents) {
messageText = gettext('Unpublished changes to live content');
} else if (!published) {
messageText = gettext('Unpublished units will not be released');
} else {
messageText = gettext('Unpublished changes to content that will release in the future');
}
addStatusMessage(messageType, messageText);
}
if (selectedPartitionIndex !== -1 && !isNaN(selectedPartitionIndex) && xblockInfo.isVertical()) {
messageType = 'partition-groups';
messageText = edx.StringUtils.interpolate(
gettext('Access to this unit is restricted to: {selectedGroupsLabel}'),
{
selectedGroupsLabel: selectedGroupsLabel
}
)
addStatusMessage(messageType, messageText);
} else if (hasPartitionGroups && xblockInfo.isVertical()) {
addStatusMessage(
'partition-groups',
gettext('Access to some content in this unit is restricted to specific groups of learners')
);
}
}
var gradingType = gettext('Ungraded');
if (xblockInfo.get('graded')) {
gradingType = xblockInfo.get('format')
}
var is_proctored_exam = xblockInfo.get('is_proctored_exam');
var is_practice_exam = xblockInfo.get('is_practice_exam');
var is_onboarding_exam = xblockInfo.get('is_onboarding_exam');
var exam_value;
if (is_proctored_exam) {
if (is_onboarding_exam) {
exam_value = gettext('Onboarding Exam');
} else if (is_practice_exam) {
exam_value = gettext('Practice proctored Exam');
} else {
exam_value = gettext('Proctored Exam');
}
} else {
exam_value = gettext('Timed Exam');
}
%>
<% if (parentInfo) { %>
<li class="outline-item outline-<%- xblockType %> <%- visibilityClass %> is-draggable <%- includesChildren ? 'is-collapsible' : '' %> <%- isCollapsed ? 'is-collapsed' : '' %>"
data-parent="<%- parentInfo.get('id') %>" data-locator="<%- xblockInfo.get('id') %>" id="<%- xblockInfo.get('id') %>">
<span class="draggable-drop-indicator draggable-drop-indicator-before"><span class="icon fa fa-caret-right" aria-hidden="true"></span></span>
<% if (xblockInfo.isHeaderVisible()) { %>
<div class="<%- xblockType %>-header">
<% if (includesChildren) { %>
<h3 class="<%- xblockType %>-header-details expand-collapse <%- isCollapsed ? 'expand' : 'collapse' %> ui-toggle-expansion"
title="<%- interpolate(
gettext('Collapse/Expand this %(xblock_type)s'), { xblock_type: xblockTypeDisplayName }, true
) %>"
>
<span class="icon fa fa-caret-down" aria-hidden="true"></span>
<% } else { %>
<h3 class="<%- xblockType %>-header-details">
<% } %>
<% if (xblockInfo.isVertical()) { %>
<span class="unit-title item-title">
<span class="wrapper-<%- xblockType %>-title wrapper-xblock-field incontext-editor is-editable" data-field="display_name" data-field-display-name="<%- gettext("Display Name") %>">
<a class="<%- xblockType %>-title item-title xblock-field-value incontext-editor-value" href="<%- xblockInfo.get('studio_url') %>"><%- xblockInfo.get('display_name') %></a>
</span>
</span>
<% } else { %>
<span class="wrapper-<%- xblockType %>-title wrapper-xblock-field incontext-editor is-editable" data-field="display_name" data-field-display-name="<%- gettext("Display Name") %>">
<span class="<%- xblockType %>-title item-title xblock-field-value incontext-editor-value"><%- xblockInfo.get('display_name') %></span>
</span>
<% } %>
</h3>
<div class="<%- xblockType %>-header-actions">
<ul class="actions-list">
<% if (xblockInfo.isSequential() && xblockInfo.get('proctoring_exam_configuration_link')) { %>
<li class="action-item">
<a href="<%- xblockInfo.get('proctoring_exam_configuration_link') %>" data-tooltip="<%- gettext('Proctoring Settings') %>" class="proctoring-configuration-button" rel="noopener" target="_blank">
<span class="action-button-text"><%- gettext('Proctoring Settings') %></span>
</a>
</li>
<% } %>
<% if (xblockInfo.isPublishable()) { %>
<li class="action-item action-publish">
<a href="#" data-tooltip="<%- gettext('Publish') %>" class="publish-button action-button">
<span class="icon fa fa-upload" aria-hidden="true"></span>
<span class="sr action-button-text"><%- gettext('Publish') %></span>
</a>
</li>
<% } %>
<% if (xblockInfo.isEditableOnCourseOutline()) { %>
<li class="action-item action-configure">
<a href="#" data-tooltip="<%- gettext('Configure') %>" class="configure-button action-button">
<span class="icon fa fa-gear" aria-hidden="true"></span>
<span class="sr action-button-text"><%- gettext('Configure') %></span>
</a>
</li>
<% } %>
<% if (xblockInfo.isDuplicable()) { %>
<li class="action-item action-duplicate">
<a href="#" data-tooltip="<%- gettext('Duplicate') %>" class="duplicate-button action-button">
<span class="icon fa fa-copy" aria-hidden="true"></span>
<span class="sr action-button-text"><%- gettext('Duplicate') %></span>
</a>
</li>
<% } %>
<% if (xblockInfo.isDeletable()) { %>
<li class="action-item action-delete">
<a href="#" data-tooltip="<%- gettext('Delete') %>" class="delete-button action-button">
<span class="icon fa fa-trash-o" aria-hidden="true"></span>
<span class="sr action-button-text"><%- gettext('Delete') %></span>
</a>
</li>
<% } %>
<% if (xblockInfo.isDraggable()) { %>
<li class="action-item action-drag">
<span data-tooltip="<%- gettext('Drag to reorder') %>"
class="drag-handle <%- xblockType %>-drag-handle action">
<span class="sr"><%- gettext('Drag to reorder') %></span>
</span>
</li>
<% } %>
</ul>
</div>
</div>
<div class="<%- xblockType %>-status">
<% if (!xblockInfo.isVertical()) { %>
<% if (xblockInfo.get('explanatory_message') !=null) { %>
<div class="explanatory-message">
<span>
<%- xblockInfo.get('explanatory_message') %>
</span>
</div>
<% } else { %>
<div class="status-release">
<p>
<span class="sr status-release-label"><%- gettext('Release Status:') %></span>
<span class="status-release-value">
<% if (!course.get('self_paced')) { %>
<% if (xblockInfo.get('released_to_students')) { %>
<span class="icon fa fa-check" aria-hidden="true"></span>
<%- gettext('Released:') %>
<% } else if (xblockInfo.get('release_date')) { %>
<span class="icon fa fa-clock-o" aria-hidden="true"></span>
<%- gettext('Scheduled:') %>
<% } else { %>
<span class="icon fa fa-clock-o" aria-hidden="true"></span>
<%- gettext('Unscheduled') %>
<% } %>
<% if (xblockInfo.get('release_date')) { %>
<%- xblockInfo.get('release_date') %>
<% } %>
<% } %>
</span>
</p>
</div>
<% } %>
<% if (xblockInfo.isChapter()) { %>
<div class="block-highlights">
<% var number_of_highlights = (xblockInfo.get('highlights') || []).length; %>
<button class="block-highlights-value highlights-button action-button">
<span class="number-highlights"><%- number_of_highlights %></span>
<%- gettext('Section Highlights') %>
</button>
</div>
<% } %>
<% if (xblockInfo.get('is_time_limited')) { %>
<div class="status-timed-proctored-exam">
<p>
<span class="sr status-grading-label"> <%- gettext('Graded as:') %> </span>
<span class="icon fa fa-check" aria-hidden="true"></span>
<span class="status-grading-value"> <%- gradingType %> </span>
-
<span class="sr status-proctored-exam-label"> <%- exam_value %> </span>
<span class="status-proctored-exam-value"> <%- exam_value %> </span>
<% if (xblockInfo.get('due_date') && !course.get('self_paced')) { %>
<span class="status-grading-date"> <%- gettext('Due:') %> <%- xblockInfo.get('due_date') %> </span>
<% } %>
</p>
</div>
<% } else if (xblockInfo.get('due_date') || xblockInfo.get('graded')) { %>
<div class="status-grading">
<p>
<span class="sr status-grading-label"> <%- gettext('Graded as:') %> </span>
<span class="icon fa fa-check" aria-hidden="true"></span>
<span class="status-grading-value"> <%- gradingType %> </span>
<% if (xblockInfo.get('due_date') && !course.get('self_paced')) { %>
<span class="status-grading-date"> <%- gettext('Due:') %> <%- xblockInfo.get('due_date') %> </span>
<% } %>
</p>
</div>
<% } %>
<div class="status-hide-after-due">
<p>
<% if (xblockInfo.get('hide_after_due')) { %>
<span class="icon fa fa-eye-slash" aria-hidden="true"></span>
<span class="status-hide-after-due-value">
<% if (course.get('self_paced')) { %>
<%- gettext("Subsection is hidden after course end date") %> </span>
<% } else { %>
<%- gettext("Subsection is hidden after due date") %> </span>
<% } %>
<% } %>
</p>
</div>
<% } %>
<% if (statusMessages.length > 0) { %>
<div class="status-messages">
<% for (var i=0; i<statusMessages.length; i++) { %>
<div class="status-message">
<span class="icon fa <%- statusMessages[i].iconClass %>" aria-hidden="true"></span>
<p class="status-message-copy"><%- statusMessages[i].text %></p>
</div>
<% } %>
</div>
<% } %>
</div>
<% } %>
<% } %>
<% if (!parentInfo && xblockInfo.get('child_info') && xblockInfo.get('child_info').children.length === 0) { %>
<div class="no-content add-section">
<p><%- gettext("You haven't added any content to this course yet.") %>
<a href="#" class="button button-new" data-category="<%- childCategory %>"
data-parent="<%- xblockInfo.get('id') %>" data-default-name="<%- defaultNewChildName %>"
title="<%- interpolate(
gettext('Click to add a new %(xblock_type)s'), { xblock_type: defaultNewChildName }, true
) %>"
>
<span class="icon fa fa-plus" aria-hidden="true"></span><%- addChildLabel %>
</a>
</p>
</div>
<% } else if (!xblockInfo.isVertical()) { %>
<div class="outline-content <%- xblockType %>-content">
<ol class="<%- typeListClass %> is-sortable">
<li class="ui-splint ui-splint-indicator">
<span class="draggable-drop-indicator draggable-drop-indicator-initial"><span class="icon fa fa-caret-right" aria-hidden="true"></span></span>
</li>
</ol>
<% if (childType) { %>
<% if (xblockInfo.isChildAddable()) { %>
<div class="add-<%- childType %> add-item">
<a href="#" class="button button-new" data-category="<%- childCategory %>"
data-parent="<%- xblockInfo.get('id') %>" data-default-name="<%- defaultNewChildName %>"
title="<%- interpolate(
gettext('Click to add a new %(xblock_type)s'), { xblock_type: defaultNewChildName }, true
) %>"
>
<span class="icon fa fa-plus" aria-hidden="true"></span><%- addChildLabel %>
</a>
</div>
<% } %>
<% } %>
</div>
<% } %>
<% if (parentInfo) { %>
<span class="draggable-drop-indicator draggable-drop-indicator-after"><span class="icon fa fa-caret-right" aria-hidden="true"></span></span>
</li>
<% } %>