Merge pull request #25865 from edx/ddumesnil/aa-260
AA-260/AA-500: Improvements to in course shift deadlines
This commit is contained in:
@@ -1019,8 +1019,11 @@ div.problem .action {
|
||||
.submit-cta-description {
|
||||
color: $blue;
|
||||
font-size: small;
|
||||
padding-right: $baseline / 2;
|
||||
}
|
||||
.submit-cta-link-button {
|
||||
border: none;
|
||||
padding-right: $baseline / 4;
|
||||
text-decoration: underline;
|
||||
text-transform: none;
|
||||
}
|
||||
@@ -1035,6 +1038,10 @@ div.problem .action {
|
||||
font-size: $medium-font-size;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
vertical-align: middle;
|
||||
|
||||
&.cta-enabled {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,11 +92,11 @@ class VerticalBlock(SequenceFields, XModuleFields, StudioEditableBlock, XmlParse
|
||||
'content': rendered_child.content
|
||||
})
|
||||
|
||||
cta_service = self.runtime.service(self, 'call_to_action')
|
||||
vertical_banner_ctas = cta_service and cta_service.get_ctas(self, 'vertical_banner')
|
||||
|
||||
completed = self.is_block_complete_for_assignments(completion_service)
|
||||
past_due = completed is False and self.due and self.due < datetime.now(pytz.UTC)
|
||||
cta_service = self.runtime.service(self, 'call_to_action')
|
||||
vertical_banner_ctas = (cta_service and cta_service.get_ctas(self, 'vertical_banner', completed)) or []
|
||||
|
||||
fragment_context = {
|
||||
'items': contents,
|
||||
'xblock_context': context,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<%page expression_filter="h"/>
|
||||
<%!
|
||||
from django.utils.translation import ungettext, ugettext as _
|
||||
from django.utils.translation import ngettext, gettext as _
|
||||
from openedx.core.djangolib.markup import HTML
|
||||
%>
|
||||
|
||||
@@ -85,9 +85,10 @@ from openedx.core.djangolib.markup import HTML
|
||||
</form>
|
||||
% endif
|
||||
% endif
|
||||
<div class="submission-feedback" id="submission_feedback_${short_id}">
|
||||
% if attempts_allowed:
|
||||
${ungettext("You have used {num_used} of {num_total} attempt", "You have used {num_used} of {num_total} attempts", attempts_allowed).format(num_used=attempts_used, num_total=attempts_allowed)}
|
||||
<div class="submission-feedback ${'cta-enabled' if submit_disabled_cta else ''}" id="submission_feedback_${short_id}">
|
||||
## When attempts are not 0, the CTA above will contain a message about the number of used attempts
|
||||
% if attempts_allowed and (not submit_disabled_cta or attempts_used == 0):
|
||||
${ngettext("You have used {num_used} of {num_total} attempt", "You have used {num_used} of {num_total} attempts", attempts_allowed).format(num_used=attempts_used, num_total=attempts_allowed)}
|
||||
% endif
|
||||
<span class="sr">${_("Some problems have options such as save, reset, hints, or show answer. These options follow the Submit button.")}</span>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@ class CallToActionService(PluginManager):
|
||||
"""
|
||||
NAMESPACE = 'openedx.call_to_action'
|
||||
|
||||
def get_ctas(self, xblock, category):
|
||||
def get_ctas(self, xblock, category, completion=False):
|
||||
"""
|
||||
Return the calls to action associated with the specified category for the given xblock.
|
||||
|
||||
@@ -45,5 +45,5 @@ class CallToActionService(PluginManager):
|
||||
"""
|
||||
ctas = []
|
||||
for cta_provider in self.get_available_plugins().values():
|
||||
ctas.extend(cta_provider().get_ctas(xblock, category))
|
||||
ctas.extend(cta_provider().get_ctas(xblock, category, completion))
|
||||
return ctas
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
"""
|
||||
Creates Call to Actions for resetting a Personalized Learner Schedule for use inside of Courseware.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from crum import get_current_request
|
||||
|
||||
from django.conf import settings
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.translation import ngettext, gettext as _
|
||||
|
||||
from lms.djangoapps.course_home_api.utils import is_request_from_learning_mfe
|
||||
from openedx.core.lib.mobile_utils import is_request_from_mobile_app
|
||||
@@ -14,12 +18,14 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PersonalizedLearnerScheduleCallToAction:
|
||||
"""
|
||||
Creates Call to Actions for resetting a Personalized Learner Schedule for use inside of Courseware.
|
||||
"""
|
||||
CAPA_SUBMIT_DISABLED = 'capa_submit_disabled'
|
||||
VERTICAL_BANNER = 'vertical_banner'
|
||||
|
||||
past_due_class_warnings = set()
|
||||
|
||||
def get_ctas(self, xblock, category):
|
||||
def get_ctas(self, xblock, category, completed):
|
||||
"""
|
||||
Return the calls to action associated with the specified category for the given xblock.
|
||||
|
||||
@@ -44,13 +50,13 @@ class PersonalizedLearnerScheduleCallToAction:
|
||||
# xblock is a capa problem, and the submit button is disabled. Check if it's because of a personalized
|
||||
# schedule due date being missed, and if so, we can offer to shift it.
|
||||
if self._is_block_shiftable(xblock):
|
||||
ctas.append(self._make_reset_deadlines_cta(xblock, is_learning_mfe))
|
||||
ctas.append(self._make_reset_deadlines_cta(xblock, category, is_learning_mfe))
|
||||
|
||||
elif category == self.VERTICAL_BANNER:
|
||||
elif category == self.VERTICAL_BANNER and not completed:
|
||||
# xblock is a vertical, so we'll check all the problems inside it. If there are any that will show a
|
||||
# a "shift dates" CTA under CAPA_SUBMIT_DISABLED, then we'll also show the same CTA as a vertical banner.
|
||||
if any(self._is_block_shiftable(item) for item in xblock.get_display_items()):
|
||||
ctas.append(self._make_reset_deadlines_cta(xblock, is_learning_mfe))
|
||||
ctas.append(self._make_reset_deadlines_cta(xblock, category, is_learning_mfe))
|
||||
|
||||
return ctas
|
||||
|
||||
@@ -79,6 +85,10 @@ class PersonalizedLearnerScheduleCallToAction:
|
||||
|
||||
@staticmethod
|
||||
def _log_past_due_warning(name):
|
||||
"""
|
||||
Logs out if an xblock has is_past_due defined as a property
|
||||
(since we want to move to using it as a function everywhere)
|
||||
"""
|
||||
if name in PersonalizedLearnerScheduleCallToAction.past_due_class_warnings:
|
||||
return
|
||||
|
||||
@@ -87,8 +97,11 @@ class PersonalizedLearnerScheduleCallToAction:
|
||||
'%s.is_past_due into a method.', name)
|
||||
PersonalizedLearnerScheduleCallToAction.past_due_class_warnings.add(name)
|
||||
|
||||
@staticmethod
|
||||
def _make_reset_deadlines_cta(xblock, is_learning_mfe=False):
|
||||
@classmethod
|
||||
def _make_reset_deadlines_cta(cls, xblock, category, is_learning_mfe=False):
|
||||
"""
|
||||
Constructs a call to action object containing the necessary information for the view
|
||||
"""
|
||||
from lms.urls import RESET_COURSE_DEADLINES_NAME
|
||||
course_key = xblock.scope_ids.usage_id.context_key
|
||||
|
||||
@@ -103,6 +116,24 @@ class PersonalizedLearnerScheduleCallToAction:
|
||||
'any of your progress.'),
|
||||
}
|
||||
|
||||
has_attempts = hasattr(xblock, 'attempts') and hasattr(xblock, 'max_attempts')
|
||||
|
||||
if category == cls.CAPA_SUBMIT_DISABLED and has_attempts and xblock.attempts:
|
||||
if xblock.max_attempts:
|
||||
cta_data['link_name'] = ngettext('Try again ({attempts} attempt remaining)',
|
||||
'Try again ({attempts} attempts remaining)',
|
||||
(xblock.max_attempts - xblock.attempts)).format(
|
||||
attempts=(xblock.max_attempts - xblock.attempts)
|
||||
)
|
||||
cta_data['description'] = (_('You have used {attempts} of {max_attempts} attempts for this '
|
||||
'problem.').format(
|
||||
attempts=xblock.attempts, max_attempts=xblock.max_attempts
|
||||
) + ' ' + cta_data['description'])
|
||||
else:
|
||||
cta_data['link_name'] = _('Try again (unlimited attempts)')
|
||||
cta_data['description'] = _('You have used {attempts} of unlimited attempts for this '
|
||||
'problem.').format(attempts=xblock.attempts) + ' ' + cta_data['description']
|
||||
|
||||
if is_learning_mfe:
|
||||
cta_data['event_data'] = {
|
||||
'event_name': 'post_event',
|
||||
|
||||
Reference in New Issue
Block a user