diff --git a/app/assets/stylesheets/shared/inline_edit.scss b/app/assets/stylesheets/shared/inline_edit.scss index d946a6a3b..336ec8a92 100644 --- a/app/assets/stylesheets/shared/inline_edit.scss +++ b/app/assets/stylesheets/shared/inline_edit.scss @@ -1,5 +1,9 @@ .sci-inline-edit { display: flex; + + &.editing { + margin-top: -0.5em; + } } .sci-inline-edit__content { @@ -7,7 +11,6 @@ span { cursor: pointer; - white-space: pre; &.blank { color: $color-silver-chalice; @@ -19,10 +22,10 @@ border-color: $brand-focus; border-radius: 4px; height: 36px; - line-height: 36px; + min-height: 36px; outline: none; overflow: hidden; - padding: 0 16px; + padding: 0.5em 1em; width: 100%; &:focus { diff --git a/app/assets/stylesheets/steps/checklist.scss b/app/assets/stylesheets/steps/checklist.scss new file mode 100644 index 000000000..2e2448cc1 --- /dev/null +++ b/app/assets/stylesheets/steps/checklist.scss @@ -0,0 +1,41 @@ +.step-checklist-container { + margin-left: -1.5em; + + .step-element-name { + align-items: flex-start; + display: flex; + + .sci-checkbox-container { + margin-right: 8px; + margin-top: 4px; + } + + .step-checklist-text { + width: 100%; + } + + &.done .step-checklist-text { + text-decoration: line-through; + } + + &:hover.done .step-checklist-text { + text-decoration: none; + } + } + + .step-checklist-add-item { + margin-left: 9px; + margin-top: 2px; + } +} + +.step-checklist-items { + .sci-inline-edit { + font-weight: normal; + + textarea { + padding-left: 4px; + margin-left: -5px; + } + } +} diff --git a/app/assets/stylesheets/steps/step.scss b/app/assets/stylesheets/steps/step.scss index 8d7446cca..2b9998c27 100644 --- a/app/assets/stylesheets/steps/step.scss +++ b/app/assets/stylesheets/steps/step.scss @@ -91,11 +91,12 @@ .step-element-header { align-items: center; display: flex; + min-height: 40px; padding: 0 0 0 8px; + position: relative; + padding: 8px; &.editing-name { - padding: 0; - .step-element-controls { display: none; } @@ -111,10 +112,16 @@ } .step-element-controls { + background: linear-gradient(90deg, rgba(255,255,255,0) 0%, $color-concrete 15%, $color-concrete 100%); display: flex; margin-left: auto; + position: absolute; + right: 4px; + top: 4px; .btn { + height: 32px; + width: 32px; padding: 0; } diff --git a/app/controllers/step_components/checklist_items_controller.rb b/app/controllers/step_components/checklist_items_controller.rb new file mode 100644 index 000000000..45028f984 --- /dev/null +++ b/app/controllers/step_components/checklist_items_controller.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +module StepComponents + class ChecklistItemsController < ApplicationController + include ApplicationHelper + + before_action :load_vars + before_action :load_checklist, only: %i(update destroy) + before_action :check_manage_permissions, only: %i(create update destroy) + + def create + checklist_item = @checklist.checklist_items.build(checklist_item_params.merge!(created_by: current_user)) + checklist_item.save! + render json: checklist_item, serializer: ChecklistItemSerializer + rescue ActiveRecord::RecordInvalid + render json: checklist_item, serializer: ChecklistItemSerializer, status: :unprocessable_entity + end + + 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) + end + + render json: @checklist_item, serializer: ChecklistItemSerializer + rescue ActiveRecord::RecordInvalid + render json: @checklist_item, serializer: ChecklistItemSerializer, status: :unprocessable_entity + end + + def destroy + if @checklist_item.destroy + render json: @checklist_item, serializer: ChecklistItemSerializer + else + render json: @checklist, serializer: ChecklistItemSerializer, status: :unprocessable_entity + end + end + + private + + def check_manage_permissions + render_403 unless can_manage_step?(@step) + end + + def checklist_item_params + params.require(:attributes).permit(:checked, :text, :position) + end + + def load_vars + @step = Step.find_by(id: params[:step_id]) + return render_404 unless @step + + @checklist = @step.checklists.find_by(id: params[:checklist_id]) + return render_404 unless @checklist + end + + def load_checklist + @checklist_item = @checklist.checklist_items.find_by(id: params[:id]) + return render_404 unless @checklist_item + end + + def log_activity(type_of, message_items = {}) + default_items = { 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) + end + end +end diff --git a/app/javascript/vue/protocol/step_components/checklist.vue b/app/javascript/vue/protocol/step_components/checklist.vue index 375fe9977..cf27761a5 100644 --- a/app/javascript/vue/protocol/step_components/checklist.vue +++ b/app/javascript/vue/protocol/step_components/checklist.vue @@ -26,6 +26,21 @@ +