Merge remote-tracking branch 'origin/master' into flowr

# Conflicts:
#	app/assets/javascripts/editor/evaluation.js
#	app/assets/javascripts/editor/participantsupport.js
#	app/views/exercises/_editor_output.html.slim
#	config/code_ocean.yml.example
#	config/routes.rb
This commit is contained in:
Maximilian Grundke
2018-11-28 13:14:21 +01:00
500 changed files with 12187 additions and 3430 deletions

View File

@@ -1,9 +1,21 @@
- content_for :head do
= javascript_include_tag(asset_path('vis.min.js', type: :javascript))
= stylesheet_link_tag(asset_path('vis.min.css', type: :stylesheet))
// Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326.
Otherwise, the global variable `vis` might be uninitialized in the assets (race condition)
meta name='turbolinks-visit-control' content='reload'
= javascript_pack_tag('vis', 'data-turbolinks-track': true)
= stylesheet_pack_tag('vis', media: 'all', 'data-turbolinks-track': true)
h1 = t('breadcrumbs.dashboard.show')
h2 Version
div
= "Branch:"
pre = `git rev-parse --abbrev-ref HEAD`
div
= "Commit:"
pre = `git log -n 1 --pretty`
h2 Docker
- if DockerContainerPool.config[:active]

View File

@@ -1,19 +1,19 @@
- if current_user.try(:internal_user?)
ul.breadcrumb
- if model = Kernel.const_get(controller_name.classify) rescue nil
- if model = Kernel.const_get(controller_path.classify) rescue nil
- object = model.find_by(id: params[:id])
- if model.try(:nested_resource?)
li = model.model_name.human(count: 2)
li.breadcrumb-item = model.model_name.human(count: 2)
- if object
li = object
li.breadcrumb-item = object
- else
li = link_to(model.model_name.human(count: 2), send(:"#{model.model_name.collection}_path"))
li.breadcrumb-item = link_to(model.model_name.human(count: 2), send(:"#{model.model_name.collection}_path"))
- if object
li = link_to(object, send(:"#{model.model_name.singular}_path", object))
li.active
li.breadcrumb-item = link_to(object, send(:"#{model.model_name.singular}_path", object))
li.breadcrumb-item.active
- if I18n.translation_present?("shared.#{params[:action]}")
= t("shared.#{params[:action]}")
- else
= t("#{controller_name}.index.#{params[:action]}")
- else
li.active = t("breadcrumbs.#{controller_name}.#{params[:action]}")
li.breadcrumb-item.active = t("breadcrumbs.#{controller_name}.#{params[:action]}")

View File

@@ -1,6 +1,7 @@
#flash-container
#flash.container.fixed_error_messages data-message-failure=t('shared.message_failure')
- %w[alert danger info notice success warning].each do |severity|
div.alert.flash class="alert-#{{'alert' => 'warning', 'notice' => 'success'}.fetch(severity, severity)}"
p id="flash-#{severity}" = flash[severity]
span.fa.fa-times
div.alert.flash class="alert-#{{'alert' => 'warning', 'notice' => 'success'}.fetch(severity, severity)} alert-dismissible fade show"
p.mb-0 id="flash-#{severity}" = flash[severity]
button type="button" class="close" data-dismiss="alert" aria-label="Close"
span.text-white aria-hidden="true" ×

View File

@@ -1,7 +1,7 @@
li.dropdown
a.dropdown-toggle data-toggle='dropdown' href='#'
li.nav-item.dropdown
a.nav-link.dropdown-toggle.mx-3 data-toggle='dropdown' href='#'
= t("locales.#{I18n.locale}")
span.caret
ul.dropdown-menu role='menu'
ul.dropdown-menu.p-0.mt-1 role='menu'
- I18n.available_locales.sort_by { |locale| t("locales.#{locale}") }.each do |locale|
li = link_to(t("locales.#{locale}"), url_for(params.merge(locale: locale)))
li = link_to(t("locales.#{locale}"), url_for(params.permit!.merge(locale: locale)), class: 'dropdown-item')

View File

@@ -1,16 +1,16 @@
- if current_user.try(:internal_user?)
ul.nav.navbar-nav
li.dropdown
a.dropdown-toggle data-toggle='dropdown' href='#'
li.nav-item.dropdown
a.nav-link.dropdown-toggle.mx-3 data-toggle='dropdown' href='#'
= t('shared.administration')
span.caret
ul.dropdown-menu role='menu'
ul.dropdown-menu.p-0.mt-1 role='menu'
- if current_user.admin?
li = link_to(t('breadcrumbs.dashboard.show'), admin_dashboard_path)
li = link_to(t('breadcrumbs.statistics.show'), statistics_path)
li.divider
li = link_to(t('breadcrumbs.dashboard.show'), admin_dashboard_path, class: 'dropdown-item', 'data-turbolinks' => "false")
li = link_to(t('breadcrumbs.statistics.show'), statistics_path, class: 'dropdown-item')
li.dropdown-divider role='separator'
= render('navigation_submenu', title: t('activerecord.models.exercise.other'),
models: [Exercise, ExerciseCollection, ProxyExercise, Tag], link: exercises_path, cached: true)
models: [Exercise, ExerciseCollection, ProxyExercise, Tag, Submission], link: exercises_path, cached: true)
= render('navigation_submenu', title: t('navigation.sections.users'), models: [InternalUser, ExternalUser],
cached: true)
= render('navigation_collection_link', model: ExecutionEnvironment, cached: true)

View File

@@ -1,2 +1,2 @@
- if policy(model).index?
li = link_to(model.model_name.human(count: 2), send(:"#{model.model_name.collection}_path"))
li = link_to(model.model_name.human(count: 2), send(:"#{model.model_name.collection}_path"), class: 'dropdown-item')

View File

@@ -1,6 +1,6 @@
li.dropdown.dropdown-submenu
li.dropdown-submenu
- link = link.nil? ? "#" : link
a href=link class="dropdown-toggle" data-toggle="dropdown" = title
ul class="dropdown-menu"
a.dropdown-item.dropdown-toggle href=link data-toggle="dropdown" = title
ul.dropdown-menu.p-0
- models.each do |model|
= render('navigation_collection_link', model: model, cached: true)

View File

@@ -1,19 +1,19 @@
- if current_user
li.dropdown
a.dropdown-toggle data-toggle='dropdown' href='#'
li.nav-item.dropdown
a.nav-link.dropdown-toggle data-toggle='dropdown' href='#'
i.fa.fa-user
= current_user
span.caret
ul.dropdown-menu role='menu'
ul.dropdown-menu.p-0.mt-1 role='menu'
- if current_user.internal_user?
li = link_to(t('consumers.show.link'), current_user.consumer) if current_user.consumer
li = link_to(t('internal_users.show.link'), current_user)
li = link_to(t('request_for_comments.index.all'), request_for_comments_path)
li = link_to(t('request_for_comments.index.get_my_rfc_activity'), my_rfc_activity_path)
li = link_to(t('request_for_comments.index.get_my_comment_requests'), my_request_for_comments_path)
li = link_to(t('consumers.show.link'), current_user.consumer, class: 'dropdown-item') if current_user.consumer
li = link_to(t('internal_users.show.link'), current_user, class: 'dropdown-item')
li = link_to(t('request_for_comments.index.all'), request_for_comments_path, class: 'dropdown-item')
li = link_to(t('request_for_comments.index.get_my_rfc_activity'), my_rfc_activity_path, class: 'dropdown-item')
li = link_to(t('request_for_comments.index.get_my_comment_requests'), my_request_for_comments_path, class: 'dropdown-item')
- if current_user.internal_user?
li = link_to(t('sessions.destroy.link'), sign_out_path, method: :delete)
li = link_to(t('sessions.destroy.link'), sign_out_path, method: :delete, class: 'dropdown-item')
- else
li = link_to(sign_in_path) do
li.nav-item = link_to(sign_in_path, class: 'nav-link') do
i.fa.fa-sign-in
= t('sessions.new.link')

View File

@@ -9,7 +9,7 @@ h1 = CodeHarborLink.model_name.human(count: 2)
tbody
- @code_harbor_links.each do |code_harbor_link|
tr
td = code_harbor_link.oauth2token
td = link_to(code_harbor_link.oauth2token, code_harbor_link)
td = link_to(t('shared.show'), code_harbor_link)
td = link_to(t('shared.edit'), edit_code_harbor_link_path(code_harbor_link))
td = link_to(t('shared.destroy'), code_harbor_link, data: {confirm: t('shared.confirm_destroy')}, method: :delete)

View File

@@ -1,10 +1,10 @@
h1 = ::Error.model_name.human(count: 2)
h1 = CodeOcean::Error.model_name.human(count: 2)
.table-responsive
table.table
thead
tr
th = t('.count')
th = t('errors.index.count')
th = t('activerecord.attributes.error.message')
th = t('shared.created_at')
th = t('shared.actions')

View File

@@ -1,4 +1,4 @@
h1 = ::Error.model_name.human
h1 = CodeOcean::Error.model_name.human
= row(label: 'error.message', value: @error.message)
= row(label: 'shared.created_at', value: l(@error.created_at, format: :short))

View File

@@ -12,5 +12,5 @@
= f.label(:file_template_id, t('activerecord.attributes.file.file_template_id'))
= f.collection_select(:file_template_id, FileTemplate.all.order(:name), :id, :name, {:include_blank => true}, class: 'form-control')
= f.hidden_field(:context_id)
.hidden#noTemplateLabel data-text=t('file_template.no_template_label')
.d-none#noTemplateLabel data-text=t('file_template.no_template_label')
.actions = render('shared/submit_button', f: f, object: CodeOcean::File.new)

View File

@@ -1,37 +0,0 @@
<%= form_for(@comment) do |f| %>
<% if @comment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@comment.errors.count, "error") %> prohibited this comment from being saved:</h2>
<ul>
<% @comment.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :user_id %><br>
<%= f.text_field :user_id %>
</div>
<div class="field">
<%= f.label :file_id %><br>
<%= f.text_field :file_id %>
</div>
<div class="field">
<%= f.label :row %><br>
<%= f.number_field :row %>
</div>
<div class="field">
<%= f.label :column %><br>
<%= f.number_field :column %>
</div>
<div class="field">
<%= f.label :text %><br>
<%= f.text_field :text %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

View File

@@ -0,0 +1,33 @@
= form_for(@comment) do |f|
- if @comment.errors.any?
#error_explanation
h2
= pluralize(@comment.errors.count, "error")
| prohibited this comment from being saved:
ul
- @comment.errors.full_messages.each do |message|
li= message
.field
= f.label :user_id
br/
= f.text_field :user_id
.field
= f.label :file_id
br/
= f.text_field :file_id
.field
= f.label :row
br/
= f.number_field :row
.field
= f.label :column
br/
= f.number_field :column
.field
= f.label :text
br/
= f.text_field :text
.actions
= f.submit

View File

@@ -1,6 +0,0 @@
<h1>Editing comment</h1>
<%= render 'form' %>
<%= link_to 'Show', @comment %> |
<%= link_to 'Back', comments_path %>

View File

@@ -0,0 +1,7 @@
h1 Editing comment
= render 'form'
= link_to 'Show', @comment
| |
= link_to 'Back', comments_path

View File

@@ -1,33 +0,0 @@
<h1>Listing comments</h1>
<table>
<thead>
<tr>
<th>User</th>
<th>File</th>
<th>Row</th>
<th>Column</th>
<th>Text</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @comments.each do |comment| %>
<tr>
<td><%= comment.user %></td>
<td><%= comment.file %></td>
<td><%= comment.row %></td>
<td><%= comment.column %></td>
<td><%= comment.text %></td>
<td><%= link_to 'Show', comment %></td>
<td><%= link_to 'Edit', edit_comment_path(comment) %></td>
<td><%= link_to 'Destroy', comment, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Comment', new_comment_path %>

View File

@@ -0,0 +1,24 @@
h1 Listing comments
table
thead
tr
th User
th File
th Row
th Column
th Text
th colspan="3"
tbody
- @comments.each do |comment|
tr
td= comment.user
td= comment.file
td= comment.row
td= comment.column
td= comment.text
td= link_to 'Show', comment
td= link_to 'Edit', edit_comment_path(comment)
td= link_to 'Destroy', comment, method: :delete, data: confirm: 'Are you sure?'
br/
= link_to 'New Comment', new_comment_path

View File

@@ -1,5 +0,0 @@
<h1>New comment</h1>
<%= render 'form' %>
<%= link_to 'Back', comments_path %>

View File

@@ -0,0 +1,5 @@
h1 New comment
= render 'form'
= link_to 'Back', comments_path

View File

@@ -1,29 +0,0 @@
<p id="notice"><%= notice %></p>
<p>
<strong>User:</strong>
<%= @comment.user %>
</p>
<p>
<strong>File:</strong>
<%= @comment.file %>
</p>
<p>
<strong>Row:</strong>
<%= @comment.row %>
</p>
<p>
<strong>Column:</strong>
<%= @comment.column %>
</p>
<p>
<strong>Text:</strong>
<%= @comment.text %>
</p>
<%= link_to 'Edit', edit_comment_path(@comment) %> |
<%= link_to 'Back', comments_path %>

View File

@@ -0,0 +1,25 @@
p#notice= notice
p
strong User:
= @comment.user
p
strong File:
= @comment.file
p
strong Row:
= @comment.row
p
strong Column:
= @comment.column
p
strong Text:
= @comment.text
= link_to 'Edit', edit_comment_path(@comment)
| |
= link_to 'Back', comments_path

View File

@@ -9,7 +9,7 @@ h1 = Consumer.model_name.human(count: 2)
tbody
- @consumers.each do |consumer|
tr
td = consumer.name
td = link_to(consumer.name, consumer)
td = link_to(t('shared.show'), consumer)
td = link_to(t('shared.edit'), edit_consumer_path(consumer))
td = link_to(t('shared.destroy'), consumer, data: {confirm: t('shared.confirm_destroy')}, method: :delete)

View File

@@ -9,8 +9,9 @@
.form-group
= f.label(:regex)
= f.text_field(:regex, class: 'form-control', required: true)
.help-block == t('error_templates.hints.signature')
.form-group
= f.check_box(:important)
.help-block.form-text == t('error_templates.hints.signature')
.form-check.form-group
label.form-check-label
= f.check_box(:important, class: 'form-check-input')
= t('activerecord.attributes.error_template_attribute.important')
.actions = render('shared/submit_button', f: f, object: @error_template_attribute)

View File

@@ -17,9 +17,10 @@ h1 = ErrorTemplateAttribute.model_name.human(count: 2)
span class="fa fa-star" aria-hidden="true"
- else
span class="fa fa-star-o" aria-hidden="true"
td = error_template_attribute.key
td = link_to(error_template_attribute.key, error_template_attribute)
td = error_template_attribute.description
td = error_template_attribute.regex
td
code = error_template_attribute.regex
td = link_to(t('shared.show'), error_template_attribute)
td = link_to(t('shared.edit'), edit_error_template_attribute_path(error_template_attribute))
td = link_to(t('shared.destroy'), error_template_attribute, data: {confirm: t('shared.confirm_destroy')}, method: :delete)

View File

@@ -2,7 +2,10 @@ h1
= @error_template_attribute
= render('shared/edit_button', object: @error_template_attribute)
- [:key, :description, :regex, :important].each do |attribute|
- [:key, :description].each do |attribute|
= row(label: "error_template_attribute.#{attribute}", value: @error_template_attribute.send(attribute))
= row(label: "error_template_attribute.key") do
code = @error_template_attribute.key
= row(label: "error_template_attribute.important", value: @error_template_attribute.important)
// todo: used by

View File

@@ -9,12 +9,12 @@
.form-group
= f.label(:signature)
= f.text_field(:signature, class: 'form-control')
.help-block == t('error_templates.hints.signature')
.help-block.form-text == t('error_templates.hints.signature')
.form-group
= f.label(:description)
= f.text_field(:description, class: 'form-control')
.form-group
= f.label(:hint)
= f.text_field(:hint, class: 'form-control')
.help-block == t('error_templates.hints.hint_templates')
.help-block.form-text == t('error_templates.hints.hint_templates')
.actions = render('shared/submit_button', f: f, object: @error_template)

View File

@@ -11,7 +11,7 @@ h1 = ErrorTemplate.model_name.human(count: 2)
tbody
- @error_templates.each do |error_template|
tr
td = error_template.name
td = link_to(error_template.name, error_template)
td = error_template.description
td = link_to(error_template.execution_environment)
td = link_to(t('shared.show'), error_template)

View File

@@ -4,10 +4,12 @@ h1
= row(label: 'error_template.name', value: @error_template.name)
= row(label: 'exercise.execution_environment', value: link_to(@error_template.execution_environment))
- [:signature, :description, :hint].each do |attribute|
= row(label: "error_template.signature") do
code = @error_template.signature
- [:description, :hint].each do |attribute|
= row(label: "error_template.#{attribute}", value: @error_template.send(attribute))
h3
h2.mt-4
= t 'error_templates.attributes'
.table-responsive
@@ -27,9 +29,10 @@ h3
span class="fa fa-star" aria-hidden="true"
- else
span class="fa fa-star-o" aria-hidden="true"
td = attribute.key
td = link_to(attribute.key, attribute)
td = attribute.description
td = attribute.regex
td
code = attribute.regex
td = link_to(t('shared.show'), attribute)
td = link_to(t('shared.destroy'), attribute_error_template_url(:error_template_attribute_id => attribute.id), :method => :delete)
@@ -37,4 +40,4 @@ h3
= collection_select({}, :error_template_attribute_id,
ErrorTemplateAttribute.where.not(id: @error_template.error_template_attributes.select(:id).to_a).order('important DESC', :key),
:id, :key, {include_blank: false}, class: '')
button.btn.btn-default = t('error_templates.add_attribute')
button.btn.btn-outline-primary = t('error_templates.add_attribute')

View File

@@ -12,17 +12,17 @@
a.toggle-input data={text_initial: t('shared.new'), text_toggled: t('shared.back')} href='#' = t('shared.new')
.original-input = f.select(:docker_image, @docker_images, {}, class: 'form-control')
= f.text_field(:docker_image, class: 'alternative-input form-control', disabled: true)
.help-block == t('.hints.docker_image')
.help-block.form-text == t('.hints.docker_image')
.form-group
= f.label(:exposed_ports)
= f.text_field(:exposed_ports, class: 'form-control', placeholder: '3000, 4000')
.help-block == t('.hints.exposed_ports')
.help-block.form-text == t('.hints.exposed_ports')
.form-group
= f.label(:memory_limit)
= f.number_field(:memory_limit, class: 'form-control', min: DockerClient::MINIMUM_MEMORY_LIMIT, value: f.object.memory_limit || DockerClient::DEFAULT_MEMORY_LIMIT)
.checkbox
label
= f.check_box(:network_enabled)
.form-check.mb-3
label.form-check-label
= f.check_box(:network_enabled, class: 'form-check-input')
= t('activerecord.attributes.execution_environment.network_enabled')
.form-group
= f.label(:permitted_execution_time)
@@ -33,11 +33,11 @@
.form-group
= f.label(:run_command)
= f.text_field(:run_command, class: 'form-control', placeholder: 'command %{filename}', required: true)
.help-block == t('.hints.command')
.help-block.form-text == t('.hints.command')
.form-group
= f.label(:test_command)
= f.text_field(:test_command, class: 'form-control', placeholder: 'command %{filename}')
.help-block == t('.hints.command')
.help-block.form-text == t('.hints.command')
.form-group
= f.label(:testing_framework)
= f.select(:testing_framework, @testing_framework_adapters, {include_blank: true}, class: 'form-control')

View File

@@ -15,7 +15,7 @@ h1 = ExecutionEnvironment.model_name.human(count: 2)
tbody
- @execution_environments.each do |execution_environment|
tr
td = execution_environment.name
td = link_to(execution_environment.name, execution_environment)
td = link_to(execution_environment.author, execution_environment.author)
td = execution_environment.pool_size
td = execution_environment.memory_limit

View File

@@ -5,7 +5,10 @@ h1
= row(label: 'execution_environment.name', value: @execution_environment.name)
= row(label: 'execution_environment.user', value: link_to(@execution_environment.author, @execution_environment.author))
= row(label: 'execution_environment.file_type', value: @execution_environment.file_type.present? ? link_to(@execution_environment.file_type, @execution_environment.file_type) : nil)
- [:docker_image, :exposed_ports, :memory_limit, :network_enabled, :permitted_execution_time, :pool_size, :run_command, :test_command].each do |attribute|
- [:docker_image, :exposed_ports, :memory_limit, :network_enabled, :permitted_execution_time, :pool_size].each do |attribute|
= row(label: "execution_environment.#{attribute}", value: @execution_environment.send(attribute))
- [:run_command, :test_command].each do |attribute|
= row(label: "execution_environment.#{attribute}") do
code = @execution_environment.send(attribute)
= row(label: 'execution_environment.testing_framework', value: @testing_framework_adapter.try(:framework_name))
= row(label: 'execution_environment.help', value: render_markdown(@execution_environment.help))

View File

@@ -14,7 +14,7 @@ h1 = @execution_environment
- if wts then average_time = wts["average_time"] else 0
- if wts then stddev_time = wts["stddev_time"] else 0
tr
td = link_to exercise.title, controller: "exercises", action: "statistics", id: exercise.id
td = link_to exercise.title, controller: "exercises", action: "statistics", id: exercise.id, 'data-turbolinks' => "false"
td = us["users"]
td = us["average_score"].to_f.round(4)
td = us["maximum_score"].to_f.round(2)

View File

@@ -2,7 +2,8 @@
form#exercise-selection
.form-group
span.label = t('activerecord.attributes.exercise_collections.exercises')
span.badge = t('activerecord.attributes.exercise_collections.exercises')
.mb-2
= collection_select({}, :exercise_ids, exercises, :id, :title, {}, {id: 'add-exercise-list', class: 'form-control', multiple: true})
button.btn.btn-primary#add-exercises = t('exercise_collections.form.add_exercises')

View File

@@ -3,9 +3,10 @@
.form-group
= f.label(t('activerecord.attributes.exercise_collections.name'))
= f.text_field(:name, class: 'form-control', required: true)
.form-group
= f.label(t('activerecord.attributes.exercise_collections.use_anomaly_detection'))
= f.check_box(:use_anomaly_detection, {class: 'form-control'})
.form-check.form-group
label.form-check-label
= f.check_box(:use_anomaly_detection, class: 'form-check-input')
= t('activerecord.attributes.exercise_collections.use_anomaly_detection')
.form-group
= f.label(t('activerecord.attributes.exercise_collections.user'))
= f.collection_select(:user_id, InternalUser.order(:name), :id, :name, {}, {class: 'form-control'})
@@ -23,13 +24,13 @@
td
span.fa.fa-bars
td = item.exercise.title
td = link_to(t('shared.show'), item.exercise)
td = link_to(t('shared.show'), item.exercise, 'data-turbolinks' => "false")
td
a.remove-exercise href='#' = t('shared.destroy')
.hidden
.d-none
= f.collection_select(:exercise_ids, Exercise.all, :id, :title, {}, {id: 'exercise-select', class: 'form-control', multiple: true})
.exercise-actions
button.btn.btn-primary type='button' data-toggle='modal' data-target='#add-exercise-modal' = t('exercise_collections.form.add_exercises')
button.btn.btn-outline-primary type='button' data-toggle='modal' data-target='#add-exercise-modal' = t('exercise_collections.form.add_exercises')
button.btn.btn-secondary#sort-button type='button' = t('exercise_collections.form.sort_by_title')
.actions = render('shared/submit_button', f: f, object: @exercise_collection)

View File

@@ -7,7 +7,7 @@ h1
= row(label: 'exercise_collections.use_anomaly_detection', value: @exercise_collection.use_anomaly_detection)
= row(label: 'exercise_collections.updated_at', value: @exercise_collection.updated_at)
h4 = t('activerecord.attributes.exercise_collections.exercises')
h4.mt-4 = t('activerecord.attributes.exercise_collections.exercises')
.table-responsive#exercise-list
table.table
thead
@@ -24,5 +24,5 @@ h4 = t('activerecord.attributes.exercise_collections.exercises')
td = exercise_collection_item.position
td = link_to(exercise.title, exercise)
td = link_to_if(exercise.execution_environment && policy(exercise.execution_environment).show?, exercise.execution_environment, exercise.execution_environment)
td = exercise.user.name
td = link_to(t('shared.statistics'), statistics_exercise_path(exercise))
td = link_to_if(exercise.user && policy(exercise.user).show?, exercise.user.name, exercise.user)
td = link_to(t('shared.statistics'), statistics_exercise_path(exercise), 'data-turbolinks' => "false")

View File

@@ -6,7 +6,7 @@ h1 = @exercise_collection
= row(label: 'exercises.statistics.average_worktime', value: @exercise_collection.average_working_time.round(3).to_s + 's')
#graph
#data.hidden(data-working-times=ActiveSupport::JSON.encode(@exercise_collection.collection_statistics) data-average-working-time=@exercise_collection.average_working_time)
#data.d-none(data-working-times=ActiveSupport::JSON.encode(@exercise_collection.collection_statistics) data-average-working-time=@exercise_collection.average_working_time)
#legend
- {time: t('exercises.statistics.average_worktime'),
min: 'min. anomaly threshold',

View File

@@ -3,5 +3,5 @@
| &nbsp;
a.toggle-input data={text_initial: t('shared.upload_file'), text_toggled: t('shared.back')} href='#' = t('shared.upload_file')
= form.text_area(attribute, class: 'code-field form-control', rows: 16, style: "display:none;")
= form.file_field(attribute, class: 'alternative-input form-control', disabled: true)
= form.file_field(attribute, class: 'alternative-input form-control-file', disabled: true)
= render partial: 'editor_edit', locals: { exercise: @exercise }

View File

@@ -6,8 +6,7 @@
- hide_rfc_button = @hide_rfc_button || false
#editor.row data-exercise-id=@exercise.id data-message-depleted=t('exercises.editor.depleted') data-message-timeout=t('exercises.editor.timeout', permitted_execution_time: @exercise.execution_environment.permitted_execution_time) data-errors-url=execution_environment_errors_path(exercise.execution_environment) data-submissions-url=submissions_path data-user-id=@current_user.id data-user-external-id=external_user_external_id data-working-times-url=working_times_exercise_path(@exercise) data-intervention-save-url=intervention_exercise_path(@exercise) data-rfc-interventions=show_rfc_interventions data-break-interventions=show_break_interventions data-course_token=@course_token data-search-save-url=search_exercise_path(@exercise)
div id="sidebar" class=(@exercise.hide_file_tree ? 'sidebar-col-collapsed' : 'sidebar-col') = render('editor_file_tree', exercise: @exercise, files: @files)
div id='output_sidebar' class='output-col-collapsed' = render('exercises/editor_output', external_user_id: external_user_id, consumer_id: consumer_id )
div id='frames' class='editor-col'
div.editor-col.col.p-0 id='frames'
#editor-buttons.btn-group.enforce-bottom-margin
= render('editor_button', disabled: true, icon: 'fa fa-ban', id: 'dummy', label: t('exercises.editor.dummy'))
= render('editor_button', icon: 'fa fa-desktop', id: 'render', label: t('exercises.editor.render'))
@@ -24,6 +23,7 @@
= t('exercises.editor.lastsaved')
span
button style="display:none" id="autosave"
div id='output_sidebar' class='output-col-collapsed' = render('exercises/editor_output', external_user_id: external_user_id, consumer_id: consumer_id )
= render('shared/modal', id: 'comment-modal', title: t('exercises.implement.comment.request'), template: 'exercises/_request_comment_dialogcontent')

View File

@@ -1,4 +1,4 @@
button.btn class=local_assigns.fetch(:classes, 'btn-primary btn-sm') *local_assigns.fetch(:data, {}) disabled=local_assigns.fetch(:disabled, false) id=id title=local_assigns[:title] type='button'
button.btn class=local_assigns.fetch(:classes, 'btn-primary') *local_assigns.fetch(:data, {}) disabled=local_assigns.fetch(:disabled, false) id=id title=local_assigns[:title] type='button'
i.fa.fa-circle-o-notch.fa-spin
i class=icon
i class=(label.present? ? icon : "#{icon} m-0")
= label

View File

@@ -1,5 +1,5 @@
#editor-edit.panel-group.row.original-input data-exercise-id=@exercise.id
#editor-edit.original-input data-exercise-id=@exercise.id
#frames
.edit-frame
.editor-content.hidden
.editor
.editor-content.d-none
.editor.allow_ace_tooltip

View File

@@ -1,18 +1,18 @@
div id='sidebar-collapsed' class=(@exercise.hide_file_tree ? '' : 'hidden')
= render('editor_button', classes: 'btn-block btn-primary btn-sm', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-plus-square', id: 'sidebar-collapse-collapsed', label:'', title:t('exercises.editor.expand_action_sidebar'))
div id='sidebar-collapsed' class=(@exercise.hide_file_tree ? '' : 'd-none')
= render('editor_button', classes: 'btn-block btn-primary btn', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-plus-square', id: 'sidebar-collapse-collapsed', label:'', title:t('exercises.editor.expand_action_sidebar'))
- if @exercise.allow_file_creation and not @exercise.hide_file_tree?
= render('editor_button', classes: 'btn-block btn-primary btn-sm enforce-top-margin', data: {:'data-cause' => 'file', :'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-plus', id: 'create-file-collapsed', label:'', title: t('exercises.editor.create_file'))
= render('editor_button', classes: 'btn-block btn-primary btn enforce-top-margin', data: {:'data-cause' => 'file', :'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-plus', id: 'create-file-collapsed', label:'', title: t('exercises.editor.create_file'))
= render('editor_button', classes: 'btn-block btn-primary btn-sm enforce-top-margin', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-download', id: 'download-collapsed', label:'', title: t('exercises.editor.download'))
= render('editor_button', classes: 'btn-block btn-primary btn-sm enforce-top-margin', data: {:'data-message-confirm' => t('exercises.editor.confirm_start_over'), :'data-url' => reload_exercise_path(@exercise), :'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-history', id: 'start-over-collapsed', label:'', title: t('exercises.editor.start_over'))
- if !@course_token.blank?
= render('editor_button', classes: 'btn-block btn-primary btn-sm enforce-top-margin', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-search', id: 'sidebar-search-collapsed', label: '', title: t('search.search_in_forum'))
= render('editor_button', classes: 'btn-block btn-primary btn enforce-top-margin', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-download', id: 'download-collapsed', label:'', title: t('exercises.editor.download'))
= render('editor_button', classes: 'btn-block btn-primary btn enforce-top-margin', data: {:'data-message-confirm' => t('exercises.editor.confirm_start_over'), :'data-url' => reload_exercise_path(@exercise), :'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-history', id: 'start-over-collapsed', label:'', title: t('exercises.editor.start_over'))
//- if !@course_token.blank?
= render('editor_button', classes: 'btn-block btn-primary btn enforce-top-margin', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-search', id: 'sidebar-search-collapsed', label: '', title: t('search.search_in_forum'))
div id='sidebar-uncollapsed' class=(@exercise.hide_file_tree ? 'hidden' : '')
= render('editor_button', classes: 'btn-block btn-primary btn-sm', icon: 'fa fa-minus-square', id: 'sidebar-collapse', label: t('exercises.editor.collapse_action_sidebar'))
div id='sidebar-uncollapsed' class=(@exercise.hide_file_tree ? 'd-none' : '')
= render('editor_button', classes: 'btn-block btn-primary btn', icon: 'fa fa-minus-square', id: 'sidebar-collapse', label: t('exercises.editor.collapse_action_sidebar'))
div class=(@exercise.hide_file_tree ? 'hidden' : '')
div class=(@exercise.hide_file_tree ? 'd-none' : '')
hr
#files data-entries=FileTree.new(files).to_js_tree
@@ -20,11 +20,11 @@ div id='sidebar-uncollapsed' class=(@exercise.hide_file_tree ? 'hidden' : '')
hr
- if @exercise.allow_file_creation and not @exercise.hide_file_tree?
= render('editor_button', classes: 'btn-block btn-primary btn-sm', data: {:'data-cause' => 'file'}, icon: 'fa fa-plus', id: 'create-file', label: t('exercises.editor.create_file'))
= render('editor_button', classes: 'btn-block btn-warning btn-sm', data: {:'data-cause' => 'file', :'data-message-confirm' => t('shared.confirm_destroy')}, icon: 'fa fa-times', id: 'destroy-file', label: t('exercises.editor.destroy_file'))
= render('editor_button', classes: 'btn-block btn-primary btn', data: {:'data-cause' => 'file'}, icon: 'fa fa-plus', id: 'create-file', label: t('exercises.editor.create_file'))
= render('editor_button', classes: 'btn-block btn-warning btn', data: {:'data-cause' => 'file', :'data-message-confirm' => t('shared.confirm_destroy')}, icon: 'fa fa-times', id: 'destroy-file', label: t('exercises.editor.destroy_file'))
= render('editor_button', classes: 'btn-block btn-primary btn-sm enforce-top-margin', icon: 'fa fa-download', id: 'download', label: t('exercises.editor.download'))
= render('editor_button', classes: 'btn-block btn-primary btn-sm', data: {:'data-message-confirm' => t('exercises.editor.confirm_start_over'), :'data-url' => reload_exercise_path(@exercise)}, icon: 'fa fa-history', id: 'start-over', label: t('exercises.editor.start_over'))
= render('editor_button', classes: 'btn-block btn-primary btn enforce-top-margin', icon: 'fa fa-download', id: 'download', label: t('exercises.editor.download'))
= render('editor_button', classes: 'btn-block btn-primary btn', data: {:'data-message-confirm' => t('exercises.editor.confirm_start_over'), :'data-url' => reload_exercise_path(@exercise)}, icon: 'fa fa-history', id: 'start-over', label: t('exercises.editor.start_over'))
//- if !@course_token.blank?
.input-group.enforce-top-margin

View File

@@ -11,5 +11,5 @@
- else
= link_to(file.native_file.file.name_with_extension, file.native_file.url)
- else
.editor-content.hidden data-file-id=file.ancestor_id = file.content
.editor-content.d-none data-file-id=file.ancestor_id = file.content
.editor data-file-id=file.ancestor_id data-indent-size=file.file_type.indent_size data-mode=file.file_type.editor_mode data-read-only=file.read_only data-allow-auto-completion=exercise.allow_auto_completion.to_s data-id=file.id

View File

@@ -1,58 +1,60 @@
div id='output_sidebar_collapsed'
= render('editor_button', classes: 'btn-block btn-primary btn-sm', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'left'}, title: t('exercises.editor.expand_output_sidebar'), icon: 'fa fa-plus-square', id: 'toggle-sidebar-output-collapsed', label: '')
div id='output_sidebar_uncollapsed' class='hidden col-sm-12 enforce-bottom-margin' data-message-no-output=t('exercises.implement.no_output')
= render('editor_button', classes: 'btn-block btn-primary btn', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'left'}, title: t('exercises.editor.expand_output_sidebar'), icon: 'fa fa-plus-square', id: 'toggle-sidebar-output-collapsed', label: '')
div.h-100 id='output_sidebar_uncollapsed' class='d-none col-sm-12 enforce-bottom-margin' data-message-no-output=t('exercises.implement.no_output')
.row
= render('editor_button', classes: 'btn-block btn-primary btn-sm', icon: 'fa fa-minus-square', id: 'toggle-sidebar-output', label: t('exercises.editor.collapse_output_sidebar'))
= render('editor_button', classes: 'btn-block btn-primary btn', icon: 'fa fa-minus-square', id: 'toggle-sidebar-output', label: t('exercises.editor.collapse_output_sidebar'))
div.enforce-big-top-margin.hidden id='score_div'
#results
h2 = t('exercises.implement.results')
p.test-count == t('exercises.implement.test_count', count: 0)
ul.list-unstyled
ul#dummies.hidden.list-unstyled
li.panel.panel-default
.panel-heading
h3.panel-title == t('exercises.implement.file', filename: '', number: 0)
.panel-body
= row(label: 'exercises.implement.passed_tests', value: t('shared.out_of', maximum_value: 0, value: 0).html_safe)
= row(label: 'activerecord.attributes.submission.score', value: t('shared.out_of', maximum_value: 0, value: 0).html_safe)
= row(label: 'exercises.implement.feedback')
= row(label: 'exercises.implement.error_messages')
/= row(label: 'exercises.implement.output', value: link_to(t('shared.show'), '#'))
#score data-maximum-score=@exercise.maximum_score data-score=@submission.try(:score)
h4
span == "#{t('activerecord.attributes.submission.score')}:&nbsp;"
span.score
.progress
.progress-bar role='progressbar'
div.position-absolute.d-flex.mb-1.w-100 style="overflow: auto; left: 0; bottom: 0; height: calc(100% - 3rem);"
div.w-100
div.enforce-big-top-margin.d-none id='score_div'
#results
h2 = t('exercises.implement.results')
p.test-count == t('exercises.implement.test_count', count: 0)
ul.list-unstyled
ul#dummies.d-none.list-unstyled
li.card.mt-2
.card-header.py-2
h5.card-title.m-0 == t('exercises.implement.file', filename: '', number: 0)
.card-body.bg-white.text-dark
= row(label: 'exercises.implement.passed_tests', value: t('shared.out_of', maximum_value: 0, value: 0).html_safe)
= row(label: 'activerecord.attributes.submission.score', value: t('shared.out_of', maximum_value: 0, value: 0).html_safe)
= row(label: 'exercises.implement.feedback')
= row(label: 'exercises.implement.error_messages')
/= row(label: 'exercises.implement.output', value: link_to(t('shared.show'), '#'))
#score data-maximum-score=@exercise.maximum_score data-score=@submission.try(:score)
h4
span == "#{t('activerecord.attributes.submission.score')}:&nbsp;"
span.score
.progress
.progress-bar role='progressbar'
br
- if lti_outcome_service?(@exercise.id, external_user_id, consumer_id)
p.text-center = render('editor_button', classes: 'btn-lg btn-success', data: {:'data-url' => submit_exercise_path(@exercise)}, icon: 'fa fa-send', id: 'submit', label: t('exercises.editor.submit'))
- else
p.text-center = render('editor_button', classes: 'btn-lg btn-warning-outline', data: {:'data-placement' => 'bottom', :'data-tooltip' => true}, icon: 'fa fa-clock-o', id: 'submit_outdated', label: t('exercises.editor.exercise_deadline_passed'), title: t('exercises.editor.tooltips.exercise_deadline_passed'))
hr
div.enforce-big-top-margin
#turtlediv
canvas#turtlecanvas.hidden width=400 height=400
div.enforce-big-top-margin
#hint
.panel.panel-warning
.panel-heading = t('exercises.implement.hint')
.panel-body
div.enforce-big-top-margin
#prompt.input-group.hidden
span.input-group-addon data-prompt=t('exercises.editor.input') = t('exercises.editor.input')
input#prompt-input.form-control type='text'
span.input-group-btn
button#prompt-submit.btn.btn-primary type="button" = t('exercises.editor.send')
#error-hints
.heading = t('exercises.implement.error_hints.heading')
ul.body
#output
pre = t('exercises.implement.no_output_yet')
- if CodeOcean::Config.new(:code_ocean).read[:flowr][:enabled]
#flowrHint.panel.panel-info data-url=CodeOcean::Config.new(:code_ocean).read[:flowr][:url] role='tab'
.panel-heading = t('exercises.implement.flowr.heading')
.panel-body
br
- if lti_outcome_service?(@exercise.id, external_user_id, consumer_id)
p.text-center = render('editor_button', classes: 'btn-lg btn-success', data: {:'data-url' => submit_exercise_path(@exercise)}, icon: 'fa fa-send', id: 'submit', label: t('exercises.editor.submit'))
- else
p.text-center = render('editor_button', classes: 'btn-lg btn-secondary disabled', data: {:'data-placement' => 'bottom', :'data-tooltip' => true}, icon: 'fa fa-clock-o', id: 'submit_outdated', label: t('exercises.editor.exercise_deadline_passed'), title: t('exercises.editor.tooltips.exercise_deadline_passed'))
hr
div.enforce-big-top-margin
#turtlediv
canvas#turtlecanvas.d-none width=400 height=400
div.enforce-big-top-margin
#hint
.card.bg-warning.text-white
.card-header = t('exercises.implement.hint')
.card-body
div.enforce-big-top-margin
#prompt.input-group.d-none
div.input-group-prepend
span.input-group-text data-prompt=t('exercises.editor.input') = t('exercises.editor.input')
input#prompt-input.form-control type='text'
span.input-group-btn
button#prompt-submit.btn.btn-primary type="button" = t('exercises.editor.send')
#error-hints
.heading = t('exercises.implement.error_hints.heading')
ul.body
#output.mt-2
pre = t('exercises.implement.no_output_yet')
- if CodeOcean::Config.new(:code_ocean).read[:flowr][:enabled]
#flowrHint.card.text-white.bg-info data-url=CodeOcean::Config.new(:code_ocean).read[:flowr][:url] role='tab'
.card-header = t('exercises.implement.flowr.heading')
.card-body

View File

@@ -1,41 +1,42 @@
- id = f.object.id
li.panel.panel-default
.panel-heading role="tab" id="heading"
a.file-heading data-toggle="collapse" href="#collapse#{id}"
li.card.mt-2
.card-header role="tab" id="heading"
a.file-heading.collapsed data-toggle="collapse" href="#collapse#{id}"
div.clearfix role="button"
i class="fa" aria-hidden="true"
span = f.object.name
.panel-collapse.collapse class=('in' if f.object.name.nil?) id="collapse#{id}" role="tabpanel"
.panel-body
.card-collapse.collapse class=('in' if f.object.name.nil?) id="collapse#{id}" role="tabpanel"
.card-body
- if policy(f.object).destroy?
.clearfix
.btn.btn-warning.btn-sm.pull-right.delete-file data-file-url=code_ocean_file_path(id) = t('shared.destroy')
.btn.btn-warning.btn-sm.float-right.delete-file data-file-url=code_ocean_file_path(id) = t('shared.destroy')
.form-group
= f.label(:name, t('activerecord.attributes.file.name'))
= f.text_field(:name, class: 'form-control')
.form-group
= f.label(:path, t('activerecord.attributes.file.path'))
= f.text_field(:path, class: 'form-control')
.help-block = t('.hints.path')
.help-block.form-text = t('.hints.path')
.form-group
= f.label(:file_type_id, t('activerecord.attributes.file.file_type_id'))
= f.collection_select(:file_type_id, @file_types, :id, :name, {}, class: 'form-control')
.form-group
= f.label(:role, t('activerecord.attributes.file.role'))
= f.select(:role, CodeOcean::File::TEACHER_DEFINED_ROLES.map { |role| [t("files.roles.#{role}"), role] }, {include_blank: true}, class: 'form-control')
.checkbox
label
= f.check_box(:hidden)
.form-check
label.form-check-label
= f.check_box(:hidden, class: 'form-check-input')
= t('activerecord.attributes.file.hidden')
.checkbox
label
= f.check_box(:read_only)
.form-check.mb-3
label.form-check-label
= f.check_box(:read_only, class: 'form-check-input')
= t('activerecord.attributes.file.read_only')
.test-related-fields style="display: #{f.object.teacher_defined_test? ? 'initial' : 'none'};"
.form-group
= f.label(:name, t('activerecord.attributes.file.feedback_message'))
= f.text_area(:feedback_message, class: 'form-control', maxlength: 255)
.help-block = t('.hints.feedback_message')
.help-block.form-text = t('.hints.feedback_message')
.form-group
= f.label(:role, t('activerecord.attributes.file.weight'))
= f.number_field(:weight, class: 'form-control', min: 1, step: 'any')

View File

@@ -1,14 +1,14 @@
- execution_environments = ExecutionEnvironment.where('file_type_id IS NOT NULL').select(:file_type_id, :id)
- file_types = FileType.where('file_extension IS NOT NULL').select(:file_extension, :id)
= form_for(@exercise, data: {execution_environments: execution_environments, file_types: file_types}, multipart: true) do |f|
= form_for(@exercise, data: {execution_environments: execution_environments, file_types: file_types}, multipart: true, builder: PagedownFormBuilder) do |f|
= render('shared/form_errors', object: @exercise)
.form-group
= f.label(:title)
= f.text_field(:title, class: 'form-control', required: true)
.form-group
= f.label(:description)
= f.pagedown_editor :description
= f.pagedown :description, input_html: { preview: true, rows: 10 }
.form-group
= f.label(:execution_environment_id)
= f.collection_select(:execution_environment_id, @execution_environments, :id, :name, {}, class: 'form-control')
@@ -16,34 +16,34 @@
= f.label(:instructions)
= f.hidden_field(:instructions)
.form-control.markdown
.checkbox
label
= f.check_box(:public)
.form-check
label.form-check-label
= f.check_box(:public, class: 'form-check-input')
= t('activerecord.attributes.exercise.public')
.checkbox
label
= f.check_box(:hide_file_tree)
.form-check
label.form-check-label
= f.check_box(:hide_file_tree, class: 'form-check-input')
= t('activerecord.attributes.exercise.hide_file_tree')
.checkbox
label
= f.check_box(:allow_file_creation)
.form-check
label.form-check-label
= f.check_box(:allow_file_creation, class: 'form-check-input')
= t('activerecord.attributes.exercise.allow_file_creation')
.checkbox
label
= f.check_box(:allow_auto_completion)
.form-check.mb-3
label.form-check-label
= f.check_box(:allow_auto_completion, class: 'form-check-input')
= t('activerecord.attributes.exercise.allow_auto_completion')
.form-group
= f.label(t('activerecord.attributes.exercise.difficulty'))
= f.number_field :expected_difficulty, in: 1..10, step: 1
= f.number_field :expected_difficulty, in: 1..10, step: 1, class: 'form-control'
h2 = t('exercises.form.tags')
ul.list-unstyled.panel-group
li.panel.panel-default
.panel-heading role="tab" id="heading"
ul.list-unstyled.card-group
li.card
.card-header role="tab" id="heading"
a.file-heading data-toggle="collapse" href="#tag-collapse"
div.clearfix role="button"
span = t('exercises.form.click_to_collapse')
.panel-collapse.collapse id="tag-collapse" role="tabpanel"
.card-collapse.collapse id="tag-collapse" role="tabpanel"
.table-responsive
table.table#tags-table
thead
@@ -55,15 +55,15 @@
tr
td = b.check_box
td = b.object.tag.name
td = number_field "tag_factors[#{b.object.tag.id}]", :factor, :value => b.object.factor, in: 1..10, step: 1
td = number_field "tag_factors[#{b.object.tag.id}]", :factor, :value => b.object.factor, in: 1..10, step: 1, class: 'form-control-sm'
h2 = t('activerecord.attributes.exercise.files')
ul#files.list-unstyled.panel-group
ul#files.list-unstyled
= f.fields_for :files do |files_form|
= render('file_form', f: files_form)
a#add-file.btn.btn-default.btn-sm.pull-right href='#' = t('.add_file')
ul#dummies.hidden = f.fields_for(:files, CodeOcean::File.new, child_index: 'index') do |files_form|
a#add-file.btn.btn-secondary.btn-sm.float-right href='#' = t('.add_file')
ul#dummies.d-none = f.fields_for(:files, CodeOcean::File.new, child_index: 'index') do |files_form|
= render('file_form', f: files_form)
.actions = render('shared/submit_button', f: f, object: @exercise)

View File

@@ -2,7 +2,7 @@ h5#rfc_intervention_text style='display: none;' = t('exercises.implement.rfc_int
h5 = t('exercises.implement.comment.question')
textarea.form-control#question(style='resize:none;')
textarea.form-control.flex-grow-1#question(style='resize:none;')
p = ''
/ data-cause='requestComments' is not used here right now, we pass the button #requestComments (not askForCommentsButton) as initiator of the action.
/ But if we use this button, it will work since the correct cause is supplied

View File

@@ -10,21 +10,21 @@ h1 = "#{@exercise} (external user #{@external_user})"
- file_types.add(ActiveSupport::JSON.encode(file.file_type))
- all_files.push(submission.files)
.hidden#data data-submissions=ActiveSupport::JSON.encode(@submissions) data-files=ActiveSupport::JSON.encode(all_files) data-file-types=ActiveSupport::JSON.encode(file_types)
.d-none#data data-submissions=ActiveSupport::JSON.encode(@submissions) data-files=ActiveSupport::JSON.encode(all_files) data-file-types=ActiveSupport::JSON.encode(file_types)
#stats-editor.row
- index = 0
- all_files.each do |files|
.files class=(@exercise.hide_file_tree ? 'hidden col-sm-3' : 'col-sm-3') data-index=index data-entries=FileTree.new(files).to_js_tree
.files class=(@exercise.hide_file_tree ? 'd-none col-sm-3' : 'col-sm-3') data-index=index data-entries=FileTree.new(files).to_js_tree
- index += 1
div class=(@exercise.hide_file_tree ? 'col-sm-12' : 'col-sm-9')
#current-file.editor
.flex-container
button.btn.btn-default id='play-button'
button.btn.btn-secondary id='play-button'
span.fa.fa-play
#submissions-slider.flex-item
input type='range' orient='horizontal' list='datapoints' min=0 max=@submissions.length-1 value=0
input type='range' orient='horizontal' list='datapoints' min=0 max=@submissions.length-1 value=0 style="width: 100%"
datalist#datapoints
- index=0
- @submissions.each do |submission|
@@ -59,7 +59,7 @@ h1 = "#{@exercise} (external user #{@external_user})"
td =
td = @working_times_until[index] if index > 0
p = t('.addendum')
.hidden#wtimes data-working_times=ActiveSupport::JSON.encode(@working_times_until);
.d-none#wtimes data-working_times=ActiveSupport::JSON.encode(@working_times_until);
div#progress_chart.col-lg-12
.graph-functions-2

View File

@@ -8,17 +8,17 @@ h1 = link_to(@exercise, exercise_path(@exercise))
- if @feedbacks.nil? or @feedbacks.size == 0
.no-feedback = t('user_exercise_feedback.no_feedback')
ul.list-unstyled.panel-group
ul.list-unstyled
- @feedbacks.each do |feedback|
li.panel.panel-default
.panel-heading role="tab" id="heading"
li.card.mt-2
.card-header role="tab" id="heading"
div.clearfix.feedback-header
span.username = link_to(feedback.user.name, statistics_external_user_exercise_path(id: @exercise.id, external_user_id: feedback.user.id))
- if feedback.anomaly_notification
i class="fa fa-envelope-o" data-placement="top" data-toggle="tooltip" data-container="body" title=feedback.anomaly_notification.reason
span.date = feedback.created_at
.panel-collapse role="tabpanel"
.panel-body.feedback
.card-collapse role="tabpanel"
.card-body.feedback
.text = feedback.feedback_text
.difficulty = "#{t('user_exercise_feedback.difficulty')} #{feedback.difficulty}" if feedback.difficulty
.worktime = "#{t('user_exercise_feedback.working_time')} #{feedback.user_estimated_worktime}" if feedback.user_estimated_worktime

View File

@@ -2,13 +2,13 @@
#editor-column.col-md-12
.exercise.clearfix
div
span.badge.pull-right.score
span.badge.badge-pill.badge-primary.float-right.score
h1 id="exercise-headline"
i class="fa fa-chevron-down" id="description-symbol"
= @exercise.title
#description-panel.lead.description-panel
#description-card.lead.description-card
= render_markdown(@exercise.description)
a#toggle href="#" data-show=t('shared.show') data-hide=t('shared.hide') = t('shared.hide')

View File

@@ -9,45 +9,43 @@ h1 = Exercise.model_name.human(count: 2)
= f.search_field(:title_cont, class: 'form-control', placeholder: t('activerecord.attributes.exercise.title'))
.table-responsive
table.table
table.table.mt-4
thead
tr
th = sort_link(@search, :title, t('activerecord.attributes.exercise.title'))
th = sort_link(@search, :execution_environment_id, t('activerecord.attributes.exercise.execution_environment'))
th = t('.test_files')
th = t('activerecord.attributes.exercise.maximum_score')
th = t('activerecord.attributes.exercise.tags')
th = t('activerecord.attributes.exercise.difficulty')
th
th.p-1 = sort_link(@search, :title, t('activerecord.attributes.exercise.title'))
th.p-1 = sort_link(@search, :execution_environment_id, t('activerecord.attributes.exercise.execution_environment'))
th.p-1 = t('.test_files')
th.p-1 = t('activerecord.attributes.exercise.maximum_score')
th.p-1 = t('activerecord.attributes.exercise.tags')
th.p-1 = t('activerecord.attributes.exercise.difficulty')
th.p-1
= t('activerecord.attributes.exercise.public')
- if policy(Exercise).batch_update?
br
span.batch = link_to(t('shared.batch_update'), '#', 'data-text' => t('shared.update', model: t('activerecord.models.exercise.other')))
th colspan=6 = t('shared.actions')
th.p-1 colspan=6 = t('shared.actions')
tbody
- @exercises.each do |exercise|
tr data-id=exercise.id
td = exercise.title
td = link_to_if(exercise.execution_environment && policy(exercise.execution_environment).show?, exercise.execution_environment, exercise.execution_environment)
td = exercise.files.teacher_defined_tests.count
td = exercise.maximum_score
td = exercise.exercise_tags.count
td = exercise.expected_difficulty
td.public data-value=exercise.public? = symbol_for(exercise.public?)
td = link_to(t('shared.edit'), edit_exercise_path(exercise)) if policy(exercise).edit?
td = link_to(t('.implement'), implement_exercise_path(exercise)) if policy(exercise).implement?
td = link_to(t('shared.statistics'), statistics_exercise_path(exercise)) if policy(exercise).statistics?
td.p-1.pt-2 = link_to(exercise.title, exercise, 'data-turbolinks' => "false") if policy(exercise).show?
td.p-1.pt-2 = link_to_if(exercise.execution_environment && policy(exercise.execution_environment).show?, exercise.execution_environment, exercise.execution_environment)
td.p-1.pt-2 = exercise.files.teacher_defined_tests.count
td.p-1.pt-2 = exercise.maximum_score
td.p-1.pt-2 = exercise.exercise_tags.count
td.p-1.pt-2 = exercise.expected_difficulty
td.p-1.pt-2.public data-value=exercise.public? = symbol_for(exercise.public?)
td.p-1.pt-2 = link_to(t('shared.edit'), edit_exercise_path(exercise)) if policy(exercise).edit?
td.p-1.pt-2 = link_to(t('.implement'), implement_exercise_path(exercise)) if policy(exercise).implement?
td.p-1.pt-2 = link_to(t('shared.statistics'), statistics_exercise_path(exercise), 'data-turbolinks' => "false") if policy(exercise).statistics?
td
td.p-1
.btn-group
button.btn.btn-primary-outline.btn-xs.dropdown-toggle data-toggle="dropdown" type="button" = t('shared.actions_button')
span.caret
span.sr-only Toggle Dropdown
ul.dropdown-menu.pull-right role="menu"
li = link_to(t('shared.show'), exercise) if policy(exercise).show?
li = link_to(t('activerecord.models.user_exercise_feedback.other'), feedback_exercise_path(exercise)) if policy(exercise).feedback?
li = link_to(t('shared.destroy'), exercise, data: {confirm: t('shared.confirm_destroy')}, method: :delete) if policy(exercise).destroy?
li = link_to(t('.clone'), clone_exercise_path(exercise), data: {confirm: t('shared.confirm_destroy')}, method: :post) if policy(exercise).clone?
button.btn.btn-outline-primary.btn-sm.dropdown-toggle data-toggle="dropdown" type="button" = t('shared.actions_button')
ul.dropdown-menu.float-right role="menu"
li = link_to(t('shared.show'), exercise, 'data-turbolinks' => "false", class: 'dropdown-item') if policy(exercise).show?
li = link_to(t('activerecord.models.user_exercise_feedback.other'), feedback_exercise_path(exercise), class: 'dropdown-item') if policy(exercise).feedback?
li = link_to(t('shared.destroy'), exercise, data: {confirm: t('shared.confirm_destroy')}, method: :delete, class: 'dropdown-item') if policy(exercise).destroy?
li = link_to(t('.clone'), clone_exercise_path(exercise), data: {confirm: t('shared.confirm_destroy')}, method: :post, class: 'dropdown-item') if policy(exercise).clone?
= render('shared/pagination', collection: @exercises)
p = render('shared/new_button', model: Exercise)

View File

@@ -1,6 +1,9 @@
- content_for :head do
= javascript_include_tag('http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/highlight.min.js')
= stylesheet_link_tag('http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/default.min.css')
// Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326.
Otherwise, code might not be highlighted correctly (race condition)
meta name='turbolinks-visit-control' content='reload'
= javascript_pack_tag('highlight', 'data-turbolinks-track': true)
= stylesheet_pack_tag('highlight', media: 'all', 'data-turbolinks-track': true)
h1
= @exercise
@@ -9,7 +12,7 @@ h1
= row(label: 'exercise.title', value: @exercise.title)
= row(label: 'exercise.user', value: link_to_if(policy(@exercise.author).show?, @exercise.author, @exercise.author))
= row(label: 'exercise.description', value: render_markdown(@exercise.description))
= row(label: 'exercise.description', value: render_markdown(@exercise.description), class: 'm-0')
= row(label: 'exercise.execution_environment', value: link_to_if(policy(@exercise.execution_environment).show?, @exercise.execution_environment, @exercise.execution_environment))
/= row(label: 'exercise.instructions', value: render_markdown(@exercise.instructions))
= row(label: 'exercise.maximum_score', value: @exercise.maximum_score)
@@ -17,24 +20,23 @@ h1
= row(label: 'exercise.hide_file_tree', value: @exercise.hide_file_tree?)
= row(label: 'exercise.allow_file_creation', value: @exercise.allow_file_creation?)
= row(label: 'exercise.allow_auto_completion', value: @exercise.allow_auto_completion?)
= row(label: 'exercise.embedding_parameters') do
= content_tag(:input, nil, class: 'form-control', readonly: true, value: embedding_parameters(@exercise))
= row(label: 'exercise.difficulty', value: @exercise.expected_difficulty)
= row(label: 'exercise.tags', value: @exercise.exercise_tags.map{|et| "#{et.tag.name} (#{et.factor})"}.sort.join(", "))
= row(label: 'exercise.embedding_parameters', class: 'mb-4') do
= content_tag(:input, nil, class: 'form-control mb-4', readonly: true, value: embedding_parameters(@exercise))
h2 = t('activerecord.attributes.exercise.files')
h2.mt-4 = t('activerecord.attributes.exercise.files')
ul.list-unstyled.panel-group#files
- @exercise.files.order('name').each do |file|
li.panel.panel-default
.panel-heading role="tab" id="heading"
a.file-heading data-toggle="collapse" data-parent="#files" href=".collapse#{file.id}"
ul.list-unstyled#files
- @exercise.files.each do |file|
li.card.mt-2
.card-header role="tab" id="heading"
a.file-heading.collapsed data-toggle="collapse" data-parent="#files" href=".collapse#{file.id}"
div.clearfix role="button"
i class="fa" aria-hidden="true"
span = file.name_with_extension
// probably set an icon here that shows that the rows can be collapsed
//span.pull-right.collapse.in class="collapse#{file.id}" &#9788
.panel-collapse.collapse class="collapse#{file.id}" role="tabpanel"
.panel-body
.card-collapse.collapse class="collapse#{file.id}" role="tabpanel"
.card-body
- if policy(file).destroy?
.clearfix = link_to(t('shared.destroy'), file, class:'btn btn-warning btn-sm pull-right', data: {confirm: t('shared.confirm_destroy')}, method: :delete)
.clearfix = link_to(t('shared.destroy'), file, class:'btn btn-warning btn-sm float-right', data: {confirm: t('shared.confirm_destroy')}, method: :delete)
= render('shared/file', file: file)

View File

@@ -1,4 +1,8 @@
script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"
- content_for :head do
// Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326.
Otherwise, code might not be highlighted correctly (race condition)
meta name='turbolinks-visit-control' content='reload'
= javascript_pack_tag('d3-tip', 'data-turbolinks-track': true)
h1 = @exercise
= row(label: '.participants', value: @exercise.users.distinct.count)
@@ -28,12 +32,12 @@ h1 = @exercise
-working_time = @exercise.average_working_time_for(user.id) or 0
-working_time_array.push working_time
hr
.hidden#data data-working-time=ActiveSupport::JSON.encode(working_time_array)
.d-none#data data-working-time=ActiveSupport::JSON.encode(working_time_array)
.graph-functions
div#chart_1
hr
/div#chart_2
/hr
div#chart_2
hr
.table-responsive
table.table.table-striped.sortable
thead

View File

@@ -4,9 +4,9 @@ h1 = @user.name
//= row(label: 'external_user.email', value: @user.email)
= row(label: 'external_user.consumer', value: link_to(@user.consumer, @user.consumer))
h4 = link_to(t('.exercise_statistics'), statistics_external_user_path(@user))
h4.mt-4 = link_to(t('.exercise_statistics'), statistics_external_user_path(@user))
h4 = t('.tag_statistics')
h4.mt-4 = t('.tag_statistics')
#loading
.spinner
= t('.loading_tag_statistics')

View File

@@ -10,7 +10,7 @@ h1 = FileTemplate.model_name.human(count: 2)
tbody
- @file_templates.each do |file_template|
tr
td = file_template.name
td = link_to(file_template.name, file_template)
td = link_to(file_template.file_type, file_type_path(file_template.file_type))
td = link_to(t('shared.show'), file_template)
td = link_to(t('shared.edit'), edit_file_template_path(file_template))

View File

@@ -12,16 +12,16 @@
.form-group
= f.label(:indent_size)
= f.number_field(:indent_size, class: 'form-control', placeholder: 2, required: true)
.checkbox
label
= f.check_box(:binary)
.form-check
label.form-check-label
= f.check_box(:binary, class: 'form-check-input')
= t('activerecord.attributes.file_type.binary')
.checkbox
label
= f.check_box(:executable)
.form-check
label.form-check-label
= f.check_box(:executable, class: 'form-check-input')
= t('activerecord.attributes.file_type.executable')
.checkbox
label
= f.check_box(:renderable)
.form-check.mb-3
label.form-check-label
= f.check_box(:renderable, class: 'form-check-input')
= t('activerecord.attributes.file_type.renderable')
.actions = render('shared/submit_button', f: f, object: @file_type)

View File

@@ -11,7 +11,7 @@ h1 = FileType.model_name.human(count: 2)
tbody
- @file_types.each do |file_type|
tr
td = file_type.name
td = link_to(file_type.name, file_type)
td = link_to(file_type.author, file_type.author)
td = file_type.file_extension
td = link_to(t('shared.show'), file_type)

View File

@@ -0,0 +1 @@
json.extract! @file_type, :id, :name, :editor_mode, :file_extension, :executable, :renderable, :binary

View File

@@ -3,15 +3,15 @@
.form-group
= f.label(:name)
= f.text_field(:name, class: 'form-control', required: true)
.form
.form-group
= f.label(:locale)
= f.select(:locale, I18n.available_locales.map { |locale| [t("locales.#{locale}"), locale] }, {}, class: 'form-control')
.form-group
= f.label(:message)
= f.text_field(:message, class: 'form-control', placeholder: "'$2' has no method '$1'.", required: true)
.help-block = t('.hints.message')
.help-block.form-text = t('.hints.message')
.form-group
= f.label(:regular_expression)
= f.text_field(:regular_expression, class: 'form-control', placeholder: 'undefined method (\w+) for (\w+)', required: true)
.help-block = t('.hints.regular_expression')
.help-block.form-text = t('.hints.regular_expression')
.actions = render('shared/submit_button', f: f, object: @hint)

View File

@@ -5,7 +5,7 @@
= f.collection_select(:consumer_id, Consumer.all.sort_by(&:name), :id, :name, {}, class: 'form-control')
.form-group
= f.label(:email)
= f.text_field(:email, class: 'form-control', required: true)
= f.email_field(:email, class: 'form-control', required: true)
.form-group
= f.label(:name)
= f.text_field(:name, class: 'form-control', required: true)

View File

@@ -9,4 +9,4 @@ h1 = t('.headline')
= f.label(:password_confirmation)
= f.password_field(:password_confirmation, class: 'form-control', required: true)
= f.hidden_field(:activation_token)
.actions = submit_tag(t('.submit'), class: 'btn btn-default')
.actions = submit_tag(t('.submit'), class: 'btn btn-primary')

View File

@@ -3,5 +3,5 @@ h1 = t('.headline')
= form_tag do
.form-group
= label_tag(:email, t('activerecord.attributes.internal_user.email'))
= text_field_tag(:email, params[:email], autofocus: true, class: 'form-control', required: true)
.actions = submit_tag(t('.submit'), class: 'btn btn-default')
= email_field_tag(:email, params[:email], autofocus: true, class: 'form-control', required: true)
.actions = submit_tag(t('.submit'), class: 'btn btn-primary')

View File

@@ -12,7 +12,7 @@ h1 = InternalUser.model_name.human(count: 2)
= f.select(:role_eq, User::ROLES.map { |role| [t("users.roles.#{role}"), role] }, {}, class: 'form-control', prompt: t('activerecord.attributes.internal_user.role'))
.table-responsive
table.table
table.table.mt-4
thead
tr
th = t('activerecord.attributes.internal_user.name')

View File

@@ -9,4 +9,4 @@ h1 = t('.headline')
= f.label(:password_confirmation)
= f.password_field(:password_confirmation, class: 'form-control', required: true)
= f.hidden_field(:reset_password_token)
.actions = submit_tag(t('.submit'), class: 'btn btn-default')
.actions = submit_tag(t('.submit'), class: 'btn btn-primary')

View File

@@ -5,35 +5,30 @@ html lang='en'
meta name='viewport' content='width=device-width, initial-scale=1'
title = application_name
link href=asset_path('favicon.png') rel='icon' type='image/png'
= stylesheet_link_tag(asset_path('bootstrap.min.css', type: :stylesheet))
= stylesheet_link_tag(asset_path('font-awesome.min.css', type: :stylesheet))
= stylesheet_link_tag('application', media: 'all', 'data-turbolinks-track' => true)
= javascript_include_tag('application', 'data-turbolinks-track' => true)
= javascript_include_tag(asset_path('underscore-min.js', type: :javascript))
= javascript_include_tag(asset_path('bootstrap.min.js', type: :javascript))
= stylesheet_pack_tag('application', media: 'all', 'data-turbolinks-track': true)
= stylesheet_pack_tag('stylesheets', media: 'all', 'data-turbolinks-track': true)
= stylesheet_link_tag('application', media: 'all', 'data-turbolinks-track': true)
= javascript_pack_tag('application', 'data-turbolinks-track': true)
= javascript_include_tag('application', 'data-turbolinks-track': true)
= yield(:head)
= csrf_meta_tags
body
nav.navbar.navbar-default role='navigation'
nav.navbar.navbar-dark.bg-dark.navbar-expand-md.mb-4.py-1 role='navigation'
.container
.navbar-header
button.navbar-toggle data-target='#navbar-collapse' data-toggle='collapse' type='button'
span.sr-only Toggle navigation
span.icon-bar
span.icon-bar
span.icon-bar
.navbar-brand
i.fa.fa-code
= application_name
.navbar-brand
i.fa.fa-code
= application_name
button.navbar-toggler data-target='#navbar-collapse' data-toggle='collapse' type='button' aria-expanded='false' aria-label='Toggle navigation'
span.navbar-toggler-icon
#navbar-collapse.collapse.navbar-collapse
= render('navigation', cached: true)
ul.nav.navbar-nav.navbar-right
ul.nav.navbar-nav.ml-auto
= render('locale_selector', cached: true)
li = link_to(t('shared.help.link'), '#modal-help', data: {toggle: 'modal'})
li.nav-item.mr-3 = link_to(t('shared.help.link'), '#modal-help', data: {toggle: 'modal'}, class: 'nav-link')
= render('session')
.container data-controller=controller_name
= render('flash')
= render('breadcrumbs')
= render('breadcrumbs') if current_user.try(:internal_user?)
- if (controller_name == "exercises" && action_name == "implement")
.container-fluid
= yield

View File

@@ -1,11 +1,11 @@
= form_for(@proxy_exercise, multipart: true) do |f|
= form_for(@proxy_exercise, multipart: true, builder: PagedownFormBuilder) do |f|
= render('shared/form_errors', object: @proxy_exercise)
.form-group
= f.label(:title)
= f.text_field(:title, class: 'form-control', required: true)
.form-group
= f.label(:description)
= f.pagedown_editor :description
= f.pagedown :description, input_html: { preview: true, rows: 10 }
h3 Exercises
.table-responsive

View File

@@ -6,30 +6,30 @@ h1 = ProxyExercise.model_name.human(count: 2)
= f.search_field(:title_cont, class: 'form-control', placeholder: t('activerecord.attributes.proxy_exercise.title'))
.table-responsive
table.table
table.table.mt-4
thead
tr
th = sort_link(@search, :title, t('activerecord.attributes.proxy_exercise.title'))
th = t('activerecord.attributes.exercise.token')
th = t('activerecord.attributes.proxy_exercise.files_count')
th colspan=6 = t('shared.actions')
th.p-1 = sort_link(@search, :title, t('activerecord.attributes.proxy_exercise.title'))
th.p-1 = t('activerecord.attributes.exercise.token')
th.p-1 = t('activerecord.attributes.proxy_exercise.files_count')
th.p-1 colspan=6 = t('shared.actions')
tbody
- @proxy_exercises.each do |proxy_exercise|
tr data-id=proxy_exercise.id
td = link_to(proxy_exercise.title,proxy_exercise)
td = proxy_exercise.token
td = proxy_exercise.count_files
td = link_to(t('shared.edit'), edit_proxy_exercise_path(proxy_exercise)) if policy(proxy_exercise).edit?
td.p-1.pt-2 = link_to(proxy_exercise.title,proxy_exercise)
td.p-1.pt-2 = proxy_exercise.token
td.p-1.pt-2 = proxy_exercise.count_files
td.p-1.pt-2 = link_to(t('shared.edit'), edit_proxy_exercise_path(proxy_exercise)) if policy(proxy_exercise).edit?
td
td.p-1
.btn-group
button.btn.btn-primary-outline.btn-xs.dropdown-toggle data-toggle="dropdown" type="button" = t('shared.actions_button')
button.btn.btn-outline-primary.btn-sm.dropdown-toggle data-toggle="dropdown" type="button" = t('shared.actions_button')
span.caret
span.sr-only Toggle Dropdown
ul.dropdown-menu.pull-right role="menu"
li = link_to(t('shared.show'), proxy_exercise) if policy(proxy_exercise).show?
li = link_to(t('shared.destroy'), proxy_exercise, data: {confirm: t('shared.confirm_destroy')}, method: :delete) if policy(proxy_exercise).destroy?
li = link_to(t('.clone'), clone_proxy_exercise_path(proxy_exercise), data: {confirm: t('shared.confirm_destroy')}, method: :post) if policy(proxy_exercise).clone?
ul.dropdown-menu.float-right role="menu"
li = link_to(t('shared.show'), proxy_exercise, 'data-turbolinks' => "false", class: 'dropdown-item') if policy(proxy_exercise).show?
li = link_to(t('shared.destroy'), proxy_exercise, data: {confirm: t('shared.confirm_destroy')}, method: :delete, class: 'dropdown-item') if policy(proxy_exercise).destroy?
li = link_to(t('.clone'), clone_proxy_exercise_path(proxy_exercise), data: {confirm: t('shared.confirm_destroy')}, method: :post, class: 'dropdown-item') if policy(proxy_exercise).clone?
= render('shared/pagination', collection: @proxy_exercises)
p = render('shared/new_button', model: ProxyExercise)

View File

@@ -1,6 +1,9 @@
- content_for :head do
= javascript_include_tag('http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/highlight.min.js')
= stylesheet_link_tag('http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/default.min.css')
// Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326.
Otherwise, code might not be highlighted correctly (race condition)
meta name='turbolinks-visit-control' content='reload'
= javascript_pack_tag('highlight', 'data-turbolinks-track': true)
= stylesheet_pack_tag('highlight', media: 'all', 'data-turbolinks-track': true)
h1
= @proxy_exercise.title
@@ -11,7 +14,8 @@ h1
= row(label: 'proxy_exercise.files_count', value: @exercises.count)
= row(label: 'exercise.description', value: @proxy_exercise.description)
= row(label: 'exercise.token', value: @proxy_exercise.token)
h3 Exercises
h2.mt-4 Exercises
.table-responsive
table.table
thead

View File

@@ -1,9 +1,8 @@
br
h4 Admin Menu
h5
ul
li = link_to "User's current status of this exercise", statistics_external_user_exercise_path(id: @request_for_comment.exercise_id, external_user_id: @request_for_comment.user_id)
li = link_to "All exercises of this user", statistics_external_user_path(id: @request_for_comment.user_id)
ul
li = link_to "Implement the exercise yourself", implement_exercise_path(id: @request_for_comment.exercise_id)
li = link_to "Show the exercise", exercise_path(id: @request_for_comment.exercise_id)
hr
h5.mt-4 Admin Menu
ul.text
li = link_to "User's current status of this exercise", statistics_external_user_exercise_path(id: @request_for_comment.exercise_id, external_user_id: @request_for_comment.user_id)
li = link_to "All exercises of this user", statistics_external_user_path(id: @request_for_comment.user_id)
ul.text
li = link_to "Implement the exercise yourself", implement_exercise_path(id: @request_for_comment.exercise_id)
li = link_to "Show the exercise", exercise_path(id: @request_for_comment.exercise_id)

View File

@@ -1,33 +0,0 @@
<%= form_for(@request_for_comment) do |f| %>
<% if @request_for_comment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@request_for_comment.errors.count, "error") %> prohibited this request_for_comment from being saved:</h2>
<ul>
<% @request_for_comment.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :user_id %><br>
<%= f.number_field :user_id %>
</div>
<div class="field">
<%= f.label :exercise_id %><br>
<%= f.number_field :exercise_id %>
</div>
<div class="field">
<%= f.label :file_id %><br>
<%= f.number_field :file_id %>
</div>
<div class="field">
<%= f.label :user_type %><br>
<%= f.text_field :user_type %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

View File

@@ -0,0 +1,28 @@
= form_for(@request_for_comment) do |f|
- if @request_for_comment.errors.any?
#error_explanation
h2
= pluralize(@request_for_comment.errors.count, "error")
| prohibited this request_for_comment from being saved:
ul
- @request_for_comment.errors.full_messages.each do |message|
li= message
.field
= f.label :user_id
br/
= f.number_field :user_id
.field
= f.label :exercise_id
br/
= f.number_field :exercise_id
.field
= f.label :file_id
br/
= f.number_field :file_id
.field
= f.label :user_type
br/
= f.text_field :user_type
.actions
= f.submit

View File

@@ -4,4 +4,4 @@ button.btn.btn-primary#mark-as-solved-button = t('request_for_comments.mark_as_s
p = t('request_for_comments.write_a_thank_you_node')
textarea#thank-you-note
button.btn.btn-primary#send-thank-you-note = t('request_for_comments.send_thank_you_note')
button.btn.btn-default#cancel-thank-you-note = t('request_for_comments.cancel_thank_you_note')
button.btn.btn-secondary#cancel-thank-you-note = t('request_for_comments.cancel_thank_you_note')

View File

@@ -9,7 +9,7 @@ h1 = RequestForComment.model_name.human(count: 2)
= f.select(:solved_not_eq, [[t('request_for_comments.show_all'), 2], [t('request_for_comments.show_unsolved'), 1], [t('request_for_comments.show_solved'), 0]])
.table-responsive
table.table.sortable
table.table.sortable.mt-4
thead
tr
th
@@ -23,8 +23,7 @@ h1 = RequestForComment.model_name.human(count: 2)
th = t('activerecord.attributes.request_for_comments.last_update')
tbody
- @request_for_comments.each do |request_for_comment|
- do_not_answer = [:rfc_intervention_stale_rfc, :break_intervention_stale_rfc, :no_intervention_stale_rfc].include?(UserGroupSeparator.getInterventionGroup(request_for_comment.user)) and current_user.internal_user?
tr data-id=request_for_comment.id class=('do-not-answer' if do_not_answer)
tr data-id=request_for_comment.id
- if request_for_comment.solved?
td
span class="fa fa-check" aria-hidden="true"
@@ -39,7 +38,7 @@ h1 = RequestForComment.model_name.human(count: 2)
- else
td = '-'
td = request_for_comment.comments_count
td = request_for_comment.user.displayname
td = link_to_if(request_for_comment.user && policy(request_for_comment.user).show?, request_for_comment.user.displayname, request_for_comment.user)
td = t('shared.time.before', time: distance_of_time_in_words_to_now(request_for_comment.created_at))
td = t('shared.time.before', time: distance_of_time_in_words_to_now(request_for_comment.last_comment.nil? ? request_for_comment.updated_at : request_for_comment.last_comment))

View File

@@ -1,116 +1,87 @@
<div class="list-group">
<h4 id ="exercise_caption" class="list-group-item-heading" data-exercise-id="<%=@request_for_comment.exercise.id%>" data-comment-exercise-url="<%=create_comment_exercise_request_for_comment_path%>" data-rfc-id = "<%= @request_for_comment.id %>" >
<% if @request_for_comment.solved? %>
<span class="fa fa-check" aria-hidden="true"></span>
<% end %>
<%= link_to(@request_for_comment.exercise.title, [:implement, @request_for_comment.exercise]) %>
</h4>
<p class="list-group-item-text">
<%
user = @request_for_comment.user
submission = @request_for_comment.submission
testruns = Testrun.where(:submission_id => @request_for_comment.submission)
%>
<%= user.displayname %> | <%= @request_for_comment.created_at.localtime %>
</p>
<div class="rfc">
<div class="description">
<h5>
<%= t('activerecord.attributes.exercise.description') %>
</h5>
<div class="text">
<span class="fa fa-chevron-up collapse-button"></span>
<%= render_markdown(@request_for_comment.exercise.description) %>
</div>
</div>
.list-group
h4#exercise_caption.list-group-item-heading data-comment-exercise-url=create_comment_exercise_request_for_comment_path data-exercise-id="#{@request_for_comment.exercise.id}" data-rfc-id="#{@request_for_comment.id}"
- if @request_for_comment.solved?
span.fa.fa-check aria-hidden="true"
= link_to(@request_for_comment.exercise.title, [:implement, @request_for_comment.exercise])
p.list-group-item-text
- user = @request_for_comment.user
- submission = @request_for_comment.submission
- testruns = Testrun.where(:submission_id => @request_for_comment.submission)
= user.displayname
| | #{@request_for_comment.created_at.localtime}
.rfc
.description
h5
= t('activerecord.attributes.exercise.description')
.text
span.fa.fa-chevron-up.collapse-button
= render_markdown(@request_for_comment.exercise.description)
<div class="question">
<h5>
<%= t('activerecord.attributes.request_for_comments.question')%>
</h5>
<div class="text">
<% question = @request_for_comment.question %>
<%= question.nil? or question.empty? ? t('request_for_comments.no_question') : question %>
</div>
</div>
.question
h5.mt-4
= t('activerecord.attributes.request_for_comments.question')
.text
- question = @request_for_comment.question
= question.nil? or question.empty? ? t('request_for_comments.no_question') : question
<% if policy(@request_for_comment).mark_as_solved? and not @request_for_comment.solved? %>
<%= render('mark_as_solved') %>
<% end %>
<% if testruns.size > 0 %>
<div class="testruns">
<% output_runs = testruns.select { |run| run.cause == 'run' } %>
<% if output_runs.size > 0 %>
<h5><%= t('request_for_comments.runtime_output') %></h5>
<div class="collapsed testrun-output text">
<span class="fa fa-chevron-down collapse-button"></span>
<% output_runs.each do |testrun| %>
<%
output = testrun.try(:output)
if output
messages = output.scan(/{(?:(?:".+?":".+?")+?,?)+}/)
messages.map! {|el| JSON.parse(el)}
messages.keep_if {|message| message['cmd'] == 'write'}
messages.map! {|message| message['data']}
output = messages.join ''
end
%>
<pre><%= output or t('request_for_comments.no_output') %></pre>
<% end %>
</div>
<% end %>
- if policy(@request_for_comment).mark_as_solved? and not @request_for_comment.solved?
= render('mark_as_solved')
<% assess_runs = testruns.select { |run| run.cause == 'assess' } %>
<% if assess_runs.size > 0 %>
<h5><%= t('request_for_comments.test_results') %></h5>
<div class="testrun-assess-results">
<% assess_runs.each do |testrun| %>
<div class="testrun-container">
<div class="result <%= testrun.passed ? 'passed' : 'failed' %>"></div>
<div class="collapsed testrun-output text">
<span class="fa fa-chevron-down collapse-button"></span>
<pre><%= testrun.output or t('request_for_comments.no_output')%></pre>
</div>
</div>
<% end %>
</div>
<% end %>
</div>
<% end %>
- if testruns.size > 0
.testruns
- output_runs = testruns.select {|run| run.cause == 'run'}
- if output_runs.size > 0
h5.mt-4= t('request_for_comments.runtime_output')
.collapsed.testrun-output.text
span.fa.fa-chevron-down.collapse-button
- output_runs.each do |testrun|
- output = testrun.try(:output)
- if output
- messages = output.scan(/{(?:(?:".+?":".+?")+?,?)+}/)
- messages.map! {|el| JSON.parse(el)}
- messages.keep_if {|message| message['cmd'] == 'write'}
- messages.map! {|message| message['data']}
- output = messages.join ''
pre= output or t('request_for_comments.no_output')
<% if @current_user.admin? && user.is_a?(ExternalUser) %>
<%= render('admin_menu') %>
<% end %>
- assess_runs = testruns.select {|run| run.cause == 'assess'}
- if assess_runs.size > 0
h5.mt-4= t('request_for_comments.test_results')
.testrun-assess-results
- assess_runs.each do |testrun|
.testrun-container
div class=("result #{testrun.passed ? 'passed' : 'failed'}")
.collapsed.testrun-output.text
span.fa.fa-chevron-down.collapse-button
pre= testrun.output or t('request_for_comments.no_output')
<hr>
- if @current_user.admin? && user.is_a?(ExternalUser)
= render('admin_menu')
<div class="howto">
<h5>
<%= t('request_for_comments.howto_title') %>
</h5>
<div class="text">
<%= render_markdown(t('request_for_comments.howto')) %>
</div>
</div>
</div>
</div>
hr/
<div class="hidden sanitizer"></div>
<!--
do not put a carriage return in the line below. it will be present in the presentation of the source code, otherwise.
also, all settings from the rails model needed for the editor configuration in the JavaScript are attached to the editor as data attributes here.
-->
<% submission.files.each do |file| %>
<%= (file.path or "") + "/" + file.name + file.file_type.file_extension %><br>
&nbsp;&nbsp;<i class="fa fa-arrow-down" aria-hidden="true"></i> <%= t('request_for_comments.click_here') %>
<div id='commentitor' class='editor' data-read-only='true' data-file-id='<%=file.id%>' data-mode='<%=file.file_type.editor_mode%>'><%= file.content %>
</div>
<% end %>
.howto
h5.mt-4
= t('request_for_comments.howto_title')
.text
= render_markdown(t('request_for_comments.howto'))
<%= render('shared/modal', id: 'comment-modal', title: t('exercises.implement.comment.dialogtitle'), template: 'exercises/_comment_dialogcontent') %>
.d-none.sanitizer
/!
| do not put a carriage return in the line below. it will be present in the presentation of the source code, otherwise.
| also, all settings from the rails model needed for the editor configuration in the JavaScript are attached to the editor as data attributes here.
- submission.files.each do |file|
= (file.path or "") + "/" + file.name + file.file_type.file_extension
br/
|   
i.fa.fa-arrow-down aria-hidden="true"
= t('request_for_comments.click_here')
#commentitor.editor data-file-id="#{file.id}" data-mode="#{file.file_type.editor_mode}" data-read-only="true"
= file.content
<script type="text/javascript">
= render('shared/modal', id: 'comment-modal', title: t('exercises.implement.comment.dialogtitle'), template: 'exercises/_comment_dialogcontent')
javascript:
$('.modal-content').draggable({
handle: '.modal-header'
@@ -132,7 +103,7 @@ also, all settings from the rails model needed for the editor configuration in t
if(response.solved){
solvedButton.removeClass('btn-primary');
solvedButton.addClass('btn-success');
solvedButton.html('<%= t('request_for_comments.solved') %>');
solvedButton.html("#{t('request_for_comments.solved')}");
solvedButton.off('click');
thankYouContainer.show();
}
@@ -205,16 +176,16 @@ also, all settings from the rails model needed for the editor configuration in t
<div class="comment-header"> \
<div class="comment-username">' + preprocess(comment.username) + '</div> \
<div class="comment-date">' + comment.date + '</div> \
<div class="comment-updated' + (comment.updated ? '' : ' hidden') + '"> \
<div class="comment-updated' + (comment.updated ? '' : ' d-none') + '"> \
<i class="fa fa-pencil" aria-hidden="true"></i> \
<%= t('request_for_comments.comment_edited') %> \
#{{ t('request_for_comments.comment_edited') }} \
</div> \
</div> \
<div class="comment-content">' + commentText + '</div> \
<textarea class="comment-editor">' + commentText + '</textarea> \
<div class="comment-actions' + (comment.editable ? '' : ' hidden') + '"> \
<button class="action-edit btn btn-xs btn-warning"><%= t('shared.edit') %></button> \
<button class="action-delete btn btn-xs btn-danger"><%= t('shared.destroy') %></button> \
<div class="comment-actions' + (comment.editable ? '' : ' d-none') + '"> \
<button class="action-edit btn btn-sm btn-warning">#{ t('shared.edit') }</button> \
<button class="action-delete btn btn-sm btn-danger">#{ t('shared.destroy') }</button> \
</div> \
</div>';
});
@@ -227,7 +198,7 @@ also, all settings from the rails model needed for the editor configuration in t
var htmlContent = generateCommentHtmlContent(comments.reverse().slice(0, maxComments));
if (comments.length > maxComments) {
// add a hint that there are more comments than shown here
htmlContent += '<div class="popover-footer"><%= t('request_for_comments.click_for_more_comments') %></div>'
htmlContent += '<div class="popover-footer">#{ t('request_for_comments.click_for_more_comments') }</div>'
.replace('${numComments}', String(comments.length - maxComments));
}
where.popover({
@@ -380,7 +351,7 @@ also, all settings from the rails model needed for the editor configuration in t
$(target).popover('show');
$(target).on('mouseleave', function () {
$(this).off('mouseleave');
$(this).popover('destroy');
$(this).popover('dispose');
});
}
@@ -398,7 +369,7 @@ also, all settings from the rails model needed for the editor configuration in t
var row = e.getDocumentPosition().row;
e.stop();
$('.modal-title').text('<%= t('request_for_comments.modal_title') %>'.replace('${line}', row + 1));
$('.modal-title').text("#{ t('request_for_comments.modal_title') }".replace('${line}', row + 1));
var commentModal = $('#comment-modal');
@@ -416,7 +387,7 @@ also, all settings from the rails model needed for the editor configuration in t
var commentId = parent.data('comment-id');
deleteComment(commentId, editor, fileid, function () {
parent.html('<div class="comment-removed"><%= t('comments.deleted') %></div>');
parent.html('<div class="comment-removed">#{ t('comments.deleted') }</div>');
});
});
@@ -434,16 +405,16 @@ also, all settings from the rails model needed for the editor configuration in t
if (currentlyEditing) {
updateComment(commentId, commentEditor.val(), editor, fileid, function () {
button.text('<%= t('shared.edit') %>');
button.text("#{ t('shared.edit') }");
button.data('editing', false);
commentContent.text(commentEditor.val());
deleteButton.show();
commentContent.show();
commentEditor.hide();
commentUpdated.removeClass('hidden');
commentUpdated.removeClass('d-none');
});
} else {
button.text('<%= t('comments.save_update') %>');
button.text("#{ t('comments.save_update') }");
button.data('editing', true);
deleteButton.hide();
commentContent.hide();
@@ -487,5 +458,3 @@ also, all settings from the rails model needed for the editor configuration in t
text: message.length > 0 ? message : $('#flash').data('message-failure')
});
}
</script>

View File

@@ -3,13 +3,14 @@ h1 = t('.headline')
= form_tag(sessions_path) do
.form-group
= label_tag(:email, t('activerecord.attributes.internal_user.email'))
= text_field_tag(:email, params[:email], autofocus: true, class: 'form-control', required: true)
= email_field_tag(:email, params[:email], autofocus: true, class: 'form-control', required: true)
.form-group
= label_tag(:password, t('activerecord.attributes.internal_user.password'))
= password_field_tag(:password, nil, class: 'form-control', required: true)
.checkbox
label
= check_box_tag(:remember_me)
.form-check.form-group
label.form-check-label
// Set values 1 and true/false explicit to allow passing a custom HTML class
= check_box_tag(:remember_me, 1, true, class: 'form-check-input')
= t('.remember_me')
span.pull-right = link_to(t('.forgot_password'), forgot_password_path)
.actions = submit_tag(t('.link'), class: 'btn btn-default')
span.float-right = link_to(t('.forgot_password'), forgot_password_path)
.actions = submit_tag(t('.link'), class: 'btn btn-primary')

View File

@@ -1 +1,3 @@
= link_to(t('shared.edit'), local_assigns.fetch(:path, send(:"edit_#{object.class.name.underscore}_path", object)), class: 'btn btn-default pull-right')
// default value for fetch will always be evaluated even if it is not returned
- link_target = local_assigns.fetch(:path, false) || send(:"edit_#{object.class.name.underscore}_path", object)
= link_to(t('shared.edit'), link_target, class: 'btn btn-secondary float-right')

View File

@@ -5,6 +5,6 @@
= row(label: 'file.hidden', value: file.hidden)
= row(label: 'file.read_only', value: file.read_only)
- if file.teacher_defined_test?
= row(label: 'file.feedback_message', value: render_markdown(file.feedback_message))
= row(label: 'file.feedback_message', value: render_markdown(file.feedback_message), class: 'm-0')
= row(label: 'file.weight', value: file.weight)
= row(label: 'file.content', value: file.native_file? ? link_to(file.native_file.file.filename, file.native_file.url) : code_tag(file.content))

View File

@@ -1,11 +1,9 @@
.well
.card.card-body.bg-light
= search_form_for(@search, class: 'clearfix filter-form form-inline') do |f|
= yield(f)
.btn-group.pull-right
button.btn.btn-default.btn-sm type='submit' = t('shared.apply_filters')
button.btn.btn-default.btn-sm.dropdown-toggle data-toggle='dropdown' type='button'
span.caret
span.sr-only Toggle Dropdown
.btn-group.ml-auto
button.btn.btn-primary type='submit' = t('shared.apply_filters')
button.btn.btn-primary.dropdown-toggle data-toggle='dropdown' type='button'
ul.dropdown-menu role='menu'
li
a href=request.path = t('shared.reset_filters')
a.dropdown-item href=request.path = t('shared.reset_filters')

View File

@@ -2,10 +2,10 @@
.modal-dialog class=local_assigns[:classes]
.modal-content
.modal-header
h4#modal-title.modal-title = title
button.close data-dismiss='modal' type='button'
span aria-hidden=true &times;
span.sr-only Close
h4#modal-title.modal-title = title
.modal-body
- if local_assigns.has_key?(:body)
= body

View File

@@ -1,4 +1,6 @@
- if policy(model).new?
a.btn.btn-success href=local_assigns.fetch(:path, send(:"new_#{model.model_name.singular}_path"))
// default value for fetch will always be evaluated even if it is not returned
- href_target = local_assigns.fetch(:path, false) || send(:"new_#{model.model_name.singular}_path")
a.btn.btn-success href=href_target
i.fa.fa-plus
= t('shared.new_model', model: model.model_name.human)

View File

@@ -1,3 +1,2 @@
- if (pagination = will_paginate(collection, container: false)).present?
.text-center
ul.pagination = pagination
- if (pagination = will_paginate(collection, container: false, renderer: WillPaginate::ActionView::Bootstrap4LinkRenderer)).present?
ul.pagination.justify-content-center = pagination

View File

@@ -1 +1 @@
= f.submit(class: 'btn btn-default', value: t(object.new_record? ? 'shared.create' : 'shared.update', model: object.class.model_name.human))
= f.submit(class: 'btn btn-primary', value: t(object.new_record? ? 'shared.create' : 'shared.update', model: object.class.model_name.human))

View File

@@ -1,6 +1,9 @@
- content_for :head do
= javascript_include_tag(asset_path('vis.min.js', type: :javascript))
= stylesheet_link_tag(asset_path('vis.min.css', type: :stylesheet))
// Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326.
Otherwise, the global variable `vis` might be uninitialized in the assets (race condition)
meta name='turbolinks-visit-control' content='reload'
= javascript_pack_tag('vis', 'data-turbolinks-track': true)
= stylesheet_pack_tag('vis', media: 'all', 'data-turbolinks-track': true)
.group
.title

View File

@@ -1,17 +1,20 @@
- content_for :head do
= javascript_include_tag(asset_path('vis.min.js', type: :javascript))
= stylesheet_link_tag(asset_path('vis.min.css', type: :stylesheet))
// Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326.
Otherwise, the global variable `vis` might be uninitialized in the assets (race condition)
meta name='turbolinks-visit-control' content='reload'
= javascript_pack_tag('vis', 'data-turbolinks-track': true)
= stylesheet_pack_tag('vis', media: 'all', 'data-turbolinks-track': true)
.group
.title
h1 = t('.user_activity')
a href=statistics_graphs_user_activity_history_path = t('.history')
.spinner
.graph#user-activity
.graph.mb-5#user-activity
.group
.title
h1 = t('.rfc_activity')
a href=statistics_graphs_rfc_activity_history_path = t('.history')
.spinner
.graph#rfc-activity
.graph.mb-5#rfc-activity

View File

@@ -6,10 +6,10 @@ h1 = Submission.model_name.human(count: 2)
= f.collection_select(:exercise_id_eq, Exercise.with_submissions, :id, :title, class: 'form-control', prompt: t('activerecord.attributes.submission.exercise'))
.form-group
= f.label(:cause_eq, t('activerecord.attributes.submission.cause'), class: 'sr-only')
= f.select(:cause_eq, Submission.all.map(&:cause).uniq.sort, class: 'form-control', prompt: t('activerecord.attributes.submission.cause'))
= f.select(:cause_eq, Submission.select(:cause).distinct.map(&:cause).sort, class: 'form-control', prompt: t('activerecord.attributes.submission.cause'))
.table-responsive
table.table
table.table.mt-4
thead
tr
th = sort_link(@search, :exercise_id, t('activerecord.attributes.submission.exercise'))

View File

@@ -1,3 +1,10 @@
- content_for :head do
// Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326.
Otherwise, code might not be highlighted correctly (race condition)
meta name='turbolinks-visit-control' content='reload'
= javascript_pack_tag('highlight', 'data-turbolinks-track': true)
= stylesheet_pack_tag('highlight', media: 'all', 'data-turbolinks-track': true)
h1 = @submission
= row(label: 'submission.exercise', value: link_to(@submission.exercise, @submission.exercise))
@@ -5,9 +12,9 @@ h1 = @submission
= row(label: 'submission.cause', value: t("submissions.causes.#{@submission.cause}"))
= row(label: 'submission.score', value: @submission.score)
h2 = t('activerecord.attributes.submission.files')
h2.mt-4 = t('activerecord.attributes.submission.files')
ul.list-unstyled
- @files.each do |file|
li.panel.panel-default
.panel-body = render('shared/file', file: file)
li.card.mt-2
.card-body = render('shared/file', file: file)

View File

@@ -4,7 +4,7 @@ h1 = @submission
= row(label: 'submission.score', value: @submission.score)
= row(label: '.siblings', value: @submission.siblings.count)
h2 = t('.history')
h2.mt-4 = t('.history')
.table-responsive
table.table

View File

@@ -1,23 +1,22 @@
= form_for(@uef) do |f|
div
span.badge.pull-right.score
span.badge.badge-pill.badge-primary.float-right.score
h1 id="exercise-headline"
= t('activerecord.models.user_exercise_feedback.one') + " "
= link_to(@exercise.title, [:implement, @exercise])
= t('activerecord.models.user_exercise_feedback.one') + " " + @exercise.title
= render('shared/form_errors', object: @uef)
h4
p
== t('user_exercise_feedback.description')
#description-panel.lead.description-panel
#description-card.lead.description-card
u = t('activerecord.attributes.exercise.description')
= render_markdown(@exercise.description)
.form-group
= f.text_area(:feedback_text, class: 'form-control', required: true, :rows => "10")
h4 = t('user_exercise_feedback.difficulty')
= f.collection_radio_buttons :difficulty, @texts, :first, :last, html_options={class: "radio-inline"} do |b|
= b.label(:class => 'radio') { b.radio_button + b.text }
h4 = t('user_exercise_feedback.working_time')
= f.collection_radio_buttons :user_estimated_worktime, @times, :first, :last, html_options={class: "radio-inline"} do |b|
= b.label(:class => 'radio') { b.radio_button + b.text }
h4.mt-4 = t('user_exercise_feedback.difficulty')
= f.collection_radio_buttons :difficulty, @texts, :first, :last, html_options: {class: "form-check-inline"} do |b|
= b.label(:class => 'form-check') { b.radio_button + b.text }
h4.mt-4 = t('user_exercise_feedback.working_time')
= f.collection_radio_buttons :user_estimated_worktime, @times, :first, :last, html_options: {class: "form-check-inline"} do |b|
= b.label(:class => 'form-check') { b.radio_button + b.text }
= f.hidden_field(:exercise_id, :value => @exercise.id)
.actions = render('shared/submit_button', f: f, object: @uef)