diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js new file mode 100644 index 0000000..b4b6ab2 --- /dev/null +++ b/app/assets/javascripts/application.js @@ -0,0 +1,39 @@ +document.addEventListener('DOMContentLoaded', function () { + const migrationActions = document.querySelectorAll('.migration-action'); + + migrationActions.forEach(button => { + button.addEventListener('click', function (event) { + const originalText = button.value; + button.value = 'Loading...'; + disableButtons(); + + fetch(event.target.form.action, { method: 'POST'}) + .then(response => { + if (response.ok) { + window.location.reload(); + } else { + throw new Error('Network response was not ok.'); + } + }) + .catch(error => { + console.error('There has been a problem with your fetch operation:', error); + enableButtons(); + button.value = originalText; + }); + + event.preventDefault(); + }); + }); + + function disableButtons() { + migrationActions.forEach(button => { + button.disabled = true; + }); + } + + function enableButtons() { + migrationActions.forEach(button => { + button.disabled = false; + }); + } +}); diff --git a/app/assets/stylesheets/actual_db_schema/styles.css b/app/assets/stylesheets/styles.css similarity index 81% rename from app/assets/stylesheets/actual_db_schema/styles.css rename to app/assets/stylesheets/styles.css index e217533..f9bd4aa 100644 --- a/app/assets/stylesheets/actual_db_schema/styles.css +++ b/app/assets/stylesheets/styles.css @@ -75,6 +75,12 @@ table { background-color: #000; } +.button:disabled, .button:hover:disabled { + background-color: transparent; + color: #666; + cursor: not-allowed; +} + .button-container { display: flex; } @@ -90,3 +96,19 @@ pre { overflow: hidden; text-overflow: ellipsis; } + +.flash { + padding: 10px; + margin-bottom: 10px; + border-radius: 5px; +} + +.flash.notice { + background-color: #d4edda; + color: #155724; +} + +.flash.alert { + background-color: #f8d7da; + color: #721c24; +} diff --git a/app/controllers/actual_db_schema/migrations_controller.rb b/app/controllers/actual_db_schema/migrations_controller.rb index 979bcc9..7d12fe7 100644 --- a/app/controllers/actual_db_schema/migrations_controller.rb +++ b/app/controllers/actual_db_schema/migrations_controller.rb @@ -3,6 +3,9 @@ module ActualDbSchema # Controller to display the list of migrations for each database connection. class MigrationsController < ActionController::Base + protect_from_forgery with: :exception + skip_before_action :verify_authenticity_token + def index; end def show @@ -10,17 +13,31 @@ def show end def rollback - ActualDbSchema::Migration.instance.rollback(params[:id], params[:database]) + handle_rollback(params[:id], params[:database]) redirect_to migrations_path end def migrate - ActualDbSchema::Migration.instance.migrate(params[:id], params[:database]) + handle_migrate(params[:id], params[:database]) redirect_to migrations_path end private + def handle_rollback(id, database) + ActualDbSchema::Migration.instance.rollback(id, database) + flash[:notice] = "Migration #{id} was successfully rolled back." + rescue StandardError => e + flash[:alert] = e.message + end + + def handle_migrate(id, database) + ActualDbSchema::Migration.instance.migrate(id, database) + flash[:notice] = "Migration #{id} was successfully migrated." + rescue StandardError => e + flash[:alert] = e.message + end + helper_method def migrations @migrations ||= ActualDbSchema::Migration.instance.all end diff --git a/app/controllers/actual_db_schema/phantom_migrations_controller.rb b/app/controllers/actual_db_schema/phantom_migrations_controller.rb index 8356e8a..c0c6954 100644 --- a/app/controllers/actual_db_schema/phantom_migrations_controller.rb +++ b/app/controllers/actual_db_schema/phantom_migrations_controller.rb @@ -3,6 +3,9 @@ module ActualDbSchema # Controller to display the list of phantom migrations for each database connection. class PhantomMigrationsController < ActionController::Base + protect_from_forgery with: :exception + skip_before_action :verify_authenticity_token + def index; end def show @@ -10,17 +13,31 @@ def show end def rollback - ActualDbSchema::Migration.instance.rollback(params[:id], params[:database]) + handle_rollback(params[:id], params[:database]) redirect_to phantom_migrations_path end def rollback_all - ActualDbSchema::Migration.instance.rollback_all + handle_rollback_all redirect_to phantom_migrations_path end private + def handle_rollback(id, database) + ActualDbSchema::Migration.instance.rollback(id, database) + flash[:notice] = "Migration #{id} was successfully rolled back." + rescue StandardError => e + flash[:alert] = e.message + end + + def handle_rollback_all + ActualDbSchema::Migration.instance.rollback_all + flash[:notice] = "Migrations was successfully rolled back." + rescue StandardError => e + flash[:alert] = e.message + end + helper_method def phantom_migrations @phantom_migrations ||= ActualDbSchema::Migration.instance.all_phantom end diff --git a/app/views/actual_db_schema/migrations/index.html.erb b/app/views/actual_db_schema/migrations/index.html.erb index 896f0a5..c1eaca6 100644 --- a/app/views/actual_db_schema/migrations/index.html.erb +++ b/app/views/actual_db_schema/migrations/index.html.erb @@ -2,10 +2,14 @@ Migrations - <%= stylesheet_link_tag 'actual_db_schema/styles', media: 'all' %> + <%= stylesheet_link_tag 'styles', media: 'all' %> + <%= javascript_include_tag 'application' %>
+ <% flash.each do |key, message| %> +
<%= message %>
+ <% end %>

Migrations

Red rows represent phantom migrations. @@ -45,12 +49,12 @@ <%= button_to '⎌ Rollback', rollback_migration_path(id: migration[:version], database: migration[:database]), method: :post, - class: 'button', + class: 'button migration-action', style: ('display: none;' if migration[:status] == "down") %> <%= button_to '⬆ Migrate', migrate_migration_path(id: migration[:version], database: migration[:database]), method: :post, - class: 'button', + class: 'button migration-action', style: ('display: none;' if migration[:status] == "up" || migration[:phantom]) %>

diff --git a/app/views/actual_db_schema/migrations/show.html.erb b/app/views/actual_db_schema/migrations/show.html.erb index e8d122f..7eac545 100644 --- a/app/views/actual_db_schema/migrations/show.html.erb +++ b/app/views/actual_db_schema/migrations/show.html.erb @@ -2,10 +2,14 @@ Migration Details - <%= stylesheet_link_tag 'actual_db_schema/styles', media: 'all' %> + <%= stylesheet_link_tag 'styles', media: 'all' %> + <%= javascript_include_tag 'application' %>
+ <% flash.each do |key, message| %> +
<%= message %>
+ <% end %>

Migration <%= migration[:name] %> Details

@@ -41,12 +45,12 @@ <%= button_to '⎌ Rollback', rollback_migration_path(id: migration[:version], database: migration[:database]), method: :post, - class: 'button', + class: 'button migration-action', style: ('display: none;' if migration[:status] == "down") %> <%= button_to '⬆ Migrate', migrate_migration_path(id: migration[:version], database: migration[:database]), method: :post, - class: 'button', + class: 'button migration-action', style: ('display: none;' if migration[:status] == "up" || migration[:phantom]) %> diff --git a/app/views/actual_db_schema/phantom_migrations/index.html.erb b/app/views/actual_db_schema/phantom_migrations/index.html.erb index 5707276..9492cf4 100644 --- a/app/views/actual_db_schema/phantom_migrations/index.html.erb +++ b/app/views/actual_db_schema/phantom_migrations/index.html.erb @@ -2,15 +2,22 @@ Phantom Migrations - <%= stylesheet_link_tag 'actual_db_schema/styles', media: 'all' %> + <%= stylesheet_link_tag 'styles', media: 'all' %> + <%= javascript_include_tag 'application' %>
+ <% flash.each do |key, message| %> +
<%= message %>
+ <% end %>

Phantom Migrations

<%= link_to 'All Migrations', migrations_path, class: "top-button" %> <% if phantom_migrations.present? %> - <%= button_to '⎌ Rollback all', rollback_all_phantom_migrations_path, method: :post, class: 'button' %> + <%= button_to '⎌ Rollback all', + rollback_all_phantom_migrations_path, + method: :post, + class: 'button migration-action' %> <% end %>
<% if phantom_migrations.present? %> @@ -39,8 +46,13 @@
diff --git a/app/views/actual_db_schema/phantom_migrations/show.html.erb b/app/views/actual_db_schema/phantom_migrations/show.html.erb index 96681cf..97ccba3 100644 --- a/app/views/actual_db_schema/phantom_migrations/show.html.erb +++ b/app/views/actual_db_schema/phantom_migrations/show.html.erb @@ -2,10 +2,14 @@ Phantom Migration Details - <%= stylesheet_link_tag 'actual_db_schema/styles', media: 'all' %> + <%= stylesheet_link_tag 'styles', media: 'all' %> + <%= javascript_include_tag 'application' %>
+ <% flash.each do |key, message| %> +
<%= message %>
+ <% end %>

Phantom Migration <%= phantom_migration[:name] %> Details

<%= migration[:database] %>
- <%= link_to '👁 Show', phantom_migration_path(id: migration[:version], database: migration[:database]), class: 'button' %> - <%= button_to '⎌ Rollback', rollback_phantom_migration_path(id: migration[:version], database: migration[:database]), method: :post, class: 'button' %> + <%= link_to '👁 Show', + phantom_migration_path(id: migration[:version], database: migration[:database]), + class: 'button' %> + <%= button_to '⎌ Rollback', + rollback_phantom_migration_path(id: migration[:version], database: migration[:database]), + method: :post, + class: 'button migration-action' %>
@@ -38,7 +42,10 @@
<%= link_to '← Back', phantom_migrations_path, class: 'button' %> - <%= button_to '⎌ Rollback', rollback_phantom_migration_path(id: params[:id], database: params[:database]), method: :post, class: 'button' %> + <%= button_to '⎌ Rollback', + rollback_phantom_migration_path(id: params[:id], database: params[:database]), + method: :post, + class: 'button migration-action' %>
diff --git a/lib/actual_db_schema/engine.rb b/lib/actual_db_schema/engine.rb index a245b27..8e9121a 100644 --- a/lib/actual_db_schema/engine.rb +++ b/lib/actual_db_schema/engine.rb @@ -11,7 +11,7 @@ class Engine < ::Rails::Engine mount ActualDbSchema::Engine => "/rails" end - app.config.assets.precompile += %w[actual_db_schema/styles.css] + app.config.assets.precompile += %w[styles.css application.js] end end end diff --git a/test/controllers/actual_db_schema/migrations_controller_test.rb b/test/controllers/actual_db_schema/migrations_controller_test.rb index f810e4f..2b4288c 100644 --- a/test/controllers/actual_db_schema/migrations_controller_test.rb +++ b/test/controllers/actual_db_schema/migrations_controller_test.rb @@ -100,6 +100,28 @@ def active_record_setup assert_response :not_found end + test "POST #rollback with irreversible migration returns error message" do + %w[primary secondary].each do |prefix| + @utils.define_migration_file("20130906111513_irreversible_#{prefix}.rb", <<~RUBY, prefix: prefix) + class Irreversible#{prefix.camelize} < ActiveRecord::Migration[6.0] + def up + TestingState.up << :irreversible_#{prefix} + end + + def down + raise ActiveRecord::IrreversibleMigration + end + end + RUBY + end + @utils.prepare_phantom_migrations(TestingState.db_config) + post :rollback, params: { id: "20130906111513", database: "tmp/primary.sqlite3" } + assert_response :redirect + get :index + message = "An error has occurred, this and all later migrations canceled:\n\nActiveRecord::IrreversibleMigration" + assert_select ".flash", text: message + end + test "POST #rollback changes migration status to down and hide migration with down status" do post :rollback, params: { id: "20130906111511", database: "tmp/primary.sqlite3" } assert_response :redirect @@ -113,6 +135,7 @@ def active_record_setup end end end + assert_select ".flash", text: "Migration 20130906111511 was successfully rolled back." end end end diff --git a/test/controllers/actual_db_schema/phantom_migrations_controller_test.rb b/test/controllers/actual_db_schema/phantom_migrations_controller_test.rb index 2cb7738..7f9274d 100644 --- a/test/controllers/actual_db_schema/phantom_migrations_controller_test.rb +++ b/test/controllers/actual_db_schema/phantom_migrations_controller_test.rb @@ -133,6 +133,29 @@ def active_record_setup end end end + assert_select ".flash", text: "Migration 20130906111511 was successfully rolled back." + end + + test "POST #rollback with irreversible migration returns error message" do + %w[primary secondary].each do |prefix| + @utils.define_migration_file("20130906111513_irreversible_#{prefix}.rb", <<~RUBY, prefix: prefix) + class Irreversible#{prefix.camelize} < ActiveRecord::Migration[6.0] + def up + TestingState.up << :irreversible_#{prefix} + end + + def down + raise ActiveRecord::IrreversibleMigration + end + end + RUBY + end + @utils.prepare_phantom_migrations(TestingState.db_config) + post :rollback, params: { id: "20130906111513", database: "tmp/primary.sqlite3" } + assert_response :redirect + get :index + message = "An error has occurred, this and all later migrations canceled:\n\nActiveRecord::IrreversibleMigration" + assert_select ".flash", text: message end test "POST #rollback_all changes all phantom migrations status to down and hide migration with down status" do