Commit ec399645 by Mushtaq Ali Committed by muzaffaryousaf

Course video settings UI - EDUCATOR-1063

parent 9009669c
......@@ -982,7 +982,9 @@ class TranscriptPreferencesTestCase(VideoUploadTestBase, CourseTestCase):
@override_settings(AWS_ACCESS_KEY_ID='test_key_id', AWS_SECRET_ACCESS_KEY='test_secret')
@patch('boto.s3.key.Key')
@patch('boto.s3.connection.S3Connection')
def test_transcript_preferences_metadata(self, transcript_preferences, mock_conn, mock_key):
@patch('contentstore.views.videos.get_transcript_preferences')
def test_transcript_preferences_metadata(self, transcript_preferences, mock_transcript_preferences,
mock_conn, mock_key):
"""
Tests that transcript preference metadata is only set if it is transcript
preferences are present in request data.
......@@ -990,8 +992,7 @@ class TranscriptPreferencesTestCase(VideoUploadTestBase, CourseTestCase):
file_name = 'test-video.mp4'
request_data = {'files': [{'file_name': file_name, 'content_type': 'video/mp4'}]}
if transcript_preferences:
request_data.update({'transcript_preferences': transcript_preferences})
mock_transcript_preferences.return_value = transcript_preferences
bucket = Mock()
mock_conn.return_value = Mock(get_bucket=Mock(return_value=bucket))
......@@ -1009,10 +1010,12 @@ class TranscriptPreferencesTestCase(VideoUploadTestBase, CourseTestCase):
# Ensure `transcript_preferences` was set up in Key correctly if sent through request.
if transcript_preferences:
mock_key_instance.set_metadata.assert_any_call('transcript_preferences', transcript_preferences)
mock_key_instance.set_metadata.assert_any_call('transcript_preferences', json.dumps(transcript_preferences))
else:
with self.assertRaises(AssertionError):
mock_key_instance.set_metadata.assert_any_call('transcript_preferences', transcript_preferences)
mock_key_instance.set_metadata.assert_any_call(
'transcript_preferences', json.dumps(transcript_preferences)
)
@patch.dict("django.conf.settings.FEATURES", {"ENABLE_VIDEO_UPLOAD_PIPELINE": True})
......
......@@ -4,6 +4,7 @@ Views related to the video upload feature
from contextlib import closing
import csv
import json
import logging
from datetime import datetime, timedelta
from uuid import uuid4
......@@ -340,6 +341,9 @@ def transcript_preferences_handler(request, course_key_string):
data = request.json
provider = data.get('provider', '')
# TODO: if provider == '': delete course preferences
# i.e call delete api end point like delete_transcript_preferences(course_key_string)
error, preferences = validate_transcript_preferences(
provider=provider,
cielo24_fidelity=data.get('cielo24_fidelity', ''),
......@@ -567,7 +571,7 @@ def videos_index_html(course):
}
context.update({
'third_party_transcript_settings': {
'video_transcript_settings': {
'transcript_preferences_handler_url': reverse_course_url(
'transcript_preferences_handler',
unicode(course.id)
......@@ -658,9 +662,9 @@ def videos_post(course, request):
('course_key', unicode(course.id)),
]
transcript_preferences = data.get('transcript_preferences', None)
transcript_preferences = get_transcript_preferences(unicode(course.id))
if transcript_preferences is not None:
metadata_list.append(('transcript_preferences', transcript_preferences))
metadata_list.append(('transcript_preferences', json.dumps(transcript_preferences)))
for metadata_name, value in metadata_list:
key.set_metadata(metadata_name, value)
......
......@@ -64,7 +64,8 @@
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: JSON.stringify(data),
success: callback
success: callback,
global: data ? data.global : true // Trigger global AJAX error handler or not
});
};
$.postJSON = function(url, data, callback) { // eslint-disable-line no-param-reassign
......
......@@ -258,6 +258,7 @@
'js/spec/views/active_video_upload_list_spec',
'js/spec/views/previous_video_upload_spec',
'js/spec/views/video_thumbnail_spec',
'js/spec/views/course_video_settings_spec',
'js/spec/views/previous_video_upload_list_spec',
'js/spec/views/assets_spec',
'js/spec/views/baseview_spec',
......
......@@ -10,19 +10,23 @@ define([
encodingsDownloadUrl,
defaultVideoImageURL,
concurrentUploadLimit,
uploadButton,
courseVideoSettingsButton,
previousUploads,
videoSupportedFileFormats,
videoUploadMaxFileSizeInGB,
activeTranscriptPreferences,
videoTranscriptSettings,
videoImageSettings
) {
var activeView = new ActiveVideoUploadListView({
postUrl: videoHandlerUrl,
concurrentUploadLimit: concurrentUploadLimit,
uploadButton: uploadButton,
courseVideoSettingsButton: courseVideoSettingsButton,
videoSupportedFileFormats: videoSupportedFileFormats,
videoUploadMaxFileSizeInGB: videoUploadMaxFileSizeInGB,
videoImageSettings: videoImageSettings,
activeTranscriptPreferences: activeTranscriptPreferences,
videoTranscriptSettings: videoTranscriptSettings,
onFileUploadDone: function(activeVideos) {
$.ajax({
url: videoHandlerUrl,
......
......@@ -32,20 +32,29 @@ define(
describe('ActiveVideoUploadListView', function() {
beforeEach(function() {
setFixtures(
'<div id="page-prompt"></div><div id="page-notification"></div><div id="reader-feedback"></div>'
'<div id="page-prompt"></div>' +
'<div id="page-notification"></div>' +
'<div id="reader-feedback"></div>' +
'<div class="video-transcript-settings-wrapper"></div>' +
'<button class="button course-video-settings-button"></button>'
);
TemplateHelpers.installTemplate('active-video-upload');
TemplateHelpers.installTemplate('active-video-upload-list');
this.postUrl = POST_URL;
this.uploadButton = $('<button>');
this.courseVideoSettingsButton = $('.course-video-settings-button');
this.videoSupportedFileFormats = ['.mp4', '.mov'];
this.videoUploadMaxFileSizeInGB = 5;
this.view = new ActiveVideoUploadListView({
concurrentUploadLimit: concurrentUploadLimit,
postUrl: this.postUrl,
uploadButton: this.uploadButton,
courseVideoSettingsButton: this.courseVideoSettingsButton,
videoSupportedFileFormats: this.videoSupportedFileFormats,
videoUploadMaxFileSizeInGB: this.videoUploadMaxFileSizeInGB
videoUploadMaxFileSizeInGB: this.videoUploadMaxFileSizeInGB,
activeTranscriptPreferences: {},
videoTranscriptSettings: {
transcript_preferences_handler_url: '',
transcription_plans: {}
}
});
this.view.render();
jasmine.Ajax.install();
......@@ -55,6 +64,10 @@ define(
afterEach(function() {
$(window).off('beforeunload');
jasmine.Ajax.uninstall();
if (this.view.courseVideoSettingsView) {
this.view.courseVideoSettingsView = null;
}
});
it('renders correct text in file drag/drop area', function() {
......@@ -71,15 +84,19 @@ define(
});
});
it('should trigger file selection when either the upload button or the drop zone is clicked', function() {
it('should trigger file selection when the drop zone is clicked', function() {
var clickSpy = jasmine.createSpy();
clickSpy.and.callFake(function(event) { event.preventDefault(); });
this.view.$('.js-file-input').on('click', clickSpy);
this.view.$('.file-drop-area').click();
expect(clickSpy).toHaveBeenCalled();
clickSpy.calls.reset();
this.uploadButton.click();
expect(clickSpy).toHaveBeenCalled();
});
it('shows course video settings pane when course video settings button is clicked', function() {
expect($('.course-video-settings-container')).not.toExist();
this.courseVideoSettingsButton.click();
expect($('.course-video-settings-container')).toExist();
});
it('should not show a notification message if there are no active video uploads', function() {
......
......@@ -5,12 +5,13 @@ define([
'js/models/active_video_upload',
'js/views/baseview',
'js/views/active_video_upload',
'js/views/course_video_settings',
'edx-ui-toolkit/js/utils/html-utils',
'edx-ui-toolkit/js/utils/string-utils',
'text!templates/active-video-upload-list.underscore',
'jquery.fileupload'
],
function($, _, Backbone, ActiveVideoUpload, BaseView, ActiveVideoUploadView,
function($, _, Backbone, ActiveVideoUpload, BaseView, ActiveVideoUploadView, CourseVideoSettingsView,
HtmlUtils, StringUtils, activeVideoUploadListTemplate) {
'use strict';
var ActiveVideoUploadListView,
......@@ -40,11 +41,13 @@ define([
this.listenTo(this.collection, 'add', this.addUpload);
this.concurrentUploadLimit = options.concurrentUploadLimit || 0;
this.postUrl = options.postUrl;
this.activeTranscriptPreferences = options.activeTranscriptPreferences;
this.videoTranscriptSettings = options.videoTranscriptSettings;
this.videoSupportedFileFormats = options.videoSupportedFileFormats;
this.videoUploadMaxFileSizeInGB = options.videoUploadMaxFileSizeInGB;
this.onFileUploadDone = options.onFileUploadDone;
if (options.uploadButton) {
options.uploadButton.click(this.chooseFile.bind(this));
if (options.courseVideoSettingsButton) {
options.courseVideoSettingsButton.click(this.showCourseVideoSettingsView.bind(this));
}
this.maxSizeText = StringUtils.interpolate(
......@@ -59,6 +62,33 @@ define([
supportedVideoTypes: this.videoSupportedFileFormats.join(', ')
}
);
this.listenTo(
Backbone,
'coursevideosettings:syncActiveTranscriptPreferences',
this.syncActiveTranscriptPreferences
);
this.listenTo(
Backbone,
'coursevideosettings:destroyCourseVideoSettingsView',
this.destroyCourseVideoSettingsView
);
},
syncActiveTranscriptPreferences: function(activeTranscriptPreferences) {
this.activeTranscriptPreferences = activeTranscriptPreferences;
},
showCourseVideoSettingsView: function(event) {
this.courseVideoSettingsView = new CourseVideoSettingsView({
activeTranscriptPreferences: this.activeTranscriptPreferences,
videoTranscriptSettings: this.videoTranscriptSettings
});
this.courseVideoSettingsView.render();
event.stopPropagation();
},
destroyCourseVideoSettingsView: function() {
this.courseVideoSettingsView = null;
},
render: function() {
......@@ -98,7 +128,6 @@ define([
$(window).on('drop', preventDefault);
$(window).on('beforeunload', this.onBeforeUnload.bind(this));
$(window).on('unload', this.onUnload.bind(this));
return this;
},
......
......@@ -83,6 +83,8 @@ $gray-d1: shade($gray, 20%) !default;
$gray-d2: shade($gray, 40%) !default;
$gray-d3: shade($gray, 60%) !default;
$gray-d4: shade($gray, 80%) !default;
$gray-u1: #ECF0F1;
// These define button styles similar to LMS
// The goal here is consistency (until we can overhaul all of this...)
......@@ -302,3 +304,5 @@ $state-warning-border: darken($state-warning-bg, 5%) !default;
$state-danger-text: $black !default;
$state-danger-bg: #f2dede !default;
$state-danger-border: darken($state-danger-bg, 5%) !default;
$text-dark-black-blue: #2C3E50;
......@@ -12,6 +12,172 @@
}
}
.fixed-container {
position: fixed !important;
top: 0 !important;
}
.course-video-settings-container {
position: absolute;
overflow: scroll;
top: 0;
right: -100%;
z-index: 1000;
width: 352px;
transition: all 0.3s ease;
background-color: $white;
-webkit-box-shadow: -3px 0px 3px 0px rgba(153,153,153,0.3);
-moz-box-shadow: -3px 0px 3px 0px rgba(153,153,153,0.3);
box-shadow: -3px 0px 3px 0px rgba(153,153,153,0.3);
.button-link {
background:none;
border:none;
padding:0;
color: $ui-link-color;
cursor:pointer
}
.action-close-wrapper {
.action-close-course-video-settings {
width: 100%;
padding: ($baseline/2) ($baseline*0.8);
background-color: $gray-u1;
border: transparent;
height: ($baseline*2.4);
color: $text-dark-black-blue;
@include font-size(16);
@include text-align(left);
}
}
.course-video-settings-wrapper {
margin-top: ($baseline*1.60);
padding: ($baseline) ($baseline*0.8);
.course-video-settings-title {
color: $black-t4;
margin: ($baseline*1.6) 0 ($baseline*0.8) 0;
font-weight: font-weight(semi-bold);
@include font-size(24);
}
.course-video-settings-message {
padding: ($baseline/2);
margin-bottom: ($baseline*0.8);
max-height: ($baseline*2.4);
color: $black;
@include font-size(16);
.icon {
@include margin-right($baseline/4);
}
}
.course-video-settings-message-wrapper.success .course-video-settings-message {
background-color: $state-success-bg;
border: solid 1px $state-success-border;
}
.course-video-settings-message-wrapper.error .course-video-settings-message {
background-color: $state-danger-bg;
border: solid 1px $state-danger-border;
}
.transcript-preferance-wrapper {
margin-top: ($baseline*1.6);
.icon.fa-info-circle {
@include margin-left($baseline*0.75);
}
}
.transcript-preferance-wrapper.error .transcript-preferance-label {
color: $color-error;
}
.error-info, .error-icon .fa-info-circle {
color: $color-error;
}
.error-info {
@include font-size(16);
}
.transcript-preferance-label {
color: $black-t4;
@include font-size(15);
font-weight: font-weight(semi-bold);
}
.transcript-provider-group, .transcript-turnaround, .transcript-fidelity {
margin-top: ($baseline*0.8);
}
.transcript-provider-group {
input[type=radio] {
margin: 0 ($baseline/2);
}
label {
font-weight: normal;
color: $black-t4;
@include font-size(15);
}
}
.transcript-turnaround-wrapper, .transcript-fidelity-wrapper, .transcript-languages-wrapper {
display: none;
}
.transcript-languages-container .languages-container {
margin-top: ($baseline*0.8);
.transcript-language-container {
padding: ($baseline/4);
background-color: $gray-l6;
border-top: solid 1px $gray-l4;
border-bottom: solid 1px $gray-l4;
.remove-language-action {
display: inline-block;
@include float(right);
}
}
}
.transcript-language-menu-container {
margin-top: ($baseline*0.8);
.transcript-language-menu {
width: 65%;
}
.add-language-action {
display: inline-block;
.action-add-language {
@include margin-left($baseline/4);
}
}
}
}
.course-video-settings-footer {
margin-top: ($baseline*1.6);
.last-updated-text {
@include font-size(12);
@include margin-left($baseline/4);
}
}
.button {
@extend %btn-primary-blue;
@extend %sizing;
.action-button-text {
display: inline-block;
vertical-align: baseline;
}
.icon {
display: inline-block;
vertical-align: baseline;
}
}
}
.file-upload-form {
@include clearfix();
......
<div class='course-video-settings-container'>
<div class="course-video-settings-header">
<div class="action-close-wrapper">
<button class="action-close-course-video-settings">
<span class="icon fa fa-times" aria-hidden="true"></span>
<%-gettext('Close') %>
<span class='sr'><%-gettext('Press close to hide course video settings') %></span>
</button>
</div>
</div>
<div class='course-video-settings-wrapper'>
<div class='course-video-settings-message-wrapper'></div>
<span class="course-video-settings-title"><%- gettext('Transcript Settings') %></span>
<div class='transcript-preferance-wrapper transcript-provider-wrapper'>
<label class='transcript-preferance-label' for='transcript-provider'><%- gettext('Transcript Provider') %><span class='error-icon' aria-hidden="true"></span></label>
<div class='transcript-provider-group' id='transcript-provider'></div>
<span class='error-info' aria-hidden="true"></span>
</div>
<div class='transcript-preferance-wrapper transcript-turnaround-wrapper'>
<label class='transcript-preferance-label' for='transcript-turnaround'><%- gettext('Transcript Turnaround') %><span class='error-icon' aria-hidden="true"></span></label>
<select id='transcript-turnaround' class='transcript-turnaround'></select>
<span class='error-info' aria-hidden="true"></span>
</div>
<div class='transcript-preferance-wrapper transcript-fidelity-wrapper'>
<label class='transcript-preferance-label' for='transcript-fidelity'><%- gettext('Transcript Fidelity') %><span class='error-icon' aria-hidden="true"></span></label>
<select id='transcript-fidelity' class='transcript-fidelity'></select>
<span class='error-info' aria-hidden="true"></span>
</div>
<div class='transcript-preferance-wrapper transcript-languages-wrapper'>
<span class='transcript-preferance-label'><%- gettext('Transcript Languages') %></span>
<span class='error-icon' aria-hidden="true"></span>
<div class='transcript-languages-container'>
<div class='languages-container'></div>
<div class="transcript-language-menu-container">
<select class="transcript-language-menu" id="transcript-language" aria-labelledby="transcript-language-none"></select>
<div class="add-language-action">
<button class="button-link action-add-language"><%- gettext('Add') %><span class="sr"><%- gettext('Press Add to language') %></span></button>
<span class="error-info" aria-hidden="true"></span>
</div>
</div>
</div>
</div>
<div class='course-video-settings-footer'>
<button class="button button action-update-course-video-settings" aria-describedby='update-button-text'>
<%- gettext('Update Settings') %>
<span id='update-button-text' class='sr'><%-gettext('Press update settings to update course video settings') %></span>
</button>
<%if (dateModified) { %>
<span class='last-updated-text'><%- gettext('Last updated')%> <%- dateModified %></span>
<% } %>
</div>
</div>
</div>
......@@ -34,10 +34,12 @@
"${encodings_download_url | n, js_escaped_string}",
"${default_video_image_url | n, js_escaped_string}",
${concurrent_upload_limit | n, dump_js_escaped_json},
$(".nav-actions .upload-button"),
$(".nav-actions .course-video-settings-button"),
$contentWrapper.data("previous-uploads"),
${video_supported_file_formats | n, dump_js_escaped_json},
${video_upload_max_file_size | n, dump_js_escaped_json},
${active_transcript_preferences | n, dump_js_escaped_json},
${video_transcript_settings | n, dump_js_escaped_json},
${video_image_settings | n, dump_js_escaped_json}
);
});
......@@ -46,6 +48,7 @@
<%block name="content">
<div class="wrapper-mast wrapper">
<div class="video-transcript-settings-wrapper"></div>
<header class="mast has-actions has-subtitle">
<h1 class="page-header">
<small class="subtitle">${_("Content")}</small>
......@@ -54,11 +57,9 @@
<nav class="nav-actions" aria-label="${_('Page Actions')}">
<h3 class="sr">${_("Page Actions")}</h3>
<ul>
<li class="nav-item">
<a href="#" class="button upload-button new-button"><span class="icon fa fa-plus" aria-hidden="true"></span> ${_("Upload New File")}</a>
</li>
</ul>
<div class="nav-item">
<button class="button course-video-settings-button"><span class="icon fa fa-cog" aria-hidden="true"></span> ${_("Course Video Settings")}</button>
</div>
</nav>
</header>
</div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment