From 6d92d72830d92f036962016ea32a98a42f71ba03 Mon Sep 17 00:00:00 2001 From: Andrew Vogel Date: Sat, 25 Jan 2025 13:03:50 -0500 Subject: [PATCH 1/7] chore: add tailwindcss --- .gitignore | 3 +++ Gemfile | 4 ++++ Gemfile.lock | 9 ++++++++ Procfile.dev | 2 ++ app/assets/builds/.keep | 0 .../stylesheets/application.tailwind.css | 13 +++++++++++ app/views/layouts/application.html.erb | 5 ++++- bin/dev | 18 +++++++++++++-- config/tailwind.config.js | 22 +++++++++++++++++++ 9 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 Procfile.dev create mode 100644 app/assets/builds/.keep create mode 100644 app/assets/stylesheets/application.tailwind.css create mode 100644 config/tailwind.config.js diff --git a/.gitignore b/.gitignore index f92525c..1303e39 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,6 @@ # Ignore master key for decrypting credentials and more. /config/master.key + +/app/assets/builds/* +!/app/assets/builds/.keep diff --git a/Gemfile b/Gemfile index c59db3d..eaf145f 100644 --- a/Gemfile +++ b/Gemfile @@ -61,3 +61,7 @@ group :test do gem "capybara" gem "selenium-webdriver" end + +gem "tailwindcss-rails" + +gem "tailwindcss-ruby", "3.4.13" diff --git a/Gemfile.lock b/Gemfile.lock index 85d0279..135fe32 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -317,6 +317,13 @@ GEM stimulus-rails (1.3.4) railties (>= 6.0.0) stringio (3.1.2) + tailwindcss-rails (3.3.1) + railties (>= 7.0.0) + tailwindcss-ruby (~> 3.0) + tailwindcss-ruby (3.4.13-aarch64-linux) + tailwindcss-ruby (3.4.13-arm-linux) + tailwindcss-ruby (3.4.13-arm64-darwin) + tailwindcss-ruby (3.4.13-x86_64-linux) thor (1.3.2) thruster (0.1.10) thruster (0.1.10-aarch64-linux) @@ -377,6 +384,8 @@ DEPENDENCIES solid_queue sqlite3 (>= 2.1) stimulus-rails + tailwindcss-rails + tailwindcss-ruby (= 3.4.13) thruster turbo-rails tzinfo-data diff --git a/Procfile.dev b/Procfile.dev new file mode 100644 index 0000000..da151fe --- /dev/null +++ b/Procfile.dev @@ -0,0 +1,2 @@ +web: bin/rails server +css: bin/rails tailwindcss:watch diff --git a/app/assets/builds/.keep b/app/assets/builds/.keep new file mode 100644 index 0000000..e69de29 diff --git a/app/assets/stylesheets/application.tailwind.css b/app/assets/stylesheets/application.tailwind.css new file mode 100644 index 0000000..8666d2f --- /dev/null +++ b/app/assets/stylesheets/application.tailwind.css @@ -0,0 +1,13 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* + +@layer components { + .btn-primary { + @apply py-2 px-4 bg-blue-200; + } +} + +*/ diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 7c4c2af..f189b6c 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -18,11 +18,14 @@ <%# Includes all stylesheet files in app/assets/stylesheets %> + <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %> <%= stylesheet_link_tag :app, "data-turbo-track": "reload" %> <%= javascript_importmap_tags %> - <%= yield %> +
+ <%= yield %> +
diff --git a/bin/dev b/bin/dev index 5f91c20..ad72c7d 100755 --- a/bin/dev +++ b/bin/dev @@ -1,2 +1,16 @@ -#!/usr/bin/env ruby -exec "./bin/rails", "server", *ARGV +#!/usr/bin/env sh + +if ! gem list foreman -i --silent; then + echo "Installing foreman..." + gem install foreman +fi + +# Default to port 3000 if not specified +export PORT="${PORT:-3000}" + +# Let the debug gem allow remote connections, +# but avoid loading until `debugger` is called +export RUBY_DEBUG_OPEN="true" +export RUBY_DEBUG_LAZY="true" + +exec foreman start -f Procfile.dev "$@" diff --git a/config/tailwind.config.js b/config/tailwind.config.js new file mode 100644 index 0000000..c3deef1 --- /dev/null +++ b/config/tailwind.config.js @@ -0,0 +1,22 @@ +const defaultTheme = require('tailwindcss/defaultTheme') + +module.exports = { + content: [ + './public/*.html', + './app/helpers/**/*.rb', + './app/javascript/**/*.js', + './app/views/**/*.{erb,haml,html,slim}' + ], + theme: { + extend: { + fontFamily: { + sans: ['Inter var', ...defaultTheme.fontFamily.sans], + }, + }, + }, + plugins: [ + // require('@tailwindcss/forms'), + // require('@tailwindcss/typography'), + // require('@tailwindcss/container-queries'), + ] +} From 787a68a565f634f33f9f7f14f4729b68dab5491e Mon Sep 17 00:00:00 2001 From: Andrew Vogel Date: Sat, 25 Jan 2025 13:54:36 -0500 Subject: [PATCH 2/7] feat: add layout flash --- app/javascript/application.js | 4 ++++ app/views/layouts/_flash.html.erb | 21 +++++++++++++++++++++ app/views/layouts/application.html.erb | 3 ++- 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 app/views/layouts/_flash.html.erb diff --git a/app/javascript/application.js b/app/javascript/application.js index 0d7b494..d6605c6 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -1,3 +1,7 @@ // Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails import "@hotwired/turbo-rails" import "controllers" + +window.removeFlash = (closeButton) => { + closeButton.parentElement.remove(); +} diff --git a/app/views/layouts/_flash.html.erb b/app/views/layouts/_flash.html.erb new file mode 100644 index 0000000..34f07d6 --- /dev/null +++ b/app/views/layouts/_flash.html.erb @@ -0,0 +1,21 @@ +<% flash.each do |type, msg| %> + <% if type.to_s == "notice" %> +
+ <%= msg %> + +
+ <% else %> +
+ <%= msg %> + +
+ <% end %> +<% end %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index f189b6c..9eda789 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -24,7 +24,8 @@ -
+
+ <%= render "layouts/flash" %> <%= yield %>
From f414429f4cd99371209e480f7a99924479361f01 Mon Sep 17 00:00:00 2001 From: Andrew Vogel Date: Sat, 25 Jan 2025 13:58:52 -0500 Subject: [PATCH 3/7] fu tailwind --- config/tailwind.config.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/tailwind.config.js b/config/tailwind.config.js index c3deef1..d6ad82c 100644 --- a/config/tailwind.config.js +++ b/config/tailwind.config.js @@ -15,8 +15,8 @@ module.exports = { }, }, plugins: [ - // require('@tailwindcss/forms'), - // require('@tailwindcss/typography'), - // require('@tailwindcss/container-queries'), + require('@tailwindcss/forms'), + require('@tailwindcss/typography'), + require('@tailwindcss/container-queries'), ] } From 328f9f928d58e0b456aac1c5545b7f236f16d280 Mon Sep 17 00:00:00 2001 From: Andrew Vogel Date: Sat, 25 Jan 2025 14:05:44 -0500 Subject: [PATCH 4/7] feat: add edit/update views for appointment we are not checking who is allowed to edit in the appointment partial yet --- app/controllers/appointments_controller.rb | 30 +++++++++++++++++-- app/models/appointment.rb | 4 +++ app/views/appointments/_appointment.html.erb | 31 ++++++++++++++++---- app/views/appointments/edit.html.erb | 19 ++++++++++++ app/views/appointments/index.html.erb | 8 +++-- config/routes.rb | 2 +- 6 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 app/views/appointments/edit.html.erb diff --git a/app/controllers/appointments_controller.rb b/app/controllers/appointments_controller.rb index 5769f51..225c751 100644 --- a/app/controllers/appointments_controller.rb +++ b/app/controllers/appointments_controller.rb @@ -1,12 +1,36 @@ class AppointmentsController < ApplicationController - helper_method :appointments + helper_method :appointments, :appointment - def index + before_action :check_created_by, only: [:edit, :update] + + def update + if appointment.update(appointment_params) + redirect_to appointments_path, notice: "Appointment updated!" + else + render :edit, status: :unprocessable_entity + end end private + def check_created_by + unless appointment.created_by?(Current.user) + redirect_to appointments_path, alert: "Can't modify appointment - you are not the creator." + end + end + + def appointment_params + params.require(:appointment).permit( + :requested_datetime, + :notes + ) + end + + def appointment + @appointment ||= Appointment.find(params[:id]) + end + def appointments - @appointments ||= Appointment.all + @appointments ||= Appointment.includes(:created_by).all end end diff --git a/app/models/appointment.rb b/app/models/appointment.rb index f0d75de..2c03bff 100644 --- a/app/models/appointment.rb +++ b/app/models/appointment.rb @@ -2,4 +2,8 @@ class Appointment < ApplicationRecord belongs_to :created_by, foreign_key: :created_by_user_id, class_name: "User" validates :requested_datetime, presence: true + + def created_by?(user) + created_by == user + end end diff --git a/app/views/appointments/_appointment.html.erb b/app/views/appointments/_appointment.html.erb index 1bb8f3d..69b8797 100644 --- a/app/views/appointments/_appointment.html.erb +++ b/app/views/appointments/_appointment.html.erb @@ -1,5 +1,26 @@ -
- <%= appointment.requested_datetime %> - <%= appointment.notes %> - <%= appointment.created_by_user_id %> -
+<%= turbo_frame_tag(appointment) do %> +
+
+

+ Requested Time - <%= appointment.requested_datetime.strftime("%B %-d %Y at %I:%H%P") %> +

+
+

+ <%= truncate(appointment.notes, length: 40) %> +

+
+ <%= appointment.created_by.email_address %> + +
+
+
+
+
+ Actions + <%= link_to "Edit", edit_appointment_path(appointment), class: "text-xs text-indigo-500 hover:text-indigo-400", data: { turbo: false } %> +
+
+
+<% end %> diff --git a/app/views/appointments/edit.html.erb b/app/views/appointments/edit.html.erb new file mode 100644 index 0000000..ec2d4c0 --- /dev/null +++ b/app/views/appointments/edit.html.erb @@ -0,0 +1,19 @@ +
+

Edit Appointment

+ + <%= form_for appointment, html: { class: "mt-12" } do |f| %> +
+
+ <%= f.label :requested_datetime, class: "font-semibold" %> + <%= f.datetime_field :requested_datetime %> +
+ +
+ <%= f.label :notes, class: "font-semibold" %> + <%= f.text_area :notes, cols: 40, rows: 10 %> +
+ + <%= f.submit class: "rounded-md bg-indigo-600 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" %> +
+ <% end %> +
diff --git a/app/views/appointments/index.html.erb b/app/views/appointments/index.html.erb index 08e5eb6..6bc3c9e 100644 --- a/app/views/appointments/index.html.erb +++ b/app/views/appointments/index.html.erb @@ -1,3 +1,7 @@ -

Appointments

+
+

Appointments

-<%= render appointments, as: :appointment %> +
+ <%= render appointments, as: :appointment %> +
+
diff --git a/config/routes.rb b/config/routes.rb index a6b64da..5083402 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,7 @@ Rails.application.routes.draw do resource :session resources :passwords, param: :token - resources :appointments, only: :index + resources :appointments, only: [:index, :edit, :update] # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. From 6e689a83f50c181fec00323c5501acfae8f3efe0 Mon Sep 17 00:00:00 2001 From: Andrew Vogel Date: Sun, 26 Jan 2025 16:27:47 -0500 Subject: [PATCH 5/7] feat: broadcast appointments list updates on save this is the broken state. Current.user will always be nil and therefore, the edit link will fail to render for all attached clients --- app/views/appointments/_appointment.html.erb | 4 +++- app/views/appointments/index.html.erb | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/views/appointments/_appointment.html.erb b/app/views/appointments/_appointment.html.erb index 69b8797..f0eb703 100644 --- a/app/views/appointments/_appointment.html.erb +++ b/app/views/appointments/_appointment.html.erb @@ -19,7 +19,9 @@
Actions - <%= link_to "Edit", edit_appointment_path(appointment), class: "text-xs text-indigo-500 hover:text-indigo-400", data: { turbo: false } %> + <% if appointment.created_by?(Current.user) %> + <%= link_to "Edit", edit_appointment_path(appointment), class: "text-xs text-indigo-500 hover:text-indigo-400", data: { turbo: false } %> + <% end %>
diff --git a/app/views/appointments/index.html.erb b/app/views/appointments/index.html.erb index 6bc3c9e..fd9cb4f 100644 --- a/app/views/appointments/index.html.erb +++ b/app/views/appointments/index.html.erb @@ -1,3 +1,5 @@ +<%= turbo_stream_from "appointments_list" %> +

Appointments

From 2ed80856a6fca6839ef9dc1a4b64674dd0a3546d Mon Sep 17 00:00:00 2001 From: Andrew Vogel Date: Sun, 26 Jan 2025 22:52:51 -0500 Subject: [PATCH 6/7] WIP --- app/models/appointment.rb | 8 ++++++++ app/views/appointments/_load_row.html.erb | 1 + app/views/appointments/row.html.erb | 1 + config/routes.rb | 6 +++++- 4 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 app/views/appointments/_load_row.html.erb create mode 100644 app/views/appointments/row.html.erb diff --git a/app/models/appointment.rb b/app/models/appointment.rb index 2c03bff..26fb918 100644 --- a/app/models/appointment.rb +++ b/app/models/appointment.rb @@ -3,6 +3,14 @@ class Appointment < ApplicationRecord validates :requested_datetime, presence: true + after_save_commit -> { + broadcast_replace_to( + "appointments_list", + partial: "appointments/load_row", + locals: { appointment: self } + ) + } + def created_by?(user) created_by == user end diff --git a/app/views/appointments/_load_row.html.erb b/app/views/appointments/_load_row.html.erb new file mode 100644 index 0000000..0a77516 --- /dev/null +++ b/app/views/appointments/_load_row.html.erb @@ -0,0 +1 @@ +<%= turbo_frame_tag(appointment, src: row_appointment_path(appointment)) %> diff --git a/app/views/appointments/row.html.erb b/app/views/appointments/row.html.erb new file mode 100644 index 0000000..41db675 --- /dev/null +++ b/app/views/appointments/row.html.erb @@ -0,0 +1 @@ +<%= render "appointment", appointment: %> diff --git a/config/routes.rb b/config/routes.rb index 5083402..673bd13 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,11 @@ Rails.application.routes.draw do resource :session resources :passwords, param: :token - resources :appointments, only: [:index, :edit, :update] + resources :appointments, only: [:index, :edit, :update] do + member do + get :row + end + end # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. From 1e96ddcc75834d9e88724aa39eaedaf465c7dd2b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 04:32:49 +0000 Subject: [PATCH 7/7] chore(deps): bump solid_cable from 3.0.6 to 3.0.7 Bumps [solid_cable](https://github.com/rails/solid_cable) from 3.0.6 to 3.0.7. - [Release notes](https://github.com/rails/solid_cable/releases) - [Commits](https://github.com/rails/solid_cable/compare/v3.0.6...v3.0.7) --- updated-dependencies: - dependency-name: solid_cable dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 135fe32..c0b311b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -285,7 +285,7 @@ GEM rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) - solid_cable (3.0.6) + solid_cable (3.0.7) actioncable (>= 7.2) activejob (>= 7.2) activerecord (>= 7.2)