Merge branch 'main' into add-card-description

* main:
  Fix trailing empty line
  --skip-server in ci setup
  Enumerate all the options for logging in
  Have an empty first-run tenant too
  Convert to conventional Rails style
  Seed multiple seed accounts with basic DSL
  Stlye
  No need to run Solid Cache in development
  Use morphing to replace the card and exclude turbo frames from being replaced
  Name is already schema and UI required
  Cards have a not-null schema and collections destroy all cards on deletion
  No longer used
  Inline touch check thats only used once

# Conflicts:
#	app/views/cards/_container.html.erb
This commit is contained in:
Jorge Manrubia
2025-04-21 16:04:06 +02:00
18 changed files with 118 additions and 58 deletions
+1 -1
View File
@@ -15,6 +15,6 @@ module CardScoped
end
def render_card_replacement
render turbo_stream: turbo_stream.replace([ @card, :card_container ], partial: "cards/container", locals: { card: @card.reload })
render turbo_stream: turbo_stream.replace([ @card, :card_container ], partial: "cards/container", method: :morph, locals: { card: @card.reload })
end
end
@@ -1,10 +1,10 @@
import { Controller } from "@hotwired/stimulus"
import { nextEventNamed } from "helpers/timing_helpers"
import { isTouchDevice } from "helpers/navigator_helpers"
export default class extends Controller {
// Only load for touch devices
static get shouldLoad() {
return isTouchDevice()
return "ontouchstart" in window && navigator.maxTouchPoints > 0
}
// Use a fake input to trigger the soft keyboard on actions that load async content
@@ -1,3 +0,0 @@
export function isTouchDevice() {
return "ontouchstart" in window && navigator.maxTouchPoints > 0
}
@@ -1,8 +0,0 @@
import { Turbo } from "@hotwired/turbo-rails"
Turbo.StreamActions.set_css_variable = function() {
const name = this.getAttribute("name")
const value = this.getAttribute("value")
this.targetElements.forEach(element => element.style.setProperty(name, value))
}
-1
View File
@@ -1,2 +1 @@
import "initializers/current"
import "initializers/custom_stream_actions"
+1 -1
View File
@@ -31,6 +31,6 @@ class Card < ApplicationRecord
end
def cache_key
[ super, collection&.name ].compact.join("/")
[ super, collection.name ].compact.join("/")
end
end
-2
View File
@@ -7,8 +7,6 @@ class Collection < ApplicationRecord
has_many :cards, dependent: :destroy
has_many :tags, -> { distinct }, through: :cards
validates_presence_of :name
after_save :update_cards_workflow, if: :saved_change_to_workflow_id?
scope :alphabetically, -> { order("lower(name)") }
+3 -1
View File
@@ -1,5 +1,7 @@
#!/usr/bin/env sh
echo "Starting Fizzy on http://development-tenant.fizzy.localhost:3006"
echo "Access with david@37signals.com / secret123456 on http://37signals.fizzy.localhost:3006"
echo "Access with david@37signals.com / secret123456 on http://honcho.fizzy.localhost:3006"
echo "Access first run on http://first-run.fizzy.localhost:3006"
exec ./bin/rails server -p 3006
+25 -20
View File
@@ -1,26 +1,31 @@
#!/usr/bin/env bash
set -eo pipefail
#!/usr/bin/env ruby
require "fileutils"
# Use application binstubs
export PATH="./bin:$PATH"
APP_ROOT = File.expand_path("..", __dir__)
announce() {
printf "\n--- $@\n"
}
def system!(*args)
system(*args, exception: true)
end
announce "Installing dependencies"
gem install bundler --conservative
bundle check || bundle install
FileUtils.chdir APP_ROOT do
# This script is a way to set up or update your development environment automatically.
# This script is idempotent, so that you can run it at any time and get an expectable outcome.
# Add necessary setup steps to this file.
announce "Preparing database"
if [[ $* == *--reset* ]]; then
rails db:reset
else
rails db:prepare
fi
puts "== Installing dependencies =="
system("gem install bundler --conservative")
system("bundle check") || system!("bundle install")
announce "Removing old logs and tempfiles"
rails log:clear tmp:clear
puts "\n== Preparing database =="
system! "bin/rails db:prepare"
system! "bin/rails db:reset" if ARGV.include?("--reset")
echo
echo "Start developing with bin/dev"
puts "\n== Removing old logs and tempfiles =="
system! "bin/rails log:clear tmp:clear"
unless ARGV.include?("--skip-server")
puts "\n== Starting development server =="
STDOUT.flush # flush the output before exec(2) so that it displays
exec "bin/dev"
end
end
+1 -1
View File
@@ -1,7 +1,7 @@
# Run using bin/ci
CI.run do
step "Setup", "bin/setup"
step "Setup", "bin/setup --skip-server"
step "Style: Ruby", "bin/rubocop"
+2 -4
View File
@@ -23,10 +23,8 @@ Rails.application.configure do
config.action_controller.perform_caching = true
config.action_controller.enable_fragment_cache_logging = true
config.cache_store = :solid_cache_store
config.public_file_server.headers = {
"Cache-Control" => "public, max-age=#{2.days.to_i}"
}
config.cache_store = :memory_store
config.public_file_server.headers = { "Cache-Control" => "public, max-age=#{2.days.to_i}" }
else
config.action_controller.perform_caching = true
+7
View File
@@ -0,0 +1,7 @@
require_relative "seeds/helpers"
raise "Seeding is just for development" unless Rails.env.development?
# Seed accounts
seed_account "37signals"
seed_account "honcho"
seed_account "first-run"
+21
View File
@@ -0,0 +1,21 @@
create_tenant "37signals"
david = create_first_run "David Heinemeier Hansson", "david@37signals.com"
login_as david
jz = create_user "Jason Zimdars", "jz@37signals.com"
kevin = create_user "Kevin Mcconnell", "kevin@37signals.com"
create_collection("Fizzy", access_to: [ jz, kevin ]).tap do |fizzy|
create_card("Prepare sign-up page", description: "We need to do this before the launch.", collection: fizzy)
create_card("Prepare sign-up page", description: "We need to do this before the launch.", collection: fizzy).tap do |card|
card.toggle_assignment(kevin)
card.engage
end
create_card("Plain text mentions", description: "We'll support plain text mentions first.", collection: fizzy).tap do |card|
card.toggle_assignment(david)
card.close
end
end
+1
View File
@@ -0,0 +1 @@
create_tenant "first-run"
+33
View File
@@ -0,0 +1,33 @@
def seed_account(name)
print " #{name}"
elapsed = Benchmark.realtime { require_relative name }
puts " #{elapsed.round(2)} sec"
end
def create_tenant(name)
ApplicationRecord.destroy_tenant name
ApplicationRecord.create_tenant name
ApplicationRecord.current_tenant = name
end
def create_first_run(name, email_address, password: "secret123456")
FirstRun.create!(name:, email_address:, password:)
end
def login_as(user)
Current.session = user.sessions.create
end
def create_user(name, email_address, password: "secret123456")
User.create!(name:, email_address:, password:)
end
def create_collection(name, creator: Current.user, all_access: true, access_to: [])
Collection.create!(name:, creator:, all_access:).tap { it.accesses.grant_to(access_to) }
end
def create_card(title, collection:, description: nil, status: :published, creator: Current.user)
collection.cards.create!(title:, creator:, status:).tap do |card|
card.capture(Comment.new(body: description)) if description
end
end
+21
View File
@@ -0,0 +1,21 @@
create_tenant "honcho"
david = create_first_run "David Heinemeier Hansson", "david@37signals.com"
login_as david
jz = create_user "Jason Zimdars", "jz@37signals.com"
kevin = create_user "Kevin Mcconnell", "kevin@37signals.com"
create_collection("Mucho", access_to: [ jz, kevin ]).tap do |fizzy|
create_card("Prepare MUCHO sign-up page", description: "We need to do this before the launch.", collection: fizzy)
create_card("Prepare MUCHO sign-up page", description: "We need to do this before the launch.", collection: fizzy).tap do |card|
card.toggle_assignment(kevin)
card.engage
end
create_card("Plain MUCHO text mentions", description: "We'll support plain text mentions first.", collection: fizzy).tap do |card|
card.toggle_assignment(david)
card.close
end
end
@@ -1,7 +0,0 @@
module TurboStreamsActionsHelper
def set_css_variable(target, name:, value:)
tag.turbo_stream target: target, action: "set_css_variable", name:, value:
end
end
Turbo::Streams::TagBuilder.prepend(TurboStreamsActionsHelper)
-7
View File
@@ -120,11 +120,4 @@ class CardTest < ActiveSupport::TestCase
assert_includes card.cache_key, ApplicationRecord.current_tenant, "cache key must always include the tenant"
end
test "cache key gracefully handles a nil collection" do
card = cards(:logo)
card.update_column :collection_id, Collection.last.id + 1
assert_nothing_raised { card.reload.cache_key }
end
end