diff --git a/.gitignore b/.gitignore index 1a68f5b..be8cf26 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ /config/master.key /coverage + +/app/assets/builds/* +!/app/assets/builds/.keep diff --git a/Gemfile b/Gemfile index de247cf..10deeda 100644 --- a/Gemfile +++ b/Gemfile @@ -24,6 +24,8 @@ gem "turbo-rails" # Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev] gem "stimulus-rails" +gem 'tailwindcss-rails' + # Use Redis adapter to run Action Cable in production # gem "redis", ">= 4.0.1" diff --git a/Gemfile.lock b/Gemfile.lock index 2832e3f..b3f2dea 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -296,6 +296,16 @@ GEM stimulus-rails (1.3.4) railties (>= 6.0.0) stringio (3.1.7) + tailwindcss-rails (4.3.0) + railties (>= 7.0.0) + tailwindcss-ruby (~> 4.0) + tailwindcss-ruby (4.1.13) + tailwindcss-ruby (4.1.13-aarch64-linux-gnu) + tailwindcss-ruby (4.1.13-aarch64-linux-musl) + tailwindcss-ruby (4.1.13-arm64-darwin) + tailwindcss-ruby (4.1.13-x86_64-darwin) + tailwindcss-ruby (4.1.13-x86_64-linux-gnu) + tailwindcss-ruby (4.1.13-x86_64-linux-musl) thor (1.4.0) timeout (0.4.3) tsort (0.2.0) @@ -353,6 +363,7 @@ DEPENDENCIES simplecov sprockets-rails stimulus-rails + tailwindcss-rails turbo-rails tzinfo-data web-console 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/config/manifest.js b/app/assets/config/manifest.js index 5918193..338a0e8 100644 --- a/app/assets/config/manifest.js +++ b/app/assets/config/manifest.js @@ -1,2 +1,3 @@ //= link_tree ../images //= link_directory ../stylesheets .css +//= link_tree ../builds diff --git a/app/assets/tailwind/application.css b/app/assets/tailwind/application.css new file mode 100644 index 0000000..f1d8c73 --- /dev/null +++ b/app/assets/tailwind/application.css @@ -0,0 +1 @@ +@import "tailwindcss"; diff --git a/app/controllers/messages_controller.rb b/app/controllers/messages_controller.rb index 0af40a8..e9101db 100644 --- a/app/controllers/messages_controller.rb +++ b/app/controllers/messages_controller.rb @@ -5,7 +5,10 @@ class MessagesController < ApplicationController def index if (list_name = params[:list_name]) @list = List.find_by_name list_name - @messages = Message.where(list_id: @list.id).order(:id) + + messages = Message.with_recursive(parent_and_children: [Message.where(list_id: @list.id, parent_id: nil).order(:id).limit(100), Message.joins('inner join parent_and_children on messages.parent_id = parent_and_children.id')]) + .joins('inner join parent_and_children on parent_and_children.id = messages.id') + @messages = compose_tree(messages) elsif (query = params[:q]) search query @@ -47,4 +50,17 @@ def search(query) message_where = Message.where('body %> ? AND list_id IN (?)', query, list_ids).order(Arel.sql('body <-> ?', query)) @messages = message_where.offset(page * PER_PAGE).limit(PER_PAGE) end + + def compose_tree(messages) + [].tap do |ret| + messages.each do |m| + if m.parent_id && (parent = messages.detect { it.id == m.parent_id }) + (parent.children ||= []) << m + else + ret << m + end + end + ret.sort_by!(&:id) + end + end end diff --git a/app/models/message.rb b/app/models/message.rb index c6d051f..fc561a9 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -10,6 +10,8 @@ class Message < ApplicationRecord # https://blade.ruby-lang.org/ruby-talk/410000 is not. self.skip_time_zone_conversion_for_attributes = [:published_at] + attr_accessor :children + class << self def from_mail(mail, list, list_seq) body = Kconv.toutf8 mail.body.raw_source @@ -33,13 +35,13 @@ def from_mail(mail, list, list_seq) # mail.in_reply_to returns strange Array object in some cases (?), so let's use the raw value parent_message_id_header = extract_message_id_from_in_reply_to(mail.header[:in_reply_to]&.value) - parent_message_id = Message.where(message_id_header: parent_message_id_header).pick(:id) if parent_message_id_header + parent_message_id = Message.where(list_id: list.id, message_id_header: parent_message_id_header).pick(:id) if parent_message_id_header if !parent_message_id && (String === mail.references) - parent_message_id = Message.where(message_id_header: mail.references).pick(:id) + parent_message_id = Message.where(list_id: list.id, message_id_header: mail.references).pick(:id) end if !parent_message_id && (Array === mail.references) mail.references.compact.each do |ref| - break if (parent_message_id = Message.where(message_id_header: ref).pick(:id)) + break if (parent_message_id = Message.where(list_id: list.id, message_id_header: ref).pick(:id)) end end @@ -85,6 +87,10 @@ def from_string(str) end end + def count_recursively(count = 0) + count + 1 + (children&.sum(&:count_recursively) || 0) + end + def reload_from_s3(s3_client = Aws::S3::Client.new(region: BLADE_BUCKET_REGION)) m = Message.from_s3(List.find_by_id(self.list_id).name, self.list_seq, s3_client) diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 9d58673..3fadb48 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -11,11 +11,22 @@ <%= csrf_meta_tags %> <%= csp_meta_tag %> + <%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %> <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> -
- <%= yield %> + +