feat: Update new files notification banner styles (#33197)

Uses the updated styles for the notification based on the new designs.
Includes a button to open view the files directly in the notification.

This also fix a bug where the notification was not appearing when paste
a whole Unit.
This commit is contained in:
Yusuf Musleh
2023-09-15 18:58:50 +03:00
committed by GitHub
parent 0d15ca7240
commit 3eb4e0ce9c
9 changed files with 101 additions and 19 deletions

View File

@@ -1406,11 +1406,16 @@ class ContentStoreTest(ContentStoreTestCase):
self.assertEqual(resp.status_code, 404)
return
assets_url = reverse_course_url(
'assets_handler',
course.location.course_key
)
self.assertContains(
resp,
'<article class="outline outline-complex outline-course" data-locator="{locator}" data-course-key="{course_key}">'.format( # lint-amnesty, pylint: disable=line-too-long
'<article class="outline outline-complex outline-course" data-locator="{locator}" data-course-key="{course_key}" data-course-assets="{assets_url}">'.format( # lint-amnesty, pylint: disable=line-too-long
locator=str(course.location),
course_key=str(course.id),
assets_url=assets_url,
),
status_code=200,
html=True

View File

@@ -9,6 +9,7 @@ from unittest.mock import Mock, patch
from django.http import Http404
from django.test.client import RequestFactory
from django.urls import reverse
from pytz import UTC
from urllib.parse import quote
@@ -57,11 +58,16 @@ class ContainerPageTestCase(StudioPageTestCase, LibraryTestCase):
self.store.publish(self.vertical.location, self.user.id)
def test_container_html(self):
assets_url = reverse(
'assets_handler', kwargs={'course_key_string': str(self.child_container.location.course_key)}
)
self._test_html_content(
self.child_container,
expected_section_tag=(
'<section class="wrapper-xblock level-page is-hidden studio-xblock-wrapper" '
'data-locator="{0}" data-course-key="{0.course_key}">'.format(self.child_container.location)
'data-locator="{0}" data-course-key="{0.course_key}" data-course-assets="{1}">'.format(
self.child_container.location, assets_url
)
),
expected_breadcrumbs=(
'<li class="nav-item">\\s*<a href="/course/{course}{section_parameters}">Week 1<\\/a>.*'
@@ -86,11 +92,16 @@ class ContainerPageTestCase(StudioPageTestCase, LibraryTestCase):
self._create_block(draft_container, "html", "Child HTML")
def test_container_html(xblock):
assets_url = reverse(
'assets_handler', kwargs={'course_key_string': str(draft_container.location.course_key)}
)
self._test_html_content(
xblock,
expected_section_tag=(
'<section class="wrapper-xblock level-page is-hidden studio-xblock-wrapper" '
'data-locator="{0}" data-course-key="{0.course_key}">'.format(draft_container.location)
'data-locator="{0}" data-course-key="{0.course_key}" data-course-assets="{1}">'.format(
draft_container.location, assets_url
)
),
expected_breadcrumbs=(
'<a href="/course/{course}{subsection_parameters}">Lesson 1</a>.*'

View File

@@ -10,10 +10,11 @@
*/
define(['jquery', 'underscore', 'js/views/xblock_outline', 'edx-ui-toolkit/js/utils/string-utils',
'common/js/components/utils/view_utils', 'js/views/utils/xblock_utils',
'js/models/xblock_outline_info', 'js/views/modals/course_outline_modals', 'js/utils/drag_and_drop'],
'js/models/xblock_outline_info', 'js/views/modals/course_outline_modals', 'js/utils/drag_and_drop',
'common/js/components/views/feedback_notification', 'common/js/components/views/feedback_prompt',],
function(
$, _, XBlockOutlineView, StringUtils, ViewUtils, XBlockViewUtils,
XBlockOutlineInfo, CourseOutlineModalsFactory, ContentDragger
XBlockOutlineInfo, CourseOutlineModalsFactory, ContentDragger, NotificationView, PromptView
) {
var CourseOutlineView = XBlockOutlineView.extend({
// takes XBlockOutlineInfo as a model
@@ -380,13 +381,29 @@ function(
}));
}
if (newFiles.length) {
notices.push(() => new NotificationView.Confirmation({
title: gettext("New files were added to this course's Files & Uploads"),
notices.push(() => new NotificationView.Info({
title: gettext("New file(s) added to Files & Uploads."),
message: (
gettext("The following required files were imported to this course:") +
" " + newFiles.join(", ")
),
closeIcon: true,
actions: {
primary: {
text: gettext('View files'),
click: function(notification) {
const article = document.querySelector('[data-course-assets]');
const assetsUrl = $(article).attr('data-course-assets');
window.location.href = assetsUrl;
return;
}
},
secondary: {
text: gettext('Dismiss'),
click: function(notification) {
return notification.hide();
}
}
}
}));
}
if (notices.length) {

View File

@@ -293,13 +293,29 @@ function($, _, Backbone, gettext, BasePage, ViewUtils, ContainerView, XBlockView
}));
}
if (newFiles.length) {
notices.push(() => new NotificationView.Confirmation({
title: gettext("New files were added to this course's Files & Uploads"),
notices.push(() => new NotificationView.Info({
title: gettext("New file(s) added to Files & Uploads."),
message: (
gettext("The following required files were imported to this course:") +
" " + newFiles.join(", ")
),
closeIcon: true,
actions: {
primary: {
text: gettext('View files'),
click: function(notification) {
const section = document.querySelector('[data-course-assets]');
const assetsUrl = $(section).attr('data-course-assets');
window.location.href = assetsUrl;
return;
}
},
secondary: {
text: gettext('Dismiss'),
click: function(notification) {
return notification.hide();
}
}
}
}));
}
if (notices.length) {

View File

@@ -401,6 +401,14 @@
}
}
&.wrapper-notification-info {
box-shadow: 0 -1px 3px $shadow, inset 0 3px 1px $blue;
.feedback-symbol {
color: $blue;
}
}
&.wrapper-notification-mini {
box-shadow: 0 -1px 3px $shadow, inset 0 3px 1px $pink;
}
@@ -554,15 +562,35 @@
}
.action-primary {
@include blue-button();
@extend %btn-primary-blue;
@extend %sizing;
@extend %t-strong;
.action-button-text {
display: inline-block;
vertical-align: baseline;
}
border-color: $blue-d2;
.icon {
display: inline-block;
vertical-align: baseline;
}
// CASE: new/create button
&.new-button,
&.button-new {
@extend %btn-primary-green;
@extend %sizing;
}
}
.action-secondary {
@extend %t-action4;
color: $white;
cursor: pointer;
&:hover {
color: $gray-l3;
}
}
}

View File

@@ -9,6 +9,7 @@ else:
%>
</%def>
<%!
from django.urls import reverse
from django.utils.translation import gettext as _
from cms.djangoapps.contentstore.helpers import xblock_studio_url, xblock_type_display_name
@@ -166,7 +167,10 @@ from openedx.core.djangolib.markup import HTML, Text
<article class="content-primary">
<div class="container-message wrapper-message"></div>
<section class="wrapper-xblock level-page is-hidden studio-xblock-wrapper" data-locator="${xblock_locator}" data-course-key="${xblock_locator.course_key}">
<%
assets_url = reverse('assets_handler', kwargs={'course_key_string': str(xblock_locator.course_key)})
%>
<section class="wrapper-xblock level-page is-hidden studio-xblock-wrapper" data-locator="${xblock_locator}" data-course-key="${xblock_locator.course_key}" data-course-assets="${assets_url}">
</section>
<div class="ui-loading">
<p><span class="spin"><span class="icon fa fa-refresh" aria-hidden="true"></span></span> <span class="copy">${_("Loading")}</span></p>

View File

@@ -278,9 +278,10 @@ from django.urls import reverse
>
<%
course_locator = context_course.location
assets_url = reverse('assets_handler', kwargs={'course_key_string': str(course_locator.course_key)})
%>
<h2 class="sr">${_("Course Outline")}</h2>
<article class="outline outline-complex outline-course" data-locator="${course_locator}" data-course-key="${course_locator.course_key}">
<article class="outline outline-complex outline-course" data-locator="${course_locator}" data-course-key="${course_locator.course_key}" data-course-assets="${assets_url}">
</article>
</div>
<div class="ui-loading">

View File

@@ -13,7 +13,7 @@
// create Notification.Warning, Notification.Confirmation, etc
var capitalCamel, intents, miniOptions;
capitalCamel = _.compose(str.capitalize, str.camelize);
intents = ['warning', 'error', 'confirmation', 'announcement', 'step-required', 'help', 'mini'];
intents = ['warning', 'error', 'confirmation', 'announcement', 'step-required', 'help', 'mini', 'info'];
_.each(intents, function(intent) {
var subclass;
subclass = Notification.extend({

View File

@@ -10,7 +10,7 @@
>
<div class="<%- type %> <%- intent %> <% if(obj.actions) { %>has-actions<% } %>">
<% if(obj.icon) { %>
<% var iconClass = {"warning": "warning", "confirmation": "check", "error": "warning", "announcement": "bullhorn", "step-required": "exclamation-circle", "help": "question", "mini": "cog"} %>
<% var iconClass = {"warning": "warning", "confirmation": "check", "error": "warning", "announcement": "bullhorn", "step-required": "exclamation-circle", "help": "question", "mini": "cog", "info": "info-circle"} %>
<span class="feedback-symbol fa fa-<%- iconClass[intent] %>" aria-hidden="true"></span>
<% } %>
@@ -30,7 +30,7 @@
<% if(actions.secondary) {
_.each(actions.secondary, function(secondary) { %>
<li class="nav-item">
<button class="action-secondary <%- secondary.class %>"><%- secondary.text %></button>
<a class="action-secondary <%- secondary.class %>" tabindex="0"><%- secondary.text %></a>
</li>
<% });
} %>