Skip to content

Commit

Permalink
Merge branch 'undo'
Browse files Browse the repository at this point in the history
  • Loading branch information
stufro committed Mar 30, 2023
2 parents 2d4fcdb + 43b4cc3 commit 74e9b03
Show file tree
Hide file tree
Showing 19 changed files with 256 additions and 23 deletions.
1 change: 1 addition & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
ruby 3.1.2
nodejs 19.4.0
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ gem "jsbundling-rails"
gem "local_time"
gem "meta-tags"
gem "music"
gem "paper_trail", "~> 14.0"
gem "pg", "~> 1.1"
gem "puma", "~> 5.0"
gem "rails"
Expand Down
6 changes: 6 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@ GEM
nokogiri (1.14.2-x86_64-linux)
racc (~> 1.4)
orm_adapter (0.5.0)
paper_trail (14.0.0)
activerecord (>= 6.0)
request_store (~> 1.4)
parallel (1.22.1)
parser (3.2.1.1)
ast (~> 2.4.1)
Expand Down Expand Up @@ -250,6 +253,8 @@ GEM
regexp_parser (2.7.0)
reline (0.3.2)
io-console (~> 0.5)
request_store (1.5.1)
rack (>= 1.4)
require_all (3.0.0)
responders (3.1.0)
actionpack (>= 5.2)
Expand Down Expand Up @@ -404,6 +409,7 @@ DEPENDENCIES
local_time
meta-tags
music
paper_trail (~> 14.0)
pg (~> 1.1)
puma (~> 5.0)
rack-mini-profiler
Expand Down
11 changes: 6 additions & 5 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
---

## Potential ideas for beyond the planned releases below
- [ ] Chord diagrams at top of sheet
- [ ] Prefer sharps/flats option
- [ ] Alert when creating a chord sheet with the same name
- [ ] Better formatting for PDFs (page breaks etc.)
- [ ] Option to print PDF with content in 1 column or 2
- [ ] Export set list as separate PDFs
- [ ] Set list enhancements
- [ ] Show 2 tabs on available chord sheets: recent & A-Z
- [ ] Add chord sheet to set list from chord sheet show
- [ ] Restore deleted chord sheets
- [ ] Styling chord sheets

---
Expand All @@ -19,10 +19,11 @@

---

## v0.5.0
- [ ] Chord diagrams at top of sheet

## v0.4.0
- [ ] Restore deleted chord sheets
- [ ] Undo changes for chord sheets
- [ ] Alert when creating a chord sheet with the same name
- [x] Undo changes for chord sheets

---

Expand Down
9 changes: 9 additions & 0 deletions app/assets/stylesheets/chord_sheets.scss
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,12 @@ a.sort-by-icon.is-active:hover {

transition: max-height 1s ease-in;
}

.version-container {
border-radius: 2rem;
border: 1px solid $grey-lightest;
padding: 1rem;
margin-bottom: 2rem;
box-shadow: 0 0.5em 1em -0.125em rgba(10,10,10,.1),
0 0px 0 1px rgba(10,10,10,.02);;
}
10 changes: 9 additions & 1 deletion app/controllers/chord_sheets_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class ChordSheetsController < ApplicationController
skip_before_action :authenticate_user!, only: %i[create show transpose update]
before_action :authorize_user, only: %i[show transpose update destroy]
before_action :authorize_user, only: %i[show transpose update destroy versions restore]
before_action :adjust_new_lines, only: %i[create]

def index
Expand Down Expand Up @@ -50,6 +50,14 @@ def destroy
redirect_to chord_sheets_path
end

def versions; end

def restore
version = @chord_sheet.versions.find(params[:version_id])
version.reify.save
redirect_to @chord_sheet
end

private

def chord_sheet_params
Expand Down
1 change: 1 addition & 0 deletions app/javascript/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import '@fortawesome/fontawesome-free/js/regular.js'
import '@fortawesome/fontawesome-free/js/brands.js'
import "trix"
import "@rails/actiontext"
import "./modal"

import LocalTime from "local-time"
LocalTime.start()
59 changes: 59 additions & 0 deletions app/javascript/modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
document.addEventListener('DOMContentLoaded', () => {
// Functions to open and close a modal
function openModal($el) {
$el.classList.add('is-active');
}

function setTurboFrameSrc($el) {
const frame = $el.querySelector('turbo-frame')
frame.setAttribute('src', $el.getAttribute("data-turbo-frame-src"))
}

function closeModal($el) {
$el.classList.remove('is-active');
if($el.classList.contains('modal-turbo-frame')) {
$el.querySelector(".modal-content .box turbo-frame").innerHTML = '<div class="is-flex is-justify-content-center"><div class="spinner"></div></div>'
}
}

function closeAllModals() {
(document.querySelectorAll('.modal') || []).forEach(($modal) => {
closeModal($modal);
if($modal.classList.contains('modal-turbo-frame')) {
$modal.querySelector(".modal-content .box turbo-frame").innerHTML = '<div class="is-flex is-justify-content-center"><div class="spinner"></div></div>'
}
});
}

// Add a click event on buttons to open a specific modal
(document.querySelectorAll('.modal-trigger') || []).forEach(($trigger) => {
const modal = $trigger.dataset.target;
const $target = document.getElementById(modal);

$trigger.addEventListener('click', (event) => {
event.preventDefault();
openModal($target);
if($target.classList.contains('modal-turbo-frame')) {
setTurboFrameSrc($target);
}
});
});

// Add a click event on various child elements to close the parent modal
(document.querySelectorAll('.modal-background, .modal-close, .modal-card-head .delete, .modal-card-foot .button') || []).forEach(($close) => {
const $target = $close.closest('.modal');

$close.addEventListener('click', () => {
closeModal($target);
});
});

// Add a keyboard event to close all modals
document.addEventListener('keydown', (event) => {
const e = event || window.event;

if (e.keyCode === 27) { // Escape key
closeAllModals();
}
});
});
2 changes: 2 additions & 0 deletions app/models/chord_sheet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ class ChordSheet < ApplicationRecord
validates :name, presence: true
validates :content, presence: true

has_paper_trail limit: 10

scope :not_deleted, -> { where(deleted: [false, nil]) }

def transpose(direction)
Expand Down
17 changes: 16 additions & 1 deletion app/views/chord_sheets/show.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ div[data-controller="clipboard"
method: :delete, title: "Delete chord sheet")
span.icon
i.fas.fa-trash
= button_to("#", class: "button is-rounded is-info mr-2 modal-trigger",
id: "versions", data: { target: "versions-modal" })
span.icon
i.fas.fa-history
= button_to "#", class: "button is-rounded is-info mr-2", id: "copy-to-clipboard",
"data-clipboard-target" => "button", "data-action" => "clipboard#copy",
title: "Copy to clipboard"
Expand All @@ -67,4 +71,15 @@ div[data-controller="clipboard"
span.icon
i.fas.fa-download

= render("chord_sheets/content", chord_sheet: @chord_sheet)
= render("content", chord_sheet: @chord_sheet)

#versions-modal.modal.modal-turbo-frame data-turbo-frame-src=versions_chord_sheet_path(@chord_sheet)
.modal-background

.modal-content style="width: 75%"
.box
= turbo_frame_tag "versions", target: "_top"
.is-flex.is-justify-content-center
.spinner

button.modal-close.is-large aria-label="close"
35 changes: 35 additions & 0 deletions app/views/chord_sheets/versions.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
= turbo_frame_tag "versions"
h1.title.is-2.mb-0 Previous Versions
i Last 10 versions are stored

- @chord_sheet.versions.reverse.each do |version|
- next if version.reify.blank?

hr
.version-container
.is-flex.is-justify-content-space-between.is-flex-wrap-wrap style="gap: .5rem"
p
b Name:&nbsp;
span = version.reify.name

div
small.has-text-grey-light
span.icon
i.fas.fa-clock
span = local_time(version.created_at)

= button_to(restore_chord_sheet_path(@chord_sheet, version_id: version.id),
class: "button is-warning is-small")
span.icon-text.is-flex-wrap-nowrap
span.icon
i.fas.fa-history
span Restore

p
b Content:&nbsp;

div style="max-height: 20em; overflow: auto"
pre
- version.reify.content.each do |line|
span class=(line["type"] == "chords" ? "chord-line" : "lyric-line")
= line["content"]
12 changes: 12 additions & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,17 @@ class Application < Rails::Application
config.to_prepare do
Devise::Mailer.layout "mailer"
end

# https://discuss.rubyonrails.org/t/cve-2022-32224-possible-rce-escalation-bug-with-serialized-columns-in-active-record/81017
config.active_record.yaml_column_permitted_classes = [
::ActiveSupport::HashWithIndifferentAccess,
::ActiveRecord::Type::Time::Value,
::ActiveSupport::TimeWithZone,
::ActiveSupport::TimeZone,
::BigDecimal,
::Date,
::Symbol,
::Time
]
end
end
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

resources :chord_sheets, only: %i[index new create show update destroy] do
put :transpose, on: :member
get :versions, on: :member
post :restore, on: :member
end

resource :home, only: %i[index], controller: "home" do
Expand Down
38 changes: 38 additions & 0 deletions db/migrate/20230330155819_create_versions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# This migration creates the `versions` table, the only schema PT requires.
# All other migrations PT provides are optional.
class CreateVersions < ActiveRecord::Migration[7.0]

# The largest text column available in all supported RDBMS is
# 1024^3 - 1 bytes, roughly one gibibyte. We specify a size
# so that MySQL will use `longtext` instead of `text`. Otherwise,
# when serializing very large objects, `text` might not be big enough.
TEXT_BYTES = 1_073_741_823

def change
create_table :versions do |t|
t.string :item_type, null: false
t.bigint :item_id, null: false
t.string :event, null: false
t.string :whodunnit
t.text :object, limit: TEXT_BYTES

# Known issue in MySQL: fractional second precision
# -------------------------------------------------
#
# MySQL timestamp columns do not support fractional seconds unless
# defined with "fractional seconds precision". MySQL users should manually
# add fractional seconds precision to this migration, specifically, to
# the `created_at` column.
# (https://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html)
#
# MySQL users should also upgrade to at least rails 4.2, which is the first
# version of ActiveRecord with support for fractional seconds in MySQL.
# (https://github.com/rails/rails/pull/14359)
#
# MySQL users should use the following line for `created_at`
# t.datetime :created_at, limit: 6
t.datetime :created_at
end
add_index :versions, %i[item_type item_id]
end
end
12 changes: 11 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@
},
"devDependencies": {
"@4tw/cypress-drag-drop": "^2.2.2",
"cypress": "^10.9.0"
"cypress": "12.9.0"
}
}
5 changes: 2 additions & 3 deletions spec/cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
baseUrl: "http://localhost:5017",
defaultCommandTimeout: 3000,
defaultCommandTimeout: 5000,
viewportHeight: 1080,
viewportWidth: 1920,
experimentalSessionAndOrigin: true
viewportWidth: 1920
}
});
Loading

0 comments on commit 74e9b03

Please sign in to comment.