mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-10-06 11:57:16 +08:00
Add some basic result component layout [SCI-8959]
This commit is contained in:
parent
c1cfb80de4
commit
23a8872e11
6 changed files with 146 additions and 86 deletions
|
@ -1,10 +1,10 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ResultsController < ApplicationController
|
class ResultsController < ApplicationController
|
||||||
skip_before_action :verify_authenticity_token, only: %i(create destroy)
|
skip_before_action :verify_authenticity_token, only: %i(create update destroy)
|
||||||
|
|
||||||
before_action :load_my_module
|
before_action :load_my_module
|
||||||
before_action :load_vars, only: %i(destroy elements assets upload_attachment update_view_state update_asset_view_mode )
|
before_action :load_vars, only: %i(destroy elements assets upload_attachment update_view_state update_asset_view_mode update)
|
||||||
before_action :check_destroy_permissions, only: :destroy
|
before_action :check_destroy_permissions, only: :destroy
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
@ -32,6 +32,12 @@ class ResultsController < ApplicationController
|
||||||
render json: result
|
render json: result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@result.update!(result_params)
|
||||||
|
|
||||||
|
render json: @result
|
||||||
|
end
|
||||||
|
|
||||||
def elements
|
def elements
|
||||||
render json: @result.result_orderable_elements.order(:position),
|
render json: @result.result_orderable_elements.order(:position),
|
||||||
each_serializer: ResultOrderableElementSerializer,
|
each_serializer: ResultOrderableElementSerializer,
|
||||||
|
@ -107,6 +113,10 @@ class ResultsController < ApplicationController
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def result_params
|
||||||
|
params.require(:result).permit(:name)
|
||||||
|
end
|
||||||
|
|
||||||
def apply_sort(results)
|
def apply_sort(results)
|
||||||
case params[:sort]
|
case params[:sort]
|
||||||
when 'updated_at_asc'
|
when 'updated_at_asc'
|
||||||
|
|
|
@ -1,85 +1,123 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="result-wrapper">
|
<div class="result-wrapper bg-white">
|
||||||
{{ result.id }}
|
<div class="result-header flex justify-between p-3">
|
||||||
{{ result.attributes.name }}
|
<div class="result-head-left">
|
||||||
<button @click="openReorderModal">
|
<InlineEdit
|
||||||
Open Rearrange Modal
|
:value="result.attributes.name"
|
||||||
</button>
|
:class="{ 'result-element--locked': !urls.update_url }"
|
||||||
<div class="inline-block">
|
:characterLimit="255"
|
||||||
<input type="file" class="hidden" ref="fileSelector" @change="loadFromComputer" multiple />
|
:allowBlank="false"
|
||||||
<div ref="elementsDropdownButton" v-if="urls.update_url" class="dropdown">
|
:attributeName="`${i18n.t('Result')} ${i18n.t('name')}`"
|
||||||
<button class="btn btn-light dropdown-toggle insert-button" type="button" :id="'resultInsertMenu_' + result.id" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
:autofocus="editingName"
|
||||||
{{ i18n.t('protocols.steps.insert.button') }}
|
:placeholder="i18n.t('my_modules.results.placeholder')"
|
||||||
<span class="sn-icon sn-icon-down"></span>
|
:defaultValue="i18n.t('my_modules.results.default_name')"
|
||||||
</button>
|
@editingEnabled="editingName = true"
|
||||||
<ul ref="elementsDropdown" class="dropdown-menu insert-element-dropdown dropdown-menu-right" :aria-labelledby="'resultInsertMenu_' + result.id">
|
@editingDisabled="editingName = false"
|
||||||
<li class="title">
|
:editOnload="result.newResult == true"
|
||||||
{{ i18n.t('protocols.steps.insert.title') }}
|
@update="updateName"
|
||||||
</li>
|
/>
|
||||||
<li class="action" @click="createElement('table')">
|
|
||||||
<i class="sn-icon sn-icon-tables"></i>
|
|
||||||
{{ i18n.t('protocols.steps.insert.table') }}
|
|
||||||
</li>
|
|
||||||
<li class="action dropdown-submenu-item">
|
|
||||||
<i class="sn-icon sn-icon-tables"></i>
|
|
||||||
{{ i18n.t('protocols.steps.insert.well_plate') }}
|
|
||||||
<span class="caret"></span>
|
|
||||||
|
|
||||||
<ul class="dropdown-submenu">
|
|
||||||
<li v-for="option in wellPlateOptions" :key="option.dimensions.toString()" class="action" @click="createElement('table', option.dimensions, true)">
|
|
||||||
{{ i18n.t(option.label) }}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li class="action" @click="createElement('text')">
|
|
||||||
<i class="sn-icon sn-icon-result-text"></i>
|
|
||||||
{{ i18n.t('protocols.steps.insert.text') }}
|
|
||||||
</li>
|
|
||||||
<li class="action dropdown-submenu-item">
|
|
||||||
<i class="sn-icon sn-icon-files"></i>
|
|
||||||
{{ i18n.t('protocols.steps.insert.attachment') }}
|
|
||||||
<span class="caret"></span>
|
|
||||||
<ul class="dropdown-submenu">
|
|
||||||
<li class="action" @click="openLoadFromComputer">
|
|
||||||
{{ i18n.t('protocols.steps.insert.add_file') }}
|
|
||||||
</li>
|
|
||||||
<li class="action" v-if="result.attributes.wopi_enabled" @click="openWopiFileModal">
|
|
||||||
{{ i18n.t('assets.create_wopi_file.button_text') }}
|
|
||||||
</li>
|
|
||||||
<li class="action" v-if="result.attributes.marvinjs_enabled" @click="openMarvinJsModal($refs.marvinJsButton)">
|
|
||||||
<span
|
|
||||||
class="new-marvinjs-upload-button text-sn-black text-decoration-none"
|
|
||||||
:data-object-id="result.id"
|
|
||||||
ref="marvinJsButton"
|
|
||||||
:data-marvin-url="result.attributes.marvinjs_context.marvin_js_asset_url"
|
|
||||||
:data-object-type="result.attributes.type"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
{{ i18n.t('marvinjs.new_button') }}
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
<div ref="actionsDropdownButton" class="dropdown">
|
<div class="result-head-right flex">
|
||||||
<button class="btn btn-light icon-btn dropdown-toggle insert-button" type="button" :id="'resultOptionsMenu_' + result.id" data-toggle="dropdown" data-display="static" aria-haspopup="true" aria-expanded="true">
|
<input type="file" class="hidden" ref="fileSelector" @change="loadFromComputer" multiple />
|
||||||
<i class="sn-icon sn-icon-more-hori"></i>
|
<div ref="elementsDropdownButton" v-if="urls.update_url" class="dropdown">
|
||||||
</button>
|
<button class="btn btn-light dropdown-toggle insert-button" type="button" :id="'resultInsertMenu_' + result.id" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||||
<ul ref="actionsDropdown" class="dropdown-menu dropdown-menu-right insert-element-dropdown" :aria-labelledby="'resultOptionsMenu_' + result.id">
|
{{ i18n.t('protocols.steps.insert.button') }}
|
||||||
<li class="action" @click="openReorderModal">
|
<span class="sn-icon sn-icon-down"></span>
|
||||||
{{ i18n.t('my_modules.results.actions.rearrange') }}
|
</button>
|
||||||
</li>
|
<ul ref="elementsDropdown" class="dropdown-menu insert-element-dropdown dropdown-menu-right" :aria-labelledby="'resultInsertMenu_' + result.id">
|
||||||
<li class="action" @click="duplicateResult">
|
<li class="title">
|
||||||
{{ i18n.t('my_modules.results.actions.duplicate') }}
|
<a>
|
||||||
</li>
|
{{ i18n.t('protocols.steps.insert.title') }}
|
||||||
<li class="action" @click="archiveResult">
|
</a>
|
||||||
{{ i18n.t('my_modules.results.actions.archive') }}
|
</li>
|
||||||
</li>
|
<li class="action" @click="createElement('table')">
|
||||||
</ul>
|
<a class="cursor-pointer">
|
||||||
|
<i class="sn-icon sn-icon-tables"></i>
|
||||||
|
{{ i18n.t('protocols.steps.insert.table') }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="action dropdown-submenu-item">
|
||||||
|
<a class="cursor-pointer">
|
||||||
|
<i class="sn-icon sn-icon-tables"></i>
|
||||||
|
{{ i18n.t('protocols.steps.insert.well_plate') }}
|
||||||
|
</a>
|
||||||
|
<span class="caret"></span>
|
||||||
|
|
||||||
|
<ul class="dropdown-submenu">
|
||||||
|
<li v-for="option in wellPlateOptions" :key="option.dimensions.toString()" class="action" @click="createElement('table', option.dimensions, true)">
|
||||||
|
<a class="cursor-pointer">
|
||||||
|
{{ i18n.t(option.label) }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="action" @click="createElement('text')">
|
||||||
|
<a class="cursor-pointer">
|
||||||
|
<i class="sn-icon sn-icon-result-text"></i>
|
||||||
|
{{ i18n.t('protocols.steps.insert.text') }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="action dropdown-submenu-item">
|
||||||
|
<a class="cursor-pointer">
|
||||||
|
<i class="sn-icon sn-icon-files"></i>
|
||||||
|
{{ i18n.t('protocols.steps.insert.attachment') }}
|
||||||
|
</a>
|
||||||
|
<span class="caret"></span>
|
||||||
|
<ul class="dropdown-submenu">
|
||||||
|
<li class="action" @click="openLoadFromComputer">
|
||||||
|
<a class="cursor-pointer">
|
||||||
|
{{ i18n.t('protocols.steps.insert.add_file') }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="action" v-if="result.attributes.wopi_enabled" @click="openWopiFileModal">
|
||||||
|
<a class="cursor-pointer">
|
||||||
|
{{ i18n.t('assets.create_wopi_file.button_text') }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="action" v-if="result.attributes.marvinjs_enabled" @click="openMarvinJsModal($refs.marvinJsButton)">
|
||||||
|
<a class="cursor-point er">
|
||||||
|
<span
|
||||||
|
class="new-marvinjs-upload-button text-sn-black text-decoration-none"
|
||||||
|
:data-object-id="result.id"
|
||||||
|
ref="marvinJsButton"
|
||||||
|
:data-marvin-url="result.attributes.marvinjs_context.marvin_js_asset_url"
|
||||||
|
:data-object-type="result.attributes.type"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
{{ i18n.t('marvinjs.new_button') }}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<a href="#"
|
||||||
|
ref="comments"
|
||||||
|
class="open-comments-sidebar btn icon-btn btn-light"
|
||||||
|
data-turbolinks="false"
|
||||||
|
data-object-type="Result"
|
||||||
|
:data-object-id="result.id">
|
||||||
|
<i class="sn-icon sn-icon-comments"></i>
|
||||||
|
</a>
|
||||||
|
<div ref="actionsDropdownButton" class="dropdown">
|
||||||
|
<button class="btn btn-light icon-btn dropdown-toggle insert-button" type="button" :id="'resultOptionsMenu_' + result.id" data-toggle="dropdown" data-display="static" aria-haspopup="true" aria-expanded="true">
|
||||||
|
<i class="sn-icon sn-icon-more-hori"></i>
|
||||||
|
</button>
|
||||||
|
<ul ref="actionsDropdown" class="dropdown-menu dropdown-menu-right insert-element-dropdown" :aria-labelledby="'resultOptionsMenu_' + result.id">
|
||||||
|
<li class="action" @click="openReorderModal">
|
||||||
|
<a class="cursor-pointer">{{ i18n.t('my_modules.results.actions.rearrange') }}</a>
|
||||||
|
</li>
|
||||||
|
<li class="action" @click="duplicateResult">
|
||||||
|
<a class="cursor-pointer">{{ i18n.t('my_modules.results.actions.duplicate') }}</a>
|
||||||
|
</li>
|
||||||
|
<li class="action" @click="archiveResult">
|
||||||
|
<a class="cursor-pointer">{{ i18n.t('my_modules.results.actions.archive') }}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
|
||||||
<ReorderableItemsModal v-if="reordering"
|
<ReorderableItemsModal v-if="reordering"
|
||||||
title="Placeholder title for this modal"
|
title="Placeholder title for this modal"
|
||||||
:items="reorderableElements"
|
:items="reorderableElements"
|
||||||
|
@ -113,6 +151,7 @@
|
||||||
@attachments:viewMode="changeAttachmentsViewMode"
|
@attachments:viewMode="changeAttachmentsViewMode"
|
||||||
@attachment:viewMode="updateAttachmentViewMode"/>
|
@attachment:viewMode="updateAttachmentViewMode"/>
|
||||||
</div>
|
</div>
|
||||||
|
<hr>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -122,6 +161,7 @@
|
||||||
import ResultTable from '../shared/content/table.vue';
|
import ResultTable from '../shared/content/table.vue';
|
||||||
import ResultText from '../shared/content/text.vue';
|
import ResultText from '../shared/content/text.vue';
|
||||||
import Attachments from '../shared/content/attachments.vue';
|
import Attachments from '../shared/content/attachments.vue';
|
||||||
|
import InlineEdit from '../shared/inline_edit.vue'
|
||||||
|
|
||||||
import AttachmentsMixin from '../shared/content/mixins/attachments.js'
|
import AttachmentsMixin from '../shared/content/mixins/attachments.js'
|
||||||
import WopiFileModal from '../shared/content/attachments/mixins/wopi_file_modal.js'
|
import WopiFileModal from '../shared/content/attachments/mixins/wopi_file_modal.js'
|
||||||
|
@ -146,7 +186,8 @@
|
||||||
{ label: 'protocols.steps.insert.well_plate_options.6_x_8', dimensions: [6, 8] },
|
{ label: 'protocols.steps.insert.well_plate_options.6_x_8', dimensions: [6, 8] },
|
||||||
{ label: 'protocols.steps.insert.well_plate_options.6_x_4', dimensions: [6, 4] },
|
{ label: 'protocols.steps.insert.well_plate_options.6_x_4', dimensions: [6, 4] },
|
||||||
{ label: 'protocols.steps.insert.well_plate_options.2_x_3', dimensions: [2, 3] }
|
{ label: 'protocols.steps.insert.well_plate_options.2_x_3', dimensions: [2, 3] }
|
||||||
]
|
],
|
||||||
|
editingName: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mixins: [UtilsMixin, AttachmentsMixin, WopiFileModal],
|
mixins: [UtilsMixin, AttachmentsMixin, WopiFileModal],
|
||||||
|
@ -154,7 +195,8 @@
|
||||||
ReorderableItemsModal,
|
ReorderableItemsModal,
|
||||||
ResultTable,
|
ResultTable,
|
||||||
ResultText,
|
ResultText,
|
||||||
Attachments
|
Attachments,
|
||||||
|
InlineEdit
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
reorderableElements() {
|
reorderableElements() {
|
||||||
|
@ -278,7 +320,7 @@
|
||||||
$.post(this.urls[`create_${elementType}_url`], { tableDimensions: tableDimensions, plateTemplate: plateTemplate }, (result) => {
|
$.post(this.urls[`create_${elementType}_url`], { tableDimensions: tableDimensions, plateTemplate: plateTemplate }, (result) => {
|
||||||
result.data.isNew = true;
|
result.data.isNew = true;
|
||||||
this.elements.push(result.data)
|
this.elements.push(result.data)
|
||||||
this.$emit('stepUpdated')
|
this.$emit('resultUpdated')
|
||||||
}).fail(() => {
|
}).fail(() => {
|
||||||
HelperModule.flashAlertMsg(this.i18n.t('errors.general'), 'danger');
|
HelperModule.flashAlertMsg(this.i18n.t('errors.general'), 'danger');
|
||||||
}).done(() => {
|
}).done(() => {
|
||||||
|
@ -298,6 +340,11 @@
|
||||||
},
|
},
|
||||||
duplicateResult() {
|
duplicateResult() {
|
||||||
|
|
||||||
|
},
|
||||||
|
updateName(name) {
|
||||||
|
axios.patch(this.urls.update_url, { result: { name: name } }, (_) => {
|
||||||
|
this.$emit('resultUpdated')
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="results-wrapper">
|
<div class="results-wrapper">
|
||||||
<ResultsToolbar :sort="sort" @setSort="setSort" @newResult="createResult" @expandAll="expandAll" @collapseAll="collapseAll" lass="mb-3" />
|
<ResultsToolbar :sort="sort" @setSort="setSort" @newResult="createResult" @expandAll="expandAll" @collapseAll="collapseAll" class="mb-3" />
|
||||||
<div class="results-list">
|
<div class="results-list">
|
||||||
<Result v-for="result in results" :key="result.id" :result="result" />
|
<Result v-for="result in results" :key="result.id" :result="result" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -28,7 +28,6 @@ class ResultSerializer < ActiveModel::Serializer
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def updated_at
|
def updated_at
|
||||||
object.updated_at.to_i
|
object.updated_at.to_i
|
||||||
end
|
end
|
||||||
|
@ -74,7 +73,7 @@ class ResultSerializer < ActiveModel::Serializer
|
||||||
if can_manage_result?(object)
|
if can_manage_result?(object)
|
||||||
urls_list.merge!({
|
urls_list.merge!({
|
||||||
delete_url: result_path(object),
|
delete_url: result_path(object),
|
||||||
update_url: result_path(object),
|
update_url: my_module_result_path(object.my_module, object),
|
||||||
create_table_url: my_module_result_tables_path(object.my_module, object),
|
create_table_url: my_module_result_tables_path(object.my_module, object),
|
||||||
create_text_url: my_module_result_texts_path(object.my_module, object),
|
create_text_url: my_module_result_texts_path(object.my_module, object),
|
||||||
update_asset_view_mode_url: update_asset_view_mode_my_module_result_path(object.my_module, object),
|
update_asset_view_mode_url: update_asset_view_mode_my_module_result_path(object.my_module, object),
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
<%= render partial: 'assets/wopi/create_wopi_file_modal' %>
|
<%= render partial: 'assets/wopi/create_wopi_file_modal' %>
|
||||||
<% provide(:container_class, 'no-second-nav-container') %>
|
<% provide(:container_class, 'no-second-nav-container') %>
|
||||||
|
|
||||||
|
<%= render partial: 'my_modules/header_actions' %>
|
||||||
|
|
||||||
<div id="results" data-behaviour="vue">
|
<div id="results" data-behaviour="vue">
|
||||||
<results url="<%= my_module_results_url(@my_module) %>">
|
<results url="<%= my_module_results_url(@my_module) %>">
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1240,6 +1240,8 @@ en:
|
||||||
load_from_file_protocol_general_error: "Failed to load the protocol from file. It is likely that certain fields (protocol and individual step titles and names) contain too many or too few characters.(max is %{max} and min is %{min})"
|
load_from_file_protocol_general_error: "Failed to load the protocol from file. It is likely that certain fields (protocol and individual step titles and names) contain too many or too few characters.(max is %{max} and min is %{min})"
|
||||||
results:
|
results:
|
||||||
head_title: "%{project} | %{module} | Results"
|
head_title: "%{project} | %{module} | Results"
|
||||||
|
default_name: "New result"
|
||||||
|
placeholder: "Enter result name"
|
||||||
add_label: "New result"
|
add_label: "New result"
|
||||||
new_text_result: "Text"
|
new_text_result: "Text"
|
||||||
new_table_result: "Table"
|
new_table_result: "Table"
|
||||||
|
|
Loading…
Add table
Reference in a new issue