Merge branch 'master' into dev/grading-periods-update

Change-Id: Idaf66797a745b9c43aeb70361d476b621799a43f
This commit is contained in:
Spencer Olson 2016-05-16 13:39:41 -04:00
commit 3ba3d62761
69 changed files with 998 additions and 649 deletions

View File

@ -110,9 +110,6 @@ define [
htmlUrl: => htmlUrl: =>
@get 'url' @get 'url'
togglePostToSISUrl: =>
@get 'toggle_post_to_sis_url'
defaultDates: => defaultDates: =>
group = new DateGroup group = new DateGroup
due_at: @get("due_at") due_at: @get("due_at")

View File

@ -0,0 +1,67 @@
define [
'i18n!assignments',
'Backbone',
'jquery',
'jst/_sisButton'
], (I18n, Backbone, $, template) ->
class SisButtonView extends Backbone.View
template: template
tagName: 'span'
className: 'sis-button'
events:
'click': 'togglePostToSIS'
SIS_ATTRIBUTES = {
enabled: {
src: '/images/svg-icons/svg_icon_post_to_sis_active.svg',
description: I18n.t('Post grade to SIS enabled. Click to toggle.'),
label: I18n.t('The grade for this assignment will sync to the student information system.'),
},
disabled: {
src: '/images/svg-icons/svg_icon_post_to_sis.svg',
description: I18n.t('Post grade to SIS disabled. Click to toggle.'),
label: I18n.t('The grade for this assignment will not sync to the student information system.')
}
}
setAttributes: ->
newSisAttributes = @sisAttributes()
@$input.attr({
'src': newSisAttributes['src'],
'alt': newSisAttributes['description'],
'title': newSisAttributes['description']
})
@$label.text(newSisAttributes['label'])
togglePostToSIS: (e) =>
e.preventDefault()
sisUrl = @model.get('toggle_post_to_sis_url')
c = @model.postToSIS()
@model.postToSIS(!c)
if sisUrl
@model.save({}, {
type: 'POST',
url: sisUrl,
success: =>
@setAttributes()
})
else
@model.save({}, {
success: =>
@setAttributes()
})
sisAttributes: =>
sisStatus = if @model.postToSIS() then "enabled" else "disabled"
SIS_ATTRIBUTES[sisStatus]
render: ->
super
labelId = 'sis-status-label-'+ @model.id
@$label = @$el.find('label')
@$input = @$el.find('input')
@$input.attr('aria-describedby': labelId)
@$label.attr('id', labelId)
@setAttributes()

View File

@ -7,6 +7,7 @@ define [
'compiled/views/assignments/DateDueColumnView' 'compiled/views/assignments/DateDueColumnView'
'compiled/views/assignments/DateAvailableColumnView' 'compiled/views/assignments/DateAvailableColumnView'
'compiled/views/assignments/CreateAssignmentView' 'compiled/views/assignments/CreateAssignmentView'
'compiled/views/SisButtonView'
'compiled/views/MoveDialogView' 'compiled/views/MoveDialogView'
'compiled/fn/preventDefault' 'compiled/fn/preventDefault'
'jst/assignments/AssignmentListItem' 'jst/assignments/AssignmentListItem'
@ -16,7 +17,7 @@ define [
'jqueryui/tooltip' 'jqueryui/tooltip'
'compiled/behaviors/tooltip' 'compiled/behaviors/tooltip'
'compiled/jquery.rails_flash_notifications' 'compiled/jquery.rails_flash_notifications'
], (I18n, Backbone, $, _, PublishIconView, DateDueColumnView, DateAvailableColumnView, CreateAssignmentView, MoveDialogView, preventDefault, template, scoreTemplate, round, AssignmentKeyBindingsMixin) -> ], (I18n, Backbone, $, _, PublishIconView, DateDueColumnView, DateAvailableColumnView, CreateAssignmentView, SisButtonView, MoveDialogView, preventDefault, template, scoreTemplate, round, AssignmentKeyBindingsMixin) ->
class AssignmentListItemView extends Backbone.View class AssignmentListItemView extends Backbone.View
@mixin AssignmentKeyBindingsMixin @mixin AssignmentKeyBindingsMixin
@ -28,6 +29,7 @@ define [
@child 'dateDueColumnView', '[data-view=date-due]' @child 'dateDueColumnView', '[data-view=date-due]'
@child 'dateAvailableColumnView', '[data-view=date-available]' @child 'dateAvailableColumnView', '[data-view=date-available]'
@child 'editAssignmentView', '[data-view=edit-assignment]' @child 'editAssignmentView', '[data-view=edit-assignment]'
@child 'sisButtonView', '[data-view=sis-button]'
@child 'moveAssignmentView', '[data-view=moveAssignment]' @child 'moveAssignmentView', '[data-view=moveAssignment]'
els: els:
@ -38,7 +40,6 @@ define [
'click .delete_assignment': 'onDelete' 'click .delete_assignment': 'onDelete'
'click .tooltip_link': preventDefault -> 'click .tooltip_link': preventDefault ->
'keydown': 'handleKeys' 'keydown': 'handleKeys'
'click .post-to-sis-status': 'togglePostToSIS'
messages: messages:
confirm: I18n.t('confirms.delete_assignment', 'Are you sure you want to delete this assignment?') confirm: I18n.t('confirms.delete_assignment', 'Are you sure you want to delete this assignment?')
@ -64,6 +65,7 @@ define [
initializeChildViews: -> initializeChildViews: ->
@publishIconView = false @publishIconView = false
@sisButtonView = false
@editAssignmentView = false @editAssignmentView = false
@dateAvailableColumnView = false @dateAvailableColumnView = false
@moveAssignmentView = false @moveAssignmentView = false
@ -85,6 +87,9 @@ define [
closeTarget: @$el.find('a[id*=manage_link]') closeTarget: @$el.find('a[id*=manage_link]')
saveURL: -> "#{ENV.URLS.assignment_sort_base_url}/#{@parentListView.value()}/reorder" saveURL: -> "#{ENV.URLS.assignment_sort_base_url}/#{@parentListView.value()}/reorder"
if @model.postToSISEnabled()
@sisButtonView = new SisButtonView(model: @model)
@dateDueColumnView = new DateDueColumnView(model: @model) @dateDueColumnView = new DateDueColumnView(model: @model)
@dateAvailableColumnView = new DateAvailableColumnView(model: @model) @dateAvailableColumnView = new DateAvailableColumnView(model: @model)
@ -95,6 +100,7 @@ define [
render: -> render: ->
@toggleHidden(@model, @model.get('hidden')) @toggleHidden(@model, @model.get('hidden'))
@publishIconView.remove() if @publishIconView @publishIconView.remove() if @publishIconView
@sisButtonView.remove() if @sisButtonView
@editAssignmentView.remove() if @editAssignmentView @editAssignmentView.remove() if @editAssignmentView
@dateDueColumnView.remove() if @dateDueColumnView @dateDueColumnView.remove() if @dateDueColumnView
@dateAvailableColumnView.remove() if @dateAvailableColumnView @dateAvailableColumnView.remove() if @dateAvailableColumnView
@ -267,27 +273,6 @@ define [
editItem: => editItem: =>
@$("#assignment_#{@model.id}_settings_edit_item").click() @$("#assignment_#{@model.id}_settings_edit_item").click()
togglePostToSIS: (e) =>
c = @model.postToSIS()
@model.postToSIS(!c)
e.preventDefault()
$t = $(e.currentTarget)
@model.save({}, {
success: =>
if c
$t.removeClass('post-to-sis-status enabled')
$t.addClass('post-to-sis-status disabled')
$t.find('.icon-post-to-sis').prop('title', I18n.t("Post grade to SIS disabled. Click to toggle."))
.prop('src', '/images/svg-icons/svg_icon_post_to_sis.svg')
$t.find('.screenreader-only').text(I18n.t("The grade for this assignment will not sync to the student information system. Click here to toggle this setting."))
else
$t.removeClass('post-to-sis-status disabled')
$t.addClass('post-to-sis-status enabled')
$t.find('.icon-post-to-sis').prop('title', I18n.t("Post grade to SIS enabled. Click to toggle."))
.prop('src', '/images/svg-icons/svg_icon_post_to_sis_active.svg')
$t.find('.screenreader-only').text(I18n.t("The grade for this assignment will sync to the student information system. Click here to toggle this setting."))
})
deleteItem: => deleteItem: =>
@$("#assignment_#{@model.id}_settings_delete_item").click() @$("#assignment_#{@model.id}_settings_delete_item").click()

View File

@ -20,6 +20,24 @@ define [
if ENV.canManageCourse if ENV.canManageCourse
@collection.fetch() @collection.fetch()
render: ->
super
@refreshTabs()
refreshTabs: ->
$tabs = $('#group_categories_tabs')
$tabs.tabs().show()
$tabs.tabs
beforeActivate: (event, ui) ->
ui.newTab.hasClass('static')
$groupTabs = $tabs.find('li').not('.static')
$groupTabs.find('a').unbind()
$groupTabs.on 'keydown', (event) ->
event.stopPropagation()
if event.keyCode == 13 or event.keyCode == 32
window.location.href = $(this).find('a').attr('href')
toJSON: -> toJSON: ->
json = {} json = {}
json.collection = super json.collection = super

View File

@ -64,7 +64,6 @@ define [
showEditForm: -> showEditForm: ->
@$el.addClass('editing').removeClass('not-editing') @$el.addClass('editing').removeClass('not-editing')
@$('.profile_links').removeClass('span6')
initEdit: -> initEdit: ->
if @options.links?.length if @options.links?.length
@ -77,7 +76,6 @@ define [
cancelEditProfile: -> cancelEditProfile: ->
@$el.addClass('not-editing').removeClass('editing') @$el.addClass('not-editing').removeClass('editing')
@$('.profile_links').addClass('span6')
## ##
# Event handler that can also be called manually. # Event handler that can also be called manually.

View File

@ -6,8 +6,9 @@ define [
'compiled/views/PublishIconView' 'compiled/views/PublishIconView'
'compiled/views/assignments/DateDueColumnView' 'compiled/views/assignments/DateDueColumnView'
'compiled/views/assignments/DateAvailableColumnView' 'compiled/views/assignments/DateAvailableColumnView'
'compiled/views/SisButtonView'
'jst/quizzes/QuizItemView' 'jst/quizzes/QuizItemView'
], (I18n, $, _, Backbone, PublishIconView, DateDueColumnView, DateAvailableColumnView, template) -> ], (I18n, $, _, Backbone, PublishIconView, DateDueColumnView, DateAvailableColumnView, SisButtonView, template) ->
class ItemView extends Backbone.View class ItemView extends Backbone.View
@ -19,11 +20,11 @@ define [
@child 'publishIconView', '[data-view=publish-icon]' @child 'publishIconView', '[data-view=publish-icon]'
@child 'dateDueColumnView', '[data-view=date-due]' @child 'dateDueColumnView', '[data-view=date-due]'
@child 'dateAvailableColumnView', '[data-view=date-available]' @child 'dateAvailableColumnView', '[data-view=date-available]'
@child 'sisButtonView', '[data-view=sis-button]'
events: events:
'click': 'clickRow' 'click': 'clickRow'
'click .delete-item': 'onDelete' 'click .delete-item': 'onDelete'
'click .post-to-sis-status': 'togglePostToSIS'
messages: messages:
confirm: I18n.t('confirms.delete_quiz', 'Are you sure you want to delete this quiz?') confirm: I18n.t('confirms.delete_quiz', 'Are you sure you want to delete this quiz?')
@ -38,9 +39,12 @@ define [
initializeChildViews: -> initializeChildViews: ->
@publishIconView = false @publishIconView = false
@sisButtonView = false
if @canManage() if @canManage()
@publishIconView = new PublishIconView(model: @model) @publishIconView = new PublishIconView(model: @model)
if @model.postToSISEnabled()
@sisButtonView = new SisButtonView(model: @model)
@dateDueColumnView = new DateDueColumnView(model: @model) @dateDueColumnView = new DateDueColumnView(model: @model)
@dateAvailableColumnView = new DateAvailableColumnView(model: @model) @dateAvailableColumnView = new DateAvailableColumnView(model: @model)
@ -82,25 +86,6 @@ define [
updatePublishState: => updatePublishState: =>
@$('.ig-row').toggleClass('ig-published', @model.get('published')) @$('.ig-row').toggleClass('ig-published', @model.get('published'))
togglePostToSIS: (e) =>
c = @model.postToSIS()
@model.postToSIS(!c)
e.preventDefault()
$t = $(e.currentTarget)
@model.save({}, { type: 'POST', url: @model.togglePostToSISUrl(),
success: =>
if c
$t.removeClass('post-to-sis-status enabled')
$t.addClass('post-to-sis-status disabled')
$t.find('.icon-post-to-sis').prop('title', I18n.t("Post grade to SIS disabled. Click to toggle."))
$t.find('.screenreader-only').text(I18n.t("The grade for this assignment will not sync to the student information system. Click here to toggle this setting."))
else
$t.removeClass('post-to-sis-status disabled')
$t.addClass('post-to-sis-status enabled')
$t.find('.icon-post-to-sis').prop('title', I18n.t("Post grade to SIS enabled. Click to toggle."))
$t.find('.screenreader-only').text(I18n.t("The grade for this assignment will sync to the student information system. Click here to toggle this setting."))
})
canManage: -> canManage: ->
ENV.PERMISSIONS.manage ENV.PERMISSIONS.manage

View File

@ -322,7 +322,7 @@
# "type": "boolean" # "type": "boolean"
# }, # },
# "external_tool_tag_attributes": { # "external_tool_tag_attributes": {
# "description": "(Optional) assignment's settings for external tools if submission_types include 'external_tool'. Only url and new_tab are included. Use the 'External Tools' API if you need more information about an external tool.", # "description": "(Optional) assignment's settings for external tools if submission_types include 'external_tool'. Only url and new_tab are included (new_tab defaults to false). Use the 'External Tools' API if you need more information about an external tool.",
# "$ref": "ExternalToolTagAttributes" # "$ref": "ExternalToolTagAttributes"
# }, # },
# "peer_reviews": { # "peer_reviews": {
@ -768,14 +768,8 @@ class AssignmentsApiController < ApplicationController
# assign scores to each member of the group. # assign scores to each member of the group.
# #
# @argument assignment[external_tool_tag_attributes] # @argument assignment[external_tool_tag_attributes]
# Hash of attributes if submission_types is ["external_tool"] # Hash of external tool parameters if submission_types is ["external_tool"].
# Example: # See Assignment object definition for format.
# external_tool_tag_attributes: {
# // url to the external tool
# url: "http://instructure.com",
# // create a new tab for the module, defaults to false.
# new_tab: false
# }
# #
# @argument assignment[points_possible] [Float] # @argument assignment[points_possible] [Float]
# The maximum points possible on the assignment. # The maximum points possible on the assignment.
@ -912,14 +906,8 @@ class AssignmentsApiController < ApplicationController
# assign scores to each member of the group. # assign scores to each member of the group.
# #
# @argument assignment[external_tool_tag_attributes] # @argument assignment[external_tool_tag_attributes]
# Hash of attributes if submission_types is ["external_tool"] # Hash of external tool parameters if submission_types is ["external_tool"].
# Example: # See Assignment object definition for format.
# external_tool_tag_attributes: {
# // url to the external tool
# url: "http://instructure.com",
# // create a new tab for the module, defaults to false.
# new_tab: false
# }
# #
# @argument assignment[points_possible] [Float] # @argument assignment[points_possible] [Float]
# The maximum points possible on the assignment. # The maximum points possible on the assignment.

View File

@ -493,6 +493,7 @@ class GradebooksController < ApplicationController
end end
def submissions_zip_upload def submissions_zip_upload
return unless authorized_action(@context, @current_user, :manage_grades)
unless @context.allows_gradebook_uploads? unless @context.allows_gradebook_uploads?
flash[:error] = t('errors.not_allowed', "This course does not allow score uploads.") flash[:error] = t('errors.not_allowed', "This course does not allow score uploads.")
redirect_to named_context_url(@context, :context_assignment_url, @assignment.id) redirect_to named_context_url(@context, :context_assignment_url, @assignment.id)

View File

@ -172,7 +172,7 @@ class ProfileController < ApplicationController
known_user = @user_data[:common_contexts].present? known_user = @user_data[:common_contexts].present?
if @user_data[:known_user] # if you can message them, you can see the profile if @user_data[:known_user] # if you can message them, you can see the profile
add_crumb(t('crumbs.settings_frd', "%{user}'s settings", :user => @user.short_name), user_profile_path(@user)) add_crumb(t('crumbs.settings_frd', "%{user}'s Profile", :user => @user.short_name), user_profile_path(@user))
render render
else else
render :unauthorized render :unauthorized

View File

@ -414,7 +414,7 @@ module ApplicationHelper
# #
# Returns an HTML string. # Returns an HTML string.
def sidebar_button(url, label, img = nil) def sidebar_button(url, label, img = nil)
link_to(url, :class => 'btn button-sidebar-wide') do link_to(url) do
img ? ("<i class='icon-" + img + "'></i> ").html_safe + label : label img ? ("<i class='icon-" + img + "'></i> ").html_safe + label : label
end end
end end

View File

@ -23,7 +23,8 @@
<td valign="top"><%= date_string(asset.start_at, asset.end_at, :no_words) %></td> <td valign="top"><%= date_string(asset.start_at, asset.end_at, :no_words) %></td>
</tr> </tr>
<tr> <tr>
<td style="padding-right: 10px;" valign="top"><%= asset.participant_type == 'Group' ? <td style="padding-right: 10px;" valign="top"><%= t "Signup Type" %>:</td>
<td valign="top"><%= asset.participant_type == 'Group' ?
t(:group_signup, "Group (%{group_category})", :group_category => asset.sub_contexts.first.name) : t(:group_signup, "Group (%{group_category})", :group_category => asset.sub_contexts.first.name) :
t(:individual_signup, "Individual") %></td> t(:individual_signup, "Individual") %></td>
</tr> </tr>

View File

@ -1180,6 +1180,22 @@ class Attachment < ActiveRecord::Base
true true
end end
def make_childless
child = children.take
return unless child
child.root_attachment_id = nil
child.filename ||= filename
if Attachment.s3_storage?
if s3object.exists? && !child.s3object.exists?
s3object.copy_to(child.s3object)
end
else
child.uploaded_data = open
end
child.save!
Attachment.where(root_attachment_id: self).where.not(id: child).update_all(root_attachment_id: child)
end
def restore def restore
self.file_state = 'available' self.file_state = 'available'
self.save self.save

View File

@ -62,7 +62,7 @@ module BroadcastPolicies
!assignment.muted? && !assignment.muted? &&
assignment.published? && assignment.published? &&
submission.quiz_submission.nil? && submission.quiz_submission.nil? &&
user_active_invited_or_concluded? user_active_or_invited?
end end
def assignment def assignment
@ -102,11 +102,8 @@ module BroadcastPolicies
AssignmentStudentVisibility.where(assignment_id: submission.assignment_id, user_id: submission.user_id).any? AssignmentStudentVisibility.where(assignment_id: submission.assignment_id, user_id: submission.user_id).any?
end end
def user_active_invited_or_concluded? def user_active_or_invited?
course.all_student_enrollments. course.student_enrollments.where(user_id: submission.user_id).to_a.any?{|e| e.active? || e.invited?}
where("enrollments.workflow_state NOT IN ('deleted','inactive','rejected')").
where(user_id: submission.user_id).
exists?
end end
end end
end end

View File

@ -35,7 +35,7 @@ class EnrollmentTerm < ActiveRecord::Base
before_validation :verify_unique_sis_source_id before_validation :verify_unique_sis_source_id
before_save :update_courses_later_if_necessary before_save :update_courses_later_if_necessary
before_save :destroy_orphaned_grading_period_group before_update :destroy_orphaned_grading_period_group
include StickySisFields include StickySisFields
are_sis_sticky :name, :start_at, :end_at are_sis_sticky :name, :start_at, :end_at

View File

@ -1,5 +1,6 @@
class EpubExport < ActiveRecord::Base class EpubExport < ActiveRecord::Base
include CC::Exporter::Epub::Exportable include CC::Exporter::Epub::Exportable
include LocaleSelection
include Workflow include Workflow
strong_params strong_params
@ -120,7 +121,9 @@ class EpubExport < ActiveRecord::Base
def convert_to_epub def convert_to_epub
begin begin
set_locale
file_paths = super file_paths = super
I18n.locale = :en
rescue => e rescue => e
mark_as_failed mark_as_failed
raise e raise e
@ -160,4 +163,14 @@ class EpubExport < ActiveRecord::Base
def sort_by_content_type? def sort_by_content_type?
self.course.organize_epub_by_content_type self.course.organize_epub_by_content_type
end end
private
def set_locale
I18n.locale = infer_locale(
context: course,
user: user,
root_account: course.root_account
)
end
end end

View File

@ -35,7 +35,8 @@ class FeatureFlag < ActiveRecord::Base
def unhides_feature? def unhides_feature?
return false unless Feature.definitions[feature].hidden? return false unless Feature.definitions[feature].hidden?
return true if context.is_a?(Account) && context.site_admin? return true if context.is_a?(Account) && context.site_admin?
Account.find(context.feature_flag_account_ids.last).lookup_feature_flag(feature, true).hidden? parent_setting = Account.find(context.feature_flag_account_ids.last).lookup_feature_flag(feature, true)
parent_setting.nil? || parent_setting.hidden?
end end
def enabled? def enabled?

View File

@ -218,7 +218,7 @@ class GradingStandard < ActiveRecord::Base
def self.default_instance def self.default_instance
gs = GradingStandard.new() gs = GradingStandard.new()
gs.data = default_grading_scheme gs.data = default_grading_scheme
gs.title = "Default Grading Standard" gs.title = "Default Grading Scheme"
gs gs
end end

View File

@ -192,8 +192,9 @@ class SisBatch < ActiveRecord::Base
end end
def fast_update_progress(val) def fast_update_progress(val)
return true if val == self.progress
self.progress = val self.progress = val
SisBatch.where(:id => self).update_all(:progress=>val) SisBatch.where(id: self).update_all(progress: val)
end end
def importing? def importing?

View File

@ -227,11 +227,41 @@
width: 25px; width: 25px;
min-width: 25px; min-width: 25px;
} }
// these are the classes that get applied to #right-side-wrapper to handle $.scrollSidebar
@mixin sidebar-logo {display: block;}
@if $use_new_styles {
.ic-sidebar-logo {
display: none;
margin-bottom: $ic-sp*2;
text-align: center;
}
.ic-sidebar-logo__image {
max-width: 180px;
max-height: 70px;
display: inline-block;
}
body:not(.course-menu-expanded) {
.ic-sidebar-logo {
@include breakpoint(desktop) {
@include sidebar-logo;
}
}
}
body.course-menu-expanded {
.ic-sidebar-logo {
@include breakpoint(desktop--nav-open) {
@include sidebar-logo;
}
}
}
}
// Legacy Styles
@if not $use_new_styles {
// These are the classes that get applied to #right-side-wrapper to handle $.scrollSidebar
// NOTE: they used to get applied to body but were moved to #right side to not force a repaint // NOTE: they used to get applied to body but were moved to #right side to not force a repaint
// of the entire page and be less jumpy going in and out display modes. // of the entire page and be less jumpy going in and out display modes.
@if not $use_new_styles {
.with-scrolling-right-side { .with-scrolling-right-side {
#right-side { #right-side {
position: fixed; position: fixed;
@ -239,7 +269,6 @@
margin-top: 0; margin-top: 0;
} }
} }
#right-side-wrapper.with-sidebar-pinned-to-bottom { #right-side-wrapper.with-sidebar-pinned-to-bottom {
position: absolute; position: absolute;
bottom: 0; bottom: 0;

View File

@ -16,6 +16,105 @@ $ic-left-side-width: $ic-sp*15;
@else { background: $ic-border-dark; } @else { background: $ic-border-dark; }
} }
body:not(.ic-no-flex-layout):not(.embedded) .ic-app-main-content {
box-sizing: border-box;
flex: 1;
// Fix Firefox and IE Edge issues with contents breaking out of flex container
min-width: 1px;
}
.ic-app-main-content__primary {
box-sizing: border-box;
}
.ic-app-main-content__secondary {
box-sizing: border-box;
padding: $ic-sp*2;
position: relative; // note: this is also set for #right-side-wrapper in _#right-side.scss
// prevent safari bug where content disappears on scroll
-webkit-transform: translate3d(0, 0, 0);
}
/// Below are the shared styles for our content pieces. Because our layout
/// changes based on whether our course menu is open or shut
/// we needed to ensure we share the right styles with these sections, but
/// still enforce different breakpoints when needed
@mixin shared-main-content {display: flex;}
@mixin shared-primary {
flex: 1;
// Fix Firefox and IE Edge issues with contents breaking out of flex container
min-width: 1px;
}
@mixin shared-secondary {
flex: 0 0 $ic-sp*24;
padding-left: $ic-sp*2;
}
/// Layout when the course nav IS OPEN
body.course-menu-expanded {
&:not(.ic-no-flex-layout):not(.embedded) .ic-app-main-content {
@include breakpoint(desktop--nav-open) { @include shared-main-content; }
}
&:not(.ic-no-flex-layout):not(.embedded) .ic-app-main-content__primary {
@include breakpoint(desktop--nav-open) {
@include shared-primary;
}
}
.ic-app-main-content__secondary {
@include breakpoint(desktop--nav-open) {
@include shared-secondary;
}
}
}
/// Layout when the course nav IS CLOSED
body:not(.course-menu-expanded) {
&:not(.ic-no-flex-layout):not(.embedded) .ic-app-main-content {
@include breakpoint(desktop) { @include shared-main-content; }
}
&:not(.ic-no-flex-layout):not(.embedded) .ic-app-main-content__primary {
@include breakpoint(desktop) {
@include shared-primary;
}
}
.ic-app-main-content__secondary {
@include breakpoint(desktop) {
@include shared-secondary;
}
}
}
.ic-app-footer {
box-sizing: border-box;
padding: $ic-sp 0;
margin: 0 $ic-sp*2;
border-top: 1px solid $ic-border-light;
@include breakpoint(desktop) {
display: flex;
align-items: center;
}
body.modal & {
margin: 0;
padding: $ic-sp $ic-sp*2;
}
}
.ic-app-footer__links {
flex: 1;
display: flex;
a {
color: $ic-font-color--subdued;
margin-right: $ic-sp;
@include fontSize($ic-font-size--xsmall);
}
@include breakpoint(desktop) {
justify-content: flex-end;
a { margin-right: 0; margin-left: $ic-sp; }
}
}
.ic-app { .ic-app {
box-sizing: border-box; box-sizing: border-box;
min-height: 100vh; min-height: 100vh;
@ -103,71 +202,6 @@ $ic-left-side-width: $ic-sp*15;
} }
} }
.ic-app-main-content {
body:not(.ic-no-flex-layout):not(.embedded) & {
box-sizing: border-box;
flex: 1;
@include breakpoint(desktop) { display: flex; }
// Fix Firefox and IE Edge issues with contents breaking out of flex container
min-width: 1px;
}
}
.ic-app-main-content__primary {
box-sizing: border-box;
@include breakpoint(desktop) {
body:not(.ic-no-flex-layout):not(.embedded) & {
flex: 1;
// Fix Firefox and IE Edge issues with contents breaking out of flex container
min-width: 1px;
}
}
}
.ic-app-main-content__secondary {
box-sizing: border-box;
padding: $ic-sp*2;
@include breakpoint(desktop) {
flex: 0 0 $ic-sp*24;
padding-left: $ic-sp*2;
}
position: relative; // note: this is also set for #right-side-wrapper in _#right-side.scss
// prevent safari bug where content disappears on scroll
-webkit-transform: translate3d(0, 0, 0);
}
.ic-app-footer {
box-sizing: border-box;
padding: $ic-sp 0;
margin: 0 $ic-sp*2;
border-top: 1px solid $ic-border-light;
@include breakpoint(desktop) {
display: flex;
align-items: center;
}
body.modal & {
margin: 0;
padding: $ic-sp $ic-sp*2;
}
}
.ic-app-footer__links {
flex: 1;
display: flex;
a {
color: $ic-font-color--subdued;
margin-right: $ic-sp;
@include fontSize($ic-font-size--xsmall);
}
@include breakpoint(desktop) {
justify-content: flex-end;
a { margin-right: 0; margin-left: $ic-sp; }
}
}
.ic-app-nav-toggle-and-crumbs { .ic-app-nav-toggle-and-crumbs {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -256,7 +256,23 @@ iframe.tool_launch {
height: 100%; height: 100%;
border: none; border: none;
} }
// implemented to make new profile page use flex for layout //
.ic-Layout {
display: flex;
padding: $ic-sp;
box-sizing: border-box;
width: 100%;
}
.ic-Layout__Primary {
flex: 2;
@include breakpoint(desktop) {
flex: 3;
}
}
.ic-Layout__Secondary {
flex: 1;
text-align: right;
}
#skip_navigation_link { #skip_navigation_link {
@include accessibility-prompt; @include accessibility-prompt;
position: absolute; position: absolute;

View File

@ -9,4 +9,7 @@
@else if $breakpoint == desktop { @else if $breakpoint == desktop {
@media only screen and (min-width: 992px) { @content; } @media only screen and (min-width: 992px) { @content; }
} }
@else if $breakpoint == desktop--nav-open {
@media only screen and (min-width: 1140px) { @content; }
}
} }

View File

@ -12,6 +12,12 @@
display: none !important; display: none !important;
} }
} }
.profile .image-block {
flex-direction: column;
@include breakpoint(desktop) {
flex-direction: row;
}
}
.profile-avatar-wrapper { .profile-avatar-wrapper {
margin-right: 20px !important; margin-right: 20px !important;
@ -83,9 +89,7 @@
#edit_links_table { #edit_links_table {
width: 100%; width: 100%;
input {
width: 95%;
}
td { td {
text-align: center; text-align: center;
} }
@ -99,21 +103,31 @@
overflow: hidden; overflow: hidden;
} }
#content { .profileContent__Block {
.h1, .h2 { display: flex;
line-height: 21px; flex-direction: column;
flex: 1;
} }
.profileDetails {
margin-top: 0;
} }
.profileEnrollment__Items {
#content h1 { padding: $ic-sp/2 0;
}
.profileLink {
margin: 0; margin: 0;
} }
.profileLink__Item {
#content h2 { list-style: none;
margin: 1em 0 0.5em 0; line-height: 2.0;
color: $gray; & a {
padding-left: $ic-sp/2;
}
}
.profileHeader {
padding: $ic-sp 0 0 0;
line-height: 1.25;
} }
.stats { .stats {
text-align: left; text-align: left;
width: 100%; width: 100%;

View File

@ -4,19 +4,28 @@
width: 100%; width: 100%;
} }
tr.login > th, tr.login > td { tr.login > th, tr.login > td {
padding-top: 5px; padding-top: 0;
padding-bottom: 5px; padding-bottom: 5px;
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
vertical-align: top; vertical-align: top;
&.sso-icon { vertical-align: middle; } &.sso-icon { vertical-align: middle; }
} }
.details { .account_name {
font-size: 0.8em; line-height: 3.0;
padding-left: 20px;
} }
.account { .login_details {
font-size: 0.8em; padding: 0;
padding-left: 10px; }
.login_details td:first-child {
font-weight: 500;
}
.login_details:last-child {
& td {
border-bottom: none;
}
}
.login_details_link {
font-style: italic;
} }
.links { .links {
white-space: nowrap; white-space: nowrap;

View File

@ -100,6 +100,7 @@
.user_content, .mceContentBody { .user_content, .mceContentBody {
position: relative; position: relative;
min-height: 5px; min-height: 5px;
max-width: 100%;
// firefox max-width images break the parent container // firefox max-width images break the parent container
@-moz-document url-prefix() { @-moz-document url-prefix() {
overflow-x: hidden; overflow-x: hidden;
@ -128,6 +129,7 @@
border: 0; border: 0;
padding: 0; padding: 0;
margin: 0; margin: 0;
max-width: 100%;
} }
.reminder, .reminder-content { .reminder, .reminder-content {

View File

@ -6,6 +6,11 @@
line-height: 17px; line-height: 17px;
cursor: pointer; cursor: pointer;
input {
width: 16px;
height: 20px;
}
&.enabled { &.enabled {
font-weight: bold; font-weight: bold;
@if $use_high_contrast { color: darken($ic-color-success, 4%); } @if $use_high_contrast { color: darken($ic-color-success, 4%); }

View File

@ -172,6 +172,9 @@ body:not(.with-left-side) & .ic-app-nav-toggle-and-crumbs--files {
position: relative; position: relative;
margin: 10px; margin: 10px;
flex: 3; flex: 3;
// long file names cause this container, of all things, to expand unreasonably even after they get elided. Work
// around that for the moment with this.
max-width: 75%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -1,36 +1,48 @@
<div class="rs-margin-lr <% unless use_new_styles? %>rs-margin-top<% end %>"> <div id="people-options" class="al-dropdown__container" style="position: relative;">
<button type="button" class="al-trigger Button">
<i class="icon-settings"></i>
<i class="icon-mini-arrow-down"></i>
<span class="screenreader-only">More Options</span>
</button>
<ul class="al-options" role="menu" tabindex="0" aria-hidden="true">
<% if @context.is_a?(Course) %> <% if @context.is_a?(Course) %>
<% if can_do(@context, @current_user, :read_roster) %> <% if can_do(@context, @current_user, :read_roster) %>
<li role="presentation">
<%= sidebar_button context_url(@context, :context_groups_url), <%= sidebar_button context_url(@context, :context_groups_url),
t('links.view_user_groups', 'View User Groups'), t('View User Groups'),
'group' %> 'group' %>
</li>
<% end %> <% end %>
<% if can_do(@context, @current_user, :manage_students && @context.enable_user_notes) %> <% if can_do(@context, @current_user, :manage_students && @context.enable_user_notes) %>
<li role="presentation">
<%= sidebar_button course_user_notes_path(@context), <%= sidebar_button course_user_notes_path(@context),
t('links.view_faculty_journals', 'View Faculty Journals') %> t('View Faculty Journals') %>
</li>
<% end %> <% end %>
<% if can_do(@context, @current_user, :manage_admin_users, :manage_students, :read_prior_roster) %> <% if can_do(@context, @current_user, :manage_admin_users, :manage_students, :read_prior_roster) %>
<li role="presentation">
<%= sidebar_button course_prior_users_path(@context), <%= sidebar_button course_prior_users_path(@context),
t('links.view_prior_enrollments', 'View Prior Enrollments'), t('View Prior Enrollments'),
'clock' %> 'clock' %>
</li>
<% end %>
<% if @context.user_is_instructor?(@current_user) && can_do(@context, @current_user, :read_reports) %>
<li role="presentation">
<%= sidebar_button user_course_teacher_activity_url(@current_user, @context),
t('Student Interactions Report'),
'user' %>
</li>
<% end %> <% end %>
<% end %> <% end %>
<% if can_do(@context, @current_user, :read_roster) %> <% if can_do(@context, @current_user, :read_roster) %>
<li role="presentation">
<%= sidebar_button context_url(@context, :context_user_services_url), <%= sidebar_button context_url(@context, :context_user_services_url),
t('links.view_services', 'View Registered Services'), t('links.view_services', 'View Registered Services'),
'link' %> 'link' %>
</li>
<% end %> <% end %>
</ul>
<% if @context.is_a?(Course) %>
<% if @context.user_is_instructor?(@current_user) && can_do(@context, @current_user, :read_reports) %>
<%= sidebar_button user_course_teacher_activity_url(@current_user, @context),
t('Student Interactions Report'),
'user' %>
<% end %>
<% end %>
</div> </div>

View File

@ -48,59 +48,67 @@
<div class="more_user_information"> <div class="more_user_information">
<% if @context.is_a?(Course) %> <% if @context.is_a?(Course) %>
<fieldset> <fieldset>
<legend><%= t('legends.memberships', %{Membership(s)}) %></legend> <legend>
<table> <h4 class="profileHeader">
<%= t('legends.memberships', %{Membership(s)}) %>
</h4>
</legend>
<table class="ic-Table--condensed">
<% @enrollments.sort_by(&:id).each do |enrollment| %> <% @enrollments.sort_by(&:id).each do |enrollment| %>
<tr class="enrollment"> <tr id="enrollment">
<td style="vertical-align: top; padding: 5px 50px 5px 5px;"> <td scope="row" style="width: 30%;">
<b><a href="<%= context_url(@context, :context_section_url, enrollment.course_section_id) rescue "#" %>"><%= enrollment.try_rescue(:course_section).try_rescue(:display_name) || enrollment.short_name %></a></b> <a href="<%= context_url(@context, :context_section_url, enrollment.course_section_id) rescue "#" %>"><%= enrollment.try_rescue(:course_section).try_rescue(:display_name) || enrollment.short_name %></a>
<div style="font-size: 0.8em; padding-left: 20px;"><%= t 'enrolled_as', "Enrolled as a %{enrollment_type}", :enrollment_type => enrollment.readable_type %></div> </td>
<div style="font-size: 0.8em; padding-left: 20px;">created <%= datetime_string(enrollment.created_at) %></div> <td style="width: 30%;">
<%= t 'enrolled_as', "Enrolled as a %{enrollment_type}", :enrollment_type => enrollment.readable_type %> | created <%= datetime_string(enrollment.created_at) %>
</td>
<% if enrollment.is_a?(ObserverEnrollment) %> <% if enrollment.is_a?(ObserverEnrollment) %>
<div style="font-size: 0.8em; padding-left: 20px; <%= hidden unless enrollment.associated_user %>" class="associated_user" > <td style="<%= hidden unless enrollment.associated_user %>" class="associated_user" >
<%= t 'enrollment_linked_to', "linked to *%{linked_user}*", <%= t 'enrollment_linked_to', "linked to *%{linked_user}*",
:linked_user => context_user_name(@context, enrollment.associated_user), :linked_user => context_user_name(@context, enrollment.associated_user),
:wrapper => '<span class="associated_user_name">\1</span>' %> :wrapper => '<span class="associated_user_name">\1</span>' %>
</div>
<% end %>
<div style="font-size: 0.8em; padding-left: 20px; <%= hidden unless enrollment.completed? %>" class="completed_at_holder"><%= t 'completed_enrollment', "completed *%{completed_at}*", :completed_at => datetime_string(enrollment.completed_at), :wrapper => '<span class="completed_at">\1</span>' %></div>
</td> </td>
<% if enrollment.admin? ? (can_manage_admins && enrollment.user_id != @current_user.id) : can_manage_students %>
<td style="vertical-align: top; padding: 5px; font-size: 0.8em;">
<% unless @context.completed? %>
<div class="conclude_enrollment_link_holder" style="margin-bottom: 5px; <%= hidden if enrollment.completed? %>">
<a class="conclude_enrollment_link" href="<%= context_url(@context, :controller => :courses, :action => :conclude_user, :id => enrollment.id) %>"><%= t('links.conclude_enrollment', %{Conclude this Enrollment}) %></a>
</div>
<div class="unconclude_enrollment_link_holder" style="margin-bottom: 5px; <%= hidden unless enrollment.explicitly_completed? || enrollment.inactive? %>">
<a class="unconclude_enrollment_link" href="<%= context_url(@context, :controller => :courses, :action => :unconclude_user, :id => enrollment.id) %>"><%= t('links.restore_enrollment', %{Restore this Enrollment}) %></a>
</div>
<% end %> <% end %>
<div><% if enrollment.defined_by_sis? %> <td style="width: 20%; <%= hidden unless enrollment.completed? %>">
<p class="completed_at_holder"><%= t 'completed_enrollment', "completed *%{completed_at}*", :completed_at => datetime_string(enrollment.completed_at), :wrapper => '<span class="completed_at">\1</span>' %></p>
</td>
<td style="width: 10%;">
<% if enrollment.admin? ? (can_manage_admins && enrollment.user_id != @current_user.id) : can_manage_students %>
<% unless @context.completed? %>
<p class="conclude_enrollment_link_holder" style="<%= hidden if enrollment.completed? %>">
<a class="conclude_enrollment_link" href="<%= context_url(@context, :controller => :courses, :action => :conclude_user, :id => enrollment.id) %>"><%= t('links.conclude_enrollment', %{Conclude}) %></a>
</p>
<p class="unconclude_enrollment_link_holder" style="<%= hidden unless enrollment.explicitly_completed? || enrollment.inactive? %>">
<a class="unconclude_enrollment_link" href="<%= context_url(@context, :controller => :courses, :action => :unconclude_user, :id => enrollment.id) %>"><%= t('links.restore_enrollment', %{Restore}) %></a>
</p>
<% end %>
</td>
<td style="width: 10%;">
<p>
<% if enrollment.defined_by_sis? %>
<a href="#" title="<%= t('links.title.enrollment_sis_defined', %{This enrollment was defined by the university, and can't be deleted}) %>"><%= t('links.cant_delete', %{Can't Delete}) %></a> <a href="#" title="<%= t('links.title.enrollment_sis_defined', %{This enrollment was defined by the university, and can't be deleted}) %>"><%= t('links.cant_delete', %{Can't Delete}) %></a>
<% else %> <% else %>
<a class="delete_enrollment_link" href="<%= context_url(@context, :context_unenroll_url, enrollment.id) %>"><%= t('links.delete_enrollment', %{Delete this Enrollment}) %></a> <a class="delete_enrollment_link" href="<%= context_url(@context, :context_unenroll_url, enrollment.id) %>"><%= t('links.delete_enrollment', %{Delete}) %></a>
<% end %> <% end %>
</div> </p>
</td> </td>
<% end %> <% end %>
</tr> </tr>
<% end %> <% end %>
<% if @context.is_a?(Course) && can_do(@context, @current_user, :manage_admin_users) %> <% if @context.is_a?(Course) && can_do(@context, @current_user, :manage_admin_users) %>
<tr> <tr id="priveleges">
<td style="border-top: 1px solid #eee; padding-top: 5px; vertical-align: top; font-weight: bold;"><%= before_label('user_privileges', %{Privileges}) %></td> <td scope="row">
<td style="border-top: 1px solid #eee; padding-top: 5px;"> <%= before_label('user_privileges', %{Privileges}) %>
<div class="elevate_enrollment_link_holder" style="<%= hidden if @enrollments.any?{|e| !e.limit_privileges_to_course_section } %>"> </td>
<%= t('user_only_view_section', %{this user can only view students in their assigned course section(s)}) %> <td colspan="2">
<div style="margin-left: 10px; font-size: 0.8em;"> <p class="elevate_enrollment_link_holder" style="<%= hidden if @enrollments.any?{|e| !e.limit_privileges_to_course_section } %>">
<%= t('user_only_view_section', %{this user can only view students in their assigned course section(s)}) %><br/>
<a href="<%= context_url(@context, :context_limit_user_grading_url, @user.id) %>" class="elevate_enrollment_link"><%= t('links.user_view_all_sections', %{let this user see all course users}) %></a> <a href="<%= context_url(@context, :context_limit_user_grading_url, @user.id) %>" class="elevate_enrollment_link"><%= t('links.user_view_all_sections', %{let this user see all course users}) %></a>
</div> </p>
</div> <p class="restrict_enrollment_link_holder" style="<%= hidden unless @enrollments.any?{|e| !e.limit_privileges_to_course_section } %>">
<div class="restrict_enrollment_link_holder" style="<%= hidden unless @enrollments.any?{|e| !e.limit_privileges_to_course_section } %>"> <%= t('user_view_all_sections', %{this user can view students in any course section}) %><br/>
<%= t('user_view_all_sections', %{this user can view students in any course section}) %>
<div style="margin-left: 10px; font-size: 0.8em;">
<a href="<%= context_url(@context, :context_limit_user_grading_url, @user.id) %>" class="restrict_enrollment_link"><%= t('links.user_only_view_section', %{limit this user to only see fellow section users}) %></a> <a href="<%= context_url(@context, :context_limit_user_grading_url, @user.id) %>" class="restrict_enrollment_link"><%= t('links.user_only_view_section', %{limit this user to only see fellow section users}) %></a>
</div> </p>
</div>
</td> </td>
</tr> </tr>
<% end %> <% end %>

View File

@ -6,12 +6,19 @@
content_for :page_title, join_title(translated_title, @context.name) content_for :page_title, join_title(translated_title, @context.name)
%> %>
<h1 class='screenreader-only'><%= t('#titles.people', 'People') %></h1>
<% content_for :right_side, render(:partial => 'context/roster_right_side') %>
<% css_bundle :roster %> <% css_bundle :roster %>
<div class="ic-Action-header">
<div class="ic-Action-header__Primary">
<h1 class="screenreader-only"><%= t('#titles.people', 'People') %></h1>
</div>
<div class="ic-Action-header__Secondary">
<%= render :partial => 'context/roster_right_side' %>
</div>
</div>
<% if @context.is_a?(Course) %> <% if @context.is_a?(Course) %>
<% js_bundle :roster %> <% js_bundle :roster %>
<% js_env :canManageCourse => can_do(@context, @current_user, :manage) %> <% js_env :canManageCourse => can_do(@context, @current_user, :manage) %>

View File

@ -92,14 +92,14 @@
<div class="more_user_information" style="display: none;"> <div class="more_user_information" style="display: none;">
<% if @context.is_a?(Course) %> <% if @context.is_a?(Course) %>
<fieldset> <fieldset>
<legend><%= t('legends.memberships', %{Membership(s)}) %></legend> <legend><h3><%= t('legends.memberships', %{Membership(s)}) %></h3></legend>
<table> <table class="ic-Table">
<% @enrollments.sort_by(&:id).each do |enrollment| %> <% @enrollments.sort_by(&:id).each do |enrollment| %>
<tr class="enrollment"> <tr class="enrollment">
<td style="vertical-align: top; padding: 5px 50px 5px 5px;"> <td>
<b><a href="<%= context_url(@context, :context_section_url, enrollment.course_section_id) rescue "#" %>"><%= enrollment.try_rescue(:course_section).try_rescue(:display_name) || enrollment.short_name %></a></b> <b><a href="<%= context_url(@context, :context_section_url, enrollment.course_section_id) rescue "#" %>"><%= enrollment.try_rescue(:course_section).try_rescue(:display_name) || enrollment.short_name %></a></b>
<div style="font-size: 0.8em; padding-left: 20px;"><%= t 'enrolled_as', "Enrolled as a %{enrollment_type}", :enrollment_type => enrollment.readable_type %></div> <div><%= t 'enrolled_as', "Enrolled as a %{enrollment_type}", :enrollment_type => enrollment.readable_type %></div>
<div style="font-size: 0.8em; padding-left: 20px;">created <%= datetime_string(enrollment.created_at) %></div> <div>created <%= datetime_string(enrollment.created_at) %></div>
<% if enrollment.is_a?(ObserverEnrollment) %> <% if enrollment.is_a?(ObserverEnrollment) %>
<div style="font-size: 0.8em; padding-left: 20px; <%= hidden unless enrollment.associated_user %>" class="associated_user" > <div style="font-size: 0.8em; padding-left: 20px; <%= hidden unless enrollment.associated_user %>" class="associated_user" >
<%= t 'enrollment_linked_to', "linked to *%{linked_user}*", <%= t 'enrollment_linked_to', "linked to *%{linked_user}*",
@ -118,7 +118,7 @@
</div> </div>
</td> </td>
<% if enrollment.admin? ? (can_manage_admins && enrollment.user_id != @current_user.id) : can_manage_students %> <% if enrollment.admin? ? (can_manage_admins && enrollment.user_id != @current_user.id) : can_manage_students %>
<td style="vertical-align: top; padding: 5px; font-size: 0.8em;"> <td>
<% unless @context.completed? %> <% unless @context.completed? %>
<div class="conclude_enrollment_link_holder" style="margin-bottom: 5px; <%= hidden if enrollment.completed? %>"> <div class="conclude_enrollment_link_holder" style="margin-bottom: 5px; <%= hidden if enrollment.completed? %>">
<a class="conclude_enrollment_link" href="<%= context_url(@context, :controller => :courses, :action => :conclude_user, :id => enrollment.id) %>"><%= t('links.conclude_enrollment', %{Conclude this Enrollment}) %></a> <a class="conclude_enrollment_link" href="<%= context_url(@context, :controller => :courses, :action => :conclude_user, :id => enrollment.id) %>"><%= t('links.conclude_enrollment', %{Conclude this Enrollment}) %></a>
@ -139,8 +139,10 @@
<% end %> <% end %>
<% if @context.is_a?(Course) && can_do(@context, @current_user, :manage_admin_users) %> <% if @context.is_a?(Course) && can_do(@context, @current_user, :manage_admin_users) %>
<tr> <tr>
<td style="border-top: 1px solid #eee; padding-top: 5px; vertical-align: top; font-weight: bold;"><%= before_label('user_privileges', %{Privileges}) %></td> <td>
<td style="border-top: 1px solid #eee; padding-top: 5px;"> <%= before_label('user_privileges', %{Privileges}) %>
</td>
<td>
<div class="elevate_enrollment_link_holder" style="<%= hidden if @enrollments.any?{|e| !e.limit_privileges_to_course_section } %>"> <div class="elevate_enrollment_link_holder" style="<%= hidden if @enrollments.any?{|e| !e.limit_privileges_to_course_section } %>">
<%= t('user_only_view_section', %{this user can only view students in their assigned course section(s)}) %> <%= t('user_only_view_section', %{this user can only view students in their assigned course section(s)}) %>
<div style="margin-left: 10px; font-size: 0.8em;"> <div style="margin-left: 10px; font-size: 0.8em;">

View File

@ -2,7 +2,7 @@
<div id="link_student_dialog" style="display: none;"> <div id="link_student_dialog" style="display: none;">
<a href="<%= context_url(@context, :context_students_url) %>" class="student_url" style="display: none;">&nbsp;</a> <a href="<%= context_url(@context, :context_students_url) %>" class="student_url" style="display: none;">&nbsp;</a>
<%= form_tag context_url(@context, :context_link_enrollment_url), {:id => "link_student_dialog_form"} do %> <%= form_tag context_url(@context, :context_link_enrollment_url), {:id => "link_student_dialog_form"} do %>
<input type="hidden" name="enrollment_id" class="enrollment_id"/> <input type="hidden" name="enrollment_id" class="enrollment_id ic-Input"/>
<%= mt 'details', %{When an observer is linked to a student, they have access to that student's grades and course interactions. *Right now this observer is linked to the student, %{student}.* <%= mt 'details', %{When an observer is linked to a student, they have access to that student's grades and course interactions. *Right now this observer is linked to the student, %{student}.*
To link the course observer %{user} to a student, select the student's name from the list below.}, To link the course observer %{user} to a student, select the student's name from the list below.},
@ -11,7 +11,7 @@ To link the course observer %{user} to a student, select the student's name from
:user => '<b class="short_name">&nbsp;</b>'.html_safe %> :user => '<b class="short_name">&nbsp;</b>'.html_safe %>
<p class="loading_message"><%= t('loading', %{Loading Students...}) %></p> <p class="loading_message"><%= t('loading', %{Loading Students...}) %></p>
<p class="students_link" style="display: none;"> <p class="students_link" style="display: none;">
<label for="student_enrollment_link_option"><%= before_label('student', %{Student}) %></label> <label for="student_enrollment_link_option" class="ic-Label"><%= before_label('student', %{Student}) %></label>
<select name="student_id" class="student_options" id="student_enrollment_link_option"> <select name="student_id" class="student_options" id="student_enrollment_link_option">
<option value="none" class="blank">[ <%= t('select_student', %{Select Student}) %> ]</option> <option value="none" class="blank">[ <%= t('select_student', %{Select Student}) %> ]</option>
</select> </select>

View File

@ -0,0 +1,4 @@
<span class="post-to-sis-status">
<label class="screenreader-only" aria-live="polite"></label>
<input type='image' class='icon-post-to-sis' data-tooltip/>
</span>

View File

@ -56,19 +56,7 @@
{{#if canManage}} {{#if canManage}}
<div class="ig-admin"> <div class="ig-admin">
{{#if postToSISEnabled}} <span class="sis-button" data-view="sis-button"></span>
{{#if postToSIS}}
<span class="post-to-sis-status enabled">
<img class='icon-post-to-sis accessible_label' src='/images/svg-icons/svg_icon_post_to_sis_active.svg' aria-label='Post grades to SIS enabled' tabindex='0' role='button' width=16 height=20 title='{{#t}}Post grade to SIS enabled. Click to toggle.{{/t}}' data-tooltip />
<span class="screenreader-only accessible_label">{{#t}}The grade for this assignment will sync to the student information system.{{/t}}</span>
</span>
{{else}}
<span class="post-to-sis-status disabled">
<img class='icon-post-to-sis accessible_label' src='/images/svg-icons/svg_icon_post_to_sis.svg' aria-label='Post grades to SIS disabled' tabindex='0' role='button' width=16 height=20 title='{{#t}}Post grade to SIS disabled. Click to toggle.{{/t}}' data-tooltip />
<span class="screenreader-only accessible_label">{{#t}}The grade for this assignment will not sync to the student information system.{{/t}}</span>
</span>
{{/if}}
{{/if}}
<span class="publish-icon" data-view="publish-icon"></span> <span class="publish-icon" data-view="publish-icon"></span>

View File

@ -7,7 +7,7 @@
</a> </a>
</div> </div>
{{/if}} {{/if}}
<div class="roster-tab tab-panel ui-tabs-panel form-inline" style="min-height: 800px;"> <div id="tab-0" class="roster-tab tab-panel ui-tabs-panel form-inline" style="min-height: 800px;">
<input <input
type="text" type="text"
name="search_term" name="search_term"

View File

@ -1,5 +1,5 @@
<li class="static ui-state-default ui-corner-top ui-tabs-active ui-state-active" role="tab" > <li class="static ui-state-default ui-corner-top ui-tabs-active ui-state-active" role="tab" >
<a href="#" class="ui-tabs-anchor" role="presentation" tabindex="-1">{{#t 'everyone_tab'}}Everyone{{/t}}</a> <a href="#tab-0" class="ui-tabs-anchor" role="presentation" tabindex="-1">{{#t 'everyone_tab'}}Everyone{{/t}}</a>
</li> </li>
{{#each collection}} {{#each collection}}
<li role="tab" class="ui-state-default ui-corner-top" > <li role="tab" class="ui-state-default ui-corner-top" >

View File

@ -1,6 +1,6 @@
<tr> <tr>
<td><input aria-label="{{t "Link title" }}" type="text" maxlength="255" name="link_titles[]" value="{{title}}"></td> <td><input aria-label="{{t "Link title" }}" type="text" class="ic-Input" maxlength="255" name="link_titles[]" value="{{title}}"></td>
<td>→</td> <td>→</td>
<td><input aria-label="{{t "Link Url" }}" type="text" name="link_urls[]" value="{{url}}"></td> <td><input aria-label="{{t "Link Url" }}" type="text" class="ic-Input" name="link_urls[]" value="{{url}}"></td>
<td><a href="#" class="remove_link_row" data-event="removeLinkRow"><span class="screenreader-only">{{t "Remove" }}</span><i class="icon-end"></i></a></td> <td><a href="#" class="remove_link_row" data-event="removeLinkRow"><span class="screenreader-only">{{t "Remove" }}</span><i class="icon-end"></i></a></td>
</tr> </tr>

View File

@ -24,19 +24,7 @@
{{#if can_update}} {{#if can_update}}
<div class="ig-admin"> <div class="ig-admin">
{{#if post_to_sis_enabled}} <span class="sis-button" data-view="sis-button"></span>
{{#if post_to_sis}}
<span class="post-to-sis-status enabled">
<i class="icon-post-to-sis" title='{{#t}}Post grade to SIS enabled. Click to toggle.{{/t}}' data-tooltip></i>
<span class="screenreader-only">{{#t}}The grade for this assignment will sync to the student information system. Click here to toggle this setting.{{/t}}</span>
</span>
{{else}}
<span class="post-to-sis-status disabled">
<i class="icon-post-to-sis" title='{{#t}}Post grade to SIS disabled. Click to toggle.{{/t}}' data-tooltip></i>
<span class="screenreader-only">{{#t}}The grade for this assignment will not sync to the student information system. Click here to toggle this setting.{{/t}}</span>
</span>
{{/if}}
{{/if}}
<span data-view="publish-icon" class="publish-icon"></span> <span data-view="publish-icon" class="publish-icon"></span>
<div class="inline-block"> <div class="inline-block">

View File

@ -1,20 +1,31 @@
<% content_for :page_title, @user_data[:short_name] %> <% content_for :page_title, @user_data[:short_name] %>
<div class="ic-Layout">
<div class="ic-Layout__Primary">
<%= render 'shared/profile' %> <%= render 'shared/profile' %>
</div>
<% content_for :right_side do %> <div class="ic-Layout__Secondary">
<div class="rs-margin-all"> <% if @user_data[:can_edit] && !can_do(@domain_root_account, @current_user, :manage) %>
<% if @user_data[:can_edit] %> <button data-event="editProfile" class="hide-if-editing Button"><i class="icon-edit"></i> <%= t('edit_profile', 'Edit Profile') %></button>
<button data-event="editProfile" class="hide-if-editing btn button-sidebar-wide"><i class="icon-edit"></i> <%= t('edit_profile', 'Edit Profile') %></button> <button data-event="cancelEditProfile" class="show-if-editing Button"><i class="icon-edit"></i> <%= t('cancel_editing', 'Cancel Editing') %></button>
<button data-event="cancelEditProfile" class="show-if-editing btn button-sidebar-wide"><i class="icon-edit"></i> <%= t('cancel_editing', 'Cancel Editing') %></button> <% elsif @user_data[:can_edit] && can_do(@domain_root_account, @current_user, :manage) %>
<% end %> <div class="al-dropdown__container">
<% if can_do(@domain_root_account, @current_user, :manage) %> <a class="al-trigger btn" role="button" href="#" id="profileDropdown">
<h1 class="h2 right-side-h2-border"><%= t :administration, 'Administration' %></h1> <i class="icon-more" role="presentation"></i>
<div><a href="<%= user_path(@user.id) %>"><%= t('links.user_account_details', %{Account Details}) %></a></div> <span class="screenreader-only">More</span>
</a>
<ul aria-labeledby="profileDropdown" class="al-options" role="menu" tabindex="0" aria-hidden="true" aria-expanded="false" >
<li class="hide-if-editing"><a data-event="editProfile" role="menuitem"><%= t('edit_profile', 'Edit Profile') %></a></li>
<li class="show-if-editing"><a data-event="cancelEditProfile" role="menuitem"><%= t('cancel_editing', 'Cancel Editing') %></a></li>
<li><a href="<%= user_path(@user.id) %>"role="menuitem"><%= t('links.user_account_details', %{Account Details}) %></a></li>
<% if @user != @current_user %> <% if @user != @current_user %>
<div><a href="<%= user_profile_url(@user, :become_user_id => @user) %>"> <%= t('become', 'Become') %></a></div> <li><a href="<%= user_profile_url(@user, :become_user_id => @user) %>"role="menuitem"> <%= t('masquerade', 'Masquerade') %></a></li>
<% end %>
<% end %> <% end %>
</ul>
</div> </div>
<% end %> <% end %>
</div>
</div>

View File

@ -53,7 +53,7 @@
<table style="width: 100%; margin-bottom: 20px;" class="grading_standard_data"> <table style="width: 100%; margin-bottom: 20px;" class="grading_standard_data">
<caption class="screenreader-only"> <caption class="screenreader-only">
<%= t("Current grading standard for this assignment") %> <%= t("Current grading scheme for this assignment") %>
</caption> </caption>
<thead> <thead>
<tr> <tr>

View File

@ -5,7 +5,7 @@
js_env PROFILE: @user_data if @user_data[:can_edit] js_env PROFILE: @user_data if @user_data[:can_edit]
js_env(folder_id: @user.profile_pics_folder.id) if @user == @current_user js_env(folder_id: @user.profile_pics_folder.id) if @user == @current_user
%> %>
<%= form_tag update_profile_profile_path, { :method => :put, :id => :edit_profile_form, :class => "bootstrap-form form-vertical" } do %> <%= form_tag update_profile_profile_path, { :method => :put, :id => :edit_profile_form, :class => "ic-Form-control" } do %>
<div class="image-block"> <div class="image-block">
<div class="image-block-image profile-avatar-wrapper"> <div class="image-block-image profile-avatar-wrapper">
<% if @user_data[:can_edit] %> <% if @user_data[:can_edit] %>
@ -17,57 +17,60 @@
<%= avatar(@user_data[:id], size: 128, url: nil) %> <%= avatar(@user_data[:id], size: 128, url: nil) %>
<% end %> <% end %>
</div> </div>
<div class="image-block-content row-fluid">
<div class="profileContent__Block">
<% if @user_data[:can_edit_name] %> <% if @user_data[:can_edit_name] %>
<h1 class="h1"> <h2 class="hide-if-editing"><%= @user_data[:short_name] %></h2>
<span class="hide-if-editing"><%= @user_data[:short_name] %></span> <label class="show-if-editing ic-Label"><%= t('name', 'Name') %>:
</h1> <input class="ic-Input" type="text" name="user[short_name]" value="<%= @user_data[:short_name] %>" required>
<label class="show-if-editing"><%= t('name', 'Name') %>: <br><input type="text" name="user[short_name]" value="<%= @user_data[:short_name] %>" required></label> </label>
<p> <p class="profileDetails">
<span class="hide-if-editing"><%= @user_data[:title] %></span> <span class="hide-if-editing"><%= @user_data[:title] %></span>
<label class="show-if-editing"><%= t('title', 'Title') %>: <br><input type="text" name="user_profile[title]" value="<%= @user_data[:title] %>"></label> <label class="show-if-editing ic-Label"><%= t('title', 'Title') %>:
<input class="ic-Input" type="text" name="user_profile[title]" value="<%= @user_data[:title] %>">
</label>
</p> </p>
<% else %> <% else %>
<h1 class="h1"> <h2><%= @user_data[:short_name] %></h2>
<span><%= @user_data[:short_name] %></span> <p><%= @user_data[:title] %></p>
</h1>
<p>
<span><%= @user_data[:title] %></span>
</p>
<% end %> <% end %>
<div class="show-if-editing edit-contact-methods"> <div class="show-if-editing edit-contact-methods">
<h2 class="h5 border border-b"><%= t('#profile.ways_to_contact_me', "Ways to contact me") %></h2> <h3 class="profileHeader"><%= t('#profile.ways_to_contact_me', "Contact") %></h3>
<% if @user_data[:user_services].present? %> <% if @user_data[:user_services].present? %>
<div class="row-fluid">
<div class="span6">
<ul class="social-links"> <ul class="social-links">
<li> <li>
<label for="social_message" class="social message" title="<%= t :message_title, 'Message' %>" data-tooltip><%= t :message_me, 'message me in Canvas' %></label> <label for="social_message" class="social message ic-Label" title="<%= t :message_title, 'Message' %>" data-tooltip><%= t :message_me, 'message me in Canvas' %></label>
</li> </li>
<% @user_data[:user_services].each do |s| %> <% @user_data[:user_services].each do |s| %>
<li> <li>
<% service_name = s[:service_name] || s[:service].to_s.titleize %> <% service_name = s[:service_name] || s[:service].to_s.titleize %>
<label for="social_<%= s[:service] %>" class="social <%= s[:service] %>" title="<%= service_name %>" data-tooltip><%= t :service_contact, 'contact %{user} with %{service}', :user => @user_data[:short_name], :service => service_name %></label> <label for="social_<%= s[:service] %>" class="social <%= s[:service] %> ic-Label" title="<%= service_name %>" data-tooltip><%= t :service_contact, 'contact %{user} with %{service}', :user => @user_data[:short_name], :service => service_name %></label>
<input type="hidden" value="0" name="user_services[<%= s[:service] %>"> <input class="ic-Input" type="hidden" value="0" name="user_services[<%= s[:service] %>">
<%= check_box_tag "user_services[#{s[:service]}]", 1, s[:visible], :id => "social_#{s[:service]}" %> <%= check_box_tag "user_services[#{s[:service]}]", 1, s[:visible], :id => "social_#{s[:service]}" %>
</li> </li>
<% end %> <% end %>
</ul> </ul>
</div> <div class="social-instructions">
<div class="span6 social-instructions">
<p> <p>
<%= t(:social_instructions, "Check the contact methods you'd like to be visible to others on your profile.") %><br> <%= t(:social_instructions, "Check the contact methods you'd like to be visible to others on your profile.") %><br>
<%= link_to(t(:manage_settings, "Manage Registered Services"), settings_profile_path) %> <%= link_to(t(:manage_settings, "Manage Registered Services"), settings_profile_path) %>
</p> </p>
</div> </div>
</div>
<% else %> <% else %>
<p><%= t('#profile.you_have_no_services', "You haven't registered any services, you can add some on the *settings* page.", :name => @user_data[:short_name], :wrapper => link_to('\1', settings_profile_path)) %></p> <p><%= t('#profile.you_have_no_services', "No registered services, you can add some on the *settings* page.", :name => @user_data[:short_name], :wrapper => link_to('\1', settings_profile_path)) %></p>
<% end %> <% end %>
</div> </div>
<div class="hide-if-editing"> <div class="hide-if-editing">
<h2 class="h5 border border-b"><%= t :ways_to_contact_user, "Ways to contact %{name}", :name => @user_data[:short_name] %></h2> <h3 class="profileHeader"><%= t :ways_to_contact_user, "Contact" %></h3>
<% if @user_data[:user_services].blank? %>
<% if @user != @current_user %>
<p><%= t('#profile.no_registered_services', "No registered services.") %></p>
<% else %>
<p><%= t('#profile.you_have_no_services', "No registered services, you can add some on the *settings* page.", :name => @user_data[:short_name], :wrapper => link_to('\1', settings_profile_path)) %></p>
<% end %>
<% else %>
<ul class="social-links"> <ul class="social-links">
<% if current_user_is_account_admin %> <% if current_user_is_account_admin %>
<li><a href="<%= message_user_path(@user) %>" class="social message" title="<%= t :message_title, 'Message' %>" data-tooltip><%= t :message_user_canvas, 'Message %{user} in Canvas', :user => @user_data[:short_name] %></a></li> <li><a href="<%= message_user_path(@user) %>" class="social message" title="<%= t :message_title, 'Message' %>" data-tooltip><%= t :message_user_canvas, 'Message %{user} in Canvas', :user => @user_data[:short_name] %></a></li>
@ -79,12 +82,11 @@
<% end %> <% end %>
<% end %> <% end %>
</ul> </ul>
</div> <% end %>
</div>
</div> </div>
<div class="v-gutter"> <div>
<h2 class="h1 border border-b"><label for="profile_bio" style="font-size: 22px"><%= t :bio, "Bio" %></label></h2> <h3 for="profile_bio" class="profileHeader"><%= t :bio, "Biography" %></h3>
<% if @user_data[:bio] %> <% if @user_data[:bio] %>
<div class="hide-if-editing"><%= raw format_message(@user_data[:bio]).first %></div> <div class="hide-if-editing"><%= raw format_message(@user_data[:bio]).first %></div>
<% else %> <% else %>
@ -92,19 +94,19 @@
<% end %> <% end %>
<% if @user_data[:can_edit] %> <% if @user_data[:can_edit] %>
<div class="show-if-editing"> <div class="show-if-editing">
<textarea id="profile_bio" name="user_profile[bio]"><%= @user_data[:bio] %></textarea> <textarea class="ic_Input" id="profile_bio" name="user_profile[bio]"><%= @user_data[:bio] %></textarea>
</div> </div>
<% end %> <% end %>
</div> </div>
<div class="row-fluid v-gutter"> <div>
<% if @user != @current_user %> <% if @user != @current_user %>
<div class="span6 hide-if-editing"> <div class="hide-if-editing">
<h2 class="h1 border border-b"><%= t :know_this_person_as, "You Know This Person as a..." %></h2> <h3 class="profileHeader"><%= t :user_enrolled, "Enrollments" %></h3>
<% if @user_data[:common_contexts] %> <% if @user_data[:common_contexts] %>
<ul> <ul>
<% @user_data[:common_contexts].each do |context| %> <% @user_data[:common_contexts].each do |context| %>
<li><%= context[:roles].join(', ') %> in <a href="<%= context[:html_url] %>"><%= context[:name] %></a></li> <li class="profileEnrollment__Items"><%= context[:roles].join(', ') %> in <a href="<%= context[:html_url] %>"><%= context[:name] %></a></li>
<% end %> <% end %>
</ul> </ul>
<% else %> <% else %>
@ -112,14 +114,18 @@
<% end %> <% end %>
</div> </div>
<% end %> <% end %>
</div>
<div class="profile_links span6"> <div class="profile_links">
<h2 class="h1 border border-b"><%= t :links, "Links" %></h2> <h3 class="profileHeader"><%= t :links, "Links" %></h3>
<div class="hide-if-editing"> <div class="hide-if-editing">
<% if @user_data[:links].length > 0 %> <% if @user_data[:links].length > 0 %>
<ul> <ul class="profileLink">
<% @user_data[:links].each do |link| %> <% @user_data[:links].each do |link| %>
<li><a href="<%= add_uri_scheme_name(link[:url]) %>"><%= link[:title] %></a></li> <li class="profileLink__Item">
<i class="icon-link" role="presentation"></i>
<a href="<%= add_uri_scheme_name(link[:url]) %>"><%= link[:title] %></a>
</li>
<% end %> <% end %>
</ul> </ul>
<% else %> <% else %>
@ -150,4 +156,5 @@
</div> </div>
<% end %> <% end %>
</div> </div>
</div>
<% end %> <% end %>

View File

@ -3,8 +3,12 @@
<% js_bundle :user_logins %> <% js_bundle :user_logins %>
<% js_env :PASSWORD_POLICY => (@domain_root_account.try(:password_policy) || {}) %> <% js_env :PASSWORD_POLICY => (@domain_root_account.try(:password_policy) || {}) %>
<fieldset id="login_information"> <fieldset id="login_information">
<legend><%= t('titles.logins', 'Login Information') %></legend> <legend>
<table> <h4 class="profileHeader">
<%= t('titles.logins', 'Login Information') %>
</h4>
</legend>
<table class="ic-Table">
<% pseudonyms = @user.all_active_pseudonyms + [nil] %> <% pseudonyms = @user.all_active_pseudonyms + [nil] %>
<% pseudonyms.each do |pseudonym| %> <% pseudonyms.each do |pseudonym| %>
<tr class='login <%= 'blank' unless pseudonym %>' style="<%= hidden unless pseudonym %>"> <tr class='login <%= 'blank' unless pseudonym %>' style="<%= hidden unless pseudonym %>">
@ -19,7 +23,7 @@
<th scope='row'> <th scope='row'>
<b class='unique_id'><%= pseudonym && pseudonym.unique_id %></b> <b class='unique_id'><%= pseudonym && pseudonym.unique_id %></b>
<% if pseudonym && ((pseudonym.sis_user_id && can_do(pseudonym.account, @current_user, :read_sis)) || can_do(pseudonym, @current_user, :manage_sis)) %> <% if pseudonym && ((pseudonym.sis_user_id && can_do(pseudonym.account, @current_user, :read_sis)) || can_do(pseudonym, @current_user, :manage_sis)) %>
<div style="font-size: 0.8em; padding-left: 20px;"> <div>
<%= before_label('sis_id', 'SIS ID') %> <span id="sis_user_id_<%= pseudonym.id %>" class="sis_user_id"><%= pseudonym.sis_user_id %></span> <%= before_label('sis_id', 'SIS ID') %> <span id="sis_user_id_<%= pseudonym.id %>" class="sis_user_id"><%= pseudonym.sis_user_id %></span>
</div> </div>
<div style="display:none" class="can_edit_sis_user_id"><%= can_do(pseudonym, @current_user, :manage_sis) %></div> <div style="display:none" class="can_edit_sis_user_id"><%= can_do(pseudonym, @current_user, :manage_sis) %></div>
@ -29,25 +33,25 @@
<%= link_to(pseudonym ? pseudonym.account.name : nbsp, account_url(pseudonym ? pseudonym.account_id : "{{ account_id }}"), :class => 'account_name') %> <%= link_to(pseudonym ? pseudonym.account.name : nbsp, account_url(pseudonym ? pseudonym.account_id : "{{ account_id }}"), :class => 'account_name') %>
</td> </td>
<td class='details'> <td class='details'>
<table> <table class="ic-Table--condensed">
<tr> <tr class='login_details'>
<th><%= before_label('last_request', 'Last request') %></th> <td scope="row"><%= before_label('last_request', 'Last request') %></td>
<td><%= datetime_string(pseudonym.try(:last_request_at)) || t('never', "never") %></td> <td><%= datetime_string(pseudonym.try(:last_request_at)) || t('never', "never") %></td>
</tr> </tr>
<tr class='login_details' style="<%= hidden if pseudonyms.length > 1 || !pseudonym %>"> <tr class='login_details' style="<%= hidden if pseudonyms.length > 1 || !pseudonym %>">
<th><%= before_label('current_login', 'Current login') %></th> <td scope="row"><%= before_label('current_login', 'Current login') %></td>
<td><%= datetime_string(pseudonym.try(:current_login_at)) || t('never', "never") %></td> <td><%= datetime_string(pseudonym.try(:current_login_at)) || t('never', "never") %></td>
</tr> </tr>
<tr class='login_details' style="<%= hidden if pseudonyms.length > 1 || !pseudonym %>"> <tr class='login_details' style="<%= hidden if pseudonyms.length > 1 || !pseudonym %>">
<th><%= before_label('current_ip', 'Current login IP') %></th> <td scope="row"><%= before_label('current_ip', 'Current login IP') %></td>
<td><%= pseudonym.try(:current_login_ip) || t('none', "none") %></td> <td><%= pseudonym.try(:current_login_ip) || t('none', "none") %></td>
</tr> </tr>
<tr class='login_details' style="<%= hidden if pseudonyms.length > 1 || !pseudonym %>"> <tr class='login_details' style="<%= hidden if pseudonyms.length > 1 || !pseudonym %>">
<th><%= before_label('last_login', 'Last login') %></th> <td scope="row"><%= before_label('last_login', 'Last login') %></td>
<td><%= datetime_string(pseudonym.try(:last_login_at)) || t('never', "never") %></td> <td><%= datetime_string(pseudonym.try(:last_login_at)) || t('never', "never") %></td>
</tr> </tr>
<tr class='login_details' style="<%= hidden if pseudonyms.length > 1 || !pseudonym %>"> <tr class='login_details' style="<%= hidden if pseudonyms.length > 1 || !pseudonym %>">
<th><%= before_label('last_ip', 'Last login IP') %></th> <td scope="row"><%= before_label('last_ip', 'Last login IP') %></td>
<td><%= pseudonym.try(:last_login_ip) || t('none', "none") %></td> <td><%= pseudonym.try(:last_login_ip) || t('none', "none") %></td>
</tr> </tr>
</table> </table>
@ -69,7 +73,7 @@
<% can_reset_mfa = @user.otp_secret_key && can_do(@user, @current_user, :reset_mfa) %> <% can_reset_mfa = @user.otp_secret_key && can_do(@user, @current_user, :reset_mfa) %>
<% if can_add_pseudonym || can_reset_mfa %> <% if can_add_pseudonym || can_reset_mfa %>
<tr class="add_holder"> <tr class="add_holder">
<td colspan="4" style="font-size: 0.8em;"> <td colspan="5">
<% if can_add_pseudonym %> <% if can_add_pseudonym %>
<a href="#" rel="<%= user_pseudonyms_url(@user.id) %>" class="add_pseudonym_link"><%= t('add_login', 'Add Login') %></a> <a href="#" rel="<%= user_pseudonyms_url(@user.id) %>" class="add_pseudonym_link"><%= t('add_login', 'Add Login') %></a>
<% end %> <% end %>

View File

@ -155,7 +155,7 @@ h3.beta {
.method_details h3.endpoint { .method_details h3.endpoint {
font-weight: normal; font-weight: normal;
font-size: 14px; font-size: 14px;
font-family: Monaco, Consolas, Courier, monospace; font-family: Monaco, Lucida Console, monospace;
padding: 6px 10px; padding: 6px 10px;
margin-top: 18px; margin-top: 18px;
color: #333; color: #333;
@ -317,7 +317,7 @@ table.request-params, table.request-params th, table.request-params td {
table.request-params td { table.request-params td {
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
vertical-align: text-top; vertical-align: text-top;
font-family: Monaco; font-family: Monaco, Lucida Console, monospace;
font-size: 12px; font-size: 12px;
} }
table.request-params td.param-desc { table.request-params td.param-desc {

View File

@ -9,18 +9,26 @@ module TatlTael
@git_dir = git_dir @git_dir = git_dir
end end
def changes(git_dir) def changes
command = "git diff-tree --no-commit-id --name-status -r HEAD" command = "git diff-tree --no-commit-id --name-status -r HEAD"
raw_changes = shell(command, git_dir) raw_changes = shell(command)
raw_changes.split("\n").map do |raw_change| raw_changes.split("\n").map do |raw_change|
status, path = raw_change.split("\t") status, path = raw_change.split("\t")
TatlTael::Change.new(status, path) TatlTael::Change.new(status, path)
end end
end end
def wip?
first_line =~ /\A(\(|\[)?wip\b/i ? true : false
end
private private
def shell(command, git_dir) def first_line
`git log --pretty=%s -1 HEAD`.strip
end
def shell(command)
if git_dir if git_dir
Dir.chdir(git_dir) do Dir.chdir(git_dir) do
Kernel.send(:`, command) Kernel.send(:`, command)

View File

@ -1,14 +1,18 @@
require_relative 'git_proxy' require_relative 'git_proxy'
require 'forwardable'
module TatlTael module TatlTael
class Linter class Linter
extend ::Forwardable
attr_reader :git attr_reader :git
private :git private :git
def_delegator :git, :wip?
attr_reader :git_dir attr_reader :git_dir
private :git_dir private :git_dir
def initialize(git_dir:, git: nil) def initialize(git_dir: ".", git: nil)
@git_dir = git_dir @git_dir = git_dir
@git = git || TatlTael::GitProxy.new(git_dir) @git = git || TatlTael::GitProxy.new(git_dir)
end end
@ -50,7 +54,7 @@ module TatlTael
end end
def changes def changes
@changes ||= git.changes(git_dir) @changes ||= git.changes
end end
end end
end end

View File

@ -4,7 +4,7 @@ module Canvas
module Cdn module Cdn
class S3Uploader class S3Uploader
attr_accessor :bucket, :config attr_accessor :bucket, :config, :mutex
def initialize(folder='dist') def initialize(folder='dist')
require 'aws-sdk' require 'aws-sdk'
@ -13,6 +13,7 @@ module Canvas
@s3 = AWS::S3.new(access_key_id: config.aws_access_key_id, @s3 = AWS::S3.new(access_key_id: config.aws_access_key_id,
secret_access_key: config.aws_secret_access_key) secret_access_key: config.aws_secret_access_key)
@bucket = @s3.buckets[config.bucket] @bucket = @s3.buckets[config.bucket]
@mutex = Mutex.new
end end
def local_files def local_files
@ -59,7 +60,7 @@ module Canvas
def upload_file(remote_path) def upload_file(remote_path)
local_path = Pathname.new("#{Rails.public_path}/#{remote_path}") local_path = Pathname.new("#{Rails.public_path}/#{remote_path}")
return if (local_path.extname == '.gz') || local_path.directory? return if (local_path.extname == '.gz') || local_path.directory?
s3_object = bucket.objects[remote_path] s3_object = mutex.synchronize { bucket.objects[remote_path] }
return log("skipping already existing #{remote_path}") if s3_object.exists? return log("skipping already existing #{remote_path}") if s3_object.exists?
options = options_for(local_path) options = options_for(local_path)
s3_object.write(handle_compression(local_path, options), options) s3_object.write(handle_compression(local_path, options), options)

View File

@ -43,14 +43,10 @@ module CC::Exporter::Epub::Converters
if should_convert_file?(unescaped) if should_convert_file?(unescaped)
match[attr] = converted_media_path(unescaped) match[attr] = converted_media_path(unescaped)
else else
match.replace(<<-SPAN_TAG) message = I18n.t(<<-TEXT, filename: File.basename(unescaped))
<span>
#{I18n.t(<<-TEXT, filename: File.basename(unescaped))
File %{filename} could not be included in the ePub document. Please see separate zip file for access. File %{filename} could not be included in the ePub document. Please see separate zip file for access.
TEXT TEXT
} match.replace(format('<span>%s</span>', ERB::Util.h(message)))
</span>
SPAN_TAG
end end
end end
end end

View File

@ -128,7 +128,7 @@ module FeatureFlags
(retval.default? || retval.context_type == 'Account' && retval.context_id == Account.site_admin.id) (retval.default? || retval.context_type == 'Account' && retval.context_id == Account.site_admin.id)
if is_root_account if is_root_account
# create a virtual feature flag in "off" state # create a virtual feature flag in "off" state
retval = self.feature_flags.build feature: feature, state: 'off' unless retval.hidden? retval = self.feature_flags.temp_record feature: feature, state: 'off' unless retval.hidden?
else else
# the feature doesn't exist beneath the root account until the root account opts in # the feature doesn't exist beneath the root account until the root account opts in
return @feature_flag_cache[feature] = nil return @feature_flag_cache[feature] = nil

View File

@ -31,6 +31,12 @@ end
linter = TatlTael::Linter.new(git_dir: git_dir) linter = TatlTael::Linter.new(git_dir: git_dir)
# don't run for wips
if linter.wip?
puts "WIP detected, TatlTael will not run."
exit 0
end
linter.ensure_specs do linter.ensure_specs do
post("Your commit does not include specs."\ post("Your commit does not include specs."\
" Please add some to verify your changes.") " Please add some to verify your changes.")

View File

@ -0,0 +1,58 @@
define [
'jquery'
'compiled/views/SisButtonView'
'Backbone'
], ($, SisButtonView, Backbone) ->
class AssignmentStub extends Backbone.Model
url: '/fake'
postToSIS: (postToSisBoolean) =>
return @get 'post_to_sis' unless arguments.length > 0
@set 'post_to_sis', postToSisBoolean
class QuizStub extends Backbone.Model
url: '/fake'
postToSIS: (postToSisBoolean) =>
return @get 'post_to_sis' unless arguments.length > 0
@set 'post_to_sis', postToSisBoolean
module 'SisButtonView',
setup: ->
@assignment = new AssignmentStub()
@quiz = new QuizStub()
@quiz.set('toggle_post_to_sis_url', '/some_other_url')
test 'properly populates initial settings', ->
@assignment.set('post_to_sis', true)
@quiz.set('post_to_sis', false)
@view1 = new SisButtonView(model: @assignment)
@view2 = new SisButtonView(model: @quiz)
@view1.render()
@view2.render()
equal @view1.$input.attr('title'), 'Post grade to SIS enabled. Click to toggle.'
equal @view2.$input.attr('title'), 'Post grade to SIS disabled. Click to toggle.'
test 'properly toggles model sis status when clicked', ->
@assignment.set('post_to_sis', false)
@view = new SisButtonView(model: @assignment)
@view.render()
@view.$el.click()
ok @assignment.postToSIS()
@view.$el.click()
ok !@assignment.postToSIS()
test 'properly saves model with a custom url if present', ->
@stub @quiz, 'save', (attributes, options) ->
ok options['url'], '/some_other_url'
@quiz.set('post_to_sis', false)
@view = new SisButtonView(model: @quiz)
@view.render()
@view.$el.click()
ok @quiz.postToSIS()
test 'properly associates button label via aria-describedby', ->
@assignment.set('id', '1')
@view = new SisButtonView(model: @assignment)
@view.render()
equal @view.$input.attr('aria-describedby'), 'sis-status-label-1'
equal @view.$label.attr('id'), 'sis-status-label-1'

View File

@ -116,6 +116,8 @@ define [
read_grades: options.canReadGrades read_grades: options.canReadGrades
} }
ENV.POST_TO_SIS = options.post_to_sis
view = new AssignmentListItemView(model: model) view = new AssignmentListItemView(model: model)
view.$el.appendTo $('#fixtures') view.$el.appendTo $('#fixtures')
view.render() view.render()
@ -171,6 +173,18 @@ define [
ok !view.vddTooltipView ok !view.vddTooltipView
ok !view.editAssignmentView ok !view.editAssignmentView
test "initializes sis toggle if post to sis enabled", ->
view = createView(@model, canManage: true, post_to_sis: true)
ok view.sisButtonView
test "does not initialize sis toggle if post to sis disabled", ->
view = createView(@model, canManage: true, post_to_sis: false)
ok !view.sisButtonView
test "does not initialize sis toggle if sis enabled but can't manage", ->
view = createView(@model, canManage: false, post_to_sis: true)
ok !view.sisButtonView
test "upatePublishState toggles ig-published", -> test "upatePublishState toggles ig-published", ->
view = createView(@model, canManage: true) view = createView(@model, canManage: true)

View File

@ -10,12 +10,20 @@ define [
fixtures = $('#fixtures') fixtures = $('#fixtures')
createView = (quiz) -> createView = (quiz, options={}) ->
quiz ?= new Quiz(id: 1, title: 'Foo') quiz ?= new Quiz(id: 1, title: 'Foo')
icon = new PublishIconView(model: quiz) icon = new PublishIconView(model: quiz)
view = new QuizItemView(model: quiz, publishIconView: icon)
ENV.PERMISSIONS = {
manage: options.canManage
}
ENV.FLAGS = {
post_to_sis_enabled: options.post_to_sis
}
view = new QuizItemView(model: quiz, publishIconView: icon)
view.$el.appendTo $('#fixtures') view.$el.appendTo $('#fixtures')
view.render() view.render()
@ -33,6 +41,20 @@ define [
view = createView(quiz) view = createView(quiz)
equal view.$('.ig-admin').length, 0 equal view.$('.ig-admin').length, 0
test "initializes sis toggle if post to sis enabled", ->
quiz = new Quiz(id: 1, title: 'Foo', can_update: true)
view = createView(quiz, canManage: true, post_to_sis: true)
ok view.sisButtonView
test "does not initialize sis toggle if post to sis disabled", ->
quiz = new Quiz(id: 1, title: 'Foo', can_update: true)
view = createView(quiz, canManage: true, post_to_sis: false)
ok !view.sisButtonView
test "does not initialize sis toggle if sis enabled but can't manage", ->
quiz = new Quiz(id: 1, title: 'Foo', can_update: false)
view = createView(quiz, canManage: false, post_to_sis: false)
ok !view.sisButtonView
test 'udpates publish status when model changes', -> test 'udpates publish status when model changes', ->
quiz = new Quiz(id: 1, title: 'Foo', published: false) quiz = new Quiz(id: 1, title: 'Foo', published: false)
@ -43,7 +65,6 @@ define [
quiz.set("published", true) quiz.set("published", true)
ok view.$el.find(".ig-row").hasClass("ig-published") ok view.$el.find(".ig-row").hasClass("ig-published")
test 'prompts confirm for delete', -> test 'prompts confirm for delete', ->
quiz = new Quiz(id: 1, title: 'Foo', can_update: true) quiz = new Quiz(id: 1, title: 'Foo', can_update: true)
view = createView(quiz) view = createView(quiz)

View File

@ -519,6 +519,15 @@ describe GradebooksController do
end end
end end
describe "POST 'submissions_zip_upload'" do
it "requires authentication" do
course
assignment_model
post 'submissions_zip_upload', :course_id => @course.id, :assignment_id => @assignment.id, :submissions_zip => 'dummy'
assert_unauthorized
end
end
describe "POST 'update_submission'" do describe "POST 'update_submission'" do
it "allows adding comments for submission" do it "allows adding comments for submission" do
user_session(@teacher) user_session(@teacher)

View File

@ -611,7 +611,7 @@ describe Assignment do
end end
it "uses the canvas default" do it "uses the canvas default" do
expect(@assignment.grading_standard_or_default.title).to eql "Default Grading Standard" expect(@assignment.grading_standard_or_default.title).to eql "Default Grading Scheme"
end end
end end

View File

@ -55,7 +55,7 @@ module BroadcastPolicies
let(:policy) do let(:policy) do
SubmissionPolicy.new(submission).tap do |policy| SubmissionPolicy.new(submission).tap do |policy|
policy.stubs(:user_active_invited_or_concluded?).returns(true) policy.stubs(:user_active_or_invited?).returns(true)
policy.stubs(:user_has_visibility?).returns(true) policy.stubs(:user_has_visibility?).returns(true)
end end
end end
@ -159,7 +159,7 @@ module BroadcastPolicies
specify { wont_send_when{ course.stubs(:available?).returns false}} specify { wont_send_when{ course.stubs(:available?).returns false}}
specify { wont_send_when{ submission.stubs(:quiz_submission).returns stub }} specify { wont_send_when{ submission.stubs(:quiz_submission).returns stub }}
specify { wont_send_when{ assignment.stubs(:published?).returns false}} specify { wont_send_when{ assignment.stubs(:published?).returns false}}
specify { wont_send_when{ policy.stubs(:user_active_invited_or_concluded?).returns(false)}} specify { wont_send_when{ policy.stubs(:user_active_or_invited?).returns(false)}}
specify { wont_send_when{ course.stubs(:concluded?).returns true }} specify { wont_send_when{ course.stubs(:concluded?).returns true }}
end end

View File

@ -222,4 +222,54 @@ describe EpubExport do
end end
end end
end end
describe '#set_locale' do
let_once(:cartridge_path) do
File.join(File.dirname(__FILE__), "/../fixtures/migration/unicode-filename-test-export.imscc")
end
let_once(:content_export) do
@course.content_exports.create({
user: @student
}).tap do |content_export|
content_export.create_attachment({
context: @course,
filename: File.basename(cartridge_path),
uploaded_data: File.open(cartridge_path)
})
end
end
let_once(:epub_export) do
@course.epub_exports.create({
user: @student,
content_export: content_export
})
end
it 'is called during export and resets locale after' do
epub_export.expects(:infer_locale).once
.with(context: @course, user: @student, root_account: @course.root_account)
.returns(:ru)
epub_export.convert_to_epub_without_send_later
expect(I18n.locale).to be :en
end
it 'sets locale based on user preference' do
@student.update_attribute(:locale, 'es')
epub_export.reload.send(:set_locale)
expect(I18n.locale).to eq :es
end
it 'sets locale based on course override' do
@course.update_attribute(:locale, 'da')
epub_export.reload.send(:set_locale)
expect(I18n.locale).to eq :da
end
it 'allows course locale to override user locale' do
@student.update_attribute(:locale, 'es')
@course.update_attribute(:locale, 'da')
epub_export.reload.send(:set_locale)
expect(I18n.locale).to eq :da
end
end
end end

View File

@ -29,7 +29,8 @@ describe FeatureFlag do
'account_feature' => Feature.new(feature: 'account_feature', applies_to: 'Account'), 'account_feature' => Feature.new(feature: 'account_feature', applies_to: 'Account'),
'course_feature' => Feature.new(feature: 'course_feature', applies_to: 'Course'), 'course_feature' => Feature.new(feature: 'course_feature', applies_to: 'Course'),
'user_feature' => Feature.new(feature: 'user_feature', applies_to: 'User'), 'user_feature' => Feature.new(feature: 'user_feature', applies_to: 'User'),
'hidden_feature' => Feature.new(feature: 'hidden_feature', state: 'hidden', applies_to: 'Course') 'hidden_feature' => Feature.new(feature: 'hidden_feature', state: 'hidden', applies_to: 'Course'),
'hidden_root_opt_in_feature' => Feature.new(feature: 'hidden_feature', state: 'hidden', applies_to: 'Course', root_opt_in: true)
}) })
end end
@ -108,5 +109,10 @@ describe FeatureFlag do
t_sub_account.enable_feature! :hidden_feature t_sub_account.enable_feature! :hidden_feature
expect(t_sub_account.lookup_feature_flag(:hidden_feature)).not_to be_unhides_feature expect(t_sub_account.lookup_feature_flag(:hidden_feature)).not_to be_unhides_feature
end end
it "should be true on a sub-account root-opt-in feature flag with no root or site admin flags set" do
t_course.enable_feature! :hidden_root_opt_in_feature
expect(t_course.feature_flag(:hidden_root_opt_in_feature)).to be_unhides_feature
end
end end
end end

View File

@ -261,6 +261,21 @@ describe Submission do
expect(@submission.messages_sent).to be_include('Submission Graded') expect(@submission.messages_sent).to be_include('Submission Graded')
end end
it "should not create a message for a soft-concluded student" do
submission_spec_model
@course.start_at = 2.weeks.ago
@course.conclude_at = 1.weeks.ago
@course.restrict_enrollments_to_course_dates = true
@course.save!
@cc = @user.communication_channels.create(:path => "somewhere")
@submission.reload
expect(@submission.assignment).to eql(@assignment)
expect(@submission.assignment.state).to eql(:published)
@submission.grade_it!
expect(@submission.messages_sent).to_not be_include('Submission Graded')
end
it "notifies observers" do it "notifies observers" do
submission_spec_model submission_spec_model
course_with_observer(course: @course, associated_user_id: @user.id, active_all: true, active_cc: true) course_with_observer(course: @course, associated_user_id: @user.id, active_all: true, active_cc: true)

View File

@ -577,61 +577,6 @@ describe "assignments" do
wait_for_ajaximations wait_for_ajaximations
expect(f("#content")).not_to contain_css('#assignment_post_to_sis') expect(f("#content")).not_to contain_css('#assignment_post_to_sis')
end end
it 'should display post to SIS icon on assignments page when enabled', priority: "2", test_id: 649314 do
Account.default.set_feature_flag!('post_grades', 'on')
@a1 = @course.assignments.create!(:name => 'assignment 1', :post_to_sis => true)
@a2 = @course.assignments.create!(:name => 'assignment 2', :post_to_sis => false)
@a3 = @course.assignments.create!(:name => 'assignment 3', :post_to_sis => true)
get "/courses/#{@course.id}/assignments/"
wait_for_ajaximations
expect(find_all('.post-to-sis-status.enabled').count).to be 2
expect(find_all('.post-to-sis-status.disabled').count).to be 1
Account.default.set_feature_flag!('post_grades', 'off')
get "/courses/#{@course.id}/assignments/"
wait_for_ajaximations
expect(find_all('.post-to-sis-status.enabled').count).to be 0
expect(find_all('.post-to-sis-status.disabled').count).to be 0
end
it 'should toggle the post to SIS feature when clicked', priority: "2", test_id: 649315 do
Account.default.set_feature_flag!('post_grades', 'on')
@a1 = @course.assignments.create!(:name => 'assignment 1', :post_to_sis => true)
@a2 = @course.assignments.create!(:name => 'assignment 2', :post_to_sis => false)
@a3 = @course.assignments.create!(:name => 'assignment 3', :post_to_sis => true)
get "/courses/#{@course.id}/assignments/"
wait_for_ajaximations
enabled = find_all('.post-to-sis-status.enabled')
disabled = find_all('.post-to-sis-status.disabled')
expect(enabled.count).to be 2
expect(disabled.count).to be 1
enabled.each(&:click)
disabled.each(&:click)
wait_for_ajaximations
@a1.reload
@a2.reload
@a3.reload
expect(@a1.post_to_sis).to be_falsey
expect(@a2.post_to_sis).to be_truthy
expect(@a3.post_to_sis).to be_falsey
expect(find_all('.post-to-sis-status.enabled').count).to be 1
expect(find_all('.post-to-sis-status.disabled').count).to be 2
end
end end
it 'should go to the assignment index page from left nav', priority: "1", test_id: 108724 do it 'should go to the assignment index page from left nav', priority: "1", test_id: 108724 do

View File

@ -3,6 +3,7 @@ require_relative '../../helpers/groups_common'
describe "gradebook2" do describe "gradebook2" do
include_context "in-process server selenium tests" include_context "in-process server selenium tests"
include_context "gradebook_components"
include Gradebook2Common include Gradebook2Common
include GroupsCommon include GroupsCommon
@ -227,6 +228,20 @@ describe "gradebook2" do
expect(f("#content")).not_to contain_jqcss('.student-placeholder:visible') expect(f("#content")).not_to contain_jqcss('.student-placeholder:visible')
end end
it "should hide and show notes", priority: "2", test_id: 164224 do
get "/courses/#{@course.id}/gradebook2"
# show notes column
gradebook_settings_cog.click
show_notes.click
expect(f("#content")).to contain_jqcss('.custom_column:visible')
# hide notes column
gradebook_settings_cog.click
hide_notes.click
expect(f("#content")).not_to contain_jqcss('.custom_column:visible')
end
context "downloading and uploading submissions" do context "downloading and uploading submissions" do
it "updates the dropdown menu after downloading and processes submission uploads" do it "updates the dropdown menu after downloading and processes submission uploads" do
# Given I have a student with an uploaded submission # Given I have a student with an uploaded submission

View File

@ -7,9 +7,17 @@ describe "gradebook2 - total points toggle" do
let!(:setup) { gradebook_data_setup } let!(:setup) { gradebook_data_setup }
def should_show_percentages def should_show_percentages
wait_for_ajaximations
ff(".slick-row .slick-cell:nth-child(5)").each { |total| expect(total.text).to match(/%/) } ff(".slick-row .slick-cell:nth-child(5)").each { |total| expect(total.text).to match(/%/) }
end end
def should_show_points
expected_points = 15, 10, 10
ff(".slick-row .slick-cell:nth-child(5)").each do |total|
expect(total.text).to match(/\A#{expected_points.shift}$/)
end
end
def open_display_dialog def open_display_dialog
f("#total_dropdown").click f("#total_dropdown").click
f(".toggle_percent").click f(".toggle_percent").click
@ -31,6 +39,19 @@ describe "gradebook2 - total points toggle" do
submit_dialog(dialog, '.ui-button') submit_dialog(dialog, '.ui-button')
end end
it "setting group weights should switch to percentage", test_id: 164231, priority: "2" do
get "/courses/#{@course.id}/gradebook2"
toggle_grade_display
should_show_points
group = AssignmentGroup.where(name: @group.name).first
set_group_weight(group, 50)
disable_group_weight
should_show_percentages
end
it "should warn the teacher that studens will see a change" do it "should warn the teacher that studens will see a change" do
get "/courses/#{@course.id}/gradebook2" get "/courses/#{@course.id}/gradebook2"
open_display_dialog open_display_dialog
@ -43,10 +64,7 @@ describe "gradebook2 - total points toggle" do
should_show_percentages should_show_percentages
toggle_grade_display toggle_grade_display
expected_points = 15, 10, 10 should_show_points
ff(".slick-row .slick-cell:nth-child(5)").each do |total|
expect(total.text).to match(/\A#{expected_points.shift}$/)
end
toggle_grade_display toggle_grade_display
should_show_percentages should_show_percentages

View File

@ -401,6 +401,7 @@ describe "new groups" do
end end
it 'should create a group with a given name and limit', priority: "2", test_id: 94166 do it 'should create a group with a given name and limit', priority: "2", test_id: 94166 do
skip("broken qa-729")
group_test_setup(5,1,1) group_test_setup(5,1,1)
3.times do |n| 3.times do |n|
add_user_to_group(@students[n+1], @testgroup.first, false) add_user_to_group(@students[n+1], @testgroup.first, false)

View File

@ -4,6 +4,8 @@ module Gradebook2Common
shared_context 'gradebook_components' do shared_context 'gradebook_components' do
let(:gradebook_settings_cog) { f('#gradebook_settings') } let(:gradebook_settings_cog) { f('#gradebook_settings') }
let(:group_weights_menu) { f('[aria-controls="assignment_group_weights_dialog"]') } let(:group_weights_menu) { f('[aria-controls="assignment_group_weights_dialog"]') }
let(:show_notes) { fj('li a:contains("Show Notes Column")') }
let(:hide_notes) { f(".hide") }
end end
shared_context 'reusable_course' do shared_context 'reusable_course' do
let(:test_course) { course(active_course: true) } let(:test_course) { course(active_course: true) }
@ -352,6 +354,22 @@ module Gradebook2Common
expect(@course.reload.group_weighting_scheme).to eq 'percent' expect(@course.reload.group_weighting_scheme).to eq 'percent'
end end
def disable_group_weight
f('#gradebook_settings').click
f('[aria-controls="assignment_group_weights_dialog"]').click
dialog = f('#assignment_group_weights_dialog')
expect(dialog).to be_displayed
group_check = dialog.find_element(:id, 'group_weighting_scheme')
keep_trying_until do
group_check.click
expect(is_checked('#group_weighting_scheme')).to be_falsey
end
fj('.ui-button:contains("Save")').click
refresh_page
end
def validate_group_weight_text(assignment_groups, weight_numbers) def validate_group_weight_text(assignment_groups, weight_numbers)
assignment_groups.each_with_index do |ag, i| assignment_groups.each_with_index do |ag, i|
heading = fj(".slick-column-name:contains('#{ag.name}') .assignment-points-possible") heading = fj(".slick-column-name:contains('#{ag.name}') .assignment-points-possible")

View File

@ -141,7 +141,10 @@ end
shared_examples 'people_page' do |context| shared_examples 'people_page' do |context|
it "should allow group users to see group registered services page", priority: pick_priority(context, student: "1", teacher: "2"),test_id: pick_test_id(context, student: 323329, teacher: 324926) do it "should allow group users to see group registered services page", priority: pick_priority(context, student: "1", teacher: "2"),test_id: pick_test_id(context, student: 323329, teacher: 324926) do
get people_page get people_page
expect_new_page_load { fln('View Registered Services').click } expect_new_page_load do
f("#people-options .Button").click
fln('View Registered Services').click
end
# Checks that we are on the Registered Services page # Checks that we are on the Registered Services page
expect(f('.btn.button-sidebar-wide')).to be_displayed expect(f('.btn.button-sidebar-wide')).to be_displayed
end end
@ -235,4 +238,3 @@ shared_examples 'conferences_page' do |context|
expect(f('#concluded-conference-list')).to include_text('There are no concluded conferences') expect(f('#concluded-conference-list')).to include_text('There are no concluded conferences')
end end
end end

View File

@ -22,7 +22,10 @@ describe "people" do
end end
def create_student_group(group_text = "new student group") def create_student_group(group_text = "new student group")
expect_new_page_load { fln('View User Groups').click } expect_new_page_load do
f("#people-options .Button").click
fln('View User Groups').click
end
open_student_group_dialog open_student_group_dialog
inputs = ffj('input:visible') inputs = ffj('input:visible')
replace_content(inputs[0], group_text) replace_content(inputs[0], group_text)
@ -167,6 +170,7 @@ describe "people" do
end end
it "should display activity report on clicking Student Interaction button", priority: "1", test_id: 244446 do it "should display activity report on clicking Student Interaction button", priority: "1", test_id: 244446 do
f("#people-options .Button").click
fln("Student Interactions Report").click fln("Student Interactions Report").click
wait_for_ajaximations wait_for_ajaximations
user_name = f(".user_name").text user_name = f(".user_name").text
@ -204,6 +208,7 @@ describe "people" do
end end
it "should navigate to registered services on profile page" do it "should navigate to registered services on profile page" do
f("#people-options .Button").click
fln('View Registered Services').click fln('View Registered Services').click
fln('Link web services to my account').click fln('Link web services to my account').click
expect(f('#unregistered_services')).to be_displayed expect(f('#unregistered_services')).to be_displayed
@ -214,6 +219,7 @@ describe "people" do
end end
it "should test self sign up help functionality" do it "should test self sign up help functionality" do
f("#people-options .Button").click
expect_new_page_load { fln('View User Groups').click } expect_new_page_load { fln('View User Groups').click }
open_student_group_dialog open_student_group_dialog
fj('.self_signup_help_link:visible').click fj('.self_signup_help_link:visible').click
@ -222,6 +228,7 @@ describe "people" do
end end
it "should test self sign up functionality" do it "should test self sign up functionality" do
f("#people-options .Button").click
expect_new_page_load { fln('View User Groups').click } expect_new_page_load { fln('View User Groups').click }
dialog = open_student_group_dialog dialog = open_student_group_dialog
dialog.find_element(:css, '#category_enable_self_signup').click dialog.find_element(:css, '#category_enable_self_signup').click
@ -231,7 +238,10 @@ describe "people" do
it "should test self sign up / group structure functionality" do it "should test self sign up / group structure functionality" do
group_count = "4" group_count = "4"
expect_new_page_load { fln('View User Groups').click } expect_new_page_load do
f("#people-options .Button").click
fln('View User Groups').click
end
dialog = open_student_group_dialog dialog = open_student_group_dialog
dialog.find_element(:css, '#category_enable_self_signup').click dialog.find_element(:css, '#category_enable_self_signup').click
dialog.find_element(:css, '#category_create_group_count').send_keys(group_count) dialog.find_element(:css, '#category_create_group_count').send_keys(group_count)
@ -245,7 +255,10 @@ describe "people" do
enroll_more_students enroll_more_students
group_count = "4" group_count = "4"
expect_new_page_load { fln('View User Groups').click } expect_new_page_load do
f("#people-options .Button").click
fln('View User Groups').click
end
dialog = open_student_group_dialog dialog = open_student_group_dialog
dialog.find_element(:css, '#category_split_groups').click dialog.find_element(:css, '#category_split_groups').click
replace_content(f('#category_split_group_count'), group_count) replace_content(f('#category_split_group_count'), group_count)
@ -286,7 +299,10 @@ describe "people" do
enroll_more_students enroll_more_students
group_count = 4 group_count = 4
expect_new_page_load { fln('View User Groups').click } expect_new_page_load do
f("#people-options .Button").click
fln('View User Groups').click
end
open_student_group_dialog open_student_group_dialog
submit_form('#add_category_form') submit_form('#add_category_form')
wait_for_ajaximations wait_for_ajaximations
@ -309,7 +325,10 @@ describe "people" do
it "should test prior enrollment functionality" do it "should test prior enrollment functionality" do
@course.complete @course.complete
get "/courses/#{@course.id}/users" get "/courses/#{@course.id}/users"
expect_new_page_load { fln('View Prior Enrollments').click } expect_new_page_load do
f("#people-options .Button").click
fln('View Prior Enrollments').click
end
expect(f('#users')).to include_text(@student_1.name) expect(f('#users')).to include_text(@student_1.name)
end end
@ -399,7 +418,7 @@ describe "people" do
student = create_user("student@example.com") student = create_user("student@example.com")
enroll_student(student) enroll_student(student)
get "/courses/#{@course.id}/users" get "/courses/#{@course.id}/users"
ff(".icon-settings")[1].click f(".StudentEnrollment .icon-settings").click
fln("Edit Sections").click fln("Edit Sections").click
f(".token_input.browsable").click f(".token_input.browsable").click
section_input_element = driver.find_element(:name, "token_capture") section_input_element = driver.find_element(:name, "token_capture")
@ -416,7 +435,7 @@ describe "people" do
@course.enroll_student(@student, allow_multiple_enrollments: true) @course.enroll_student(@student, allow_multiple_enrollments: true)
@course.enroll_student(@student, section: @section2, allow_multiple_enrollments: true) @course.enroll_student(@student, section: @section2, allow_multiple_enrollments: true)
get "/courses/#{@course.id}/users" get "/courses/#{@course.id}/users"
ff(".icon-settings")[1].click f(".StudentEnrollment .icon-settings").click
fln("Edit Sections").click fln("Edit Sections").click
fln("Remove user from section2").click fln("Remove user from section2").click
ff('.ui-button-text')[1].click ff('.ui-button-text')[1].click

View File

@ -180,8 +180,8 @@ describe "profile" do
register_form = f('#register_sms_number') register_form = f('#register_sms_number')
register_form.find_element(:css, '.sms_number').send_keys(test_cell_number) register_form.find_element(:css, '.sms_number').send_keys(test_cell_number)
click_option('select.user_selected.carrier', 'AT&T') click_option('select.user_selected.carrier', 'AT&T')
driver.action.send_keys(:tab).perform
submit_form(register_form) submit_form(register_form)
sleep 1 # wait a moment before we close any dialogs, since this spec fails intermittently ... this way we can catch any formError thingies in the video capture
wait_for_ajaximations wait_for_ajaximations
close_visible_dialog close_visible_dialog
keep_trying_until { expect(f('.other_channels .path')).to include_text(test_cell_number) } keep_trying_until { expect(f('.other_channels .path')).to include_text(test_cell_number) }

View File

@ -67,77 +67,6 @@ describe "quizzes" do
expect(group_form.find_element(:css, '.group_display.name')).to include_text('new group') expect(group_form.find_element(:css, '.group_display.name')).to include_text('new group')
end end
it 'should display post to SIS icon on quiz page when enabled' do
Account.default.set_feature_flag!('post_grades', 'on')
@q1 = quiz_create
@q2 = quiz_create
@q3 = quiz_create
@q1.post_to_sis = true
@q2.post_to_sis = false
@q3.post_to_sis = true
@q1.save!
@q2.save!
@q3.save!
get "/courses/#{@course.id}/quizzes/"
wait_for_ajaximations
expect(find_all('.post-to-sis-status.enabled').count).to be 2
expect(find_all('.post-to-sis-status.disabled').count).to be 1
Account.default.set_feature_flag!('post_grades', 'off')
get "/courses/#{@course.id}/quizzes/"
wait_for_ajaximations
expect(find_all('.post-to-sis-status.enabled').count).to be 0
expect(find_all('.post-to-sis-status.disabled').count).to be 0
end
it 'should display post to SIS icon on quiz page when enabled' do
Account.default.set_feature_flag!('post_grades', 'on')
@q1 = quiz_create
@q2 = quiz_create
@q3 = quiz_create
@q1.post_to_sis = true
@q2.post_to_sis = false
@q3.post_to_sis = true
@q1.save!
@q2.save!
@q3.save!
get "/courses/#{@course.id}/quizzes/"
wait_for_ajaximations
enabled = find_all('.post-to-sis-status.enabled')
disabled = find_all('.post-to-sis-status.disabled')
expect(enabled.count).to be 2
expect(disabled.count).to be 1
enabled.each(&:click)
disabled.each(&:click)
wait_for_ajaximations
@q1.reload
@q2.reload
@q3.reload
expect(@q1.post_to_sis?).to be_falsey
expect(@q2.post_to_sis?).to be_truthy
expect(@q3.post_to_sis?).to be_falsey
expect(find_all('.post-to-sis-status.enabled').count).to be 1
expect(find_all('.post-to-sis-status.disabled').count).to be 2
end
it "should update a question group", priority: "1", test_id: 210061 do it "should update a question group", priority: "1", test_id: 210061 do
skip('fragile') skip('fragile')
get "/courses/#{@course.id}/quizzes/new" get "/courses/#{@course.id}/quizzes/new"

View File

@ -135,7 +135,7 @@ module CustomSeleniumActions
end end
def is_checked(css_selector) def is_checked(css_selector)
driver.execute_script('return $("'+css_selector+'").prop("checked")') !!fj(css_selector)[:checked]
end end
def get_value(selector) def get_value(selector)