mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-07 05:34:55 +08:00
Merge pull request #8600 from scinote-eln/features/link-steps-results
Features/link steps results
This commit is contained in:
commit
75fa364594
13 changed files with 100 additions and 58 deletions
|
@ -9,14 +9,14 @@ class StepResultsController < ApplicationController
|
|||
def link_results
|
||||
ActiveRecord::Base.transaction do
|
||||
@step_results.where.not(result: @results).each do |step_result|
|
||||
log_activity(:step_and_result_unlinked, @steps.first.my_module, step_result.step, step_result.result)
|
||||
log_activity(:step_and_result_unlinked, step_result.step.my_module, step_result.step, step_result.result)
|
||||
step_result.destroy!
|
||||
end
|
||||
@results.where.not(id: @step_results.select(:result_id)).each do |result|
|
||||
StepResult.create!(step: @steps.first, result: result, created_by: current_user)
|
||||
log_activity(:step_and_result_linked, @steps.first.my_module, @steps.first, result)
|
||||
end
|
||||
render json: { results: @steps.first.results.map { |r| { id: r.id, name: r.name } } }, status: :created
|
||||
render json: { results: @steps.first.results.map { |r| { id: r.id, name: r.name, archived: r.archived? } } }, status: :created
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
Rails.logger.error e.message
|
||||
render json: { message: :error }, status: :unprocessable_entity
|
||||
|
@ -27,7 +27,7 @@ class StepResultsController < ApplicationController
|
|||
def link_steps
|
||||
ActiveRecord::Base.transaction do
|
||||
@step_results.where.not(step: @steps).each do |step_result|
|
||||
log_activity(:step_and_result_unlinked, @steps.first.my_module, step_result.step, step_result.result)
|
||||
log_activity(:step_and_result_unlinked, step_result.result.my_module, step_result.step, step_result.result)
|
||||
step_result.destroy!
|
||||
end
|
||||
@steps.where.not(id: @step_results.select(:step_id)).each do |step|
|
||||
|
|
|
@ -102,7 +102,7 @@ module GlobalActivitiesHelper
|
|||
when Result
|
||||
return current_value unless obj.navigable?
|
||||
|
||||
path = obj.archived? ? archive_my_module_path(obj.my_module) : my_module_results_path(obj.my_module, result_id: obj.id)
|
||||
path = obj.archived? ? my_module_results_path(obj.my_module, result_id: obj.id, view_mode: :archived) : my_module_results_path(obj.my_module, result_id: obj.id)
|
||||
when Step
|
||||
return current_value unless obj.navigable?
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
<SelectDropdown
|
||||
:options="results"
|
||||
:value="selectedResults"
|
||||
:searchable="true"
|
||||
@change="changeResults"
|
||||
:multiple="true"
|
||||
:withCheckboxes="true"
|
||||
|
|
|
@ -83,12 +83,14 @@
|
|||
:data-object-type="step.attributes.type"
|
||||
tabindex="0"
|
||||
></span> <!-- Hidden element to support legacy code -->
|
||||
<button v-if="step.attributes.results.length == 0" class="btn btn-light icon-btn" @click="this.openLinkResultsModal = true">
|
||||
<i class="sn-icon sn-icon-results"></i>
|
||||
</button>
|
||||
<template v-if="step.attributes.results.length == 0">
|
||||
<button v-if="urls.update_url" :title="i18n.t('protocols.steps.link_results')" class="btn btn-light icon-btn" @click="this.openLinkResultsModal = true">
|
||||
<i class="sn-icon sn-icon-results"></i>
|
||||
</button>
|
||||
</template>
|
||||
<GeneralDropdown v-else ref="linkedResultsDropdown" position="right">
|
||||
<template v-slot:field>
|
||||
<button class="btn btn-light icon-btn">
|
||||
<button class="btn btn-light icon-btn" :title="i18n.t('protocols.steps.linked_results')">
|
||||
<i class="sn-icon sn-icon-results"></i>
|
||||
<span class="absolute top-1 right-1 h-4 min-w-4 bg-sn-science-blue text-white flex items-center justify-center rounded-full text-[10px]">
|
||||
{{ step.attributes.results.length }}
|
||||
|
@ -96,19 +98,23 @@
|
|||
</button>
|
||||
</template>
|
||||
<template v-slot:flyout>
|
||||
<a v-for="result in step.attributes.results"
|
||||
:key="result.id"
|
||||
:title="result.name"
|
||||
:href="resultUrl(result.id)"
|
||||
class="py-2.5 px-3 hover:bg-sn-super-light-grey cursor-pointer block hover:no-underline text-sn-blue truncate"
|
||||
>
|
||||
{{ result.name }}
|
||||
</a>
|
||||
<hr class="my-0">
|
||||
<div class="py-2.5 px-3 hover:bg-sn-super-light-grey cursor-pointer text-sn-blue"
|
||||
@click="this.openLinkResultsModal = true; $refs.linkedResultsDropdown.closeMenu()">
|
||||
{{ i18n.t('protocols.steps.manage_links') }}
|
||||
<div class="overflow-y-auto max-h-[calc(50vh_-_6rem)]">
|
||||
<a v-for="result in step.attributes.results"
|
||||
:key="result.id"
|
||||
:title="result.name"
|
||||
:href="resultUrl(result.id, result.archived)"
|
||||
class="py-2.5 px-3 hover:bg-sn-super-light-grey cursor-pointer block hover:no-underline text-sn-blue truncate"
|
||||
>
|
||||
{{ result.name }}
|
||||
</a>
|
||||
</div>
|
||||
<template v-if="urls.update_url">
|
||||
<hr class="my-0">
|
||||
<div class="py-2.5 px-3 hover:bg-sn-super-light-grey cursor-pointer text-sn-blue"
|
||||
@click="this.openLinkResultsModal = true; $refs.linkedResultsDropdown.closeMenu()">
|
||||
{{ i18n.t('protocols.steps.manage_links') }}
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</GeneralDropdown>
|
||||
<a href=" #"
|
||||
|
@ -800,8 +806,8 @@
|
|||
position: this.step.attributes.position
|
||||
})
|
||||
},
|
||||
resultUrl(result_id) {
|
||||
return my_module_results_path({my_module_id: this.step.attributes.my_module_id, result_id: result_id})
|
||||
resultUrl(result_id, archived) {
|
||||
return my_module_results_path({my_module_id: this.step.attributes.my_module_id, result_id: result_id, view_mode: (archived ? 'archived' : 'active') });
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
<SelectDropdown
|
||||
:options="steps"
|
||||
:value="selectedSteps"
|
||||
:searchable="true"
|
||||
@change="changeSteps"
|
||||
:multiple="true"
|
||||
:withCheckboxes="true"
|
||||
|
|
|
@ -65,32 +65,38 @@
|
|||
:data-object-type="result.attributes.type"
|
||||
tabindex="0"
|
||||
></span> <!-- Hidden element to support legacy code -->
|
||||
<button v-if="result.attributes.steps.length == 0" class="btn btn-light icon-btn" @click="this.openLinkStepsModal = true">
|
||||
{{ i18n.t('my_modules.results.link_to_step') }}
|
||||
</button>
|
||||
<tempplate v-if="result.attributes.steps.length == 0">
|
||||
<button v-if="urls.update_url" :title="i18n.t('my_modules.results.link_steps')" class="btn btn-light icon-btn" @click="this.openLinkStepsModal = true">
|
||||
{{ i18n.t('my_modules.results.link_to_step') }}
|
||||
</button>
|
||||
</tempplate>
|
||||
<GeneralDropdown v-else ref="linkedStepsDropdown" position="right">
|
||||
<template v-slot:field>
|
||||
<button class="btn btn-light icon-btn">
|
||||
{{ i18n.t('my_modules.results.link_to_step') }}
|
||||
<button class="btn btn-light icon-btn" :title="i18n.t('my_modules.results.linked_steps')">
|
||||
<i class="sn-icon sn-icon-steps"></i>
|
||||
<span class="absolute top-1 -right-1 h-4 min-w-4 bg-sn-science-blue text-white flex items-center justify-center rounded-full text-[10px]">
|
||||
{{ result.attributes.steps.length }}
|
||||
</span>
|
||||
</button>
|
||||
</template>
|
||||
<template v-slot:flyout>
|
||||
<a v-for="step in result.attributes.steps"
|
||||
:key="step.id"
|
||||
:title="step.name"
|
||||
:href="protocolUrl(step.id)"
|
||||
class="py-2.5 px-3 hover:bg-sn-super-light-grey cursor-pointer block hover:no-underline text-sn-blue truncate"
|
||||
>
|
||||
{{ step.name }}
|
||||
</a>
|
||||
<hr class="my-0">
|
||||
<div class="py-2.5 px-3 hover:bg-sn-super-light-grey cursor-pointer text-sn-blue"
|
||||
@click="this.openLinkStepsModal = true; $refs.linkedStepsDropdown.closeMenu()">
|
||||
{{ i18n.t('protocols.steps.manage_links') }}
|
||||
<div class="overflow-y-auto max-h-[calc(50vh_-_6rem)]">
|
||||
<a v-for="step in result.attributes.steps"
|
||||
:key="step.id"
|
||||
:title="step.name"
|
||||
:href="protocolUrl(step.id)"
|
||||
class="py-2.5 px-3 hover:bg-sn-super-light-grey cursor-pointer block hover:no-underline text-sn-blue truncate"
|
||||
>
|
||||
{{ step.name }}
|
||||
</a>
|
||||
</div>
|
||||
<template v-if="urls.update_url">
|
||||
<hr class="my-0">
|
||||
<div class="py-2.5 px-3 hover:bg-sn-super-light-grey cursor-pointer text-sn-blue"
|
||||
@click="this.openLinkStepsModal = true; $refs.linkedStepsDropdown.closeMenu()">
|
||||
{{ i18n.t('protocols.steps.manage_links') }}
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</GeneralDropdown>
|
||||
<a href="#"
|
||||
|
|
|
@ -225,7 +225,7 @@ export default {
|
|||
if (this.newValue.length === 0) {
|
||||
return false;
|
||||
}
|
||||
if (this.newValue.length === 1) {
|
||||
if (this.newValue.length === 1 && this.rawOptions.length > 1) {
|
||||
this.selectAllState = 'indeterminate';
|
||||
return this.renderLabel(this.rawOptions.find((option) => option[0] === this.newValue[0]));
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ class StepSerializer < ActiveModel::Serializer
|
|||
|
||||
def results
|
||||
object.results.map do |result|
|
||||
{ id: result.id, name: result.name }
|
||||
{ id: result.id, name: result.name, archived: result.archived? }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
<span class="<%=result_icon_class(subject)%>"></span>
|
||||
<% if subject&.navigable? %>
|
||||
<% path = subject.archived? ? archive_my_module_path(subject.my_module) : my_module_results_path(subject.my_module) %>
|
||||
<% path = subject.archived? ? my_module_results_path(subject.my_module, result_id: subject.id, view_mode: :archived) : my_module_results_path(subject.my_module, result_id: subject.id) %>
|
||||
<%= route_to_other_team(path,
|
||||
team,
|
||||
subject.name&.truncate(Constants::NAME_TRUNCATION_LENGTH),
|
||||
|
|
|
@ -710,7 +710,7 @@ class Extends
|
|||
^CF0,15
|
||||
^FO0,5^FD{{ITEM_ID}}^FS
|
||||
^FO0,13^BQN,2,3^FDMA,{{ITEM_ID}}^FS
|
||||
^FO70,27^FB100,2,0,L^FD{{NAME}}^FS^FS
|
||||
^FO70,27^FB100,4,0,L^FD{{NAME}}^FS^FS
|
||||
^XZ
|
||||
HEREDOC
|
||||
}
|
||||
|
|
|
@ -1644,10 +1644,12 @@ en:
|
|||
comments_tab: "Comments"
|
||||
comment_title: "%{user} at %{time}:"
|
||||
link_to_step: "Link to step"
|
||||
link_steps: "Link steps to this result"
|
||||
linked_steps: "Linked steps"
|
||||
modals:
|
||||
link_steps:
|
||||
title: 'Link result to protocol steps'
|
||||
description: 'You can link result to multipple steps'
|
||||
description: 'You can link a result to multiple steps.'
|
||||
empty_description: 'No step found. Add a step first to enable linking with a result.'
|
||||
steps_label: 'Protocol steps'
|
||||
placeholder: 'Select steps'
|
||||
|
@ -4055,6 +4057,8 @@ en:
|
|||
timestamp: "Created on %{date} by %{user}"
|
||||
timestamp_iso_html: "Created on <span class='iso-formatted-date'>%{date}</span> by %{user}"
|
||||
manage_links: "Manage links"
|
||||
link_results: "Link results to this step"
|
||||
linked_results: "Linked results"
|
||||
status:
|
||||
complete: "Mark as done"
|
||||
uncomplete: "Unmark as done"
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
class FixDefault201dpiLabelTemplates < ActiveRecord::Migration[7.0]
|
||||
class TempLabelTemplate < ApplicationRecord
|
||||
self.table_name = 'label_templates'
|
||||
end
|
||||
|
||||
def up
|
||||
TempLabelTemplate.where(
|
||||
content: "^XA\n^MTT\n^MUD,200,200\n^PR2\n^MD30\n^LH0,8\n^PW180\n^CF0,15\n^FO0,5^FD{{ITEM_ID}}^FS\n^FO0,13^BQN,2,3^FDMA,{{ITEM_ID}}^FS\n^FO70,27^FB100,2,0,L^FD{{NAME}}^FS^FS\n^XZ\n"
|
||||
).update!(
|
||||
content: "^XA\n^MTT\n^MUD,200,200\n^PR2\n^MD30\n^LH0,8\n^PW180\n^CF0,15\n^FO0,5^FD{{ITEM_ID}}^FS\n^FO0,13^BQN,2,3^FDMA,{{ITEM_ID}}^FS\n^FO70,27^FB100,4,0,L^FD{{NAME}}^FS^FS\n^XZ\n"
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
TempLabelTemplate.where(
|
||||
content: "^XA\n^MTT\n^MUD,200,200\n^PR2\n^MD30\n^LH0,8\n^PW180\n^CF0,15\n^FO0,5^FD{{ITEM_ID}}^FS\n^FO0,13^BQN,2,3^FDMA,{{ITEM_ID}}^FS\n^FO70,27^FB100,4,0,L^FD{{NAME}}^FS^FS\n^XZ\n"
|
||||
).update!(
|
||||
content: "^XA\n^MTT\n^MUD,200,200\n^PR2\n^MD30\n^LH0,8\n^PW180\n^CF0,15\n^FO0,5^FD{{ITEM_ID}}^FS\n^FO0,13^BQN,2,3^FDMA,{{ITEM_ID}}^FS\n^FO70,27^FB100,2,0,L^FD{{NAME}}^FS^FS\n^XZ\n"
|
||||
)
|
||||
end
|
||||
end
|
|
@ -15,12 +15,12 @@ describe StepResultsController, type: :controller do
|
|||
let(:result_second) { create :result, my_module: my_modules.first, user: user }
|
||||
let(:step_result) { create :step_result, step: step_second, result: result_second }
|
||||
|
||||
describe 'POST create link step result succesfully' do
|
||||
let(:action) { post :create, params: params }
|
||||
describe 'POST create link result succesfully' do
|
||||
let(:action) { post :link_results, params: params }
|
||||
let(:params) do
|
||||
{
|
||||
step_id: step.id,
|
||||
result_id: result_text.result.id
|
||||
step_ids:[step.id],
|
||||
result_ids: [result_text.result.id]
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -30,22 +30,24 @@ describe StepResultsController, type: :controller do
|
|||
end
|
||||
|
||||
it 'calls create activity service' do
|
||||
params[:step_id] = step_second.id
|
||||
params[:step_ids] = [step_second.id]
|
||||
action
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE destroy' do
|
||||
let(:action) { delete :destroy, params: params, format: :json }
|
||||
describe 'POST create link step succesfully' do
|
||||
let(:action) { delete :link_steps, params: params, format: :json }
|
||||
let(:params) do
|
||||
{
|
||||
step_ids:[step.id],
|
||||
result_ids: [result_text.result.id]
|
||||
}
|
||||
end
|
||||
|
||||
context 'when in protocol repository' do
|
||||
let(:params) { { id: step_result.id } }
|
||||
|
||||
it 'calls create activity for deleting step in protocol repository' do
|
||||
action
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
it 'calls create activity service' do
|
||||
action
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue