diff --git a/app/assets/javascripts/bootstrap-dropdown-submenu.js b/app/assets/javascripts/bootstrap-dropdown-submenu.js index 10809c02..38ad3854 100644 --- a/app/assets/javascripts/bootstrap-dropdown-submenu.js +++ b/app/assets/javascripts/bootstrap-dropdown-submenu.js @@ -1,6 +1,6 @@ $(document).on('turbolinks:load', function() { - var subMenusSelector = 'ul.dropdown-menu [data-toggle=dropdown]'; + var subMenusSelector = 'ul.dropdown-menu [data-bs-toggle=dropdown]'; function openSubMenu(event) { if (this.pathname === '/') { diff --git a/app/assets/javascripts/codeharbor_link.js b/app/assets/javascripts/codeharbor_link.js index 4cd49ece..fdf42859 100644 --- a/app/assets/javascripts/codeharbor_link.js +++ b/app/assets/javascripts/codeharbor_link.js @@ -1,5 +1,5 @@ $(document).on('turbolinks:load', function() { - $('[data-toggle="tooltip"]').tooltip(); + $('[data-bs-toggle="tooltip"]').tooltip(); if($.isController('codeharbor_links')) { if ($('.edit_codeharbor_link, .new_codeharbor_link').isPresent()) { diff --git a/app/assets/javascripts/editor.js b/app/assets/javascripts/editor.js index 465e2f49..6dc79b7f 100644 --- a/app/assets/javascripts/editor.js +++ b/app/assets/javascripts/editor.js @@ -15,12 +15,9 @@ $(document).on('turbolinks:load', function(event) { ); if ($('#editor').isPresent() && CodeOceanEditor && event.originalEvent.data.url.includes("/implement")) { - if (CodeOceanEditor.isBrowserSupported()) { - $('#alert').hide(); - // This call will (amon other things) initializeEditors and load the content except for the last line - // It must not be called during page navigation. Otherwise, content will be duplicated! - // Search for insertLines and Turbolinks reload / cache control - CodeOceanEditor.initializeEverything(); - } + // This call will (amon other things) initializeEditors and load the content except for the last line + // It must not be called during page navigation. Otherwise, content will be duplicated! + // Search for insertLines and Turbolinks reload / cache control + CodeOceanEditor.initializeEverything(); } }); diff --git a/app/assets/javascripts/editor/editor.js.erb b/app/assets/javascripts/editor/editor.js.erb index b07341ae..d242e64b 100644 --- a/app/assets/javascripts/editor/editor.js.erb +++ b/app/assets/javascripts/editor/editor.js.erb @@ -78,7 +78,7 @@ var CodeOceanEditor = { if ($('#output-' + index).isPresent()) { return $('#output-' + index); } else { - var element = $('
').attr('id', 'output-' + index); + var element = $('').attr('id', 'output-' + index); $('#output').append(element); return element; } @@ -235,10 +235,20 @@ var CodeOceanEditor = { window.dispatchEvent(new Event('resize')); }, - resizeParentOfAceEditor: function (element) { + resizeSidebars: function () { + $('#content-left-sidebar').height(this.calculateEditorHeight('#content-left-sidebar', false)); + $('#content-right-sidebar').height(this.calculateEditorHeight('#content-right-sidebar', false)); + }, + + calculateEditorHeight: function (element, considerStatusbar) { + let bottom = considerStatusbar ? ($('#statusbar').height() || 0) : 0; // calculate needed size: window height - position of top of ACE editor - height of autosave label below editor - 5 for bar margins - var windowHeight = window.innerHeight - $(element).offset().top - ($('#statusbar').height() || 0) - 5; - $(element).parent().height(windowHeight); + return window.innerHeight - $(element).offset().top - bottom - 5; + }, + + resizeParentOfAceEditor: function (element) { + const editorHeight = this.calculateEditorHeight(element, true); + $(element).parent().height(editorHeight); }, initializeEditors: function (own_solution = false) { @@ -259,6 +269,7 @@ var CodeOceanEditor = { // Resize frame on window size change $(window).resize(function () { this.resizeParentOfAceEditor(element); + this.resizeSidebars(); }.bind(this)); var editor = ace.edit(element); @@ -390,6 +401,7 @@ var CodeOceanEditor = { tipButton.on('click', this.handleSideBarToggle.bind(this)); } $('#sidebar').on('transitionend', this.resizeAceEditors.bind(this)); + $('#sidebar').on('transitionend', this.resizeSidebars.bind(this)); }, handleSideBarToggle: function () { @@ -433,12 +445,12 @@ var CodeOceanEditor = { button.prop('disabled', true); button.on('click', function () { $('#rfc_intervention_text').hide() - $('#comment-modal').modal('show'); + new bootstrap.Modal($('#comment-modal')).show(); }); $('#askForCommentsButton').on('click', this.requestComments.bind(this)); $('#closeAskForCommentsButton').on('click', function () { - $('#comment-modal').modal('hide'); + bootstrap.Modal.getInstance($('#comment-modal')).hide(); }); setTimeout(function () { @@ -475,12 +487,6 @@ var CodeOceanEditor = { return this.isActiveFileExecutable() && ['teacher_defined_test', 'user_defined_test', 'teacher_defined_linter'].includes(this.active_frame.data('role')); }, - isBrowserSupported: function () { - // websockets are used for run, score and test - // Also exclude IE and IE 11 - return Modernizr.websockets && window.navigator.userAgent.indexOf("MSIE") <= 0 && !navigator.userAgent.match(/Trident\/7\./); - }, - populateCard: function (card, result, index) { card.addClass(this.getCardClass(result)); card.find('.card-title .filename').text(result.filename); @@ -778,7 +784,7 @@ var CodeOceanEditor = { event.preventDefault(); this.createSubmission('#create-file', null, function (response) { $('#code_ocean_file_context_id').val(response.id); - $('#modal-file').modal('show'); + new bootstrap.Modal($('#modal-file')).show(); }.bind(this)); }, @@ -786,6 +792,7 @@ var CodeOceanEditor = { $('#toggle-sidebar-output').on('click', this.hideOutputBar.bind(this)); $('#toggle-sidebar-output-collapsed').on('click', this.showOutputBar.bind(this)); $('#output_sidebar').on('transitionend', this.resizeAceEditors.bind(this)); + $('#output_sidebar').on('transitionend', this.resizeSidebars.bind(this)); }, showOutputBar: function () { @@ -801,7 +808,7 @@ var CodeOceanEditor = { }, initializeSideBarTooltips: function () { - $('[data-toggle="tooltip"]').tooltip() + $('[data-bs-toggle="tooltip"]').tooltip() }, initializeDescriptionToggle: function () { @@ -809,12 +816,13 @@ var CodeOceanEditor = { $('a#toggle').on('click', this.toggleDescriptionCard.bind(this)); }, - toggleDescriptionCard: function () { + toggleDescriptionCard: function (event) { $('#description-card').toggleClass('description-card-collapsed').toggleClass('description-card'); $('#description-symbol').toggleClass('fa-chevron-down').toggleClass('fa-chevron-right'); var toggle = $('a#toggle'); toggle.text(toggle.text() == toggle.data('hide') ? toggle.data('show') : toggle.data('hide')); this.resizeAceEditors(); + this.resizeSidebars(); event.preventDefault(); }, @@ -871,7 +879,7 @@ var CodeOceanEditor = { if (editor.data('tips-interventions')) { const modal = $('#tips-intervention-modal'); modal.find('.modal-footer').html(I18n.t("exercises.implement.intervention.explanation", {duration: Math.round(percentile75 / 60)})); - modal.modal('show'); + new bootstrap.Modal(modal).show(); $.ajax({ data: { intervention_type: 'TipsIntervention' @@ -883,7 +891,7 @@ var CodeOceanEditor = { } else if (editor.data('break-interventions')) { const modal = $('#break-intervention-modal'); modal.find('.modal-footer').html(I18n.t("exercises.implement.intervention.explanation", {duration: Math.round(percentile75 / 60)})); - modal.modal('show'); + new bootstrap.Modal(modal).show(); $.ajax({ data: { intervention_type: 'BreakIntervention' @@ -902,7 +910,7 @@ var CodeOceanEditor = { modal.on('hidden.bs.modal', function () { modal.find('.modal-footer').text(''); }); - modal.modal('show'); + new bootstrap.Modal(modal).show(); $.ajax({ data: { intervention_type: 'QuestionIntervention' @@ -945,7 +953,6 @@ var CodeOceanEditor = { CodeOceanEditor.editors = []; this.initializeRegexes(); this.initializeCodePilot(); - $('.score, #development-environment').show(); this.configureEditors(); this.initializeEditors(); this.initializeEventHandlers(); @@ -961,6 +968,7 @@ var CodeOceanEditor = { this.renderScore(); this.showFirstFile(); this.resizeAceEditors(); + this.resizeSidebars(); this.initializeDeadlines(); CodeOceanEditorTips.initializeEventHandlers(); diff --git a/app/assets/javascripts/editor/participantsupport.js.erb b/app/assets/javascripts/editor/participantsupport.js.erb index 77d2138b..db801aeb 100644 --- a/app/assets/javascripts/editor/participantsupport.js.erb +++ b/app/assets/javascripts/editor/participantsupport.js.erb @@ -4,7 +4,7 @@ CodeOceanEditorFlowr = { '' + '' + '' + '', @@ -93,7 +93,7 @@ CodeOceanEditorFlowr = { var body = resultTile.find('.card-body'); body.html(result.body); - body.append('' + + body.append('' + '<%= I18n.t('exercises.implement.flowr.go_to_question') %>'); body.find('.btn').on('click', CodeOceanEditor.createEventHandler('editor_flowr_click_question', questionUrl)); @@ -112,7 +112,7 @@ CodeOceanEditorCodePilot = { QaApiOutputBuffer: {'stdout': '', 'stderr': ''}, initializeCodePilot: function () { - if ($('#questions-column').isPresent() && (typeof QaApi != 'undefined') && QaApi.isBrowserSupported()) { + if ($('#questions-column').isPresent() && (typeof QaApi != 'undefined')) { $('#editor-column').addClass('col-md-10').removeClass('col-md-12'); $('#questions-column').addClass('col-md-2'); @@ -161,7 +161,7 @@ CodeOceanEditorRequestForComments = { this.createSubmission($('#requestComments'), null, createRequestForComments.bind(this)); - $('#comment-modal').modal('hide'); + bootstrap.Modal.getInstance($('#comment-modal')).hide(); $('#question').val(''); // we disabled the button to prevent that the user spams RFCs, but decided against this now. //var button = $('#requestComments'); diff --git a/app/assets/javascripts/editor/turtle.js b/app/assets/javascripts/editor/turtle.js index e6463ee4..d388f375 100644 --- a/app/assets/javascripts/editor/turtle.js +++ b/app/assets/javascripts/editor/turtle.js @@ -37,15 +37,16 @@ CodeOceanEditorTurtle = { }, showCanvas: function () { - if ($('#turtlediv').isPresent() && this.turtlecanvas.hasClass('d-none')) { - this.turtlecanvas.removeClass('d-none'); + const turtlediv = $('#turtlediv'); + if (turtlediv.isPresent() && turtlediv.hasClass('d-none')) { + turtlediv.removeClass('d-none'); } }, hideCanvas: function () { - const turtlecanvas = $('#turtlecanvas'); - if ($('#turtlediv').isPresent() && !turtlecanvas.hasClass('d-none')) { - turtlecanvas.addClass('d-none'); + const turtlediv = $('#turtlediv'); + if (turtlediv.isPresent() && !turtlediv.hasClass('d-none')) { + turtlediv.addClass('d-none'); } } diff --git a/app/assets/javascripts/exercise_collections.js.erb b/app/assets/javascripts/exercise_collections.js.erb index 6c8602f7..d0aad22e 100644 --- a/app/assets/javascripts/exercise_collections.js.erb +++ b/app/assets/javascripts/exercise_collections.js.erb @@ -187,7 +187,7 @@ $(document).on('turbolinks:load', function() { for (var i = 0; i < selectedExercises.length; i++) { addExercise(selectedExercises[i].value, selectedExercises[i].label); } - $('#add-exercise-modal').modal('hide') + bootstrap.Modal.getInstance($('#add-exercise-modal')).hide(); updateExerciseList(); addExercisesForm.find('select').val('').trigger("chosen:updated"); }); diff --git a/app/assets/javascripts/exercises.js.erb b/app/assets/javascripts/exercises.js.erb index 9a5f0378..a91586dd 100644 --- a/app/assets/javascripts/exercises.js.erb +++ b/app/assets/javascripts/exercises.js.erb @@ -123,7 +123,7 @@ $(document).on('turbolinks:load', function () { var buildCheckboxes = function () { $('tbody tr').each(function (index, element) { var td = $('td.public', element); - var checkbox = $('', { + var checkbox = $('', { checked: td.data('value'), type: 'checkbox' }); @@ -225,9 +225,9 @@ $(document).on('turbolinks:load', function () { const tip = {id: id, title: title} const template = ''; const tipList = $('#tip-list').append(template); @@ -243,7 +243,7 @@ $(document).on('turbolinks:load', function () { for (let i = 0; i < selectedTips.length; i++) { addTip(selectedTips[i].value, selectedTips[i].label); } - $('#add-tips-modal').modal('hide') + bootstrap.Modal.getInstance($('#add-tips-modal')).hide(); updateTipsJSON(); chosenInputTips.val('').trigger("chosen:updated"); }); @@ -328,10 +328,7 @@ $(document).on('turbolinks:load', function () { var observeExportButtons = function () { $('.export-start').on('click', function (e) { e.preventDefault(); - $('#export-modal').modal({ - height: 250 - }); - $('#export-modal').modal('show'); + new bootstrap.Modal($('#export-modal')).show(); exportExerciseStart($(this).data().exerciseId); }); $('body').on('click', '.export-retry-button', function () { @@ -382,7 +379,7 @@ $(document).on('turbolinks:load', function () { if (response.status == 'success') { $messageDiv.addClass('export-success'); setTimeout((function () { - $('#export-modal').modal('hide'); + bootstrap.Modal.getInstance($('#export-modal')).hide(); $messageDiv.html('').removeClass('export-success'); }), 3000); } else { @@ -396,7 +393,7 @@ $(document).on('turbolinks:load', function () { }; var overrideTextareaTabBehavior = function () { - $('.form-group textarea[name$="[content]"]').on('keydown', function (event) { + $('.mb-3 textarea[name$="[content]"]').on('keydown', function (event) { if (event.which === TAB_KEY_CODE) { event.preventDefault(); insertTabAtCursor($(this)); diff --git a/app/assets/javascripts/forms.js b/app/assets/javascripts/forms.js index 7e469455..2be40eba 100644 --- a/app/assets/javascripts/forms.js +++ b/app/assets/javascripts/forms.js @@ -9,7 +9,7 @@ $(document).on('turbolinks:load', function() { event.preventDefault(); if (!$(this).hasClass('disabled')) { - var parent = $(this).parents('.form-group'); + var parent = $(this).parents('.mb-3'); var original_input = parent.find('.original-input'); var alternative_input = parent.find('.alternative-input'); diff --git a/app/assets/javascripts/pagedown/markdown.editor.js.erb b/app/assets/javascripts/pagedown/markdown.editor.js.erb index 459d7cfa..8330a85c 100644 --- a/app/assets/javascripts/pagedown/markdown.editor.js.erb +++ b/app/assets/javascripts/pagedown/markdown.editor.js.erb @@ -1018,7 +1018,7 @@ text = 'http://' + text; } - $(dialog).modal('hide'); + bootstrap.Modal.getInstance($(dialog)).hide(); callback(text); return false; @@ -1032,7 +1032,7 @@ //' + - '' + + '' + '' + '////- // + // ////Modal title
//@@ -1062,7 +1062,7 @@ // The header. var header = doc.createElement("div"); header.className = "modal-header"; - header.innerHTML = ''+title+'
'; + header.innerHTML = ''+title+'
'; dialogContent.appendChild(header); // The body. @@ -1082,7 +1082,7 @@ // The input text box var formGroup = doc.createElement("div"); - formGroup.className = "form-group"; + formGroup.className = "mb-3"; form.appendChild(formGroup); var label = doc.createElement("label"); @@ -1144,15 +1144,15 @@ range.select(); } - $(dialog).on('shown', function () { + $(dialog).on('shown.bs.modal', function () { input.focus(); }); - $(dialog).on('hidden', function () { + $(dialog).on('hidden.bs.modal', function () { dialog.parentNode.removeChild(dialog); }); - $(dialog).modal() + new bootstrap.Modal($(dialog)).show(); }, 0); }; @@ -1360,8 +1360,8 @@ button.appendChild(buttonImage); button.id = id + postfix; button.title = title; - button.setAttribute("data-toggle", "tooltip"); - button.setAttribute("data-placement", "top"); + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "top"); if (textOp) button.textOp = textOp; setupButton(button, true); @@ -1416,7 +1416,7 @@ if (helpOptions) { var group5 = makeGroup(5); - group5.className = group5.className + " ml-auto"; + group5.className = group5.className + " ms-auto"; var helpButton = document.createElement("button"); var helpButtonImage = document.createElement("i"); helpButtonImage.className = "m-1 fa-solid fa-info"; @@ -1424,8 +1424,8 @@ helpButton.className = "btn btn-info btn-sm"; helpButton.id = "wmd-help-button" + postfix; helpButton.isHelp = true; - helpButton.setAttribute("data-toggle", "tooltip"); - helpButton.setAttribute("data-placement", "top"); + helpButton.setAttribute("data-bs-toggle", "tooltip"); + helpButton.setAttribute("data-bs-placement", "top"); helpButton.title = helpOptions.title || defaultHelpHoverTitle; helpButton.onclick = helpOptions.handler; diff --git a/app/assets/javascripts/pagedown/pagedown.js.erb b/app/assets/javascripts/pagedown/pagedown.js.erb index cada3497..3581b894 100644 --- a/app/assets/javascripts/pagedown/pagedown.js.erb +++ b/app/assets/javascripts/pagedown/pagedown.js.erb @@ -32,7 +32,7 @@ createPagedownEditor = function( selector, context ) { const editor = new Markdown.Editor(converter, attr, help); editor.run(); - $('[data-toggle="tooltip"]').tooltip(); + $('[data-bs-toggle="tooltip"]').tooltip(); return $(input).data('is_rendered', true); }); }; diff --git a/app/assets/stylesheets/base.css.scss b/app/assets/stylesheets/base.css.scss index 1488c4f9..f0419c32 100644 --- a/app/assets/stylesheets/base.css.scss +++ b/app/assets/stylesheets/base.css.scss @@ -12,6 +12,15 @@ h1, h2, h3, h4, h5, h6 { color: rgba(70, 70, 70, 1); } +a:not(.dropdown-item, .dropdown-toggle, .dropdown-link, .btn, .page-link), .btn-link { + text-decoration: none; + + &:hover { + text-decoration: underline; + + } +} + i.fa-solid, i.fa-regular, i.fa-solid { margin-right: 0.5em; } @@ -51,13 +60,17 @@ span.caret { .navbar { -webkit-font-smoothing: antialiased; font-weight: 500; + font-size: 0.85rem; + .dropdown-item { + padding: 1rem 1.5rem; + } } .attribute-row + .attribute-row { margin-top: 0.5em; } -.badge-pill { +.rounded-pill { font-size: 100%; font-weight: 500; } diff --git a/app/assets/stylesheets/bootstrap-dropdown-submenu.css.scss b/app/assets/stylesheets/bootstrap-dropdown-submenu.css.scss index ceb88020..ce930c28 100644 --- a/app/assets/stylesheets/bootstrap-dropdown-submenu.css.scss +++ b/app/assets/stylesheets/bootstrap-dropdown-submenu.css.scss @@ -29,11 +29,11 @@ border-left-color: #ffffff; } -.dropdown-submenu.float-left { +.dropdown-submenu.float-start { float: none; } -.dropdown-submenu.float-left > .dropdown-menu { +.dropdown-submenu.float-start > .dropdown-menu { left: -100%; margin-left: 10px; -webkit-border-radius: 6px 0 6px 6px; diff --git a/app/assets/stylesheets/editor.css.scss b/app/assets/stylesheets/editor.css.scss index 49141816..fc564439 100644 --- a/app/assets/stylesheets/editor.css.scss +++ b/app/assets/stylesheets/editor.css.scss @@ -48,10 +48,6 @@ button i.fa-spin { vertical-align: bottom; } -#development-environment { - display: none; -} - #dummy { display: none; } @@ -203,8 +199,8 @@ button i.fa-spin { visibility: visible; } -.enforce-big-top-margin { - margin-top: 15px !important; +.enforce-big-bottom-margin { + margin-bottom: 15px !important; } .enforce-bottom-margin { diff --git a/app/assets/stylesheets/exercises.css.scss b/app/assets/stylesheets/exercises.css.scss index 75a98edf..02e472fb 100644 --- a/app/assets/stylesheets/exercises.css.scss +++ b/app/assets/stylesheets/exercises.css.scss @@ -40,11 +40,11 @@ input[type='file'] { } } -[data-toggle="collapse"] .fa-solid:before { +[data-bs-toggle="collapse"] .fa-solid:before { content: "\f139"; } -[data-toggle="collapse"].collapsed .fa-solid:before { +[data-bs-toggle="collapse"].collapsed .fa-solid:before { content: "\f13a"; } diff --git a/app/assets/stylesheets/forms.css.scss b/app/assets/stylesheets/forms.css.scss index 62613e8e..fd797034 100644 --- a/app/assets/stylesheets/forms.css.scss +++ b/app/assets/stylesheets/forms.css.scss @@ -23,12 +23,6 @@ margin-bottom: 1em; } - .form-group { - &:not(:last-child) { - margin-right: 1em; - } - } - input, select { min-width: 200px !important; } diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 8ca2997f..b5391f8e 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -22,7 +22,7 @@ module ApplicationHelper end def label_column(label) - tag.div(class: 'col-sm-3') do + tag.div(class: 'col-md-3') do tag.strong do I18n.translation_present?("activerecord.attributes.#{label}") ? t("activerecord.attributes.#{label}") : t(label) end @@ -72,7 +72,7 @@ module ApplicationHelper end def value_column(value) - tag.div(class: 'col-sm-9') do + tag.div(class: 'col-md-9') do block_given? ? yield : symbol_for(value) end end diff --git a/app/javascript/application.js b/app/javascript/application.js index 04289fb2..9da4992f 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -10,12 +10,13 @@ // JS import 'jquery'; import 'jquery-ujs' -import 'bootstrap/dist/js/bootstrap.bundle.min'; +import * as bootstrap from 'bootstrap/dist/js/bootstrap.bundle'; import 'chosen-js/chosen.jquery'; import 'jstree'; import 'underscore'; import 'd3'; import '@sentry/browser'; +window.bootstrap = bootstrap; // Publish underscore's `_` in global namespace window._ = _; // Publish underscore's `_` in global namespace window.d3 = d3; // Publish d3 in global namespace window.Sentry = Sentry; // Publish sentry in global namespace diff --git a/app/views/application/_breadcrumbs_and_title.html.slim b/app/views/application/_breadcrumbs_and_title.html.slim index 1be2f47b..5829ec88 100644 --- a/app/views/application/_breadcrumbs_and_title.html.slim +++ b/app/views/application/_breadcrumbs_and_title.html.slim @@ -18,14 +18,17 @@ - title = "#{active_action} - #{application_name}" - content_for :breadcrumbs do - .container - ul.breadcrumb + .container.mb-4 + ul.breadcrumb.bg-light.px-3.py-2 - if root_element.present? - li.breadcrumb-item = root_element + li.breadcrumb-item.small + = root_element - if current_element.present? - li.breadcrumb-item = current_element + li.breadcrumb-item.small + = current_element - title = "#{object} - #{title}" - else - title = "#{model.model_name.human(count: 2)} - #{title}" - li.breadcrumb-item.active = active_action + li.breadcrumb-item.active.small + = active_action - content_for :title, title diff --git a/app/views/application/_flash.html.slim b/app/views/application/_flash.html.slim index 046c58ea..2311318e 100644 --- a/app/views/application/_flash.html.slim +++ b/app/views/application/_flash.html.slim @@ -4,5 +4,4 @@ - flash_mapping = {'alert' => 'warning', 'notice' => 'success'} div.alert.flash class="alert-#{flash_mapping.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" × + button.btn-close type="button" data-bs-dismiss="alert" aria-label="Close" diff --git a/app/views/application/_locale_selector.html.slim b/app/views/application/_locale_selector.html.slim index dd2e4787..0401e98d 100644 --- a/app/views/application/_locale_selector.html.slim +++ b/app/views/application/_locale_selector.html.slim @@ -1,5 +1,5 @@ li.nav-item.dropdown - a.nav-link.dropdown-toggle.mx-3 data-toggle='dropdown' href='#' + a.nav-link.dropdown-toggle.mx-3 data-bs-toggle='dropdown' href='#' = t("locales.#{I18n.locale}") span.caret ul.dropdown-menu.p-0.mt-1 role='menu' diff --git a/app/views/application/_navigation.html.slim b/app/views/application/_navigation.html.slim index c28939d5..831db2bc 100644 --- a/app/views/application/_navigation.html.slim +++ b/app/views/application/_navigation.html.slim @@ -1,7 +1,7 @@ - if current_user.try(:admin?) or current_user.try(:teacher?) ul.nav.navbar-nav li.nav-item.dropdown - a.nav-link.dropdown-toggle.mx-3 data-toggle='dropdown' href='#' + a.nav-link.dropdown-toggle.mx-3 data-bs-toggle='dropdown' href='#' = t('shared.administration') span.caret ul.dropdown-menu.p-0.mt-1 role='menu' diff --git a/app/views/application/_navigation_submenu.html.slim b/app/views/application/_navigation_submenu.html.slim index fc4c9dec..fa66d605 100644 --- a/app/views/application/_navigation_submenu.html.slim +++ b/app/views/application/_navigation_submenu.html.slim @@ -1,7 +1,7 @@ - if models.any? { |model| policy(model).index? } li.dropdown-submenu - link = link.nil? ? "#" : link - a.dropdown-item.dropdown-toggle href=link data-toggle="dropdown" = title + a.dropdown-item.dropdown-toggle href=link data-bs-toggle="dropdown" = title ul.dropdown-menu.p-0 - models.each do |model| = render('navigation_collection_link', model: model, cached: true) diff --git a/app/views/application/_session.html.slim b/app/views/application/_session.html.slim index d14080eb..64973d6b 100644 --- a/app/views/application/_session.html.slim +++ b/app/views/application/_session.html.slim @@ -1,6 +1,6 @@ - if current_user li.nav-item.dropdown - a.nav-link.dropdown-toggle data-toggle='dropdown' href='#' + a.nav-link.dropdown-toggle data-bs-toggle='dropdown' href='#' i.fa-solid.fa-user = current_user span.caret diff --git a/app/views/code_ocean/files/_form.html.slim b/app/views/code_ocean/files/_form.html.slim index bfdf2257..f1a556cf 100644 --- a/app/views/code_ocean/files/_form.html.slim +++ b/app/views/code_ocean/files/_form.html.slim @@ -1,19 +1,19 @@ = form_for(CodeOcean::File.new) do |f| - .form-group - = f.label(:name, t('activerecord.attributes.file.name')) + .mb-3 + = f.label(:name, t('activerecord.attributes.file.name'), class: 'form-label') = f.text_field(:name, class: 'form-control', required: true) - .form-group - = f.label(:path, t('activerecord.attributes.file.path')) + .mb-3 + = f.label(:path, t('activerecord.attributes.file.path'), class: 'form-label') | a.toggle-input data={text_initial: t('shared.new'), text_toggled: t('shared.back')} href='#' = t('shared.new') .original-input = f.select(:path, @paths, {}, class: 'form-control') = f.text_field(:path, class: 'alternative-input form-control', disabled: true) - .form-group - = f.label(:file_type_id, t('activerecord.attributes.file.file_type_id')) + .mb-3 + = f.label(:file_type_id, t('activerecord.attributes.file.file_type_id'), class: 'form-label') = f.collection_select(:file_type_id, FileType.where(binary: false).order(:name), :id, :name, {selected: @exercise.execution_environment.file_type.try(:id)}, class: 'form-control') - if FileTemplate.any? - .form-group - = f.label(:file_template_id, t('activerecord.attributes.file.file_template_id')) + .mb-3 + = f.label(:file_template_id, t('activerecord.attributes.file.file_template_id'), class: 'form-label') = f.collection_select(:file_template_id, FileTemplate.all.order(:name), :id, :name, {:include_blank => true}, class: 'form-control') = f.hidden_field(:context_id) .d-none#noTemplateLabel data-text=t('file_template.no_template_label') diff --git a/app/views/codeharbor_links/_form.html.slim b/app/views/codeharbor_links/_form.html.slim index f7b84ddc..6dd6cdb5 100644 --- a/app/views/codeharbor_links/_form.html.slim +++ b/app/views/codeharbor_links/_form.html.slim @@ -1,13 +1,13 @@ = form_for(@codeharbor_link) do |f| = render('shared/form_errors', object: @codeharbor_link) - .form-group - = f.label(:push_url) + .mb-3 + = f.label(:push_url, class: 'form-label') = f.text_field :push_url, data: {toggle: 'tooltip', placement: 'bottom'}, title: t('codeharbor_link.info.push_url'), class: 'form-control' - .form-group - = f.label(:check_uuid_url) + .mb-3 + = f.label(:check_uuid_url, class: 'form-label') = f.text_field :check_uuid_url, data: {toggle: 'tooltip', placement: 'bottom'}, title: t('codeharbor_link.info.check_uuid_url'), class: 'form-control' - .form-group - = f.label(:api_key) + .mb-3 + = f.label(:api_key, class: 'form-label') .input-group = f.text_field(:api_key, data: {toggle: 'tooltip', placement: 'bottom'}, title: t('codeharbor_link.info.api_key'), class: 'form-control api_key') .input-group-btn @@ -15,5 +15,5 @@ .actions = render('shared/submit_button', f: f, object: @codeharbor_link) - if @codeharbor_link.persisted? - = link_to(t('codeharbor_link.delete'), codeharbor_link_path(@codeharbor_link), data: {confirm: t('shared.confirm_destroy')}, method: :delete, class: 'btn btn-danger pull-right') + = link_to(t('codeharbor_link.delete'), codeharbor_link_path(@codeharbor_link), data: {confirm: t('shared.confirm_destroy')}, method: :delete, class: 'btn btn-danger float-end') diff --git a/app/views/community_solutions/_form.html.slim b/app/views/community_solutions/_form.html.slim index 05265aa9..a9d99548 100644 --- a/app/views/community_solutions/_form.html.slim +++ b/app/views/community_solutions/_form.html.slim @@ -1,6 +1,6 @@ .exercise.clearfix div - span.badge.badge-pill.badge-primary.float-right.score + span.badge.rounded-pill.bg-primary.float-end.score h1 id="exercise-headline" i id="description-symbol" class=(@embed_options[:collapse_exercise_description] ? 'fa-solid fa-chevron-right' : 'fa-solid fa-chevron-down') @@ -32,11 +32,11 @@ h4 = t('community_solutions.current_community_solution') #community-solution-editor.row - .pr-0 class=(@community_solution.exercise.hide_file_tree ? 'd-none col-sm-3' : 'col-sm-3') + .pe-0 class=(@community_solution.exercise.hide_file_tree ? 'd-none col-sm-3' : 'col-sm-3') .card.border-secondary .card-header.d-flex.justify-content-between.align-items-center.px-0.py-2 .px-2 = I18n.t('exercises.editor_file_tree.file_root') - .card-body.pt-0.pr-0.pl-1.pb-1 + .card-body.pt-0.pe-0.ps-1.pb-1 #files data-entries=FileTree.new(@files).to_js_tree div class=(@community_solution.exercise.hide_file_tree ? 'col-sm-12' : 'col-sm-9') div.editor-col.col.p-0 id='frames' @@ -44,16 +44,16 @@ = render('exercises/editor_frame', exercise: @community_solution.exercise, file: file) .col-xl-6.container-fluid - div.bg-dark.h-100.float-left.row style="width: 1px" + div.bg-dark.h-100.float-start.row style="width: 1px" div h4 = t('community_solutions.your_submission') #own-solution-editor.row - .pr-0 class=(@community_solution.exercise.hide_file_tree ? 'd-none col-sm-3' : 'col-sm-3') + .pe-0 class=(@community_solution.exercise.hide_file_tree ? 'd-none col-sm-3' : 'col-sm-3') .card.border-secondary .card-header.d-flex.justify-content-between.align-items-center.px-0.py-2 .px-2 = I18n.t('exercises.editor_file_tree.file_root') - .card-body.pt-0.pr-0.pl-1.pb-1 + .card-body.pt-0.pe-0.ps-1.pb-1 #own-files data-entries=FileTree.new(@own_files).to_js_tree div class=(@community_solution.exercise.hide_file_tree ? 'col-sm-12' : 'col-sm-9') div.editor-col.col.p-0 id='own-frames' @@ -61,6 +61,6 @@ = render('exercises/editor_frame', exercise: @community_solution.exercise, file: file, own_solution: true) #statusbar.visible.mt-2 style="height: 5em" p.text-center - = render('exercises/editor_button', classes: 'btn-lg btn-success ml-5 mr-3', data: {'data-url': community_solution_path(@community_solution), 'data-http-method': 'PUT', 'data-cause': 'change-community-solution', 'data-exercise-id': @community_solution.exercise.id}, icon: 'fa-solid fa-paper-plane', id: 'submit', label: t('community_solutions.change_community_solution')) - = render('exercises/editor_button', classes: 'btn-lg btn-secondary ml-5', data: {'data-url': community_solution_path(@community_solution), 'data-http-method': 'PUT', 'data-cause': 'accept-community-solution', 'data-exercise-id': @community_solution.exercise.id}, icon: 'fa-solid fa-check', id: 'accept', label: t('community_solutions.accept_community_solution')) + = render('exercises/editor_button', classes: 'btn-lg btn-success ms-5 me-3', data: {'data-url': community_solution_path(@community_solution), 'data-http-method': 'PUT', 'data-cause': 'change-community-solution', 'data-exercise-id': @community_solution.exercise.id}, icon: 'fa-solid fa-paper-plane', id: 'submit', label: t('community_solutions.change_community_solution')) + = render('exercises/editor_button', classes: 'btn-lg btn-secondary ms-5', data: {'data-url': community_solution_path(@community_solution), 'data-http-method': 'PUT', 'data-cause': 'accept-community-solution', 'data-exercise-id': @community_solution.exercise.id}, icon: 'fa-solid fa-check', id: 'accept', label: t('community_solutions.accept_community_solution')) button style="display:none" id="autosave" data-url=community_solution_path(@community_solution) data-http-method='PUT' data-cause='autosave-community-solution' data-exercise-id=@community_solution.exercise.id diff --git a/app/views/consumers/_form.html.slim b/app/views/consumers/_form.html.slim index f60a201c..ad6ad4e4 100644 --- a/app/views/consumers/_form.html.slim +++ b/app/views/consumers/_form.html.slim @@ -1,12 +1,12 @@ = form_for(@consumer) do |f| = render('shared/form_errors', object: @consumer) - .form-group - = f.label(:name) + .mb-3 + = f.label(:name, class: 'form-label') = f.text_field(:name, class: 'form-control', required: true) - .form-group - = f.label(:oauth_key) + .mb-3 + = f.label(:oauth_key, class: 'form-label') = f.text_field(:oauth_key, class: 'form-control', required: true) - .form-group - = f.label(:oauth_secret) + .mb-3 + = f.label(:oauth_secret, class: 'form-label') = f.text_field(:oauth_secret, class: 'form-control', required: true) .actions = render('shared/submit_button', f: f, object: @consumer) diff --git a/app/views/consumers/show.html.slim b/app/views/consumers/show.html.slim index c355d819..9da38f3b 100644 --- a/app/views/consumers/show.html.slim +++ b/app/views/consumers/show.html.slim @@ -5,4 +5,4 @@ h1 = row(label: 'consumer.name', value: @consumer.name) - %w[oauth_key oauth_secret].each do |attribute| = row(label: "consumer.#{attribute}") do - = content_tag(:input, nil, class: 'form-control', readonly: true, value: @consumer.send(attribute)) + = content_tag(:input, nil, class: 'form-control bg-secondary', readonly: true, value: @consumer.send(attribute)) diff --git a/app/views/error_template_attributes/_form.html.slim b/app/views/error_template_attributes/_form.html.slim index 72160cfd..e747a922 100644 --- a/app/views/error_template_attributes/_form.html.slim +++ b/app/views/error_template_attributes/_form.html.slim @@ -1,16 +1,16 @@ = form_for(@error_template_attribute) do |f| = render('shared/form_errors', object: @error_template_attribute) - .form-group - = f.label(:key) + .mb-3 + = f.label(:key, class: 'form-label') = f.text_field(:key, class: 'form-control', required: true) - .form-group - = f.label(:description) + .mb-3 + = f.label(:description, class: 'form-label') = f.text_field(:description, class: 'form-control') - .form-group - = f.label(:regex) + .mb-3 + = f.label(:regex, class: 'form-label') = f.text_field(:regex, class: 'form-control', required: true) .help-block.form-text == t('error_templates.hints.signature') - .form-check.form-group + .form-check.mb-3 label.form-check-label = f.check_box(:important, class: 'form-check-input') = t('activerecord.attributes.error_template_attribute.important') diff --git a/app/views/error_templates/_form.html.slim b/app/views/error_templates/_form.html.slim index f912ec7b..80784d3a 100644 --- a/app/views/error_templates/_form.html.slim +++ b/app/views/error_templates/_form.html.slim @@ -1,20 +1,20 @@ = form_for(@error_template) do |f| = render('shared/form_errors', object: @error_template) - .form-group - = f.label(:name) + .mb-3 + = f.label(:name, class: 'form-label') = f.text_field(:name, class: 'form-control', required: true) - .form-group - = f.label(:execution_environment_id) + .mb-3 + = f.label(:execution_environment_id, class: 'form-label') = f.collection_select(:execution_environment_id, ExecutionEnvironment.all.order(:name), :id, :name, {include_blank: false}, class: 'form-control') - .form-group - = f.label(:signature) + .mb-3 + = f.label(:signature, class: 'form-label') = f.text_field(:signature, class: 'form-control') .help-block.form-text == t('error_templates.hints.signature') - .form-group - = f.label(:description) + .mb-3 + = f.label(:description, class: 'form-label') = f.text_field(:description, class: 'form-control') - .form-group - = f.label(:hint) + .mb-3 + = f.label(:hint, class: 'form-label') = f.text_field(:hint, class: 'form-control') .help-block.form-text == t('error_templates.hints.hint_templates') .actions = render('shared/submit_button', f: f, object: @error_template) diff --git a/app/views/execution_environments/_form.html.slim b/app/views/execution_environments/_form.html.slim index 2a1122e8..75bf356c 100644 --- a/app/views/execution_environments/_form.html.slim +++ b/app/views/execution_environments/_form.html.slim @@ -1,52 +1,52 @@ = form_for(@execution_environment) do |f| = render('shared/form_errors', object: @execution_environment) - .form-group - = f.label(:name) + .mb-3 + = f.label(:name, class: 'form-label') = f.text_field(:name, class: 'form-control', required: true) - .form-group - = f.label(:file_type_id) + .mb-3 + = f.label(:file_type_id, class: 'form-label') = f.collection_select(:file_type_id, FileType.all.order(:name), :id, :name, {include_blank: true}, class: 'form-control') - .form-group - = f.label(:docker_image) + .mb-3 + = f.label(:docker_image, class: 'form-label') | 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.form-text == t('.hints.docker_image') - .form-group - = f.label(:exposed_ports_list) + .mb-3 + = f.label(:exposed_ports_list, class: 'form-label') = f.text_field(:exposed_ports_list, class: 'form-control', placeholder: '3000, 4000', pattern: '^(\s*(\d{1,5},\s*)*(\d{1,5}\s*))?$') .help-block.form-text = t('.hints.exposed_ports_list') - .form-group - = f.label(:memory_limit) + .mb-3 + = f.label(:memory_limit, class: 'form-label') = f.number_field(:memory_limit, class: 'form-control', min: ExecutionEnvironment::MINIMUM_MEMORY_LIMIT, value: f.object.memory_limit || ExecutionEnvironment::DEFAULT_MEMORY_LIMIT) - .form-group - = f.label(:cpu_limit) + .mb-3 + = f.label(:cpu_limit, class: 'form-label') = f.number_field(:cpu_limit, class: 'form-control', min: 1, step: 1, value: f.object.cpu_limit || ExecutionEnvironment::DEFAULT_CPU_LIMIT) .help-block.form-text = t('.hints.cpu_limit') .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) + .mb-3 + = f.label(:permitted_execution_time, class: 'form-label') = f.number_field(:permitted_execution_time, class: 'form-control', min: 1) - .form-group - = f.label(:pool_size) + .mb-3 + = f.label(:pool_size, class: 'form-label') = f.number_field(:pool_size, class: 'form-control', min: 0) - .form-group - = f.label(:run_command) + .mb-3 + = f.label(:run_command, class: 'form-label') = f.text_field(:run_command, class: 'form-control', placeholder: 'command %{filename}', required: true) .help-block.form-text == t('.hints.command') - .form-group - = f.label(:test_command) + .mb-3 + = f.label(:test_command, class: 'form-label') = f.text_field(:test_command, class: 'form-control', placeholder: 'command %{filename}') .help-block.form-text == t('.hints.command') - .form-group - = f.label(:testing_framework) + .mb-3 + = f.label(:testing_framework, class: 'form-label') = f.select(:testing_framework, @testing_framework_adapters, {include_blank: true}, class: 'form-control') - .form-group - = f.label(:help) + .mb-3 + = f.label(:help, class: 'form-label') = f.hidden_field(:help) .form-control.markdown .actions = render('shared/submit_button', f: f, object: @execution_environment) diff --git a/app/views/execution_environments/index.html.slim b/app/views/execution_environments/index.html.slim index e79b31fc..06247a17 100644 --- a/app/views/execution_environments/index.html.slim +++ b/app/views/execution_environments/index.html.slim @@ -1,11 +1,11 @@ h1.d-inline-block = ExecutionEnvironment.model_name.human(count: 2) - if Runner.management_active? - = button_to( { action: :sync_all_to_runner_management }, { form_class: 'float-right mb-2', class: 'btn btn-success' }) + = button_to( { action: :sync_all_to_runner_management }, { form_class: 'float-end mb-2', class: 'btn btn-success' }) i.fa-solid.fa-upload = t('execution_environments.index.synchronize_all.button') -.table-responsive +.table-responsive.w-100 table.table thead tr diff --git a/app/views/execution_environments/shell.html.slim b/app/views/execution_environments/shell.html.slim index 95b4cf18..f4031e25 100644 --- a/app/views/execution_environments/shell.html.slim +++ b/app/views/execution_environments/shell.html.slim @@ -1,7 +1,7 @@ h1 = @execution_environment #shell data-message-timeout=t('exercises.editor.timeout', permitted_execution_time: @execution_environment.permitted_execution_time) data-message-out-of-memory=t('exercises.editor.out_of_memory', memory_limit: @execution_environment.memory_limit) data-url=execute_command_execution_environment_path(@execution_environment) - .form-group + .mb-3 label for='command' = t('.command') input#command.form-control type='text' pre#output data-message-no-output=t('exercises.implement.no_output', timestamp: l(Time.now, format: :short)) diff --git a/app/views/execution_environments/show.html.slim b/app/views/execution_environments/show.html.slim index fbc58f0e..d29ead06 100644 --- a/app/views/execution_environments/show.html.slim +++ b/app/views/execution_environments/show.html.slim @@ -1,8 +1,8 @@ h1.d-inline-block = @execution_environment -.btn-group.float-right +.btn-group.float-end = render('shared/edit_button', object: @execution_environment) - button.btn.btn-secondary.float-right.dropdown-toggle data-toggle='dropdown' type='button' - ul.dropdown-menu.dropdown-menu-right role='menu' + button.btn.btn-secondary.float-end.dropdown-toggle data-bs-toggle='dropdown' type='button' + ul.dropdown-menu.dropdown-menu-end role='menu' li = link_to(t('execution_environments.index.synchronize.button'), sync_to_runner_management_execution_environment_path(@execution_environment), method: :post, class: 'dropdown-item text-dark') if policy(@execution_environment).sync_to_runner_management? li = link_to(t('execution_environments.index.shell'), shell_execution_environment_path(@execution_environment), class: 'dropdown-item text-dark') if policy(@execution_environment).shell? li = link_to(t('shared.statistics'), statistics_execution_environment_path(@execution_environment), 'data-turbolinks' => "false", class: 'dropdown-item text-dark') if policy(@execution_environment).statistics? diff --git a/app/views/exercise_collections/_add_exercise_modal.slim b/app/views/exercise_collections/_add_exercise_modal.slim index e0880b58..cbe241f5 100644 --- a/app/views/exercise_collections/_add_exercise_modal.slim +++ b/app/views/exercise_collections/_add_exercise_modal.slim @@ -1,7 +1,7 @@ - exercises = Exercise.order(:title) form#exercise-selection - .form-group + .mb-3 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}) diff --git a/app/views/exercise_collections/_form.html.slim b/app/views/exercise_collections/_form.html.slim index c31f8736..233aca3a 100644 --- a/app/views/exercise_collections/_form.html.slim +++ b/app/views/exercise_collections/_form.html.slim @@ -1,14 +1,14 @@ = form_for(@exercise_collection, multipart: true) do |f| = render('shared/form_errors', object: @exercise_collection) - .form-group - = f.label(t('activerecord.attributes.exercise_collections.name')) + .mb-3 + = f.label(t('activerecord.attributes.exercise_collections.name'), class: 'form-label') = f.text_field(:name, class: 'form-control', required: true) - .form-check.form-group + .form-check.mb-3 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')) + .mb-3 + = f.label(t('activerecord.attributes.exercise_collections.user'), class: 'form-label') = f.collection_select(:user_id, InternalUser.order(:name), :id, :name, {}, {class: 'form-control'}) .table-responsive#exercise-list @@ -30,7 +30,7 @@ .d-none = f.collection_select(:exercise_ids, Exercise.all, :id, :title, {}, {id: 'exercise-select', class: 'form-control', multiple: true}) .exercise-actions - button.btn.btn-outline-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-bs-toggle='modal' data-bs-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) diff --git a/app/views/exercises/_add_tip_modal.slim b/app/views/exercises/_add_tip_modal.slim index 92faa42b..ad85f524 100644 --- a/app/views/exercises/_add_tip_modal.slim +++ b/app/views/exercises/_add_tip_modal.slim @@ -1,7 +1,7 @@ - tips = Tip.order(:title) form#tip-selection - .form-group + .mb-3 span.badge = t('activerecord.attributes.exercise_tip.tip') .mb-2 = collection_select({}, :tip_ids, tips, :id, :to_s, {}, {id: 'add-tip-list', class: 'form-control', multiple: true}) diff --git a/app/views/exercises/_code_field.html.slim b/app/views/exercises/_code_field.html.slim index 5e05489b..1945178a 100644 --- a/app/views/exercises/_code_field.html.slim +++ b/app/views/exercises/_code_field.html.slim @@ -1,7 +1,7 @@ -.form-group class="form-group-#{attribute.to_s.gsub('_', '-')}" - = form.label(attribute, label) +.mb-3 + = form.label(attribute, label, class: 'form-label') = form.text_area(attribute, class: 'code-field form-control', rows: 16, style: "display:none;") = render partial: 'editor_edit', locals: { exercise: @exercise } .card.border-warning.p-2.my-2 - = form.file_field(attribute, class: 'form-control-file', style: "display: inline-block;") + = form.file_field(attribute, class: 'form-control', style: "display: inline-block;") .help-block.form-text = t('exercises.file_form.hints.upload') diff --git a/app/views/exercises/_comment_dialogcontent.html.slim b/app/views/exercises/_comment_dialogcontent.html.slim index ab6dc6b4..706c8b9e 100644 --- a/app/views/exercises/_comment_dialogcontent.html.slim +++ b/app/views/exercises/_comment_dialogcontent.html.slim @@ -3,10 +3,10 @@ .container label - input#subscribe type='checkbox' title=t('request_for_comments.subscribe_to_author') data-subscription=Subscription.where(user: current_user, request_for_comment_id: @request_for_comment.id, subscription_type: 'author', deleted: false).try(:first).try(:id) + input#subscribe.form-check-input type='checkbox' title=t('request_for_comments.subscribe_to_author') data-subscription=Subscription.where(user: current_user, request_for_comment_id: @request_for_comment.id, subscription_type: 'author', deleted: false).try(:first).try(:id) = t('request_for_comments.subscribe_to_author') -#myComment +#myComment.d-grid h5 =t('exercises.implement.comment.addyours') textarea.form-control - button#addCommentButton.btn.btn-block.btn-primary(type='button') =t('exercises.implement.comment.addCommentButton') \ No newline at end of file + button#addCommentButton.btn.btn-primary(type='button') =t('exercises.implement.comment.addCommentButton') diff --git a/app/views/exercises/_editor.html.slim b/app/views/exercises/_editor.html.slim index 4e587b9e..c9550900 100644 --- a/app/views/exercises/_editor.html.slim +++ b/app/views/exercises/_editor.html.slim @@ -1,13 +1,13 @@ -- external_user_external_id = @current_user.respond_to?(:external_id) ? @current_user.external_id : '' #'tests' #(@current_user.uuid.present? ? @current_user.uuid : '') -- external_user_id = @current_user.respond_to?(:external_id) ? @current_user.id : '' #'tests' #(@current_user.uuid.present? ? @current_user.uuid : '') -- consumer_id = @current_user.respond_to?(:external_id) ? @current_user.consumer_id : '' #'tests' #(@current_user.uuid.present? ? @current_user.uuid : '') +- external_user_external_id = @current_user.respond_to?(:external_id) ? @current_user.external_id : '' +- external_user_id = @current_user.respond_to?(:external_id) ? @current_user.id : '' +- consumer_id = @current_user.respond_to?(:external_id) ? @current_user.consumer_id : '' - show_break_interventions = @show_break_interventions || "false" - show_rfc_interventions = @show_rfc_interventions || "false" - show_tips_interventions = @show_tips_interventions || "false" - 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-message-out-of-memory=t('exercises.editor.out_of_memory', memory_limit: @exercise.execution_environment.memory_limit) 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-tips-interventions=show_tips_interventions data-course_token=@course_token data-search-save-url=search_exercise_path(@exercise) - unless @embed_options[:hide_sidebar] - - additional_classes = 'sidebar-col' - if @tips.blank? - if @exercise.hide_file_tree @@ -15,14 +15,16 @@ - else - additional_classes = 'sidebar-col w-25' div id="sidebar" class=additional_classes = render('editor_file_tree', exercise: @exercise, files: @files) + + div.editor-col.col.p-0 id='frames' #editor-buttons.btn-group.enforce-bottom-margin = render('editor_button', disabled: true, icon: 'fa-solid fa-ban', id: 'dummy', label: t('exercises.editor.dummy')) = render('editor_button', icon: 'fa-solid fa-desktop', id: 'render', label: t('exercises.editor.render')) unless @embed_options[:hide_run_button] - = render('editor_button', data: {:'data-message-failure' => t('exercises.editor.run_failure'), :'data-message-network' => t('exercises.editor.network'), :'data-message-success' => t('exercises.editor.run_success'), :'data-placement' => 'top', :'data-toggle' => 'tooltip', :'data-container' => 'body'}, icon: 'fa-solid fa-play', id: 'run', label: t('exercises.editor.run'), title: t('shared.tooltips.shortcut', shortcut: 'ALT + r')) unless @embed_options[:disable_run] - = render('editor_button', data: {:'data-placement' => 'top', :'data-toggle' => 'tooltip', :'data-container' => 'body'}, icon: 'fa-solid fa-stop', id: 'stop', label: t('exercises.editor.stop'), title: t('shared.tooltips.shortcut', shortcut: 'ALT + r')) unless @embed_options[:disable_run] - = render('editor_button', data: {:'data-placement' => 'top', :'data-toggle' => 'tooltip', :'data-container' => 'body'}, icon: 'fa-solid fa-rocket', id: 'test', label: t('exercises.editor.test'), title: t('shared.tooltips.shortcut', shortcut: 'ALT + t')) unless @embed_options[:disable_run] - = render('editor_button', data: {:'data-placement' => 'top', :'data-toggle' => 'tooltip', :'data-container' => 'body'}, icon: 'fa-solid fa-trophy', id: 'assess', label: t('exercises.editor.score'), title: t('shared.tooltips.shortcut', shortcut: 'ALT + s')) unless @embed_options[:disable_score] + = render('editor_button', data: {:'data-message-failure' => t('exercises.editor.run_failure'), :'data-message-network' => t('exercises.editor.network'), :'data-message-success' => t('exercises.editor.run_success'), :'data-bs-placement' => 'top', :'data-bs-toggle' => 'tooltip', :'data-bs-container' => 'body'}, icon: 'fa-solid fa-play', id: 'run', label: t('exercises.editor.run'), title: t('shared.tooltips.shortcut', shortcut: 'ALT + r')) unless @embed_options[:disable_run] + = render('editor_button', data: {:'data-bs-placement' => 'top', :'data-bs-toggle' => 'tooltip', :'data-bs-container' => 'body'}, icon: 'fa-solid fa-stop', id: 'stop', label: t('exercises.editor.stop'), title: t('shared.tooltips.shortcut', shortcut: 'ALT + r')) unless @embed_options[:disable_run] + = render('editor_button', data: {:'data-bs-placement' => 'top', :'data-bs-toggle' => 'tooltip', :'data-bs-container' => 'body'}, icon: 'fa-solid fa-rocket', id: 'test', label: t('exercises.editor.test'), title: t('shared.tooltips.shortcut', shortcut: 'ALT + t')) unless @embed_options[:disable_run] + = render('editor_button', data: {:'data-bs-placement' => 'top', :'data-bs-toggle' => 'tooltip', :'data-bs-container' => 'body'}, icon: 'fa-solid fa-trophy', id: 'assess', label: t('exercises.editor.score'), title: t('shared.tooltips.shortcut', shortcut: 'ALT + s')) unless @embed_options[:disable_score] - unless hide_rfc_button = render('editor_button', icon: 'fa-solid fa-comment', id: 'requestComments', label: t('exercises.editor.requestComments'), title: t('exercises.editor.requestCommentsTooltip')) @@ -33,7 +35,7 @@ #statusbar.d-flex.justify-content-between div - if !@embed_options[:disable_download] && @exercise.hide_file_tree? - button#download.p-0.border-0.btn-link.visible.bg-white + button#download.p-0.border-0.btn-link.visible.bg-white.text-primary i.fa-solid.fa-arrow-down = t('exercises.editor.download') @@ -44,7 +46,7 @@ = " | " - button#start-over-active-file.p-0.border-0.btn-link.bg-white data-message-confirm=t('exercises.editor.confirm_start_over_active_file') data-url=reload_exercise_path(@exercise) + button#start-over-active-file.p-0.border-0.btn-link.bg-white.text-primary data-message-confirm=t('exercises.editor.confirm_start_over_active_file') data-url=reload_exercise_path(@exercise) i.fa-solid.fa-clock-rotate-left = t('exercises.editor.start_over_active_file') diff --git a/app/views/exercises/_editor_file_tree.html.slim b/app/views/exercises/_editor_file_tree.html.slim index b3b1f7a5..e46d3dbe 100644 --- a/app/views/exercises/_editor_file_tree.html.slim +++ b/app/views/exercises/_editor_file_tree.html.slim @@ -1,41 +1,36 @@ -div id='sidebar-collapsed' class=(@exercise.hide_file_tree && @tips.blank? ? '' : 'd-none') - = render('editor_button', classes: 'btn-block btn-outline-dark btn', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa-solid fa-square-plus', id: 'sidebar-collapse-collapsed', label:'', title:t('exercises.editor.expand_action_sidebar')) +div.d-grid.gap-2 id='sidebar-collapsed' class=(@exercise.hide_file_tree && @tips.blank? ? '' : 'd-none') + = render('editor_button', classes: 'btn-outline-dark', data: {:'data-bs-toggle' => 'tooltip', :'data-bs-placement' => 'right'}, icon: 'fa-solid fa-square-plus', id: 'sidebar-collapse-collapsed', label:'', title:t('exercises.editor.expand_action_sidebar')) - unless @embed_options[:disable_hints] or @tips.blank? - = render('editor_button', classes: 'btn-block btn-secondary btn mb-4', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa-solid fa-lightbulb', id: 'tips-collapsed', label:'', title: t('exercises.form.tips')) + = render('editor_button', classes: 'btn-secondary btn mb-4', data: {:'data-bs-toggle' => 'tooltip', :'data-bs-placement' => 'right'}, icon: 'fa-solid fa-lightbulb', id: 'tips-collapsed', label:'', title: t('exercises.form.tips')) //- 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-solid fa-magnifying-glass', id: 'sidebar-search-collapsed', label: '', title: t('search.search_in_forum')) + = render('editor_button', classes: 'btn-primary btn enforce-top-margin', data: {:'data-bs-toggle' => 'tooltip', :'data-bs-placement' => 'right'}, icon: 'fa-solid fa-magnifying-glass', id: 'sidebar-search-collapsed', label: '', title: t('search.search_in_forum')) -div.h-100.col-sm-12.enforce-bottom-margin id='sidebar-uncollapsed' class=(@exercise.hide_file_tree && @tips.blank? ? 'd-none' : '') - .position-absolute.d-flex.mb-1.w-100 style="overflow: auto; left: 0; top: 0; height: 100%;" - .w-100 - = render('editor_button', classes: 'btn-block btn-outline-dark btn', icon: 'fa-solid fa-square-minus', id: 'sidebar-collapse', label: t('exercises.editor.collapse_action_sidebar')) +div.d-grid.enforce-bottom-margin id='sidebar-uncollapsed' class=(@exercise.hide_file_tree && @tips.blank? ? 'd-none' : '') + = render('editor_button', classes: 'btn-outline-dark overflow-hidden mb-2', icon: 'fa-solid fa-square-minus', id: 'sidebar-collapse', label: t('exercises.editor.collapse_action_sidebar')) + #content-left-sidebar.overflow-scroll + - unless false &&@exercise.hide_file_tree + div.overflow-scroll + .card.border-secondary + .card-header.d-flex.justify-content-between.align-items-center.px-0.py-1 + .px-2 = I18n.t('exercises.editor_file_tree.file_root') + div + - if @exercise.allow_file_creation + = render('editor_button', classes: 'btn-default btn-sm', data: {:'data-bs-toggle' => 'tooltip', :'data-cause' => 'file'}, icon: 'fa-solid fa-plus', id: 'create-file', label: '', title: t('exercises.editor.create_file')) + = render('editor_button', classes: 'btn-default btn-sm', data: {:'data-bs-toggle' => 'tooltip', :'data-cause' => 'file', :'data-message-confirm' => t('shared.confirm_destroy') }, icon: 'fa-regular fa-trash-can', id: 'destroy-file', label: '', title: t('exercises.editor.destroy_file')) + - unless @embed_options[:disable_download] + = render('editor_button', classes: 'btn-default btn-sm', data: {:'data-bs-toggle' => 'tooltip'}, icon: 'fa-solid fa-arrow-down', id: 'download', label:'', title: t('exercises.editor.download')) + = render('editor_button', classes: 'btn-default btn-sm', data: {:'data-bs-toggle' => 'tooltip', :'data-message-confirm' => t('exercises.editor.confirm_start_over'), :'data-url' => reload_exercise_path(@exercise)}, icon: 'fa-solid fa-clock-rotate-left', id: 'start-over', label: '', title: t('exercises.editor.start_over')) - - unless @exercise.hide_file_tree - div - hr + .card-body.pt-0.pe-0.ps-1.pb-1 - .card.border-secondary - .card-header.d-flex.justify-content-between.align-items-center.px-0.py-1 - .px-2 = I18n.t('exercises.editor_file_tree.file_root') - div - - if @exercise.allow_file_creation - = render('editor_button', classes: 'btn-default btn-sm', data: {:'data-toggle' => 'tooltip', :'data-cause' => 'file'}, icon: 'fa-solid fa-plus', id: 'create-file', label: '', title: t('exercises.editor.create_file')) - = render('editor_button', classes: 'btn-default btn-sm', data: {:'data-toggle' => 'tooltip', :'data-cause' => 'file', :'data-message-confirm' => t('shared.confirm_destroy') }, icon: 'fa-regular fa-trash-can', id: 'destroy-file', label: '', title: t('exercises.editor.destroy_file')) - - unless @embed_options[:disable_download] - = render('editor_button', classes: 'btn-default btn-sm', data: {:'data-toggle' => 'tooltip'}, icon: 'fa-solid fa-arrow-down', id: 'download', label:'', title: t('exercises.editor.download')) - = render('editor_button', classes: 'btn-default btn-sm', data: {:'data-toggle' => 'tooltip', :'data-message-confirm' => t('exercises.editor.confirm_start_over'), :'data-url' => reload_exercise_path(@exercise)}, icon: 'fa-solid fa-clock-rotate-left', id: 'start-over', label: '', title: t('exercises.editor.start_over')) + #files data-entries=FileTree.new(files).to_js_tree - .card-body.pt-0.pr-0.pl-1.pb-1 + hr - #files data-entries=FileTree.new(files).to_js_tree - - hr - - - unless @embed_options[:disable_hints] or @tips.blank? - = render(partial: 'tips_content') - .mb-4 + - unless @embed_options[:disable_hints] or @tips.blank? + = render(partial: 'tips_content') //- if !@course_token.blank? .input-group.enforce-top-margin diff --git a/app/views/exercises/_editor_output.html.slim b/app/views/exercises/_editor_output.html.slim index 8d8d1da8..2997ca3e 100644 --- a/app/views/exercises/_editor_output.html.slim +++ b/app/views/exercises/_editor_output.html.slim @@ -1,90 +1,86 @@ -div id='output_sidebar_collapsed' - = render('editor_button', classes: 'btn-block btn-outline-dark btn', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'left'}, title: t('exercises.editor.expand_output_sidebar'), icon: 'fa-solid fa-square-plus', 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_yet') - .row - = render('editor_button', classes: 'btn-block btn-outline-dark btn', icon: 'fa-solid fa-square-minus', id: 'toggle-sidebar-output', label: t('exercises.editor.collapse_output_sidebar')) +div.d-grid id='output_sidebar_collapsed' + = render('editor_button', classes: 'btn-outline-dark btn', data: {:'data-bs-toggle' => 'tooltip', :'data-bs-placement' => 'left'}, title: t('exercises.editor.expand_output_sidebar'), icon: 'fa-solid fa-square-plus', id: 'toggle-sidebar-output-collapsed', label: '') +div.d-grid id='output_sidebar_uncollapsed' class='d-none col-sm-12 enforce-bottom-margin' data-message-no-output=t('exercises.implement.no_output_yet') + = render('editor_button', classes: 'btn-outline-dark btn overflow-hidden mb-2', icon: 'fa-solid fa-square-minus', id: 'toggle-sidebar-output', label: t('exercises.editor.collapse_output_sidebar')) - 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) - - unless @embed_options[:hide_test_results] - ul.list-unstyled - ul#test-dummies.d-none.list-unstyled - li.card.mt-2 - .card-header.py-2 - h5.card-title.m-0 == t('exercises.implement.test_file', filename: '', number: 0) - .card-body.bg-white.text-dark - = row(label: 'exercises.implement.passed_tests') do - span.number - | 0 - =<> t('shared.out_of') - span.number - | 0 - = row(label: 'activerecord.attributes.submission.score') do - span.number - | 0 - =<> t('shared.out_of') - span.number - | 0 - = row(label: 'exercises.implement.feedback') - = row(label: 'exercises.implement.error_messages') - /= row(label: 'exercises.implement.output', value: link_to(t('shared.show'), '#')) - ul#linter-dummies.d-none.list-unstyled - li.card.mt-2 - .card-header.py-2 - h5.card-title.m-0 == t('exercises.implement.linter_file', filename: '', number: 0) - .card-body.bg-white.text-dark - = row(label: 'exercises.implement.code_rating') do - span.number - | 0 - =<> t('shared.out_of') - span.number - | 0 - = row(label: 'activerecord.attributes.submission.score') do - span.number - | 0 - =<> t('shared.out_of') - span.number - | 0 - = row(label: 'exercises.implement.feedback') - = row(label: 'exercises.implement.messages') - #score data-maximum-score=@exercise.maximum_score data-score=@exercise.final_submission(@current_user).try(:score) - h4 - span == "#{t('activerecord.attributes.submission.score')}: " - span.score - .progress - .progress-bar role='progressbar' + #content-right-sidebar.overflow-scroll + div.enforce-bottom-margin.overflow-auto.d-none id='score_div' + #results + h2 = t('exercises.implement.results') + p.test-count == t('exercises.implement.test_count', count: 0) + - unless @embed_options[:hide_test_results] + ul.list-unstyled + ul#test-dummies.d-none.list-unstyled + li.card.mt-2 + .card-header.py-2 + h5.card-title.m-0 == t('exercises.implement.test_file', filename: '', number: 0) + .card-body.bg-white.text-dark + = row(label: 'exercises.implement.passed_tests') do + span.number + | 0 + =<> t('shared.out_of') + span.number + | 0 + = row(label: 'activerecord.attributes.submission.score') do + span.number + | 0 + =<> t('shared.out_of') + span.number + | 0 + = row(label: 'exercises.implement.feedback') + = row(label: 'exercises.implement.error_messages') + /= row(label: 'exercises.implement.output', value: link_to(t('shared.show'), '#')) + ul#linter-dummies.d-none.list-unstyled + li.card.mt-2 + .card-header.py-2 + h5.card-title.m-0 == t('exercises.implement.linter_file', filename: '', number: 0) + .card-body.bg-white.text-dark + = row(label: 'exercises.implement.code_rating') do + span.number + | 0 + =<> t('shared.out_of') + span.number + | 0 + = row(label: 'activerecord.attributes.submission.score') do + span.number + | 0 + =<> t('shared.out_of') + span.number + | 0 + = row(label: 'exercises.implement.feedback') + = row(label: 'exercises.implement.messages') + #score data-maximum-score=@exercise.maximum_score data-score=@exercise.final_submission(@current_user).try(:score) + h4 + span == "#{t('activerecord.attributes.submission.score')}: " + span.score + .progress + .progress-bar role='progressbar' - br - - if lti_outcome_service?(@exercise.id, external_user_id) - p.text-center = render('editor_button', classes: 'btn-lg btn-success d-none', data: {:'data-url' => submit_exercise_path(@exercise)}, icon: 'fa-solid fa-paper-plane', id: 'submit', label: t('exercises.editor.submit')) - - if @exercise.submission_deadline.present? || @exercise.late_submission_deadline.present? - #deadline data-submission-deadline=@exercise.submission_deadline&.rfc2822 data-late-submission-deadline=@exercise.late_submission_deadline&.rfc2822 - h4 = t('exercises.editor.deadline') - = t('exercises.editor.hints.disclaimer') - - else - p.text-center = render('editor_button', classes: 'btn-lg btn-secondary disabled', data: {:'data-placement' => 'bottom', :'data-tooltip' => true}, icon: 'fa-regular fa-clock', 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 - #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') - - unless @embed_options[:disable_hints] - #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] && !@embed_options[:disable_hints] && !@embed_options[:hide_test_results] - #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.text-dark.bg-white + br + - if lti_outcome_service?(@exercise.id, external_user_id) + p.text-center = render('editor_button', classes: 'btn-lg btn-success d-none', data: {:'data-url' => submit_exercise_path(@exercise)}, icon: 'fa-solid fa-paper-plane', id: 'submit', label: t('exercises.editor.submit')) + - if @exercise.submission_deadline.present? || @exercise.late_submission_deadline.present? + #deadline data-submission-deadline=@exercise.submission_deadline&.rfc2822 data-late-submission-deadline=@exercise.late_submission_deadline&.rfc2822 + h4 = t('exercises.editor.deadline') + = t('exercises.editor.hints.disclaimer') + - else + p.text-center = render('editor_button', classes: 'btn-lg btn-secondary disabled', data: {:'data-bs-placement' => 'bottom', :'data-tooltip' => true}, icon: 'fa-regular fa-clock', id: 'submit_outdated', label: t('exercises.editor.exercise_deadline_passed'), title: t('exercises.editor.tooltips.exercise_deadline_passed')) + hr + #turtlediv.enforce-big-bottom-margin.overflow-auto.d-none + canvas#turtlecanvas width=400 height=400 + div.enforce-big-bottom-margin.overflow-auto + #prompt.input-group.mb-2.d-none + 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') + - unless @embed_options[:disable_hints] + #error-hints.mb-2.p-2 + .heading = t('exercises.implement.error_hints.heading') + ul.body.mb-0 + #output + pre.overflow-scroll = t('exercises.implement.no_output_yet') + - if CodeOcean::Config.new(:code_ocean).read[:flowr][:enabled] && !@embed_options[:disable_hints] && !@embed_options[:hide_test_results] + #flowrHint.mb-2.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.text-dark.bg-white diff --git a/app/views/exercises/_export_actions.html.slim b/app/views/exercises/_export_actions.html.slim index 646c82c0..c545172d 100644 --- a/app/views/exercises/_export_actions.html.slim +++ b/app/views/exercises/_export_actions.html.slim @@ -1,14 +1,14 @@ - if error - = button_tag type: 'button', class:'btn btn-primary pull-right export-button export-retry-button', data: {exercise_id: exercise.id} do + = button_tag type: 'button', class:'btn btn-primary float-end export-button export-retry-button', data: {exercise_id: exercise.id} do i.fa-solid.fa-arrows-rotate.confirm-icon = t('exercises.export_codeharbor.buttons.retry') - else - unless exported - if !exercise_found || update_right - = button_tag type: 'button', class:'btn btn-primary pull-right export-action export-button', data: {exercise_id: exercise.id} do + = button_tag type: 'button', class:'btn btn-primary float-end export-action export-button', data: {exercise_id: exercise.id} do i.fa-solid.fa-check.confirm-icon = t('exercises.export_codeharbor.buttons.export') -= button_tag type: 'submit', class:'btn btn-secondary pull-right export-button', data: {dismiss: 'modal'} do += button_tag type: 'submit', class:'btn btn-secondary float-end export-button', data: {dismiss: 'modal'} do i.fa-solid.fa-xmark.abort-icon = exported ? t('exercises.export_codeharbor.buttons.close') : t('exercises.export_codeharbor.buttons.abort') diff --git a/app/views/exercises/_file_form.html.slim b/app/views/exercises/_file_form.html.slim index 8af2cfe6..3ac07a8a 100644 --- a/app/views/exercises/_file_form.html.slim +++ b/app/views/exercises/_file_form.html.slim @@ -4,7 +4,7 @@ li.card.mt-2 .card-header role="tab" id="heading" - collapsed_class = f.index != 'index' ? 'collapsed' : nil - aria_expanded = f.index != 'index' ? 'false' : 'true' - a class=['file-heading', collapsed_class] data-toggle="collapse" href="#collapse#{f.index}" aria-expanded="#{aria_expanded}" + a class=['file-heading', collapsed_class] data-bs-toggle="collapse" href="#collapse#{f.index}" aria-expanded="#{aria_expanded}" div.clearfix role="button" i.fa-solid aria-hidden="true" span = f.object.filepath @@ -12,19 +12,19 @@ li.card.mt-2 .card-body - if policy(f.object).destroy? && id.present? .clearfix - .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')) + .btn.btn-warning.btn-sm.float-end.delete-file data-file-url=code_ocean_file_path(id) = t('shared.destroy') + .mb-3 + = f.label(:name, t('activerecord.attributes.file.name'), class: 'form-label') = f.text_field(:name, class: 'form-control') - .form-group - = f.label(:path, t('activerecord.attributes.file.path')) + .mb-3 + = f.label(:path, t('activerecord.attributes.file.path'), class: 'form-label') = f.text_field(:path, class: 'form-control') .help-block.form-text = t('.hints.path') - .form-group - = f.label(:file_type_id, t('activerecord.attributes.file.file_type_id')) + .mb-3 + = f.label(:file_type_id, t('activerecord.attributes.file.file_type_id'), class: 'form-label') = f.collection_select(:file_type_id, @file_types, :id, :name, {}, class: 'form-control') - .form-group - = f.label(:role, t('activerecord.attributes.file.role')) + .mb-3 + = f.label(:role, t('activerecord.attributes.file.role'), class: 'form-label') = f.select(:role, CodeOcean::File::TEACHER_DEFINED_ROLES.map { |role| [t("files.roles.#{role}"), role] }, {}, class: 'form-control') .form-check label.form-check-label @@ -35,11 +35,11 @@ li.card.mt-2 = f.check_box(:read_only, class: 'form-check-input') = t('activerecord.attributes.file.read_only') .test-related-fields style="display: #{f.object.teacher_defined_assessment? ? 'initial' : 'none'};" - .form-group - = f.label(:name, t('activerecord.attributes.file.feedback_message')) + .mb-3 + = f.label(:name, t('activerecord.attributes.file.feedback_message'), class: 'form-label') = f.text_area(:feedback_message, class: 'form-control', maxlength: 255) .help-block.form-text = t('.hints.feedback_message') - .form-group - = f.label(:role, t('activerecord.attributes.file.weight')) + .mb-3 + = f.label(:role, t('activerecord.attributes.file.weight'), class: 'form-label') = f.number_field(:weight, class: 'form-control', min: 0, step: 'any') = render('code_field', attribute: :content, form: f, label: t('activerecord.attributes.file.content')) diff --git a/app/views/exercises/_form.html.slim b/app/views/exercises/_form.html.slim index 4fab78d2..0ed9e03f 100644 --- a/app/views/exercises/_form.html.slim +++ b/app/views/exercises/_form.html.slim @@ -9,26 +9,26 @@ = 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) + .mb-3 + = f.label(:title, class: 'form-label') = f.text_field(:title, class: 'form-control', required: true) - .form-group - = f.label(:description) + .mb-3 + = f.label(:description, class: 'form-label') = f.pagedown :description, input_html: { preview: true, rows: 10 } - .form-group - = f.label(:execution_environment_id) + .mb-3 + = f.label(:execution_environment_id, class: 'form-label') = f.collection_select(:execution_environment_id, @execution_environments, :id, :name, {include_blank: t('exercises.form.none')}, class: 'form-control') - /.form-group - = f.label(:instructions) + /.mb-3 + = f.label(:instructions, class: 'form-label') = f.hidden_field(:instructions) .form-control.markdown - .form-group - = f.label(:submission_deadline) + .mb-3 + = f.label(:submission_deadline, class: 'form-label') .chosen-inline = f.datetime_select(:submission_deadline, include_blank: true) .help-block.form-text == t('.hints.submission_deadline') - .form-group - = f.label(:late_submission_deadline) + .mb-3 + = f.label(:late_submission_deadline, class: 'form-label') .chosen-inline = f.datetime_select(:late_submission_deadline, include_blank: true) .help-block.form-text == t('.hints.late_submission_deadline') @@ -52,15 +52,15 @@ 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')) + .mb-3 + = f.label(t('activerecord.attributes.exercise.difficulty'), class: 'form-label') = f.number_field :expected_difficulty, in: 1..10, step: 1, class: 'form-control' h2 = t('exercises.form.tags') ul.list-unstyled.card-group li.card .card-header role="tab" id="heading" - a.file-heading data-toggle="collapse" href="#tag-collapse" + a.file-heading data-bs-toggle="collapse" href="#tag-collapse" div.clearfix role="button" span = t('exercises.form.click_to_collapse') .card-collapse.collapse id="tag-collapse" role="tabpanel" @@ -73,29 +73,29 @@ th = t('activerecord.attributes.tag.difficulty') = collection_check_boxes :exercise, :tag_ids, @exercise_tags, :tag_id, :id do |b| tr - td = b.check_box + td = b.check_box class: 'form-check-input' td = b.object.tag.name - td = number_field "tag_factors[#{b.object.tag.id}]", :factor, :value => b.object.factor, in: 1..10, step: 1, class: 'form-control-sm' + td = number_field "tag_factors[#{b.object.tag.id}]", :factor, :value => b.object.factor, in: 1..10, step: 1, class: 'form-control form-control-sm' h2 = t('.tips') ul.list-unstyled.card-group li.card .card-header role="tab" id="tip-heading" - a.file-heading data-toggle="collapse" href="#tip-collapse" + a.file-heading data-bs-toggle="collapse" href="#tip-collapse" div.clearfix role="button" span = t('exercises.form.click_to_collapse') .card-collapse.collapse.mx-2 id="tip-collapse" role="tabpanel" = f.hidden_field(:tips, id: "tips-json", value: "") .list-group.nested-sortable-list.mt-2#tip-list = render(partial: 'tips/sortable_tip', collection: @tips, as: :exercise_tip) - button.btn.btn-outline-primary.my-2.w-100 type='button' data-toggle='modal' data-target='#add-tips-modal' = t('.add_tips') + button.btn.btn-outline-primary.my-2.w-100 type='button' data-bs-toggle='modal' data-bs-target='#add-tips-modal' = t('.add_tips') h2 = t('activerecord.attributes.exercise.files') ul#files.list-unstyled = f.fields_for :files do |files_form| = render('file_form', f: files_form) - a#add-file.btn.btn-secondary.btn-sm.float-right href='#' = t('.add_file') + a#add-file.btn.btn-secondary.btn-sm.float-end 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) diff --git a/app/views/exercises/_request_comment_dialogcontent.html.slim b/app/views/exercises/_request_comment_dialogcontent.html.slim index 861c4f4b..62ee2642 100644 --- a/app/views/exercises/_request_comment_dialogcontent.html.slim +++ b/app/views/exercises/_request_comment_dialogcontent.html.slim @@ -6,6 +6,6 @@ textarea.form-control.flex-grow-1#question(style='resize:none; height: 15vh;') 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 -div - button#askForCommentsButton.btn.btn-block.btn-primary(type='button' data-cause='requestComments' data-message-success=t('exercises.editor.request_for_comments_sent')) =t('exercises.implement.comment.request') - button#closeAskForCommentsButton.btn.btn-block.btn-warning(type='button') =t('activerecord.attributes.request_for_comments.close') +.d-grid.gap-2 + button#askForCommentsButton.btn.btn-primary(type='button' data-cause='requestComments' data-message-success=t('exercises.editor.request_for_comments_sent')) =t('exercises.implement.comment.request') + button#closeAskForCommentsButton.btn.btn-warning(type='button') =t('activerecord.attributes.request_for_comments.close') diff --git a/app/views/exercises/_tips_content.html.slim b/app/views/exercises/_tips_content.html.slim index 8424d378..cefd7fbb 100644 --- a/app/views/exercises/_tips_content.html.slim +++ b/app/views/exercises/_tips_content.html.slim @@ -5,7 +5,7 @@ - append_javascript_pack_tag('highlight') - append_stylesheet_pack_tag('highlight') -#tips.card.mt-2 role="tab" style="display: block;" +#tips.card.d-block.overflow-scroll role="tab" .card-header.py-2 i.fa-solid.fa-lightbulb = t('exercises.implement.tips.heading') diff --git a/app/views/exercises/external_users/statistics.html.slim b/app/views/exercises/external_users/statistics.html.slim index fe7d96b8..4b34fc89 100644 --- a/app/views/exercises/external_users/statistics.html.slim +++ b/app/views/exercises/external_users/statistics.html.slim @@ -42,15 +42,15 @@ h1 - if policy(@exercise).detailed_statistics? .bg-light.w-100.p-2.mb-4.align-items-center.d-flex.justify-content-between - if @show_autosaves - span.pl-1.pb-1 + span.ps-1.pb-1 i.fa-solid.fa-circle-info.align-middle - small.mr-5.ml-1 = t('.toggle_status_on') - = link_to t('.toggle_autosave_off'), statistics_external_user_exercise_path(show_autosaves: false), class: "btn btn-outline-dark float-right btn-sm" + small.me-5.ms-1 = t('.toggle_status_on') + = link_to t('.toggle_autosave_off'), statistics_external_user_exercise_path(show_autosaves: false), class: "btn btn-outline-dark float-end btn-sm" - else - span.pl-1.pb-1 + span.ps-1.pb-1 i.fa-solid.fa-circle-info.align-middle - small.mr-5.ml-1 = t('.toggle_status_off') - = link_to t('.toggle_autosave_on'), statistics_external_user_exercise_path(show_autosaves: true), class: "btn btn-outline-dark float-right btn-sm" + small.me-5.ms-1 = t('.toggle_status_off') + = link_to t('.toggle_autosave_on'), statistics_external_user_exercise_path(show_autosaves: true), class: "btn btn-outline-dark float-end btn-sm" #timeline .table-responsive table.table diff --git a/app/views/exercises/feedback.html.slim b/app/views/exercises/feedback.html.slim index 9b221d0d..5085ed8c 100644 --- a/app/views/exercises/feedback.html.slim +++ b/app/views/exercises/feedback.html.slim @@ -4,7 +4,7 @@ h1 = link_to_if(policy(@exercise).show?, @exercise, exercise_path(@exercise)) .header = t('activerecord.attributes.exercise.description') .value = render_markdown(@exercise.description) - span.header.col-sm-3.pl-0 = "#{t('activerecord.attributes.exercise.maximum_score')}" + span.header.col-sm-3.ps-0 = "#{t('activerecord.attributes.exercise.maximum_score')}" span.col-sm-9 = @exercise.maximum_score .header.mt-3 = t('activerecord.models.user_exercise_feedback.other') @@ -21,7 +21,7 @@ h1 = link_to_if(policy(@exercise).show?, @exercise, exercise_path(@exercise)) - if policy(@exercise).detailed_statistics? span.username = link_to_if(policy(feedback.user).show?, feedback.user.displayname, statistics_external_user_exercise_path(id: @exercise.id, external_user_id: feedback.user.id)) - if feedback.anomaly_notification - i class="fa-regular fa-envelope" data-placement="top" data-toggle="tooltip" data-container="body" title=feedback.anomaly_notification.reason + i class="fa-regular fa-envelope" data-bs-placement="top" data-bs-toggle="tooltip" data-bs-container="body" title=feedback.anomaly_notification.reason span.date = feedback.created_at .card-collapse role="tabpanel" .card-body.feedback @@ -32,8 +32,8 @@ h1 = link_to_if(policy(@exercise).show?, @exercise, exercise_path(@exercise)) .card-footer div.clearfix.feedback-header span.points.flex-grow-1 = "#{t('exercises.statistics.score')}: #{@submissions[index].score}" - span.working_time.pull-right = "#{t('exercises.statistics.worktime')}: #{@exercise.average_working_time_for(feedback.user) or 0}" + span.working_time.float-end = "#{t('exercises.statistics.worktime')}: #{@exercise.average_working_time_for(feedback.user) or 0}" = render('shared/pagination', collection: @feedbacks) - script type="text/javascript" $(function () { $('[data-toggle="tooltip"]').tooltip() }); + script type="text/javascript" $(function () { $('[data-bs-toggle="tooltip"]').tooltip() }); diff --git a/app/views/exercises/implement.html.slim b/app/views/exercises/implement.html.slim index 6666dcbb..cd455ed4 100644 --- a/app/views/exercises/implement.html.slim +++ b/app/views/exercises/implement.html.slim @@ -3,36 +3,31 @@ Otherwise, lti_parameters might be nil meta name="turbolinks-cache-control" content="no-cache" -.row - #editor-column.col-md-12 - - unless @embed_options[:hide_exercise_description] - .exercise.clearfix - div - span.badge.badge-pill.badge-primary.float-right.score +// col-md-12 required for CodePilot +#editor-column.col-md-12 + - unless @embed_options[:hide_exercise_description] + .exercise.clearfix + div + span.badge.rounded-pill.bg-primary.float-end.score - h1 id="exercise-headline" - i id="description-symbol" class=(@embed_options[:collapse_exercise_description] ? 'fa-solid fa-chevron-right' : 'fa-solid fa-chevron-down') - = @exercise.title + h1 id="exercise-headline" + i id="description-symbol" class=(@embed_options[:collapse_exercise_description] ? 'fa-solid fa-chevron-right' : 'fa-solid fa-chevron-down') + = @exercise.title - #description-card.lead class=(@embed_options[:collapse_exercise_description] ? 'description-card-collapsed' : 'description-card') - = render_markdown(@exercise.description) + #description-card.lead class=(@embed_options[:collapse_exercise_description] ? 'description-card-collapsed' : 'description-card') + = render_markdown(@exercise.description) - a#toggle href="#" data-show=t('shared.show') data-hide=t('shared.hide') - - if @embed_options[:collapse_exercise_description] - = t('shared.show') - - else - = t('shared.hide') + a#toggle href="#" data-show=t('shared.show') data-hide=t('shared.hide') + - if @embed_options[:collapse_exercise_description] + = t('shared.show') + - else + = t('shared.hide') - #alert.alert.alert-danger role='alert' - h4 = t('.alert.title') - p = t('.alert.text', application_name: application_name) - #development-environment - .tab-content - #workspace.tab-pane.active = render('editor', exercise: @exercise, files: @files, submission: @submission) + = render('editor', exercise: @exercise, files: @files, submission: @submission) - - if qa_url - #questions-column - #questions-holder data-url="#{qa_url}/qa/index/#{@exercise.id}/#{@user_id}" - = qa_js_tag +- if qa_url + #questions-column + #questions-holder data-url="#{qa_url}/qa/index/#{@exercise.id}/#{@user_id}" + = qa_js_tag diff --git a/app/views/exercises/index.html.slim b/app/views/exercises/index.html.slim index 8f6267a5..3c91b5d1 100644 --- a/app/views/exercises/index.html.slim +++ b/app/views/exercises/index.html.slim @@ -1,16 +1,15 @@ h1 = Exercise.model_name.human(count: 2) = render(layout: 'shared/form_filters') do |f| - .row.px-3 - .form-group - = f.label(:execution_environment_id_eq, t('activerecord.attributes.exercise.execution_environment'), class: 'sr-only') - = f.collection_select(:execution_environment_id_eq, @execution_environments.with_exercises, :id, :name, class: 'form-control', prompt: t('activerecord.attributes.exercise.execution_environment')) - .form-group - = f.label(:title_cont, t('activerecord.attributes.exercise.title'), class: 'sr-only') - = f.search_field(:title_cont, class: 'form-control', placeholder: t('activerecord.attributes.exercise.title')) + .col-auto + = f.label(:execution_environment_id_eq, t('activerecord.attributes.exercise.execution_environment'), class: 'visually-hidden form-label') + = f.collection_select(:execution_environment_id_eq, @execution_environments.with_exercises, :id, :name, class: 'form-control', prompt: t('activerecord.attributes.exercise.execution_environment')) + .col-auto + = f.label(:title_cont, t('activerecord.attributes.exercise.title'), class: 'visually-hidden form-label') + = f.search_field(:title_cont, class: 'form-control', placeholder: t('activerecord.attributes.exercise.title')) .table-responsive - table.table.mt-4 + table.table.mt-2 thead tr th.p-1 = sort_link(@search, :title, t('activerecord.attributes.exercise.title')) @@ -41,8 +40,8 @@ h1 = Exercise.model_name.human(count: 2) td.p-1 .btn-group - 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" + button.btn.btn-outline-primary.btn-sm.dropdown-toggle data-bs-toggle="dropdown" type="button" = t('shared.actions_button') + ul.dropdown-menu.float-end 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('activerecord.models.request_for_comment.other'), rfcs_for_exercise_path(exercise), class: 'dropdown-item') if policy(exercise).rfcs_for_exercise? diff --git a/app/views/exercises/show.html.slim b/app/views/exercises/show.html.slim index b9e3f8e3..f8762ed0 100644 --- a/app/views/exercises/show.html.slim +++ b/app/views/exercises/show.html.slim @@ -6,10 +6,10 @@ - append_stylesheet_pack_tag('highlight') h1.d-inline-block = @exercise -.btn-group.float-right +.btn-group.float-end = render('shared/edit_button', object: @exercise) - button.btn.btn-secondary.float-right.dropdown-toggle data-toggle='dropdown' type='button' - ul.dropdown-menu.dropdown-menu-right role='menu' + button.btn.btn-secondary.float-end.dropdown-toggle data-bs-toggle='dropdown' type='button' + ul.dropdown-menu.dropdown-menu-end role='menu' li = link_to(t('exercises.index.implement'), implement_exercise_path(@exercise), 'data-turbolinks' => "false", class: 'dropdown-item text-dark') if policy(@exercise).implement? li = link_to(t('shared.statistics'), statistics_exercise_path(@exercise), 'data-turbolinks' => "false", class: 'dropdown-item text-dark') if policy(@exercise).statistics? li = link_to(t('activerecord.models.user_exercise_feedback.other'), feedback_exercise_path(@exercise), class: 'dropdown-item text-dark') if policy(@exercise).feedback? @@ -35,9 +35,10 @@ h1.d-inline-block = @exercise = row(label: 'exercise.uuid', value: @exercise.uuid) = 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: @exercise.unpublished? ? t('exercises.show.is_unpublished') : embedding_parameters(@exercise)) + = content_tag(:input, nil, class: 'form-control bg-secondary mb-4', readonly: true, value: @exercise.unpublished? ? t('exercises.show.is_unpublished') : embedding_parameters(@exercise)) - unless @tips.blank? + .mt-2 = render(partial: 'tips_content') h2.mt-4 = t('activerecord.attributes.exercise.files') @@ -46,14 +47,14 @@ 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}" + a.file-heading.collapsed data-bs-toggle="collapse" data-bs-parent="#files" href=".collapse#{file.id}" div.clearfix role="button" i.fa-solid aria-hidden="true" span = file.filepath .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 float-right', data: {confirm: t('shared.confirm_destroy')}, method: :delete) + .clearfix = link_to(t('shared.destroy'), file, class:'btn btn-warning btn-sm float-end', data: {confirm: t('shared.confirm_destroy')}, method: :delete) = render('shared/file', file: file) = render('shared/modal', id: 'export-modal', title: t('exercises.export_codeharbor.dialogtitle'), template: 'exercises/_export_dialogcontent') \ No newline at end of file diff --git a/app/views/exercises/study_group_dashboard.html.slim b/app/views/exercises/study_group_dashboard.html.slim index f2e281ef..4c615561 100644 --- a/app/views/exercises/study_group_dashboard.html.slim +++ b/app/views/exercises/study_group_dashboard.html.slim @@ -15,7 +15,7 @@ h4.mt-4 .d-none#initial_graph_data data-graph_data=ActiveSupport::JSON.encode(@graph_data); div.w-100#chart_stacked -.d-none.badge-info.container.py-2#no_chart_data +.d-none.bg-info.container.py-2#no_chart_data i class="fa-solid fa-info" aria-hidden="true" = t('.no_data_yet') @@ -27,9 +27,9 @@ h4.mt-4 thead tr th.text-center - i.mr-0 class="fa-regular fa-lightbulb" aria-hidden="true" title = t('request_for_comments.solved') + i.me-0 class="fa-regular fa-lightbulb" aria-hidden="true" title = t('request_for_comments.solved') th.text-center - i.mr-0 class="fa-solid fa-comment" aria-hidden="true" title = t('request_for_comments.comments') align="center" + i.me-0 class="fa-solid fa-comment" aria-hidden="true" title = t('request_for_comments.comments') align="center" th.col-12 = t('activerecord.attributes.request_for_comments.question') th = t('activerecord.attributes.request_for_comments.username') th.text-nowrap = t('activerecord.attributes.request_for_comments.requested_at') diff --git a/app/views/external_users/index.html.slim b/app/views/external_users/index.html.slim index d621085d..91ac6ccd 100644 --- a/app/views/external_users/index.html.slim +++ b/app/views/external_users/index.html.slim @@ -2,21 +2,21 @@ h1 = ExternalUser.model_name.human(count: 2) = render(layout: 'shared/form_filters') do |f| .row.px-3 - .form-group - = f.label(:name_cont, t('activerecord.attributes.external_user.name'), class: 'sr-only') + .mb-3 + = f.label(:name_cont, t('activerecord.attributes.external_user.name'), class: 'visually-hidden form-label') = f.search_field(:name_cont, class: 'form-control', placeholder: t('activerecord.attributes.external_user.name')) - .form-group - = f.label(:email_cont, t('activerecord.attributes.external_user.email'), class: 'sr-only') + .mb-3 + = f.label(:email_cont, t('activerecord.attributes.external_user.email'), class: 'visually-hidden form-label') = f.search_field(:email_cont, class: 'form-control', placeholder: t('activerecord.attributes.external_user.email')) - .form-group - = f.label(:external_id_cont, t('activerecord.attributes.external_user.external_id'), class: 'sr-only') + .mb-3 + = f.label(:external_id_cont, t('activerecord.attributes.external_user.external_id'), class: 'visually-hidden form-label') = f.search_field(:external_id_cont, class: 'form-control', placeholder: t('activerecord.attributes.external_user.external_id')) .row.px-3 - .form-group - = f.label(:role_eq, t('activerecord.attributes.external_user.role'), class: 'sr-only') + .mb-3 + = f.label(:role_eq, t('activerecord.attributes.external_user.role'), class: 'visually-hidden form-label') = f.select(:role_eq, User::ROLES.map { |role| [t("users.roles.#{role}"), role] }, { include_blank: true }, class: 'form-control', prompt: t('activerecord.attributes.external_user.role')) - .form-group - = f.label(:consumer_id_eq, t('activerecord.attributes.external_user.consumer'), class: 'sr-only') + .mb-3 + = f.label(:consumer_id_eq, t('activerecord.attributes.external_user.consumer'), class: 'visually-hidden form-label') = f.collection_select(:consumer_id_eq, Consumer.with_external_users, :id, :name, class: 'form-control', prompt: t('activerecord.attributes.external_user.consumer')) .table-responsive table.table diff --git a/app/views/file_templates/_form.html.slim b/app/views/file_templates/_form.html.slim index 1a5c34bc..be5390da 100644 --- a/app/views/file_templates/_form.html.slim +++ b/app/views/file_templates/_form.html.slim @@ -1,12 +1,12 @@ = form_for(@file_template) do |f| = render('shared/form_errors', object: @file_template) - .form-group - = f.label(:name) + .mb-3 + = f.label(:name, class: 'form-label') = f.text_field(:name, class: 'form-control', required: true) - .form-group - = f.label(:file_type_id) + .mb-3 + = f.label(:file_type_id, class: 'form-label') = f.collection_select(:file_type_id, FileType.all.order(:name), :id, :name, {}, class: 'form-control') - .form-group - = f.label(:content) + .mb-3 + = f.label(:content, class: 'form-label') = f.text_area(:content, class: 'form-control') .actions = render('shared/submit_button', f: f, object: @file_template) diff --git a/app/views/file_types/_form.html.slim b/app/views/file_types/_form.html.slim index e234a457..0c5f94da 100644 --- a/app/views/file_types/_form.html.slim +++ b/app/views/file_types/_form.html.slim @@ -1,16 +1,16 @@ = form_for(@file_type) do |f| = render('shared/form_errors', object: @file_type) - .form-group - = f.label(:name) + .mb-3 + = f.label(:name, class: 'form-label') = f.text_field(:name, class: 'form-control', required: true) - .form-group - = f.label(:editor_mode) + .mb-3 + = f.label(:editor_mode, class: 'form-label') = f.select(:editor_mode, @editor_modes, {}, class: 'form-control') - .form-group - = f.label(:file_extension) + .mb-3 + = f.label(:file_extension, class: 'form-label') = f.text_field(:file_extension, class: 'form-control', placeholder: '.rb') - .form-group - = f.label(:indent_size) + .mb-3 + = f.label(:indent_size, class: 'form-label') = f.number_field(:indent_size, class: 'form-control', placeholder: 2, required: true) .form-check label.form-check-label diff --git a/app/views/internal_users/_form.html.slim b/app/views/internal_users/_form.html.slim index 4a6ff45c..20dd5434 100644 --- a/app/views/internal_users/_form.html.slim +++ b/app/views/internal_users/_form.html.slim @@ -1,15 +1,15 @@ = form_for(@user) do |f| = render('shared/form_errors', object: @user) - .form-group - = f.label(:consumer_id) + .mb-3 + = f.label(:consumer_id, class: 'form-label') = f.collection_select(:consumer_id, Consumer.all.sort_by(&:name), :id, :name, {}, class: 'form-control') - .form-group - = f.label(:email) + .mb-3 + = f.label(:email, class: 'form-label') = f.email_field(:email, class: 'form-control', required: true) - .form-group - = f.label(:name) + .mb-3 + = f.label(:name, class: 'form-label') = f.text_field(:name, class: 'form-control', required: true) - .form-group - = f.label(:role) + .mb-3 + = f.label(:role, class: 'form-label') = f.select(:role, User::ROLES.map { |role| [t("users.roles.#{role}"), role] }, {selected: @user.role || 'teacher'}, class: 'form-control') .actions = render('shared/submit_button', f: f, object: @user) diff --git a/app/views/internal_users/activate.html.slim b/app/views/internal_users/activate.html.slim index 25795ed6..e19459b8 100644 --- a/app/views/internal_users/activate.html.slim +++ b/app/views/internal_users/activate.html.slim @@ -2,11 +2,11 @@ h1 = t('.headline') = form_for(@user, url: activate_internal_user_path) do |f| = render('shared/form_errors', object: @user) - .form-group - = f.label(:password) + .mb-3 + = f.label(:password, class: 'form-label') = f.password_field(:password, class: 'form-control', required: true) - .form-group - = f.label(:password_confirmation) + .mb-3 + = f.label(:password_confirmation, class: 'form-label') = f.password_field(:password_confirmation, class: 'form-control', required: true) = f.hidden_field(:activation_token) .actions = submit_tag(t('.submit'), class: 'btn btn-primary') diff --git a/app/views/internal_users/forgot_password.html.slim b/app/views/internal_users/forgot_password.html.slim index ca10fdac..dc417168 100644 --- a/app/views/internal_users/forgot_password.html.slim +++ b/app/views/internal_users/forgot_password.html.slim @@ -1,7 +1,7 @@ h1 = t('.headline') = form_tag do - .form-group + .mb-3 = label_tag(:email, t('activerecord.attributes.internal_user.email')) = email_field_tag(:email, params[:email], autofocus: true, class: 'form-control', required: true) .actions = submit_tag(t('.submit'), class: 'btn btn-primary') diff --git a/app/views/internal_users/index.html.slim b/app/views/internal_users/index.html.slim index 768a6dd6..8b0c0fde 100644 --- a/app/views/internal_users/index.html.slim +++ b/app/views/internal_users/index.html.slim @@ -1,16 +1,15 @@ h1 = InternalUser.model_name.human(count: 2) = render(layout: 'shared/form_filters') do |f| - .row.px-3 - .form-group - = f.label(:consumer_id_eq, t('activerecord.attributes.internal_user.consumer'), class: 'sr-only') - = f.collection_select(:consumer_id_eq, Consumer.with_internal_users, :id, :name, class: 'form-control', prompt: t('activerecord.attributes.internal_user.consumer')) - .form-group - = f.label(:email_cont, t('activerecord.attributes.internal_user.email'), class: 'sr-only') - = f.search_field(:email_cont, class: 'form-control', placeholder: t('activerecord.attributes.internal_user.email')) - .form-group - = f.label(:role_eq, t('activerecord.attributes.internal_user.role'), class: 'sr-only') - = f.select(:role_eq, User::ROLES.map { |role| [t("users.roles.#{role}"), role] }, {}, class: 'form-control', prompt: t('activerecord.attributes.internal_user.role')) + .col-auto + = f.label(:consumer_id_eq, t('activerecord.attributes.internal_user.consumer'), class: 'visually-hidden form-label') + = f.collection_select(:consumer_id_eq, Consumer.with_internal_users, :id, :name, class: 'form-control', prompt: t('activerecord.attributes.internal_user.consumer')) + .col-sm + = f.label(:email_cont, t('activerecord.attributes.internal_user.email'), class: 'visually-hidden form-label') + = f.search_field(:email_cont, class: 'form-control', placeholder: t('activerecord.attributes.internal_user.email')) + .col-auto + = f.label(:role_eq, t('activerecord.attributes.internal_user.role'), class: 'visually-hidden form-label') + = 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.mt-4 diff --git a/app/views/internal_users/reset_password.html.slim b/app/views/internal_users/reset_password.html.slim index 857121c2..c4011867 100644 --- a/app/views/internal_users/reset_password.html.slim +++ b/app/views/internal_users/reset_password.html.slim @@ -2,11 +2,11 @@ h1 = t('.headline') = form_for(@user, url: reset_password_internal_user_path) do |f| = render('shared/form_errors', object: @user) - .form-group - = f.label(:password) + .mb-3 + = f.label(:password, class: 'form-label') = f.password_field(:password, class: 'form-control', required: true) - .form-group - = f.label(:password_confirmation) + .mb-3 + = f.label(:password_confirmation, class: 'form-label') = f.password_field(:password_confirmation, class: 'form-control', required: true) = f.hidden_field(:reset_password_token) .actions = submit_tag(t('.submit'), class: 'btn btn-primary') diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim index 6145f52d..044088d1 100644 --- a/app/views/layouts/application.html.slim +++ b/app/views/layouts/application.html.slim @@ -42,13 +42,13 @@ html lang="#{I18n.locale || I18n.default_locale}" .navbar-brand i.fa-solid.fa-code = application_name - button.navbar-toggler data-target='#navbar-collapse' data-toggle='collapse' type='button' aria-expanded='false' aria-label='Toggle navigation' + button.navbar-toggler data-bs-target='#navbar-collapse' data-bs-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.ml-auto + ul.nav.navbar-nav.ms-auto = render('locale_selector', cached: true) - li.nav-item.mr-3 = link_to(t('shared.help.link'), '#modal-help', data: {toggle: 'modal'}, class: 'nav-link') + li.nav-item.me-3 = link_to(t('shared.help.link'), '#modal-help', data: {toggle: 'modal'}, class: 'nav-link') = render('session') div data-controller=controller_name = render('flash') diff --git a/app/views/proxy_exercises/_form.html.slim b/app/views/proxy_exercises/_form.html.slim index acc54ccc..3b63229e 100644 --- a/app/views/proxy_exercises/_form.html.slim +++ b/app/views/proxy_exercises/_form.html.slim @@ -1,10 +1,10 @@ = form_for(@proxy_exercise, multipart: true, builder: PagedownFormBuilder) do |f| = render('shared/form_errors', object: @proxy_exercise) - .form-group - = f.label(:title) + .mb-3 + = f.label(:title, class: 'form-label') = f.text_field(:title, class: 'form-control', required: true) - .form-group - = f.label(:description) + .mb-3 + = f.label(:description, class: 'form-label') = f.pagedown :description, input_html: { preview: true, rows: 10 } .form-check.mb-3 label.form-check-label @@ -21,7 +21,7 @@ th = sort_link(@search, :created_at, t('shared.created_at')) = collection_check_boxes :proxy_exercise, :exercise_ids, @exercises, :id, :title do |b| tr - td = b.check_box + td = b.check_box class: 'form-check-input' td = link_to_if(policy(b.object).show?, b.object, b.object) td = l(b.object.created_at, format: :short) diff --git a/app/views/proxy_exercises/index.html.slim b/app/views/proxy_exercises/index.html.slim index b4fe7acc..74266aab 100644 --- a/app/views/proxy_exercises/index.html.slim +++ b/app/views/proxy_exercises/index.html.slim @@ -1,10 +1,9 @@ h1 = ProxyExercise.model_name.human(count: 2) = render(layout: 'shared/form_filters') do |f| - .row.px-3 - .form-group - = f.label(:title_cont, t('activerecord.attributes.proxy_exercise.title'), class: 'sr-only') - = f.search_field(:title_cont, class: 'form-control', placeholder: t('activerecord.attributes.proxy_exercise.title')) + .col-auto + = f.label(:title_cont, t('activerecord.attributes.proxy_exercise.title'), class: 'visually-hidden form-label') + = f.search_field(:title_cont, class: 'form-control', placeholder: t('activerecord.attributes.proxy_exercise.title')) .table-responsive table.table.mt-4 @@ -28,10 +27,10 @@ h1 = ProxyExercise.model_name.human(count: 2) td.p-1 .btn-group - button.btn.btn-outline-primary.btn-sm.dropdown-toggle data-toggle="dropdown" type="button" = t('shared.actions_button') + button.btn.btn-outline-primary.btn-sm.dropdown-toggle data-bs-toggle="dropdown" type="button" = t('shared.actions_button') span.caret - span.sr-only Toggle Dropdown - ul.dropdown-menu.float-right role="menu" + span.visually-hidden Toggle Dropdown + ul.dropdown-menu.float-end 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? diff --git a/app/views/proxy_exercises/show.html.slim b/app/views/proxy_exercises/show.html.slim index c8ce10a7..892ef4c6 100644 --- a/app/views/proxy_exercises/show.html.slim +++ b/app/views/proxy_exercises/show.html.slim @@ -8,7 +8,7 @@ h1 = row(label: 'exercise.public', value: @proxy_exercise.public?) = row(label: 'exercise.description', value: @proxy_exercise.description) = row(label: 'exercise.embedding_parameters', class: 'mb-4') do - = content_tag(:input, nil, class: 'form-control mb-4', readonly: true, value: embedding_parameters(@proxy_exercise)) + = content_tag(:input, nil, class: 'form-control bg-secondary mb-4', readonly: true, value: embedding_parameters(@proxy_exercise)) h2.mt-4 Exercises .table-responsive diff --git a/app/views/request_for_comments/index.html.slim b/app/views/request_for_comments/index.html.slim index c02f9868..8328308c 100644 --- a/app/views/request_for_comments/index.html.slim +++ b/app/views/request_for_comments/index.html.slim @@ -1,17 +1,19 @@ h1 = RequestForComment.model_name.human(count: 2) = render(layout: 'shared/form_filters') do |f| - .row.px-3 - .form-group - = f.label(:exercise_title_cont, t('activerecord.attributes.request_for_comments.exercise'), class: 'sr-only') - = f.search_field(:exercise_title_cont, class: 'form-control', placeholder: t('activerecord.attributes.request_for_comments.exercise')) - .form-group - = f.label(:title_cont, t('request_for_comments.solved'), class: 'sr-only') - = 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]]) - .form-group - = f.label(:submission_study_group_id_eq, t('request_for_comments.index.study_groups.placeholder'), class: 'sr-only') - = f.grouped_collection_select(:submission_study_group_id_in, @study_groups_grouping, :second, :first, :id, :to_s, {}, - { class: 'form-control', multiple: true, "data-placeholder": t('request_for_comments.index.study_groups.placeholder') }) + .col-md-9.col + .row.align-items-center + .col-auto + = f.label(:exercise_title_cont, t('activerecord.attributes.request_for_comments.exercise'), class: 'visually-hidden form-label') + = f.search_field(:exercise_title_cont, class: 'form-control', placeholder: t('activerecord.attributes.request_for_comments.exercise')) + .col-auto.mt-3.mt-md-0 + = f.label(:title_cont, t('request_for_comments.solved'), class: 'visually-hidden form-label') + = 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]]) + .row + .col + = f.label(:submission_study_group_id_eq, t('request_for_comments.index.study_groups.placeholder'), class: 'visually-hidden form-label') + = f.grouped_collection_select(:submission_study_group_id_in, @study_groups_grouping, :second, :first, :id, :to_s, {}, + { class: 'form-control', multiple: true, "data-placeholder": t('request_for_comments.index.study_groups.placeholder') }) .table-responsive table.table.sortable.mt-4 diff --git a/app/views/request_for_comments/show.html.slim b/app/views/request_for_comments/show.html.slim index c43d4467..aaaf578a 100644 --- a/app/views/request_for_comments/show.html.slim +++ b/app/views/request_for_comments/show.html.slim @@ -56,7 +56,7 @@ - if @current_user.admin? && user.is_a?(ExternalUser) = render('admin_menu') - hr/ + hr .howto h5.mt-4 @@ -70,8 +70,8 @@ | 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/ - | + br + | i.fa-solid.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" @@ -448,11 +448,11 @@ javascript: if (commenttext !== "") { createComment(fileid, row, editor, commenttext); commentTextarea.val('') ; - commentModal.modal('hide'); + bootstrap.Modal.getInstance(commentModal).hide(); } }); - commentModal.modal('show'); + new bootstrap.Modal(commentModal).show(); } function ajaxError(response) { diff --git a/app/views/sessions/new.html.slim b/app/views/sessions/new.html.slim index d2cf3211..d7ce1e31 100644 --- a/app/views/sessions/new.html.slim +++ b/app/views/sessions/new.html.slim @@ -1,16 +1,16 @@ h1 = t('.headline') = form_tag(sessions_path) do - .form-group + .mb-3 = label_tag(:email, t('activerecord.attributes.internal_user.email')) = email_field_tag(:email, params[:email], autofocus: true, class: 'form-control', required: true) - .form-group + .mb-3 = label_tag(:password, t('activerecord.attributes.internal_user.password')) = password_field_tag(:password, nil, class: 'form-control', required: true) - .form-check.form-group + .form-check.mb-3 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.float-right = link_to(t('.forgot_password'), forgot_password_path) + span.float-end = link_to(t('.forgot_password'), forgot_password_path) .actions = submit_tag(t('.link'), class: 'btn btn-primary') diff --git a/app/views/shared/_edit_button.html.slim b/app/views/shared/_edit_button.html.slim index a0c4bd21..33d1bf41 100644 --- a/app/views/shared/_edit_button.html.slim +++ b/app/views/shared/_edit_button.html.slim @@ -1,4 +1,4 @@ - if policy(object).edit? // 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') + = link_to(t('shared.edit'), link_target, class: 'btn btn-secondary float-end') diff --git a/app/views/shared/_form_filters.html.slim b/app/views/shared/_form_filters.html.slim index 3a3afb90..7f19280f 100644 --- a/app/views/shared/_form_filters.html.slim +++ b/app/views/shared/_form_filters.html.slim @@ -1,11 +1,10 @@ -.card.card-body.bg-light.flex-row.container.row.mx-0 - = search_form_for(@search, class: 'clearfix filter-form form-inline w-100') do |f| - .col-sm.p-0 - = yield(f) - .col-sm-auto.p-0 - .btn-group.ml-auto +.card.card-body.bg-light.flex-row.container.justify-content-center + = search_form_for(@search, class: 'clearfix filter-form align-items-center row g-2 w-100') do |f| + = yield(f) + .col-sm.ge-4.gy-2 + .btn-group.float-end.ms-auto.text-nowrap button.btn.btn-primary type='submit' = t('shared.apply_filters') - button.btn.btn-primary.dropdown-toggle data-toggle='dropdown' type='button' + button.btn.btn-primary.dropdown-toggle data-bs-toggle='dropdown' type='button' ul.dropdown-menu role='menu' li a.dropdown-item href=request.path = t('shared.reset_filters') diff --git a/app/views/shared/_modal.html.slim b/app/views/shared/_modal.html.slim index afddbea8..97d6fb1c 100644 --- a/app/views/shared/_modal.html.slim +++ b/app/views/shared/_modal.html.slim @@ -3,9 +3,8 @@ .modal-content .modal-header h4#modal-title.modal-title = title - button.close data-dismiss='modal' type='button' - span aria-hidden=true × - span.sr-only Close + button.btn-close data-bs-dismiss='modal' type='button' + span.visually-hidden Close .modal-body - if local_assigns.has_key?(:body) = body diff --git a/app/views/statistics/activity_history.html.slim b/app/views/statistics/activity_history.html.slim index 7e1435db..da9a50c9 100644 --- a/app/views/statistics/activity_history.html.slim +++ b/app/views/statistics/activity_history.html.slim @@ -11,13 +11,13 @@ .spinner .graph id="#{resource}-activity-history" form - .form-group + .mb-3 label for="from-date" = t('.from') input type="date" class="form-control" id="from-date" name="from" value=(params[:from] || DateTime.new(2016).to_date) - .form-group + .mb-3 label for="to-date" = t('.to') input type="date" class="form-control" id="to-date" name="to" value=(params[:to] || DateTime.now.to_date) - .form-group + .mb-3 label for="interval" = t('.interval') select class="form-control" id="interval" name="interval" = [:year, :quarter, :month, :day, :hour, :minute, :second].each do | key | diff --git a/app/views/study_groups/_form.html.slim b/app/views/study_groups/_form.html.slim index 1872cdc5..b0e705fc 100644 --- a/app/views/study_groups/_form.html.slim +++ b/app/views/study_groups/_form.html.slim @@ -1,7 +1,7 @@ = form_for(@study_group) do |f| = render('shared/form_errors', object: @study_group) - .form-group - = f.label(:name) + .mb-3 + = f.label(:name, class: 'form-label') = f.text_field(:name, class: 'form-control', required: true) h3 = t('activerecord.attributes.study_group.members') @@ -13,7 +13,7 @@ th = sort_link(@search, :name, t('navigation.sections.users')) = collection_check_boxes :study_group, :study_group_membership_ids, @members, :id, :id do |b| tr - td = b.check_box + td = b.check_box class: 'form-check-input' td = link_to_if(policy(b.object.user).show?, b.object.user.displayname, b.object.user) .actions = render('shared/submit_button', f: f, object: @study_group) diff --git a/app/views/study_groups/index.html.slim b/app/views/study_groups/index.html.slim index af0ba826..ae41914a 100644 --- a/app/views/study_groups/index.html.slim +++ b/app/views/study_groups/index.html.slim @@ -1,13 +1,12 @@ h1 = StudyGroup.model_name.human(count: 2) = render(layout: 'shared/form_filters') do |f| - .row.px-3 - .form-group - = f.label(:consumer_id_eq, t('activerecord.attributes.internal_user.consumer'), class: 'sr-only') - = f.collection_select(:consumer_id_eq, Consumer.with_study_groups, :id, :name, class: 'form-control', prompt: t('activerecord.attributes.internal_user.consumer')) - .form-group - = f.label(:name_cont, t('activerecord.attributes.study_group.name'), class: 'sr-only') - = f.search_field(:name_cont, class: 'form-control', placeholder: t('activerecord.attributes.study_group.name')) + .col-auto + = f.label(:consumer_id_eq, t('activerecord.attributes.internal_user.consumer'), class: 'visually-hidden form-label') + = f.collection_select(:consumer_id_eq, Consumer.with_study_groups, :id, :name, class: 'form-control', prompt: t('activerecord.attributes.internal_user.consumer')) + .col-auto + = f.label(:name_cont, t('activerecord.attributes.study_group.name'), class: 'visually-hidden form-label') + = f.search_field(:name_cont, class: 'form-control', placeholder: t('activerecord.attributes.study_group.name')) .table-responsive table.table.mt-4 diff --git a/app/views/submissions/index.html.slim b/app/views/submissions/index.html.slim index 3b922b82..d1a46ab7 100644 --- a/app/views/submissions/index.html.slim +++ b/app/views/submissions/index.html.slim @@ -1,13 +1,12 @@ h1 = Submission.model_name.human(count: 2) = render(layout: 'shared/form_filters') do |f| - .row.px-3 - .form-group - = f.label(:exercise_id_eq, t('activerecord.attributes.submission.exercise'), class: 'sr-only') - = 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.select(:cause).distinct.map(&:cause).sort, class: 'form-control', prompt: t('activerecord.attributes.submission.cause')) + .col-auto + = f.label(:exercise_id_eq, t('activerecord.attributes.submission.exercise'), class: 'visually-hidden form-label') + = f.collection_select(:exercise_id_eq, Exercise.with_submissions, :id, :title, class: 'form-control', prompt: t('activerecord.attributes.submission.exercise')) + .col-auto + = f.label(:cause_eq, t('activerecord.attributes.submission.cause'), class: 'visually-hidden form-label') + = f.select(:cause_eq, Submission.select(:cause).distinct.map(&:cause).sort, class: 'form-control', prompt: t('activerecord.attributes.submission.cause')) .table-responsive table.table.mt-4 diff --git a/app/views/tags/_form.html.slim b/app/views/tags/_form.html.slim index 4f02a28f..14763915 100644 --- a/app/views/tags/_form.html.slim +++ b/app/views/tags/_form.html.slim @@ -1,6 +1,6 @@ = form_for(@tag) do |f| = render('shared/form_errors', object: @tag) - .form-group - = f.label(:name) + .mb-3 + = f.label(:name, class: 'form-label') = f.text_field(:name, class: 'form-control', required: true) .actions = render('shared/submit_button', f: f, object: @tag) diff --git a/app/views/tips/_collapsed_card.html.slim b/app/views/tips/_collapsed_card.html.slim index 9aaf2782..4c2adaee 100644 --- a/app/views/tips/_collapsed_card.html.slim +++ b/app/views/tips/_collapsed_card.html.slim @@ -3,7 +3,7 @@ .card class="#{exercise_tip.parent_exercise_tip_id? || exercise_tip.rank != 1 ? 'mt-2' : ''}" .card-header.p-2 id="tip-heading-#{exercise_tip.id}" role="tab" .card-title.mb-0 - a.collapsed aria-controls="tip-collapse-#{exercise_tip.id}" aria-expanded="false" data-parent="#tips" data-toggle="collapse" href="#tip-collapse-#{exercise_tip.id}" + a.collapsed aria-controls="tip-collapse-#{exercise_tip.id}" aria-expanded="false" data-bs-parent="#tips" data-bs-toggle="collapse" href="#tip-collapse-#{exercise_tip.id}" .clearfix role="button" i.fa-solid aria-hidden="true" span diff --git a/app/views/tips/_form.html.slim b/app/views/tips/_form.html.slim index d74f0603..1af4f291 100644 --- a/app/views/tips/_form.html.slim +++ b/app/views/tips/_form.html.slim @@ -1,16 +1,16 @@ = form_for(@tip, builder: PagedownFormBuilder) do |f| = render('shared/form_errors', object: @tip) - .form-group - = f.label(:title) + .mb-3 + = f.label(:title, class: 'form-label') = f.text_field(:title, class: 'form-control', required: false) - .form-group - = f.label(:description) + .mb-3 + = f.label(:description, class: 'form-label') = f.pagedown :description, input_html: { preview: true, rows: 5 } - .form-group - = f.label(:file_type_id, t('activerecord.attributes.file.file_type_id')) + .mb-3 + = f.label(:file_type_id, t('activerecord.attributes.file.file_type_id'), class: 'form-label') = f.collection_select(:file_type_id, @file_types, :id, :name, {include_blank: true}, class: 'form-control') - .form-group - = f.label(:example) + .mb-3 + = f.label(:example, class: 'form-label') = f.text_area(:example, class: 'code-field form-control', rows: 5, style: "display:none;", required: false) #editor-edit.original-input data-file-id=@tip.id #frames diff --git a/app/views/tips/_sortable_tip.html.slim b/app/views/tips/_sortable_tip.html.slim index 183cd240..80587e0e 100644 --- a/app/views/tips/_sortable_tip.html.slim +++ b/app/views/tips/_sortable_tip.html.slim @@ -1,8 +1,8 @@ - tip = exercise_tip.tip .list-group-item.d-block data-tip-id=tip.id data-id=exercise_tip.id - span.fa-solid.fa-bars.mr-3 + span.fa-solid.fa-bars.me-3 = tip.to_s - a.fa-regular.fa-eye.ml-2 href=tip_path(tip) target='_blank' - a.fa-solid.fa-xmark.ml-2.remove-tip href='#' + a.fa-regular.fa-eye.ms-2 href=tip_path(tip) target='_blank' + a.fa-solid.fa-xmark.ms-2.remove-tip href='#' .list-group.nested-sortable-list class="#{exercise_tip.children.present? ? 'mt-3' : ''}" = render(partial: 'tips/sortable_tip', collection: exercise_tip.children, as: :exercise_tip) diff --git a/app/views/user_exercise_feedbacks/_form.html.slim b/app/views/user_exercise_feedbacks/_form.html.slim index acb3cdf5..660b60bf 100644 --- a/app/views/user_exercise_feedbacks/_form.html.slim +++ b/app/views/user_exercise_feedbacks/_form.html.slim @@ -1,6 +1,6 @@ = form_for(@uef) do |f| div - span.badge.badge-pill.badge-primary.float-right.score + span.badge.rounded-pill.bg-primary.float-end.score h1 id="exercise-headline" = t('activerecord.models.user_exercise_feedback.one') + " " + @exercise.title @@ -10,7 +10,7 @@ #description-card.lead.description-card u = t('activerecord.attributes.exercise.description') = render_markdown(@exercise.description) - .form-group + .mb-3 = f.text_area(:feedback_text, class: 'form-control', required: true, :rows => "10") h4.mt-4 = t('user_exercise_feedback.difficulty') = f.collection_radio_buttons :difficulty, @texts, :first, :last do |b| diff --git a/package.json b/package.json index 8de37fe4..3b800770 100644 --- a/package.json +++ b/package.json @@ -7,11 +7,12 @@ "@babel/preset-env": "7", "@babel/runtime": "7", "@fortawesome/fontawesome-free": "^6.1.2", + "@popperjs/core": "^2.11.6", "@sentry/browser": "^6.11.0", "@webpack-cli/serve": "^1.7.0", "babel-loader": "8", - "bootstrap": "^4.6.2", - "bootswatch": "^4.6.0", + "bootstrap": "^5.2.0", + "bootswatch": "^5.2.0", "chosen-js": "^1.8.7", "compression-webpack-plugin": "9", "css-loader": "^6.7.1", @@ -27,7 +28,6 @@ "mini-css-extract-plugin": "^2.6.1", "opensans-webkit": "^1.1.0", "pnp-webpack-plugin": "1", - "popper.js": "^1.16.1", "rails-erb-loader": "^5.5.2", "sass": "^1.54.4", "sass-loader": "^13.0.2", diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 4ec9e0db..28c172b0 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -83,7 +83,7 @@ describe ApplicationHelper do let(:html) { row(label: 'foo', value: 42) } it "builds nested 'div' tags" do - expect(html).to have_css('div.attribute-row.row div.col-sm-3 + div.col-sm-9') + expect(html).to have_css('div.attribute-row.row div.col-md-3 + div.col-md-9') end end diff --git a/yarn.lock b/yarn.lock index 8fb28aaa..06288e68 100644 --- a/yarn.lock +++ b/yarn.lock @@ -977,6 +977,11 @@ resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== +"@popperjs/core@^2.11.6": + version "2.11.6" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45" + integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw== + "@sentry/browser@^6.11.0": version "6.19.7" resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.19.7.tgz#a40b6b72d911b5f1ed70ed3b4e7d4d4e625c0b5f" @@ -1127,9 +1132,9 @@ integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== "@types/node@*": - version "18.7.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.1.tgz#352bee64f93117d867d05f7406642a52685cbca6" - integrity sha512-GKX1Qnqxo4S+Z/+Z8KKPLpH282LD7jLHWJcVryOflnsnH+BtSDfieR6ObwBMwpnNws0bUK8GI7z0unQf9bARNQ== + version "18.7.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.2.tgz#22306626110c459aedd2cdf131c749ec781e3b34" + integrity sha512-ce7MIiaYWCFv6A83oEultwhBXb22fxwNOQf5DIxWA4WXvDQ7K+L0fbWl/YOfCzlR5B/uFkSnVBhPcOfOECcWvA== "@types/qs@*": version "6.9.7" @@ -1521,15 +1526,15 @@ boolbase@^1.0.0: resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== -bootstrap@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.6.2.tgz#8e0cd61611728a5bf65a3a2b8d6ff6c77d5d7479" - integrity sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ== +bootstrap@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.2.0.tgz#838727fb60f1630db370fe57c63cbcf2962bb3d3" + integrity sha512-qlnS9GL6YZE6Wnef46GxGv1UpGGzAwO0aPL1yOjzDIJpeApeMvqV24iL+pjr2kU4dduoBA9fINKWKgMToobx9A== -bootswatch@^4.6.0: - version "4.6.2" - resolved "https://registry.yarnpkg.com/bootswatch/-/bootswatch-4.6.2.tgz#64720ddabec4fa154e7b760aaf7066d340174ea9" - integrity sha512-pHOS3d2yM/x9Y7/zwVzfGhGIIBdIa/rPwipghh756PaSNJS3ott/29d9uehakgze3pDvbH4FoQVjbho8wsLm6A== +bootswatch@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/bootswatch/-/bootswatch-5.2.0.tgz#c02a0d84e0382552f8a7b9bdd055f36b758ffed9" + integrity sha512-v9krdPdybb5hUwVwlv3f7/FhOa5cXbCb5U5CI4gdnalcxR3ekclXE6kPZWL5O8V8qwNI9BB73apASO1MLmRpIA== brace-expansion@^1.1.7: version "1.1.11" @@ -2275,9 +2280,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.4.202: - version "1.4.215" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.215.tgz#553372e74bde3164290d61f6792f93e443b16733" - integrity sha512-vqZxT8C5mlDZ//hQFhneHmOLnj1LhbzxV0+I1yqHV8SB1Oo4Y5Ne9+qQhwHl7O1s9s9cRuo2l5CoLEHdhMTwZg== + version "1.4.217" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.217.tgz#f1f51b319435f4c1587a850806a0dfebe9774598" + integrity sha512-iX8GbAMij7cOtJPZo02CClpaPMWjvN5meqXiJXkBgwvraNWTNH0Z7F9tkznI34JRPtWASoPM/xWamq3oNb49GA== emitter-component@^1.1.1: version "1.1.1" @@ -3346,11 +3351,6 @@ pnp-webpack-plugin@1: dependencies: ts-pnp "^1.1.6" -popper.js@^1.16.1: - version "1.16.1" - resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b" - integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ== - postcss-calc@^8.2.3: version "8.2.4" resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.2.4.tgz#77b9c29bfcbe8a07ff6693dc87050828889739a5"