Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Thread notes #104

Merged
merged 5 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/components/message_draft_body_component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
"class": "mb-3 pt-0 w-full"
}
) do %>
<%= text_field_tag message_title_id, @message.title, placeholder: "Predmet", "data-action": "change->messageDrafts#update", disabled: [email protected]?, class:"mb-3 px-3 py-4 placeholder-slate-300 text-slate-í00 relative bg-white bg-white rounded-lg text-base border-0 shadow outline-none focus:outline-none focus:ring w-full" %>
<%= text_area_tag message_text_id, @message.metadata["message_body"], placeholder: "Text", "data-action": "change->messageDrafts#update", rows: 10, disabled: [email protected]?, class:"px-3 py-4 placeholder-slate-300 text-slate-í00 relative bg-white bg-white rounded-lg text-base border-0 shadow outline-none focus:outline-none focus:ring w-full h-full" %>
<%= text_field_tag message_title_id, @message.title, placeholder: "Predmet", "data-action": "change->messageDrafts#update", disabled: [email protected]?, class:"mb-3 px-3 py-4 placeholder-slate-300 text-slate-900 relative bg-white bg-white rounded-lg text-base border-0 shadow outline-none focus:outline-none focus:ring w-full" %>
<%= text_area_tag message_text_id, @message.metadata["message_body"], placeholder: "Text", "data-action": "change->messageDrafts#update", rows: 10, disabled: [email protected]?, class:"px-3 py-4 placeholder-slate-300 text-slate-900 relative bg-white bg-white rounded-lg text-base border-0 shadow outline-none focus:outline-none focus:ring w-full h-full" %>
<% end %>
<% else %>
<div class="w-full">
Expand Down
1 change: 1 addition & 0 deletions app/components/message_thread_component.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<div class="flex flex-col justify-stretch items-stretch">
<%= render MessageThreadHeaderComponent.new(@message_thread, @thread_tags_with_deletable_flag) %>
<%= render MessageThreadNoteComponent.new(@message_thread_note) %>
<div class="flex flex-col justify-stretch items-stretch gap-2 p-4">
<% @notice.each do |type, msg| %>
<div class="bg-blue-100 border-t border-b border-blue-500 text-blue-700 px-4 py-3 w-full" role="alert">
Expand Down
1 change: 1 addition & 0 deletions app/components/message_thread_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ def initialize(message_thread:, thread_tags_with_deletable_flag:, thread_message
@thread_tags_with_deletable_flag = thread_tags_with_deletable_flag
@thread_messages = thread_messages
@notice = notice
@message_thread_note = @message_thread.message_thread_note
end
end
39 changes: 39 additions & 0 deletions app/components/message_thread_note_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<div data-controller="dropdown" data-dropdown-open-value=<%= @message_thread_note.note.present? %>>
<div id="dropdown-button" class="flex flex-col justify-start items-between flex-grow-0 flex-shrink-0 relative overflow-hidden p-2 rounded-md bg-white border border-gray-200">
<div role="button" tabindex="0" data-dropdown-target="button" data-action="click->dropdown#toggle" class="flex justify-between">
<button type="button" class="m-1.5 flex justify-between grow items-center gap-2 p-1.5" id="thread-note-menu-button" aria-expanded="false" aria-haspopup="true">
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" class="flex-grow-0 flex-shrink-0 w-8 h-8 relative" preserveAspectRatio="xMidYMid meet">
<path d="M14.6654 6.66666H7.9987C7.29145 6.66666 6.61318 6.94761 6.11308 7.44771C5.61298 7.9478 5.33203 8.62608 5.33203 9.33333V24C5.33203 24.7072 5.61298 25.3855 6.11308 25.8856C6.61318 26.3857 7.29145 26.6667 7.9987 26.6667H22.6654C23.3726 26.6667 24.0509 26.3857 24.551 25.8856C25.0511 25.3855 25.332 24.7072 25.332 24V17.3333M23.4467 4.78133C23.6927 4.52663 23.9869 4.32348 24.3123 4.18372C24.6376 4.04396 24.9875 3.9704 25.3416 3.96732C25.6957 3.96425 26.0469 4.03172 26.3746 4.1658C26.7023 4.29988 27 4.49789 27.2504 4.74827C27.5008 4.99865 27.6988 5.29639 27.8329 5.62412C27.967 5.95184 28.0344 6.30298 28.0314 6.65706C28.0283 7.01114 27.9547 7.36106 27.815 7.6864C27.6752 8.01175 27.4721 8.306 27.2174 8.55199L15.7694 20H11.9987V16.2293L23.4467 4.78133Z" stroke="#111827" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
<div class="flex justify-start items-start flex-grow-0 flex-shrink-0 relative gap-2">
<p class="flex-grow-0 flex-shrink-0 text-base font-bold text-left text-gray-900">Poznámky</p>
</div>
<div class="flex justify-start items-start grow relative gap-2">
<% if @message_thread_note.updated_at %>
<p class="self-stretch flex-grow align-middle text-base text-right text-gray-900"><%= l @message_thread_note.updated_at, format: :long %></p>
<% end %>
</div>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="flex-grow-0 flex-shrink-0 w-6 h-6 relative" preserveAspectRatio="xMidYMid meet">
<path d="M19 9L12 16L5 9" stroke="#9CA3AF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</button>
</div>
<div data-dropdown-target="menu"
data-transition-enter="transition ease-out duration-200"
data-transition-enter-from="opacity-0 translate-y-1"
data-transition-enter-to="opacity-100 translate-y-0"
data-transition-leave="transition ease-in duration-150"
data-transition-leave-from="opacity-100 translate-y-0"
data-transition-leave-to="opacity-0 translate-y-1"
class="hidden">
<%= form_with model:[@message_thread, @message_thread_note], class: "flex flex-col justify-start items-start flex-grow-0 flex-shrink-0 overflow-hidden gap-2 py-1 px-2 rounded-md bg-white" do |form| %>
<%= form.text_area :note, placeholder: 'Zadajte svoje poznámky k vláknu', rows:3, class: "px-3 py-4 placeholder-slate-300 text-slate-900 relative bg-white bg-white rounded-lg text-base border-0 shadow outline-none focus:outline-none focus:ring w-full h-full" %>
<div class="flex flex-col justify-start items-end self-stretch flex-grow-0 flex-shrink-0 gap-2 px-3">
<%= form.button class: "flex justify-center items-center h-11 relative overflow-hidden gap-2.5 px-3.5 py-2.5 rounded-md bg-blue-600" do %>
<div class="flex-grow-0 flex-shrink-0 text-base font-medium text-left text-white">Uložiť</div>
<% end %>
</div>
<% end %>
</div>
</div>
</div>
6 changes: 6 additions & 0 deletions app/components/message_thread_note_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class MessageThreadNoteComponent < ViewComponent::Base
def initialize(message_thread_note)
@message_thread_note = message_thread_note
@message_thread = @message_thread_note.message_thread
end
end
38 changes: 38 additions & 0 deletions app/controllers/message_thread_notes_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
class MessageThreadNotesController < ApplicationController
before_action :set_message_thread, only: %i[update create]
before_action :set_message_thread_note, only: %i[update]

def update
authorize @message_thread_note
if @message_thread_note.update(message_thread_note_params)
redirect_back_or_to message_threads_path(@message_thread), notice: 'Note was successfully updated'
else
render :edit, status: :unprocessable_entity
end
end

def create
@message_thread_note = @message_thread.build_message_thread_note(message_thread_note_params)
authorize @message_thread_note

if @message_thread_note.save
redirect_back_or_to message_threads_path(@message_thread), notice: 'Note was successfully created'
else
render :new, status: :unprocessable_entity
end
end

private

def set_message_thread
@message_thread = policy_scope(MessageThread).find(params[:message_thread_id])
end

def set_message_thread_note
@message_thread_note = policy_scope(MessageThreadNote).find(params[:id])
end

def message_thread_note_params
params.require(:message_thread_note).permit(:note, :last_updated_at)
end
end
1 change: 1 addition & 0 deletions app/controllers/message_threads_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def show
set_thread_tags_with_deletable_flag
@notice = flash
@thread_messages = @message_thread.messages_visible_to_user(Current.user).order(delivered_at: :asc)
@message_thread_note = @message_thread.message_thread_note || @message_thread.build_message_thread_note
end

def update
Expand Down
47 changes: 30 additions & 17 deletions app/models/message_thread.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def find_or_create_by_uuid!(uuid:)
has_many :message_threads_tags, dependent: :destroy
has_many :tag_users, through: :message_threads_tags
has_many :merge_identifiers, class_name: 'MessageThreadMergeIdentifier', dependent: :destroy
has_one :message_thread_note, dependent: :destroy

attr_accessor :search_highlight

Expand All @@ -47,25 +48,37 @@ def mark_all_messages_read

def self.merge_threads
transaction do
target_thread = self.first
self.all.each do |thread|
if thread != target_thread
thread.merge_identifiers.update_all(message_thread_id: target_thread.id)
target_thread.last_message_delivered_at = [target_thread.last_message_delivered_at, thread.last_message_delivered_at].max
target_thread.delivered_at = [target_thread.delivered_at, thread.delivered_at].min
thread.messages.each do |message|
message.thread = target_thread
message.save!
end
thread.tags.each do |tag|
target_thread.tags.push(tag) unless target_thread.tags.include?(tag)
end

thread.reload
thread.destroy!
end
target_thread = first
all.each do |thread|
thread.merge_thread_into(target_thread) if thread != target_thread
end
target_thread.message_thread_note&.save!
target_thread.save!
end
end

def merge_thread_into(target_thread)
merge_identifiers.update_all(message_thread_id: target_thread.id)
merge_dates(target_thread)
messages.update_all(message_thread_id: target_thread.id)
tags.each { |tag| target_thread.tags.push(tag) unless target_thread.tags.include?(tag) }
merge_notes(target_thread)
destroy!
end

def merge_dates(target_thread)
target_thread.last_message_delivered_at = [target_thread.last_message_delivered_at,
last_message_delivered_at].max
target_thread.delivered_at = [target_thread.delivered_at, delivered_at].min
end

def merge_notes(target_thread)
return unless message_thread_note&.note

if target_thread.message_thread_note
target_thread.message_thread_note.note = "#{target_thread.message_thread_note.note.rstrip}\n-----\n#{message_thread_note.note}"
else
target_thread.build_message_thread_note(note: message_thread_note.note)
end
end
end
3 changes: 3 additions & 0 deletions app/models/message_thread_note.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class MessageThreadNote < ApplicationRecord
belongs_to :message_thread
end
24 changes: 24 additions & 0 deletions app/policies/message_thread_note_policy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

class MessageThreadNotePolicy < ApplicationPolicy
attr_reader :user, :message_thread_note

def initialize(user, message_thread_note)
@user = user
@message_thread_note = message_thread_note
end

class Scope < Scope
def resolve
scope.joins(:message_thread).where(message_thread: Pundit.policy_scope(@user, MessageThread))
end
end

def update?
true
end

def create?
true
end
end
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
end
get :search_available_tags, on: :member
resources :messages
resources :message_thread_notes
end
resources :message_threads_tags

Expand Down
9 changes: 9 additions & 0 deletions db/migrate/20231012094539_create_message_thread_notes.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class CreateMessageThreadNotes < ActiveRecord::Migration[7.0]
def change
create_table :message_thread_notes do |t|
t.references :message_thread, null: false, foreign_key: true
t.text :note
t.timestamps
end
end
end
17 changes: 16 additions & 1 deletion db/schema.rb

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

7 changes: 7 additions & 0 deletions test/fixtures/message_thread_notes.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
one:
message_thread: one
note: "Note1"

two:
message_thread: two
note: "Note2"
9 changes: 9 additions & 0 deletions test/models/message_thread_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,13 @@ class MessageThreadTest < ActiveSupport::TestCase

assert_raises(ActiveRecord::RecordInvalid) { thread.save! }
end

test 'should contain notes from both merged threads after merge' do
threads = MessageThread.where(id: [message_threads(:two).id, message_threads(:one).id])

threads.merge_threads

assert_match 'Note1', message_threads(:two).message_thread_note.note
assert_match 'Note2', message_threads(:two).message_thread_note.note
end
end
Loading