diff --git a/app/controllers/step_elements/base_controller.rb b/app/controllers/step_elements/base_controller.rb index 8767fc56d..efbb97548 100644 --- a/app/controllers/step_elements/base_controller.rb +++ b/app/controllers/step_elements/base_controller.rb @@ -33,5 +33,23 @@ module StepElements step_orderable_element = orderable.step_orderable_elements.find_by!(step: @step) render json: step_orderable_element, serializer: StepOrderableElementSerializer, user: current_user end + + def log_step_activity(element_type_of, message_items) + Activities::CreateActivityService.call( + activity_type: "#{@step.protocol.in_module? ? 'protocol_step_' : 'task_step_'}#{element_type_of}", + owner: current_user, + team: @protocol.in_module? ? @protocol.my_module.experiment.project.team : @protocol.team, + project: @protocol.in_module? ? @protocol.my_module.experiment.project : nil, + subject: @protocol, + message_items: { + step: @step.id, + step_position: { + id: @step.id, + value_for: 'position_plus_one' + }, + my_module: @protocol.my_module.id + }.merge(message_items) + ) + end end end diff --git a/app/controllers/step_elements/checklist_items_controller.rb b/app/controllers/step_elements/checklist_items_controller.rb index 94c4b0a43..c8fcd6a55 100644 --- a/app/controllers/step_elements/checklist_items_controller.rb +++ b/app/controllers/step_elements/checklist_items_controller.rb @@ -10,7 +10,18 @@ module StepElements def create checklist_item = @checklist.checklist_items.build(checklist_item_params.merge!(created_by: current_user)) - checklist_item.save! + + ActiveRecord::Base.transaction do + checklist_item.save! + log_activity( + "#{@step.protocol.in_module? ? :task : :protocol}_step_checklist_item_added", + { + checklist_item: checklist_item.text, + checklist_name: @checklist.name + } + ) + end + render json: checklist_item, serializer: ChecklistItemSerializer rescue ActiveRecord::RecordInvalid render json: checklist_item, serializer: ChecklistItemSerializer, status: :unprocessable_entity @@ -19,22 +30,27 @@ module StepElements def update @checklist_item.assign_attributes(checklist_item_params) - if @checklist_item.save! && @checklist_item.saved_change_to_attribute?(:checked) - completed_items = @checklist_item.checklist.checklist_items.where(checked: true).count - all_items = @checklist_item.checklist.checklist_items.count - text_activity = smart_annotation_parser(@checklist_item.text).gsub(/\s+/, ' ') - type_of = if @checklist_item.saved_change_to_attribute(:checked).last - :check_step_checklist_item - else - :uncheck_step_checklist_item - end - log_activity(type_of, - my_module: @step.protocol.my_module.id, - step: @step.id, - step_position: { id: @step.id, value_for: 'position_plus_one' }, - checkbox: text_activity, - num_completed: completed_items.to_s, - num_all: all_items.to_s) + if @checklist_item.save! + if @checklist_item.saved_change_to_attribute?(:checked) + completed_items = @checklist_item.checklist.checklist_items.where(checked: true).count + all_items = @checklist_item.checklist.checklist_items.count + text_activity = smart_annotation_parser(@checklist_item.text).gsub(/\s+/, ' ') + type_of = if @checklist_item.saved_change_to_attribute(:checked).last + :check_step_checklist_item + else + :uncheck_step_checklist_item + end + log_activity(type_of, + checkbox: text_activity, + num_completed: completed_items.to_s, + num_all: all_items.to_s) + else + log_activity( + "#{@step.protocol.in_module? ? :task : :protocol}_step_checklist_item_edited", + checklist_item: @checklist_item.text, + checklist_name: @checklist.name + ) + end end render json: @checklist_item, serializer: ChecklistItemSerializer @@ -44,6 +60,11 @@ module StepElements def destroy if @checklist_item.destroy + log_activity( + "#{@step.protocol.in_module? ? :task : :protocol}_step_checklist_item_deleted", + checklist_item: @checklist_item.text, + checklist_name: @checklist.name + ) render json: @checklist_item, serializer: ChecklistItemSerializer else render json: @checklist_item, serializer: ChecklistItemSerializer, status: :unprocessable_entity @@ -84,15 +105,22 @@ module StepElements end def log_activity(type_of, message_items = {}) - default_items = { step: @step.id, step_position: { id: @step.id, value_for: 'position_plus_one' } } + default_items = { + my_module: (@step.protocol.in_module? ? @step.protocol.my_module.id : nil), + step: @step.id, + step_position: { id: @step.id, value_for: 'position_plus_one' } + } + message_items = default_items.merge(message_items) - Activities::CreateActivityService.call(activity_type: type_of, - owner: current_user, - subject: @step.protocol, - team: @step.protocol.team, - project: @step.protocol.my_module.experiment.project, - message_items: message_items) + Activities::CreateActivityService.call( + activity_type: type_of, + owner: current_user, + subject: @step.protocol, + team: @step.protocol.team, + project: @step.protocol.my_module.experiment.project, + message_items: message_items + ) end end end diff --git a/app/controllers/step_elements/checklists_controller.rb b/app/controllers/step_elements/checklists_controller.rb index 7cf702590..6df62f5c9 100644 --- a/app/controllers/step_elements/checklists_controller.rb +++ b/app/controllers/step_elements/checklists_controller.rb @@ -8,15 +8,21 @@ module StepElements checklist = @step.checklists.build( name: t('protocols.steps.checklist.default_name', position: @step.checklists.length + 1) ) - - create_in_step!(@step, checklist) + ActiveRecord::Base.transaction do + create_in_step!(@step, checklist) + log_step_activity(:checklist_added, { checklist_name: checklist.name }) + end render_step_orderable_element(checklist) rescue ActiveRecord::RecordInvalid head :unprocessable_entity end def update - @checklist.update!(checklist_params) + ActiveRecord::Base.transaction do + @checklist.update!(checklist_params) + log_step_activity(:checklist_edited, { checklist_name: @checklist.name }) + end + render json: @checklist, serializer: ChecklistSerializer rescue ActiveRecord::RecordInvalid head :unprocessable_entity @@ -24,6 +30,7 @@ module StepElements def destroy if @checklist.destroy + log_step_activity(:checklist_deleted, { checklist_name: @checklist.name }) head :ok else head :unprocessable_entity diff --git a/app/controllers/step_elements/tables_controller.rb b/app/controllers/step_elements/tables_controller.rb index e16e06125..aa3854e5c 100644 --- a/app/controllers/step_elements/tables_controller.rb +++ b/app/controllers/step_elements/tables_controller.rb @@ -12,7 +12,10 @@ module StepElements created_by: current_user )) - create_in_step!(@step, step_table) + ActiveRecord::Base.transaction do + create_in_step!(@step, step_table) + log_step_activity(:table_added, { table_name: step_table.table.name }) + end render_step_orderable_element(step_table) rescue ActiveRecord::RecordInvalid @@ -20,7 +23,11 @@ module StepElements end def update - @table.update!(table_params) + ActiveRecord::Base.transaction do + @table.update!(table_params) + log_step_activity(:table_edited, { table_name: @table.name }) + end + render json: @table, serializer: TableSerializer rescue ActiveRecord::RecordInvalid head :unprocessable_entity @@ -28,6 +35,7 @@ module StepElements def destroy if @table.destroy + log_step_activity(:table_deleted, { table_name: @table.name }) head :ok else head :unprocessable_entity diff --git a/app/controllers/step_elements/texts_controller.rb b/app/controllers/step_elements/texts_controller.rb index 8e6cdf54a..dad1ca80e 100644 --- a/app/controllers/step_elements/texts_controller.rb +++ b/app/controllers/step_elements/texts_controller.rb @@ -6,15 +6,24 @@ module StepElements def create step_text = @step.step_texts.build - create_in_step!(@step, step_text) + + ActiveRecord::Base.transaction do + create_in_step!(@step, step_text) + log_step_activity(:text_added, { text_name: step_text.name }) + end + render_step_orderable_element(step_text) rescue ActiveRecord::RecordInvalid head :unprocessable_entity end def update - @step_text.update!(step_text_params) - TinyMceAsset.update_images(@step_text, params[:tiny_mce_images], current_user) + ActiveRecord::Base.transaction do + @step_text.update!(step_text_params) + TinyMceAsset.update_images(@step_text, params[:tiny_mce_images], current_user) + log_step_activity(:text_edited, { text_name: @step_text.name }) + end + render json: @step_text, serializer: StepTextSerializer rescue ActiveRecord::RecordInvalid head :unprocessable_entity @@ -22,6 +31,7 @@ module StepElements def destroy if @step_text.destroy + log_step_activity(:text_deleted, { text_name: @step_text.name }) head :ok else head :unprocessable_entity diff --git a/app/javascript/vue/protocol/step_elements/checklist.vue b/app/javascript/vue/protocol/step_elements/checklist.vue index ff81b8262..18e260263 100644 --- a/app/javascript/vue/protocol/step_elements/checklist.vue +++ b/app/javascript/vue/protocol/step_elements/checklist.vue @@ -87,13 +87,13 @@ }, created() { this.checklistItems = this.element.attributes.orderable.checklist_items.map((item, index) => { - return { attributes: {...item, position: index + 1 } } + return { attributes: {...item, position: index } } }); }, computed: { orderedChecklistItems() { return this.checklistItems.map((item, index) => { - return { attributes: {...item.attributes, position: index + 1 } } + return { attributes: {...item.attributes, position: index } } }); }, pastingMultiline() { @@ -114,7 +114,7 @@ postItem(item, callback) { $.post(this.element.attributes.orderable.urls.create_item_url, item).success((result) => { this.checklistItems.splice( - result.data.attributes.position - 1, + result.data.attributes.position, 1, { attributes: { ...result.data.attributes, id: result.data.id } } ); @@ -127,7 +127,7 @@ saveItem(item) { if (item.attributes.id) { this.checklistItems.splice( - item.attributes.position - 1, 1, item + item.attributes.position, 1, item ); $.ajax({ url: item.attributes.urls.update_url, @@ -147,13 +147,13 @@ attributes: { text: '', checked: false, - position: this.checklistItems.length + 1 + position: this.checklistItems.length } } ); }, - removeItem(item) { - this.checklistItems.splice(item.attributes.position - 1, 1); + removeItem(position) { + this.checklistItems.splice(position, 1); }, startReorder() { this.reordering = true; diff --git a/app/javascript/vue/protocol/step_elements/checklistItem.vue b/app/javascript/vue/protocol/step_elements/checklistItem.vue index 3fbd629b6..68025c371 100644 --- a/app/javascript/vue/protocol/step_elements/checklistItem.vue +++ b/app/javascript/vue/protocol/step_elements/checklistItem.vue @@ -66,7 +66,12 @@ }, computed: { element() { // remap and alias to work with delete mixin - return { attributes: { orderable: this.checklistItem.attributes } } + return({ + attributes: { + orderable: this.checklistItem.attributes, + position: this.checklistItem.attributes.position + } + }); } }, methods: { @@ -92,7 +97,7 @@ } }, removeItem() { - this.$emit('removeItem', this.checklistItem); + this.$emit('removeItem', this.checklistItem.attributes.position); }, update() { this.$emit('update', this.checklistItem); diff --git a/app/models/checklist_item.rb b/app/models/checklist_item.rb index cf24b3159..9617a60fa 100644 --- a/app/models/checklist_item.rb +++ b/app/models/checklist_item.rb @@ -25,7 +25,7 @@ class ChecklistItem < ApplicationRecord def update_positions transaction do checklist.checklist_items.order(position: :asc).each_with_index do |checklist_item, i| - checklist_item.update!(position: i + 1) + checklist_item.update!(position: i) end end end diff --git a/app/models/step_text.rb b/app/models/step_text.rb index dff232a91..728f4347b 100644 --- a/app/models/step_text.rb +++ b/app/models/step_text.rb @@ -2,10 +2,15 @@ class StepText < ApplicationRecord include TinyMceImages + include ActionView::Helpers::TextHelper auto_strip_attributes :text, nullify: false validates :text, length: { maximum: Constants::RICH_TEXT_MAX_LENGTH } belongs_to :step, inverse_of: :step_texts, touch: true has_many :step_orderable_elements, as: :orderable, dependent: :destroy + + def name + strip_tags(text.truncate(64)) + end end diff --git a/app/serializers/step_text_serializer.rb b/app/serializers/step_text_serializer.rb index 8d1cfdd4b..61b10723c 100644 --- a/app/serializers/step_text_serializer.rb +++ b/app/serializers/step_text_serializer.rb @@ -23,10 +23,6 @@ class StepTextSerializer < ActiveModel::Serializer sanitize_input(object.tinymce_render('text')) end - def name - strip_tags(object.tinymce_render('text').truncate(62, '...')) - end - def icon 'fa-font' end diff --git a/config/initializers/extends.rb b/config/initializers/extends.rb index 976388b20..7e5025cd1 100644 --- a/config/initializers/extends.rb +++ b/config/initializers/extends.rb @@ -391,7 +391,31 @@ class Extends task_step_file_added: 188, task_step_file_deleted: 189, protocol_step_file_added: 190, - protocol_step_file_deleted: 191 + protocol_step_file_deleted: 191, + task_step_text_added: 192, + task_step_text_edited: 193, + task_step_text_deleted: 194, + task_step_table_added: 195, + task_step_table_edited: 196, + task_step_table_deleted: 197, + task_step_checklist_added: 198, + task_step_checklist_edited: 199, + task_step_checklist_deleted: 200, + task_step_checklist_item_added: 201, + task_step_checklist_item_edited: 202, + task_step_checklist_item_deleted: 203, + protocol_step_text_added: 204, + protocol_step_text_edited: 205, + protocol_step_text_deleted: 206, + protocol_step_table_added: 207, + protocol_step_table_edited: 208, + protocol_step_table_deleted: 209, + protocol_step_checklist_added: 210, + protocol_step_checklist_edited: 211, + protocol_step_checklist_deleted: 212, + protocol_step_checklist_item_added: 213, + protocol_step_checklist_item_edited: 214, + protocol_step_checklist_item_deleted: 215 } ACTIVITY_GROUPS = { @@ -400,7 +424,7 @@ class Extends task: [8, 58, 9, 59, *10..14, 35, 36, 37, 53, 54, *60..63, 138, 139, 140, 64, 66, 106, 126, 120, 132, *146..148, 166], task_protocol: [15, 22, 16, 18, 19, 20, 21, 17, 38, 39, 100, 111, 45, 46, 47, 121, 124, 115, 118, 127, 130, 137, - 168, 171, 177, 184, 185, 188, 189], + 168, 171, 177, 184, 185, 188, 189, *192..203], task_inventory: [55, 56, 146, 147, 183], experiment: [*27..31, 57, 141, 165], reports: [48, 50, 49, 163, 164], @@ -408,7 +432,7 @@ class Extends 78, 96, 107, 113, 114, *133..136, 180, 181, 182], protocol_repository: [80, 103, 89, 87, 79, 90, 91, 88, 85, 86, 84, 81, 82, 83, 101, 112, 123, 125, 117, 119, 129, 131, 170, 173, 179, 187, 186, - 190, 191], + 190, 191, *204..215], team: [92, 94, 93, 97, 104] } diff --git a/config/locales/global_activities/en.yml b/config/locales/global_activities/en.yml index d6d873a7c..218ecbca2 100644 --- a/config/locales/global_activities/en.yml +++ b/config/locales/global_activities/en.yml @@ -217,6 +217,30 @@ en: protocol_step_content_rearranged_html: "%{user} rearranged content of protocol's step %{step_position} %{step} in protocol %{protocol} in Protocol repository" protocol_step_file_added_html: "%{user} added file %{file} to protocol's step %{step_position} %{step} in Protocol repository" protocol_step_file_deleted_html: "%{user} deleted file %{file} in protocol's step %{step_position} %{step} in Protocol repository" + task_step_text_added_html: "%{user} created text %{text_name} in protocol's step %{step_position} %{step} on task %{my_module}" + task_step_text_edited_html: "%{user} edited text %{text_name} in protocol's step %{step_position} %{step} on task %{my_module}" + task_step_text_deleted_html: "%{user} deleted text %{text_name} in protocol's step %{step_position} %{step} on task %{my_module}" + task_step_table_added_html: "%{user} created table %{table_name} in protocol's step %{step_position} %{step} on task %{my_module}" + task_step_table_edited_html: "%{user} edited table %{table_name} in protocol's step %{step_position} %{step} on task %{my_module}" + task_step_table_deleted_html: "%{user} deleted table %{table_name} in protocol's step %{step_position} %{step} on task %{my_module}" + task_step_checklist_added_html: "%{user} created checklist %{checklist_name} in protocol's step %{step_position} %{step} on task %{my_module}" + task_step_checklist_edited_html: "%{user} edited checklist %{checklist_name} in protocol's step %{step_position} %{step} on task %{my_module}" + task_step_checklist_deleted_html: "%{user} deleted checklist %{checklist_name} in protocol's step %{step_position} %{step} on task %{my_module}" + task_step_checklist_item_added_html: "%{user} created checklist item %{checklist_item} in checklist %{checklist_name} in protocol's step %{step_position} %{step} on task %{my_module}" + task_step_checklist_item_edited_html: "%{user} edited checklist item %{checklist_item} in checklist %{checklist_name} in protocol's step %{step_position} %{step} on task %{my_module}" + task_step_checklist_item_deleted_html: "%{user} deleted checklist item %{checklist_item} in checklist %{checklist_name} in protocol's step %{step_position} %{step} on task %{my_module}" + protocol_step_text_added_html: "%{user} created text %{text_name} in protocol's step %{step_position} %{step} in Protocol repository" + protocol_step_text_edited_html: "%{user} edited text %{text_name} in protocol's step %{step_position} %{step} in Protocol repository" + protocol_step_text_deleted_html: "%{user} deleted text %{text_name} in protocol's step %{step_position} %{step} in Protocol repository" + protocol_step_table_added_html: "%{user} created table %{table_name} in protocol's step %{step_position} %{step} in Protocol repository" + protocol_step_table_edited_html: "%{user} edited table %{table_name} in protocol's step %{step_position} %{step} in Protocol repository" + protocol_step_table_deleted_html: "%{user} deleted table %{table_name} in protocol's step %{step_position} %{step} in Protocol repository" + protocol_step_checklist_added_html: "%{user} created checklist %{checklist_name} in protocol's step %{step_position} %{step} in Protocol repository" + protocol_step_checklist_edited_html: "%{user} edited checklist %{checklist_name} in protocol's step %{step_position} %{step} in Protocol repository" + protocol_step_checklist_deleted_html: "%{user} deleted checklist %{checklist_name} in protocol's step %{step_position} %{step} in Protocol repository" + task_step_checklist_item_added_html: "%{user} created checklist item %{checklist_item} in checklist %{checklist_name} in protocol's step %{step_position} %{step} in Protocol repository" + task_step_checklist_item_edited_html: "%{user} edited checklist item %{checklist_item} in checklist %{checklist_name} in protocol's step %{step_position} %{step} in Protocol repository" + task_step_checklist_item_deleted_html: "%{user} deleted checklist item %{checklist_item} in checklist %{checklist_name} in protocol's step %{step_position} %{step} in Protocol repository" activity_name: create_project: "Project created" rename_project: "Project renamed"