Skip to content

Migrate Turbolinks to Turbo #2062

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jul 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ jobs:
env:
RAILS_ENV: test
CC_TEST_REPORTER_ID: true
# Use Firefox for system tests until Chrome headless works reliably again.
# See https://github.com/SeleniumHQ/selenium/issues/15273
BROWSER: firefox
run: bundle exec rspec --color --format RSpec::Github::Formatter --format progress

- name: Upload coverage reports to Codecov
Expand Down
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ gem 'solid_cable'
gem 'solid_queue'
gem 'sprockets-rails'
gem 'terser', require: false
gem 'turbolinks'
gem 'turbo-rails'

# Authentication
gem 'devise', '~> 4.9'
Expand Down
7 changes: 1 addition & 6 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -608,9 +608,6 @@ GEM
turbo-rails (2.0.13)
actionpack (>= 7.1.0)
railties (>= 7.1.0)
turbolinks (5.2.1)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (3.1.4)
Expand Down Expand Up @@ -731,7 +728,7 @@ DEPENDENCIES
sprockets-rails
stackprof
terser
turbolinks
turbo-rails
web-console
webmock

Expand Down Expand Up @@ -969,8 +966,6 @@ CHECKSUMS
tilt (2.6.0) sha256=263d748466e0d83e510aa1a2e2281eff547937f0ef06be33d3632721e255f76b
timeout (0.4.3) sha256=9509f079b2b55fe4236d79633bd75e34c1c1e7e3fb4b56cb5fda61f80a0fe30e
turbo-rails (2.0.13) sha256=c40ac0a3ccd57c129925c8ac524a5dfd1e17fad080906e2d32135721a8bba22f
turbolinks (5.2.1) sha256=5fea5889c4e2a78a5bd9abda3860c565342b50c6e2593697d5558a08e15cce9c
turbolinks-source (5.2.0) sha256=362a41fa851a22b0f15cf8f944b6c7c5788f645dc1f61ae25478bb25c3bc85d4
tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b
unicode-display_width (3.1.4) sha256=8caf2af1c0f2f07ec89ef9e18c7d88c2790e217c482bfc78aaa65eadd5415ac1
unicode-emoji (4.0.4) sha256=2c2c4ef7f353e5809497126285a50b23056cc6e61b64433764a35eff6c36532a
Expand Down
2 changes: 1 addition & 1 deletion app/assets/javascripts/account_links.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ ready = ->
$row_value.parents('.row').remove()


$(document).on('turbolinks:load', ready)
$(document).on('turbo-migration:load', ready)
6 changes: 5 additions & 1 deletion app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require turbolinks
//= require nested_form_fields
//
// app/assets
//= require_tree .
//
// Finally, we dispatch a custom event to signal that all assets are loaded.
// This is used by our custom migration for Turbo to trigger the `turbo-migration:load` event
const sprocketsLoad = new Event('sprockets:load');
document.dispatchEvent(sprocketsLoad);
7 changes: 2 additions & 5 deletions app/assets/javascripts/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ $.fn.scrollTo = function (selector) {
}, ANIMATION_DURATION);
};

$(document).on('turbolinks:load', function () {
$(document).on('turbo-migration:load', function () {
// Update all CSRF tokens on the page to reduce InvalidAuthenticityToken errors
// See https://github.com/rails/jquery-ujs/issues/456 for details
$.rails.refreshCSRFTokens();
Expand All @@ -34,7 +34,7 @@ $(document).on('turbolinks:load', function () {
// Initialize Sentry
const sentrySettings = $('meta[name="sentry"]')

// Workaround for Turbolinks: We must not re-initialize the Relay object when visiting another page
// Workaround for Turbo: We must not re-initialize the Relay object when visiting another page
if (sentrySettings && sentrySettings.data()['enabled'] && Sentry.getReplay() === undefined) {
Sentry.init({
dsn: sentrySettings.data('dsn'),
Expand All @@ -55,9 +55,6 @@ $(document).on('turbolinks:load', function () {
});
}

// Enable all tooltips
$('[data-bs-toggle="tooltip"]').tooltip();

// Ensure that the tab button will be in active (selected) state for each page that has 'option' query (e.g. groups or messages page)
$('#' + $('#option').val()).addClass('selected');
});
4 changes: 0 additions & 4 deletions app/assets/javascripts/bootstrap.js

This file was deleted.

2 changes: 1 addition & 1 deletion app/assets/javascripts/collections.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ update_collections_tasks_order = (e) ->
$(input_element).val(index);


$(document).on('turbolinks:load', ready)
$(document).on('turbo-migration:load', ready)
12 changes: 11 additions & 1 deletion app/assets/javascripts/editor.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ initializeAce = ->
$(document).on 'fields_added.nested_form_fields', ->
$ initializeEditors()

unloadEditors = (event) ->
$('.editor').each (_, editor) ->
aceEditor = ace.edit(editor)
content = aceEditor.getValue();
aceEditor.destroy()
editor.textContent = content;
return

initializeEditors = ->
$('.editor').each ->
editor = ace.edit(this)
Expand All @@ -17,6 +25,8 @@ initializeEditors = ->
else
editor.getSession().on 'change', (e) ->
hiddenContent.val(editor.getValue()).trigger('change')
$(document).one('turbo:visit', unloadEditors);
$(window).one('beforeunload', unloadEditors);

setAceEditorValue = (editor, value) ->
aceEditor = $(editor).parent().find('.editor')[0]
Expand All @@ -34,4 +44,4 @@ root.getModeByFileExtension = getModeByFileExtension
root.changeEditorMode = changeEditorMode
root.setAceEditorValue = setAceEditorValue

$(document).on('turbolinks:load', ready)
$(document).on('turbo-migration:load', ready)
2 changes: 1 addition & 1 deletion app/assets/javascripts/flash_message.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ $(document).ajaxComplete (event, request) ->
ready = ->
$('#flash-message').children().first().delay(5000).slideUp 'medium'

$(document).on('turbolinks:load', ready)
$(document).on('turbo-migration:load', ready)
2 changes: 1 addition & 1 deletion app/assets/javascripts/groups.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ ready = ->
$(e.currentTarget.parentElement).html(data["button"])


$(document).on('turbolinks:load', ready)
$(document).on('turbo-migration:load', ready)
7 changes: 7 additions & 0 deletions app/assets/javascripts/labels.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,19 @@ ready = ->
I18n.t('labels.javascripts.max_limit_reached', {limit: limit})

$('.labels-select2-tag').on 'select2:select', clear_input
$(document).one('turbo:visit', destroy_select2);
return

clear_input = ->
$('.labels-select2-tag').siblings(".select2").find("textarea").val("");
return

destroy_select2 = ->
selectElement = $('.labels-select2-tag');
selectElement.select2('destroy');
selectElement.off('select2:select');
return


root = exports ? this;
root.verify_label_name = verify_label_name;
Expand Down
2 changes: 1 addition & 1 deletion app/assets/javascripts/labels_index.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,4 @@ ready = ->
table = new LabelsTable(table_container);


$(document).on('turbolinks:load', ready)
$(document).on('turbo-migration:load', ready)
2 changes: 1 addition & 1 deletion app/assets/javascripts/markdown_editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ const setResizeBtn = (formInput, editor) => {
});
};

$(document).on("turbolinks:load", function () {
$(document).on("turbo-migration:load", function () {
initializeMarkdownEditors();
disableImageUpload();
});
22 changes: 11 additions & 11 deletions app/assets/javascripts/nbp_wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,7 @@ const countdownValidity = () => {
}
};

window.addEventListener("turbolinks:before-render", () => {
clearInterval(intervalID);
clearTimeout(timeoutID);
});

window.addEventListener("beforeunload", () => {
clearInterval(intervalID);
clearTimeout(timeoutID);
});

$(document).on('turbolinks:load', function () {
$(document).on('turbo-migration:load', function () {
if (window.location.pathname !== Routes.nbp_wallet_connect_users_path()) {
return;
}
Expand All @@ -49,4 +39,14 @@ $(document).on('turbolinks:load', function () {
templateValidity = document.querySelector('[data-id="nbp_wallet_qr_code"]').dataset.remainingValidity - 5;
checkStatus();
intervalID = setInterval(countdownValidity, 1000);

$(document).one("turbo:visit", () => {
clearInterval(intervalID);
clearTimeout(timeoutID);
});

$(window).one("beforeunload", () => {
clearInterval(intervalID);
clearTimeout(timeoutID);
});
});
2 changes: 1 addition & 1 deletion app/assets/javascripts/task_files.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,4 @@ initializeOnUpload = ->
if fullPath
$(this).parents('.file-container').find('.file-name').val(fullName)

$(document).on 'turbolinks:load', ready
$(document).on 'turbo-migration:load', ready
2 changes: 1 addition & 1 deletion app/assets/javascripts/tasks_base.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ loadComments = (url, $wait_icon, $comment_box, onSucess)->
root = exports ? this;
root.loadComments = loadComments

$(document).on('turbolinks:load', ready)
$(document).on('turbo-migration:load', ready)
2 changes: 1 addition & 1 deletion app/assets/javascripts/tasks_checklist.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,4 @@ update_checklist = ->
, 100


$(document).on('turbolinks:load', initialize_checklist)
$(document).on('turbo-migration:load', initialize_checklist)
2 changes: 1 addition & 1 deletion app/assets/javascripts/tasks_export.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,4 @@ exportConfirm = (taskId, accountLinkId, pushType) ->
root = exports ? this;
root.exportTaskStart = exportTaskStart

$(document).on('turbolinks:load', ready)
$(document).on('turbo-migration:load', ready)
8 changes: 7 additions & 1 deletion app/assets/javascripts/tasks_form.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ initializeLoadSelect2 = ->
closeOnSelect: false
placeholder: I18n.t('tasks.javascripts.select_groups')

$(document).one('turbo:visit', destroy_select2);

initializeFileTypeSelection = ->
$('body').on 'keyup', '.file-name', (event) ->
editor = $(this).parents('.file-container').find('.editor')[0]
Expand All @@ -30,6 +32,10 @@ initializeVisibilityWarning = ->
$('#task_access_level_public').on 'change', ->
warning_message.addClass('d-none')

destroy_select2 = ->
$('#task_programming_language_id').select2('destroy');
$('.my-group').select2('destroy');
return

$(document).on('turbolinks:load', ready)
$(document).on('turbo-migration:load', ready)
$(document).on('select2:locales:loaded', initializeLoadSelect2)
2 changes: 1 addition & 1 deletion app/assets/javascripts/tasks_import.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,4 @@ importConfirm = (importId, subfileId, importType) ->
})


$(document).on('turbolinks:load', ready)
$(document).on('turbo-migration:load', ready)
11 changes: 9 additions & 2 deletions app/assets/javascripts/tasks_index.coffee
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
ready = ->
initCollapsable($('.description'), '95px')
window.addEventListener 'resize', -> initCollapsable($('.description'), '95px')
initializeDynamicHideShow()
initializeFilter()
initializeIndexComments()
Expand All @@ -25,6 +24,8 @@ initializeSelect2 = ->
closeOnSelect: false
placeholder: I18n.t('tasks.javascripts.all_languages')

$(document).one('turbo:visit', destroy_select2);

toggleHideShowMore = (element) ->
$parent = $(element).parent()
$toggle = $(element).find '.more-btn'
Expand Down Expand Up @@ -138,6 +139,12 @@ initializeInputFieldEnterCallback = ->
$('.search-submit-button-tag').click();
event.preventDefault();

destroy_select2 = ->
$('.defaultSelect2').select2('destroy');
$('.language-box').select2('destroy');
return


$(document).on('turbolinks:load', ready)
$(document).on('turbo-migration:load', ready)
$(window).on('resize', -> initCollapsable($('.description'), '95px'))
$(document).on('select2:locales:loaded', initializeSelect2)
2 changes: 1 addition & 1 deletion app/assets/javascripts/tasks_ratings.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,4 @@ initializeRatings = ->
)


$(document).on('turbolinks:load', ready)
$(document).on('turbo-migration:load', ready)
2 changes: 1 addition & 1 deletion app/assets/javascripts/tasks_show.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ initializeShowComments = ->
$comment_box.addClass('hide')


$(document).on('turbolinks:load', ready)
$(document).on('turbo-migration:load', ready)
2 changes: 1 addition & 1 deletion app/assets/javascripts/users.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ ready = ->
new bootstrap.Modal('#notification-modal').show();


$(document).on('turbolinks:load', ready)
$(document).on('turbo-migration:load', ready)
17 changes: 17 additions & 0 deletions app/assets/stylesheets/bootstrap_and_overrides.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,23 @@
}

.btn-group {

// Align buttons in a link group, similar to `.btn-group .btn + .btn` etc.
.button_to {
&:not(:first-child) {
margin-left: -1px;
.btn {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}

&:not(:last-child) .btn {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}

.btn-important {
white-space: normal;
padding: 10px 20px;
Expand Down
18 changes: 13 additions & 5 deletions app/controllers/account_links_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ def create # rubocop:disable Metrics/AbcSize

respond_to do |format|
if @account_link.save
format.html { redirect_to @user, notice: t('common.notices.object_created', model: AccountLink.model_name.human) }
format.html do
redirect_to @user, notice: t('common.notices.object_created', model: AccountLink.model_name.human), status: :see_other
end
format.json { render :show, status: :created, location: @account_link }
else
format.html { render :new }
format.html { render :new, status: :unprocessable_content }
format.json { render json: @account_link.errors, status: :unprocessable_content }
end
end
Expand All @@ -36,10 +38,14 @@ def create # rubocop:disable Metrics/AbcSize
def update
respond_to do |format|
if @account_link.update(account_link_params)
format.html { redirect_to @account_link.user, notice: t('common.notices.object_updated', model: AccountLink.model_name.human) }
format.html do
redirect_to @account_link.user,
notice: t('common.notices.object_updated', model: AccountLink.model_name.human),
status: :see_other
end
format.json { render :show, status: :ok, location: @account_link }
else
format.html { render :edit }
format.html { render :edit, status: :unprocessable_content }
format.json { render json: @account_link.errors, status: :unprocessable_content }
end
end
Expand All @@ -48,7 +54,9 @@ def update
def destroy
@account_link.destroy
respond_to do |format|
format.html { redirect_to @account_link.user, notice: t('common.notices.object_deleted', model: AccountLink.model_name.human) }
format.html do
redirect_to @account_link.user, notice: t('common.notices.object_deleted', model: AccountLink.model_name.human), status: :see_other
end
format.json { head :no_content }
end
end
Expand Down
6 changes: 3 additions & 3 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ def render_error(message, status) # rubocop:disable Metrics/AbcSize
respond_to do |format|
format.any do
if redirect_loop? || unauthorized_nbp_request?(status)
redirect_to :root, alert: message
redirect_to :root, alert: message, status: :see_other
elsif current_user.nil? && status == :unauthorized
store_location_for(:user, request.fullpath) if current_user.nil?
redirect_to new_user_session_path, alert: t('common.errors.not_signed_in')
redirect_to new_user_session_path, alert: t('common.errors.not_signed_in'), status: :see_other
else
redirect_back fallback_location: :root, allow_other_host: false, alert: message
redirect_back fallback_location: :root, allow_other_host: false, alert: message, status: :see_other
end
end
format.json { render json: {error: message}, status: }
Expand Down
Loading
Loading