From 9f8f64cffe7ac2ac918a6f29dfac8b60ee84db05 Mon Sep 17 00:00:00 2001
From: Mathew Peterson
Date: Thu, 31 Jul 2014 19:56:02 +0000
Subject: [PATCH] Course Reruns UI
Studio: adding course re-run-centric static template rendering
* initial HTML for dashboard states
* initial HTML for new course re-run view/form
* initial HTML placeholder for outline alert UI
Conflicts:
cms/templates/index.html
Studio: adding styling for course re-run-centric views
* adding new view/page mast-wizard type
* refactoring create course/element form styling
* adding course re-run view specific styling
* adding courses processing styling (w/ alerts and status)
Course rerun server-side updates: support display_name and DuplicateCourseError.
Studio: further design revisions and tweaks from feedback
* removing new window attribute from re-run control
* removing links from processing courses
* revising look/feel of dismiss action on dashboard + alert
* correcting font-weight of dashboard processing title
* adding extra space to course rerun action on dashboard
* re-wording secondary cancel action on rerun view
Conflicts:
cms/templates/index.html
Added interation on unsucceeded courses in dashboard
Studio: removing 'rel=external' property from course re-run actions
Studio: removing hover styles for processing courses
Fixed value bug in split and set course listing to display run
moved task.py for rerun
---
.../contentstore/{views => }/tasks.py | 3 +-
.../contentstore/tests/test_contentstore.py | 6 +-
.../contentstore/tests/test_course_listing.py | 4 +-
cms/djangoapps/contentstore/views/course.py | 63 ++-
cms/envs/devstack.py | 7 +
cms/static/js/index.js | 12 +
cms/static/js/views/course_rerun.js | 161 ++++++++
cms/static/js/views/overview.js | 13 +
cms/static/sass/_base.scss | 276 +++++++++++++
cms/static/sass/elements/_controls.scss | 32 +-
cms/static/sass/elements/_forms.scss | 51 +--
.../sass/elements/_system-feedback.scss | 38 +-
cms/static/sass/style-app-extend1.scss | 1 +
cms/static/sass/views/_course-create.scss | 116 ++++++
cms/static/sass/views/_dashboard.scss | 359 ++++++++++++-----
cms/templates/base.html | 4 +-
cms/templates/course-create-rerun.html | 173 ++++++++
cms/templates/course_outline.html | 25 ++
cms/templates/index.html | 112 +++++-
cms/templates/manage_users.html | 4 +-
.../ux/reference/course-create-rerun.html | 368 ++++++++++++++++++
cms/urls.py | 1 +
.../course_action_state/managers.py | 3 +-
.../migrations/0002_add_rerun_display_name.py | 76 ++++
.../djangoapps/course_action_state/models.py | 3 +
.../tests/test_rerun_manager.py | 21 +-
.../xmodule/modulestore/split_mongo/split.py | 2 +-
27 files changed, 1771 insertions(+), 163 deletions(-)
rename cms/djangoapps/contentstore/{views => }/tasks.py (99%)
create mode 100644 cms/static/js/views/course_rerun.js
create mode 100644 cms/static/sass/views/_course-create.scss
create mode 100644 cms/templates/course-create-rerun.html
create mode 100644 cms/templates/ux/reference/course-create-rerun.html
create mode 100644 common/djangoapps/course_action_state/migrations/0002_add_rerun_display_name.py
diff --git a/cms/djangoapps/contentstore/views/tasks.py b/cms/djangoapps/contentstore/tasks.py
similarity index 99%
rename from cms/djangoapps/contentstore/views/tasks.py
rename to cms/djangoapps/contentstore/tasks.py
index d0e18e62b8..8e309f2bad 100644
--- a/cms/djangoapps/contentstore/views/tasks.py
+++ b/cms/djangoapps/contentstore/tasks.py
@@ -5,6 +5,7 @@ This file contains celery tasks for contentstore views
from celery.task import task
from django.contrib.auth.models import User
from xmodule.modulestore.django import modulestore
+
from xmodule.modulestore.exceptions import DuplicateCourseError, ItemNotFoundError
from course_action_state.models import CourseRerunState
from contentstore.utils import initialize_permissions
@@ -32,13 +33,11 @@ def rerun_course(source_course_key_string, destination_course_key_string, user_i
# update state: Succeeded
CourseRerunState.objects.succeeded(course_key=destination_course_key)
-
return "succeeded"
except DuplicateCourseError as exc:
# do NOT delete the original course, only update the status
CourseRerunState.objects.failed(course_key=destination_course_key, exception=exc)
-
return "duplicate course"
# catch all exceptions so we can update the state and properly cleanup the course.
diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py
index 79f778ae9b..911d1a31bb 100644
--- a/cms/djangoapps/contentstore/tests/test_contentstore.py
+++ b/cms/djangoapps/contentstore/tests/test_contentstore.py
@@ -1580,9 +1580,12 @@ class RerunCourseTest(ContentStoreTestCase):
json_resp = parse_json(response)
self.assertNotIn('ErrMsg', json_resp)
destination_course_key = CourseKey.from_string(json_resp['destination_course_key'])
-
return destination_course_key
+ def create_course_listing_html(self, course_key):
+ """Creates html fragment that is created for the given course_key in the course listing section"""
+ return '' + data.ErrMsg + '
');
+ $('.rerun-course-save').addClass('is-disabled').removeClass('is-processing').html(gettext('Create Re-run'));
+ $('.action-cancel').removeClass('is-hidden');
+ }
+ }
+ );
+ // Go into creating re-run state
+ $('.rerun-course-save').addClass('is-disabled').addClass('is-processing').html(
+ '' + gettext('The combined length of the organization, course number, and course run fields cannot be more than 65 characters.') + '
');
+ $('.rerun-course-save').addClass('is-disabled');
+ }
+ else {
+ $('.wrap-error').removeClass('is-shown');
+ }
+ };
+
+ // Handle validation asynchronously
+ _.each(
+ ['.rerun-course-org', '.rerun-course-number', '.rerun-course-run'],
+ function (ele) {
+ var $ele = $(ele);
+ $ele.on('keyup', function (event) {
+ // Don't bother showing "required field" error when
+ // the user tabs into a new field; this is distracting
+ // and unnecessary
+ if (event.keyCode === 9) {
+ return;
+ }
+ var error = validateCourseItemEncoding($ele.val());
+ setNewCourseFieldInErr($ele.parent(), error);
+ validateTotalCourseItemsLength();
+ });
+ }
+ );
+ var $name = $('.rerun-course-name');
+ $name.on('keyup', function () {
+ var error = validateRequiredField($name.val());
+ setNewCourseFieldInErr($name.parent(), error);
+ validateTotalCourseItemsLength();
+ });
+ });
+ });
\ No newline at end of file
diff --git a/cms/static/js/views/overview.js b/cms/static/js/views/overview.js
index f33f0c908f..8ceaa40681 100644
--- a/cms/static/js/views/overview.js
+++ b/cms/static/js/views/overview.js
@@ -5,6 +5,17 @@ define(["domReady", "jquery", "jquery.ui", "underscore", "gettext", "js/views/fe
var modalSelector = '.edit-section-publish-settings';
+ var dismissNotification = function (e) {
+ e.preventDefault();
+ $.ajax({
+ url: $('.dismiss-button').data('dismiss-link'),
+ type: 'GET',
+ success: function(result) {
+ $('.wrapper-alert-announcement').remove()
+ }
+ });
+ };
+
var toggleSections = function(e) {
e.preventDefault();
@@ -222,6 +233,8 @@ define(["domReady", "jquery", "jquery.ui", "underscore", "gettext", "js/views/fe
$('.toggle-button-sections').bind('click', toggleSections);
$('.expand-collapse').bind('click', toggleSubmodules);
+ $('.dismiss-button').bind('click', dismissNotification);
+
var $body = $('body');
$body.on('click', '.section-published-date .edit-release-date', editSectionPublishDate);
$body.on('click', '.edit-section-publish-settings .action-save', saveSetSectionScheduleDate);
diff --git a/cms/static/sass/_base.scss b/cms/static/sass/_base.scss
index b1b57f5ff0..547d9b2e39 100644
--- a/cms/static/sass/_base.scss
+++ b/cms/static/sass/_base.scss
@@ -240,6 +240,282 @@ p, ul, ol, dl {
}
}
+// ====================
+
+// layout - basic
+.wrapper-view {
+
+}
+
+// ====================
+
+// layout - basic page header
+.wrapper-mast {
+ margin: ($baseline*1.5) 0 0 0;
+ padding: 0 $baseline;
+ position: relative;
+
+ .mast, .metadata {
+ @include clearfix();
+ position: relative;
+ max-width: $fg-max-width;
+ min-width: $fg-min-width;
+ width: flex-grid(12);
+ margin: 0 auto $baseline auto;
+ color: $gray-d2;
+ }
+
+ .mast {
+ border-bottom: 1px solid $gray-l4;
+ padding-bottom: ($baseline/2);
+
+ // layout with actions
+ .page-header {
+ width: flex-grid(12);
+ }
+
+ // layout with actions
+ &.has-actions {
+ @include clearfix();
+
+ .page-header {
+ float: left;
+ width: flex-grid(6,12);
+ margin-right: flex-gutter();
+ }
+
+ .nav-actions {
+ position: relative;
+ bottom: -($baseline*0.75);
+ float: right;
+ width: flex-grid(6,12);
+ text-align: right;
+
+ .nav-item {
+ display: inline-block;
+ vertical-align: top;
+ margin-right: ($baseline/2);
+
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+
+ // buttons
+ .button {
+ padding: ($baseline/4) ($baseline/2) ($baseline/3) ($baseline/2);
+ }
+
+ .new-button {
+
+ }
+
+ .view-button {
+
+ }
+ }
+ }
+
+ // layout with actions
+ &.has-subtitle {
+
+ .nav-actions {
+ bottom: -($baseline*1.5);
+ }
+ }
+
+ // layout with navigation
+ &.has-navigation {
+
+ .nav-actions {
+ bottom: -($baseline*1.5);
+ }
+
+ .navigation-link {
+ @extend %cont-truncated;
+ display: inline-block;
+ vertical-align: bottom; // correct for extra padding in FF
+ max-width: 250px;
+
+ &.navigation-current {
+ @extend %ui-disabled;
+ color: $gray;
+ max-width: 250px;
+
+ &:before {
+ color: $gray;
+ }
+ }
+ }
+
+ .navigation-link:before {
+ content: " / ";
+ margin: ($baseline/4);
+ color: $gray;
+
+ &:hover {
+ color: $gray;
+ }
+ }
+
+ .navigation .navigation-link:first-child:before {
+ content: "";
+ margin: 0;
+ }
+ }
+ }
+
+ // CASE: wizard-based mast
+ .mast-wizard {
+
+ .page-header-sub {
+ @extend %t-title4;
+ color: $gray;
+ font-weight: 300;
+ }
+
+ .page-header-super {
+ @extend %t-title4;
+ float: left;
+ width: flex-grid(12,12);
+ margin-top: ($baseline/2);
+ border-top: 1px solid $gray-l4;
+ padding-top: ($baseline/2);
+ font-weight: 600;
+ }
+ }
+
+ // page metadata/action bar
+ .metadata {
+
+ }
+}
+
+// layout - basic page content
+.wrapper-content {
+ margin: 0;
+ padding: 0 $baseline;
+ position: relative;
+}
+
+.content {
+ @include clearfix();
+ @extend %t-copy-base;
+ max-width: $fg-max-width;
+ min-width: $fg-min-width;
+ width: flex-grid(12);
+ margin: 0 auto;
+ color: $gray-d2;
+
+ header {
+ position: relative;
+ margin-bottom: $baseline;
+ border-bottom: 1px solid $gray-l4;
+ padding-bottom: ($baseline/2);
+
+ .title-sub {
+ @extend %t-copy-sub1;
+ display: block;
+ margin: 0;
+ color: $gray-l2;
+ }
+
+ .title-1 {
+ @extend %t-title3;
+ margin: 0;
+ padding: 0;
+ font-weight: 600;
+ color: $gray-d3;
+ }
+ }
+}
+
+.content-primary, .content-supplementary {
+ @include box-sizing(border-box);
+}
+
+// layout - primary content
+.content-primary {
+
+ .title-1 {
+ @extend %t-title3;
+ }
+
+ .title-2 {
+ @extend %t-title4;
+ margin: 0 0 ($baseline/2) 0;
+ }
+
+ .title-3 {
+ @extend %t-title6;
+ margin: 0 0 ($baseline/2) 0;
+ }
+
+ header {
+ @include clearfix();
+
+ .title-2 {
+ width: flex-grid(5, 12);
+ margin: 0 flex-gutter() 0 0;
+ float: left;
+ }
+
+ .tip {
+ @extend %t-copy-sub2;
+ width: flex-grid(7, 12);
+ float: right;
+ margin-top: ($baseline/2);
+ text-align: right;
+ color: $gray-l2;
+ }
+ }
+}
+
+// layout - supplemental content
+.content-supplementary {
+
+ > section {
+ margin: 0 0 $baseline 0;
+ }
+}
+
+// ====================
+
+// layout - grandfathered
+.main-wrapper {
+ position: relative;
+ margin: 0 ($baseline*2);
+}
+
+.inner-wrapper {
+ @include clearfix();
+ position: relative;
+ max-width: 1280px;
+ margin: auto;
+
+ > article {
+ clear: both;
+ }
+}
+
+.main-column {
+ clear: both;
+ float: left;
+ width: 70%;
+}
+
+.sidebar {
+ float: right;
+ width: 28%;
+}
+
+.left {
+ float: left;
+}
+
+.right {
+ float: right;
+}
// ====================
diff --git a/cms/static/sass/elements/_controls.scss b/cms/static/sass/elements/_controls.scss
index 16434c5410..f5c9eb7434 100644
--- a/cms/static/sass/elements/_controls.scss
+++ b/cms/static/sass/elements/_controls.scss
@@ -133,6 +133,27 @@
}
}
+// white secondary button
+%btn-secondary-white {
+ @extend %ui-btn-secondary;
+ border-color: $white-t2;
+ color: $white-t3;
+
+ &:hover, &:active {
+ border-color: $white;
+ color: $white;
+ }
+
+ &.current, &.active {
+ background: $gray-d2;
+ color: $gray-l5;
+
+ &:hover, &:active {
+ background: $gray-d2;
+ }
+ }
+}
+
// green secondary button
%btn-secondary-green {
@extend %ui-btn-secondary;
@@ -213,17 +234,6 @@
// ====================
-// calls-to-action
-
-// ====================
-
-// specific buttons - view live
-%view-live-button {
- @extend %t-action4;
-}
-
-// ====================
-
// UI: element actions list
%actions-list {
diff --git a/cms/static/sass/elements/_forms.scss b/cms/static/sass/elements/_forms.scss
index ea0e144ec8..08bca8770e 100644
--- a/cms/static/sass/elements/_forms.scss
+++ b/cms/static/sass/elements/_forms.scss
@@ -137,28 +137,10 @@ form {
}
}
-// ELEM: form wrapper
-.wrapper-create-element {
- height: 0;
- margin-bottom: $baseline;
- opacity: 0.0;
- pointer-events: none;
- overflow: hidden;
-
- &.animate {
- @include transition(opacity $tmg-f1 ease-in-out 0s, height $tmg-f1 ease-in-out 0s);
- }
-
- &.is-shown {
- height: auto; // define a specific height for the animating version of this UI to work properly
- opacity: 1.0;
- pointer-events: auto;
- }
-}
-
// ELEM: form
// form styling for creating a new content item (course, user, textbook)
-form[class^="create-"] {
+// TODO: refactor this into a placeholder to extend.
+.form-create {
@extend %ui-window;
.title {
@@ -253,12 +235,19 @@ form[class^="create-"] {
.tip {
@extend %t-copy-sub2;
- @include transition(color, 0.15s, ease-in-out);
+ @include transition(color 0.15s ease-in-out);
+
+
display: block;
margin-top: ($baseline/4);
color: $gray-l3;
}
+ .tip-note {
+ display: block;
+ margin-top: ($baseline/4);
+ }
+
.tip-error {
display: none;
float: none;
@@ -365,7 +354,6 @@ form[class^="create-"] {
}
}
-
// form - inline xblock name edit on unit, container, outline
// TOOD: abstract this out into a Sass placeholder
@@ -402,6 +390,25 @@ form[class^="create-"] {
}
}
+// ELEM: form wrapper
+.wrapper-create-element {
+ height: 0;
+ margin-bottom: $baseline;
+ opacity: 0.0;
+ pointer-events: none;
+ overflow: hidden;
+
+ &.animate {
+ @include transition(opacity $tmg-f1 ease-in-out 0s, height $tmg-f1 ease-in-out 0s);
+ }
+
+ &.is-shown {
+ height: auto; // define a specific height for the animating version of this UI to work properly
+ opacity: 1.0;
+ pointer-events: auto;
+ }
+}
+
// ====================
// forms - grandfathered
diff --git a/cms/static/sass/elements/_system-feedback.scss b/cms/static/sass/elements/_system-feedback.scss
index 3326ca4427..034653ad05 100644
--- a/cms/static/sass/elements/_system-feedback.scss
+++ b/cms/static/sass/elements/_system-feedback.scss
@@ -527,7 +527,7 @@
&.wrapper-alert-warning {
box-shadow: 0 1px 1px $white, inset 0 2px 2px $shadow-d1, inset 0 -4px 1px $orange;
- [class^="icon"] {
+ .alert-symbol {
color: $orange;
}
}
@@ -535,7 +535,7 @@
&.wrapper-alert-error {
box-shadow: 0 1px 1px $white, inset 0 2px 2px $shadow-d1, inset 0 -4px 1px $red-l1;
- [class^="icon"] {
+ .alert-symbol {
color: $red-l1;
}
}
@@ -543,7 +543,7 @@
&.wrapper-alert-confirmation {
box-shadow: 0 1px 1px $white, inset 0 2px 2px $shadow-d1, inset 0 -4px 1px $green;
- [class^="icon"] {
+ .alert-symbol {
color: $green;
}
}
@@ -551,7 +551,7 @@
&.wrapper-alert-announcement {
box-shadow: 0 1px 1px $white, inset 0 2px 2px $shadow-d1, inset 0 -4px 1px $blue;
- [class^="icon"] {
+ .alert-symbol {
color: $blue;
}
}
@@ -559,7 +559,7 @@
&.wrapper-alert-step-required {
box-shadow: 0 1px 1px $white, inset 0 2px 2px $shadow-d1, inset 0 -4px 1px $pink;
- [class^="icon"] {
+ .alert-symbol {
color: $pink;
}
}
@@ -579,11 +579,11 @@
@extend %t-strong;
}
- [class^="icon"], .copy {
+ .alert-symbol, .copy {
float: left;
}
- [class^="icon"] {
+ .alert-symbol {
@include transition (color 0.50s ease-in-out 0s);
@extend %t-icon3;
width: flex-grid(1, 12);
@@ -605,7 +605,7 @@
// with actions
&.has-actions {
- [class^="icon"] {
+ .alert-symbol {
width: flex-grid(1, 12);
}
@@ -667,6 +667,28 @@
background: $gray-d1;
}
}
+
+ // with dismiss (to sunset action-alert-clos)
+ .action-dismiss {
+
+ .button {
+ @extend %btn-secondary-white;
+ }
+
+ .icon,.button-copy {
+ display: inline-block;
+ vertical-align: middle;
+ }
+
+ .icon {
+ @extend %t-icon4;
+ margin-right: ($baseline/4);
+ }
+
+ .button-copy {
+ @extend %t-copy-sub1;
+ }
+ }
}
// ====================
diff --git a/cms/static/sass/style-app-extend1.scss b/cms/static/sass/style-app-extend1.scss
index bdcf8f79d1..924b7c114f 100644
--- a/cms/static/sass/style-app-extend1.scss
+++ b/cms/static/sass/style-app-extend1.scss
@@ -38,6 +38,7 @@
@import 'views/dashboard';
@import 'views/export';
@import 'views/index';
+@import 'views/course-create';
@import 'views/import';
@import 'views/outline';
@import 'views/settings';
diff --git a/cms/static/sass/views/_course-create.scss b/cms/static/sass/views/_course-create.scss
new file mode 100644
index 0000000000..7b0a500a5f
--- /dev/null
+++ b/cms/static/sass/views/_course-create.scss
@@ -0,0 +1,116 @@
+// studio - views - course creation page
+// ====================
+
+.view-course-create {
+
+ // basic layout
+ // --------------------
+ .content-primary, .content-supplementary {
+ @include box-sizing(border-box);
+ float: left;
+ }
+
+ .content-primary {
+ width: flex-grid(9, 12);
+ margin-right: flex-gutter();
+ }
+
+ .content-supplementary {
+ width: flex-grid(3, 12);
+ }
+
+ //
+
+ // header/masthead
+ // --------------------
+ .mast .page-header-super {
+
+ .course-original-title-id, .course-original-title {
+ display: block;
+ }
+
+ .course-original-title-id {
+ @extend %t-title5;
+ }
+ }
+
+
+ // course re-run form
+ // --------------------
+ .rerun-course {
+
+ .row {
+ @include clearfix();
+ margin-bottom: ($baseline*0.75);
+ }
+
+ .column {
+ float: left;
+ width: 48%;
+ }
+
+ .column:first-child {
+ margin-right: 4%;
+ }
+
+ label {
+ @extend %t-title7;
+ display: block;
+ font-weight: 700;
+ }
+
+ .rerun-course-org,
+ .rerun-course-number,
+ .rerun-course-name,
+ .rerun-course-run {
+ width: 100%;
+ }
+
+ .rerun-course-name {
+ @extend %t-title5;
+ font-weight: 300;
+ }
+
+ .rerun-course-save {
+ @include blue-button;
+ }
+
+ .rerun-course-cancel {
+ @include white-button;
+ }
+
+ .item-details {
+ padding-bottom: 0;
+ }
+
+ .wrap-error {
+ @include transition(opacity $tmg-f2 ease 0s);
+ opacity: 0;
+ }
+
+ .wrap-error.is-shown {
+ opacity: 1;
+ }
+
+ .message-status {
+ display: block;
+ margin-bottom: 0;
+ padding: ($baseline*.5) ($baseline*1.5) 8px ($baseline*1.5);
+ font-weight: bold;
+ }
+
+ // NOTE: override for modern button styling until all buttons (in _forms.scss) can be converted
+ .actions {
+
+ .action-primary {
+ @include blue-button;
+ @extend %t-action2;
+ }
+
+ .action-secondary {
+ @include grey-button;
+ @extend %t-action2;
+ }
+ }
+ }
+}
diff --git a/cms/static/sass/views/_dashboard.scss b/cms/static/sass/views/_dashboard.scss
index 69ba41fd2b..8ca15e4a36 100644
--- a/cms/static/sass/views/_dashboard.scss
+++ b/cms/static/sass/views/_dashboard.scss
@@ -294,120 +294,298 @@
// ELEM: course listings
.courses {
margin: $baseline 0;
- }
+
+ .title {
+ @extend %t-title6;
+ margin-bottom: $baseline;
+ border-bottom: 1px solid $gray-l3;
+ padding-bottom: ($baseline/2);
+ color: $gray-l2;
+ }
+ }
.list-courses {
margin-top: $baseline;
border-radius: 3px;
- border: 1px solid $gray;
+ border: 1px solid $gray-l2;
background: $white;
- box-shadow: 0 1px 2px $shadow-l1;
+ box-shadow: 0 1px 1px $shadow-l1;
- .course-item {
- @include box-sizing(border-box);
- width: flex-grid(9, 9);
- position: relative;
- border-bottom: 1px solid $gray-l1;
- padding: $baseline;
+ li:last-child {
+ margin-bottom: 0;
+ }
+ }
- // STATE: hover/focus
- &:hover {
- background: $paleYellow;
- .course-actions .view-live-button {
- opacity: 1.0;
- pointer-events: auto;
- }
+ // UI: course wrappers (needed for status messages)
+ .wrapper-course {
- .course-title {
- color: $orange-d1;
- }
+ // CASE: has status
+ &.has-status {
- .course-metadata {
- opacity: 1.0;
- }
- }
-
- .course-link, .course-actions {
+ .course-status {
@include box-sizing(border-box);
display: inline-block;
vertical-align: middle;
- }
-
- // encompassing course link
- .course-link {
- @extend %ui-depth2;
- width: flex-grid(7, 9);
- margin-right: flex-gutter();
- }
-
- // course title
- .course-title {
- @extend %t-title4;
- @extend %t-light;
- margin: 0 ($baseline*2) ($baseline/4) 0;
- }
-
- // course metadata
- .course-metadata {
- @extend %t-copy-sub1;
- @include transition(opacity $tmg-f1 ease-in-out 0);
- color: $gray;
- opacity: 0.75;
-
- .metadata-item {
- display: inline-block;
-
- &:after {
- content: "/";
- margin-left: ($baseline/10);
- margin-right: ($baseline/10);
- color: $gray-l4;
- }
-
- &:last-child {
-
- &:after {
- content: "";
- margin-left: 0;
- margin-right: 0;
- }
- }
-
- .label {
- @extend %cont-text-sr;
- }
- }
- }
-
- .course-actions {
- @extend %ui-depth3;
- position: static;
- width: flex-grid(2, 9);
+ width: flex-grid(3, 9);
+ padding-right: ($baseline/2);
text-align: right;
- // view live button
- .view-live-button {
- @extend %ui-depth3;
- @include transition(opacity $tmg-f2 ease-in-out 0);
- @include box-sizing(border-box);
- padding: ($baseline/2);
- opacity: 0.0;
- pointer-events: none;
+ .value {
- &:hover {
- opacity: 1.0;
- pointer-events: auto;
+ .copy, *[class^="icon"] {
+ display: inline-block;
+ vertical-align: middle;
+ }
+
+ *[class^="icon"] {
+ @extend %t-icon4;
+ margin-right: ($baseline/2);
+ }
+
+ .copy {
+ @extend %t-copy-sub1;
}
}
+ }
- &:last-child {
- border-bottom: none;
+ .status-message {
+ @extend %t-copy-sub1;
+ background-color: $gray-l5;
+ box-shadow: 0 2px 2px 0 $shadow inset;
+ padding: ($baseline*0.75) $baseline;
+
+ &.has-actions {
+
+ .copy, .status-actions {
+ display: inline-block;
+ vertical-align: middle;
+ }
+
+ .copy {
+ width: 65%;
+ margin: 0 $baseline 0 0;
+ }
+
+ .status-actions {
+ width: 30%;
+ text-align: right;
+
+ .button {
+ @extend %btn-secondary-white;
+ }
+
+ .icon,.button-copy {
+ display: inline-block;
+ vertical-align: middle;
+ }
+
+ .icon {
+ @extend %t-icon4;
+ margin-right: ($baseline/4);
+ }
+
+ .button-copy {
+ @extend %t-copy-sub1;
+ }
+ }
}
}
}
}
+ // UI: individual course listings
+ .course-item {
+ @include box-sizing(border-box);
+ width: flex-grid(9, 9);
+ position: relative;
+ border-bottom: 1px solid $gray-l2;
+ padding: $baseline;
+
+ // STATE: hover/focus
+ &:hover {
+ background: $paleYellow;
+
+ .course-actions {
+ opacity: 1.0;
+ pointer-events: auto;
+ }
+
+ .course-title {
+ color: $orange-d1;
+ }
+
+ .course-metadata {
+ opacity: 1.0;
+ }
+ }
+
+ .course-link, .course-actions {
+ @include box-sizing(border-box);
+ display: inline-block;
+ vertical-align: middle;
+ }
+
+ // encompassing course link
+ .course-link {
+ @extend %ui-depth2;
+ width: flex-grid(6, 9);
+ margin-right: flex-gutter();
+ }
+
+ // course title
+ .course-title {
+ @extend %t-title4;
+ margin: 0 ($baseline*2) ($baseline/4) 0;
+ font-weight: 300;
+ }
+
+ // course metadata
+ .course-metadata {
+ @extend %t-copy-sub1;
+ @include transition(opacity $tmg-f1 ease-in-out 0);
+ color: $gray;
+ opacity: 0.75;
+
+ .metadata-item {
+ display: inline-block;
+
+ &:after {
+ content: "/";
+ margin-left: ($baseline/10);
+ margin-right: ($baseline/10);
+ color: $gray-l4;
+ }
+
+ &:last-child {
+
+ &:after {
+ content: "";
+ margin-left: 0;
+ margin-right: 0;
+ }
+ }
+
+ .label {
+ @extend %cont-text-sr;
+ }
+ }
+ }
+
+ .course-actions {
+ @include transition(opacity $tmg-f2 ease-in-out 0);
+ @extend %ui-depth3;
+ position: static;
+ width: flex-grid(3, 9);
+ text-align: right;
+ opacity: 0;
+ pointer-events: none;
+
+ .action {
+ display: inline-block;
+ vertical-align: middle;
+ margin-right: ($baseline/2);
+
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+
+ .button {
+ @extend %t-action3;
+ }
+
+ // view live button
+ .view-button {
+ @include box-sizing(border-box);
+ padding: ($baseline/2);
+ }
+
+ // course re-run button
+ .action-rerun {
+ margin-right: $baseline;
+ }
+
+ .rerun-button {
+ font-weight: 600;
+ // TODO: sync up button styling and add secondary style here
+ }
+ }
+
+ // CASE: is processing
+ &.is-processing {
+
+ .course-status .value {
+ color: $gray-l2;
+ }
+ }
+
+ // CASE: has an error
+ &.has-error {
+
+ .course-status {
+ color: $red; // TODO: abstract this out to an error-based color variable
+ }
+
+ ~ .status-message {
+ background: $red-l1; // TODO: abstract this out to an error-based color variable
+ color: $white;
+ }
+ }
+
+ // CASE: last course in listing
+ &:last-child {
+ border-bottom: none;
+ }
+ }
+
+ // ====================
+
+ // CASE: courses that are being processed
+ .courses-processing {
+ margin-bottom: ($baseline*2);
+ border-bottom: 1px solid $gray-l3;
+ padding-bottom: ($baseline*2);
+
+ // TODO: abstract this case out better with normal course listings
+ .list-courses {
+ border: none;
+ background: none;
+ box-shadow: none;
+ }
+
+ .wrapper-course {
+ @extend %ui-window;
+ position: relative;
+ }
+
+ .course-item {
+ border: none;
+
+ // STATE: hover/focus
+ &:hover {
+ background: inherit;
+
+ .course-title {
+ color: inherit;
+ }
+ }
+
+ }
+
+ // course details (replacement for course-link when a course cannot be linked)
+ .course-details {
+ @extend %ui-depth2;
+ display: inline-block;
+ vertical-align: middle;
+ width: flex-grid(6, 9);
+ margin-right: flex-gutter();
+ }
+
+ }
+
+ // ====================
+
// ELEM: new user form
.wrapper-create-course {
@@ -494,6 +672,5 @@
margin-bottom: 0;
padding: ($baseline*.5) ($baseline*1.5) 8px ($baseline*1.5);
}
-
}
}
diff --git a/cms/templates/base.html b/cms/templates/base.html
index 72b8cfcc0e..a0ca8fc724 100644
--- a/cms/templates/base.html
+++ b/cms/templates/base.html
@@ -343,7 +343,9 @@
<% online_help_token = self.online_help_token() if hasattr(self, 'online_help_token') else None %>
<%include file="widgets/header.html" args="online_help_token=online_help_token" />
-
<%block name="content">%block>
diff --git a/cms/templates/course-create-rerun.html b/cms/templates/course-create-rerun.html
new file mode 100644
index 0000000000..87f18d3431
--- /dev/null
+++ b/cms/templates/course-create-rerun.html
@@ -0,0 +1,173 @@
+
+
+<%inherit file="base.html" />
+
+<%! from django.utils.translation import ugettext as _ %>
+<%! from django.core.urlresolvers import reverse %>
+
+<%block name="title">${_("Create a Course Rerun of:")}%block>
+<%block name="bodyclass">is-signedin view-course-create view-course-create-rerun%block>
+
+<%block name="jsextra">
+
+
+
+%block>
+
+<%block name="content">
+
+
+
+
+
+
+ Page Actions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${_("Provide identifying information for this re-run of the course. The original course is not affected in any way by a re-run.")}
+ ${_("Note: Together, the organization, course number, and course run must uniquely identify this new course instance.")}
+
+
+
+
+
+
+
+
+
+
+
+
+
${_("When will my course re-run start?")}
+
+ ${_("Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum.")}
+
+
+
+
+
${_("What transfers from the original course?")}
+
+ ${_("Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum.")}
+
+
+
+
+
${_("What does not transfer from the original course?")}
+
+ ${_("Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum.")}
+
+
+
+
+
+
+
+
+
+%block>
\ No newline at end of file
diff --git a/cms/templates/course_outline.html b/cms/templates/course_outline.html
index ee22386600..2fd4867b64 100644
--- a/cms/templates/course_outline.html
+++ b/cms/templates/course_outline.html
@@ -36,6 +36,31 @@ from contentstore.utils import reverse_usage_url
% endfor
%block>
+<%block name="page_alert">
+ %if notification_dismiss_url is not None:
+
+
+
+
+
+
This course was created as a re-run. Some manual configuration is needed.
+
+
Be sure to review and reset all dates (the Course Start Date was set to January 1, 2030); set up the course team; review course updates and other assets for dated material; and seed the discussions and wiki.
+
+
+
+
+
+ %endif
+%block>
+
<%block name="content">
diff --git a/cms/templates/index.html b/cms/templates/index.html
index 0b37c9ecfc..5fa9885fba 100644
--- a/cms/templates/index.html
+++ b/cms/templates/index.html
@@ -77,7 +77,7 @@ require(["domReady!", "jquery", "jquery.form", "js/index"], function(doc, $) {
% if course_creator_status=='granted':