Merge pull request #6152 from aignatov-bio/ai-sci-9223-add-archive-mode-for-results

Add archive view to results [SCI-9223]
This commit is contained in:
aignatov-bio 2023-09-06 15:31:15 +02:00 committed by GitHub
commit 38e62c9835
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 116 additions and 85 deletions

View file

@ -27,7 +27,7 @@
max-width: 100%;
}
.content__text-body:hover:not(.edit):not(.locked) {
.content__text-body:hover:not(.edit):not(.component__element--locked) {
background: $color-concrete;
}
}

View file

@ -4,7 +4,7 @@ class ResultsController < ApplicationController
include Breadcrumbs
skip_before_action :verify_authenticity_token, only: %i(create update destroy duplicate)
before_action :load_my_module
before_action :load_vars, only: %i(destroy elements assets upload_attachment
before_action :load_vars, only: %i(destroy elements assets upload_attachment archive restore destroy
update_view_state update_asset_view_mode update duplicate)
before_action :check_destroy_permissions, only: :destroy
before_action :set_breadcrumbs_items, only: %i(index)
@ -14,7 +14,11 @@ class ResultsController < ApplicationController
respond_to do |format|
format.json do
# API endpoint
@results = @my_module.results.active
@results = if params[:view_mode] == 'archived'
@my_module.results.archived
else
@my_module.results.active
end
apply_sort!
apply_filters!
@ -56,23 +60,18 @@ class ResultsController < ApplicationController
end
def archive
result = @my_module.results.find(params[:result_id])
result.archive(current_user)
if @result.archive(current_user)
render json: {}, status: :ok
else
render json: { errors: @result.errors.full_messages }, status: :unprocessable_entity
end
end
if result.save
Activities::CreateActivityService
.call(activity_type: :destroy_result,
owner: current_user,
subject: result,
team: @my_module.team,
project: @my_module.project,
message_items: { result: result.id })
flash[:success] = t('my_modules.module_archive.archive_flash',
result: result.name,
module: @my_module.name)
redirect_to my_module_results_path(@my_module)
def restore
if @result.restore(current_user)
render json: {}, status: :ok
else
render json: { errors: @result.errors.full_messages }, status: :unprocessable_entity
end
end
@ -126,26 +125,11 @@ class ResultsController < ApplicationController
end
def destroy
result_type = if @result.is_text
t('activities.result_type.text')
elsif @result.is_table
t('activities.result_type.table')
elsif @result.is_asset
t('activities.result_type.asset')
end
Activities::CreateActivityService
.call(activity_type: :destroy_result,
owner: current_user,
subject: @result,
team: @my_module.team,
project: @my_module.project,
message_items: { result: @result.id,
type_of_result: result_type })
flash[:success] = t('my_modules.module_archive.delete_flash',
result: @result.name,
module: @my_module.name)
@result.destroy
redirect_to archive_my_module_path(@my_module)
if @result.destroy
render json: {}, status: :ok
else
render json: { errors: @result.errors.full_messages }, status: :unprocessable_entity
end
end
def duplicate

View file

@ -41,7 +41,7 @@ module SecondaryNavigationHelper
end
def is_module_results?
%w(index).include?(action_name) && controller_name == 'results'
%w(index).include?(action_name) && controller_name == 'results' && !%w(archived).include?(params[:view_mode])
end
def is_module_activities?
@ -49,7 +49,7 @@ module SecondaryNavigationHelper
end
def is_module_archive?
action_name == 'archive'
%w(index).include?(action_name) && controller_name == 'results' && %w(archived).include?(params[:view_mode])
end
def title_element

View file

@ -4,7 +4,7 @@
<div class="result-head-left">
<InlineEdit
:value="result.attributes.name"
:class="{ 'result-element--locked': !urls.update_url }"
:class="{ 'pointer-events-none': !urls.update_url }"
:characterLimit="255"
:allowBlank="false"
:attributeName="`${i18n.t('Result')} ${i18n.t('name')}`"
@ -87,15 +87,21 @@
<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.attributes.id">
<li class="action" @click="openReorderModal">
<li class="action" @click="openReorderModal" v-if="urls.reorder_elements_url">
{{ i18n.t('my_modules.results.actions.rearrange') }}
</li>
<li class="action" @click="duplicateResult">
<li class="action" @click="duplicateResult" v-if="urls.duplicate_url && !result.attributes.archived">
{{ i18n.t('my_modules.results.actions.duplicate') }}
</li>
<li class="action" @click="archiveResult">
<li class="action" @click="archiveResult" v-if="urls.archive_url">
{{ i18n.t('my_modules.results.actions.archive') }}
</li>
<li class="action" @click="restoreResult" v-if="urls.restore_url">
{{ i18n.t('my_modules.results.actions.restore') }}
</li>
<li class="action" @click="deleteResult" v-if="urls.delete_url">
{{ i18n.t('my_modules.results.actions.delete') }}
</li>
</ul>
</div>
</div>
@ -334,16 +340,23 @@
});
},
archiveResult() {
if (this.urls.archive_url) {
axios.post(this.urls.archive_url).then((response) => {
this.$emit('resultArchived', response.data);
location.reload();
});
}
axios.post(this.urls.archive_url).then((response) => {
this.$emit('result:archived', this.result.attributes.id);
});
},
restoreResult() {
axios.post(this.urls.restore_url).then((response) => {
this.$emit('result:restored', this.result.attributes.id);
});
},
deleteResult() {
axios.delete(this.urls.delete_url).then((response) => {
this.$emit('result:deleted', this.result.attributes.id);
});
},
duplicateResult() {
axios.post(this.urls.duplicate_url).then((_) => {
this.$emit('duplicated');
this.$emit('result:duplicated');
});
},
moveElement(position, target_id) {

View file

@ -1,6 +1,7 @@
<template>
<div class="results-wrapper">
<ResultsToolbar :sort="sort"
:canCreate="canCreate == 'true'"
@setSort="setSort"
@setFilters="setFilters"
@newResult="createResult"
@ -16,7 +17,10 @@
@result:move_element="reloadResult"
@result:attachments:loaded="resultToReload = null"
@result:move_attachment="reloadResult"
@duplicated="resetPageAndReload"
@result:duplicated="resetPageAndReload"
@result:archived="removeResult"
@result:deleted="removeResult"
@result:restored="removeResult"
/>
</div>
</div>
@ -31,7 +35,8 @@
name: 'Results',
components: { ResultsToolbar, Result },
props: {
url: { type: String, required: true }
url: { type: String, required: true },
canCreate: { type: String, required: true }
},
data() {
return {
@ -114,6 +119,9 @@
},
collapseAll() {
$('.result-wrapper .collapse').collapse('hide')
},
removeResult(result_id) {
this.results = this.results.filter((r) => r.attributes.id != result_id);
}
}
}

View file

@ -1,7 +1,7 @@
<template>
<div class="result-toolbar p-3 flex justify-between rounded-md bg-sn-white">
<div class="result-toolbar__left">
<button class="btn btn-secondary" @click="$emit('newResult')">
<button v-if="canCreate" class="btn btn-secondary" @click="$emit('newResult')">
<i class="sn-icon sn-icon-new-task"></i>
{{ i18n.t('my_modules.results.add_label') }}
</button>
@ -48,6 +48,7 @@
name: 'ResultsToolbar',
props: {
sort: { type: String, required: true },
canCreate: { type: Boolean, required: true }
},
data() {
return {

View file

@ -7,7 +7,7 @@
@click="$emit('reorder')">
<i class="sn-icon sn-icon-sort"></i>
</div>
<div class="grow-1 text-ellipsis whitespace-nowrap grow my-1 font-bold">
<div class="grow-1 text-ellipsis whitespace-nowrap grow my-1 font-bold" :class="{ 'pointer-events-none': locked } ">
<InlineEdit
:value="element.attributes.orderable.name"
:sa_value="element.attributes.orderable.sa_name"

View file

@ -9,7 +9,8 @@
</div>
<div v-if="!locked || element.attributes.orderable.name" :key="reloadHeader"
class="grow-1 text-ellipsis whitespace-nowrap grow my-1 font-bold">
class="grow-1 text-ellipsis whitespace-nowrap grow my-1 font-bold"
:class="{'pointer-events-none': locked}">
<InlineEdit
:value="element.attributes.orderable.name"
:characterLimit="255"

View file

@ -9,7 +9,9 @@
</div>
<div v-if="element.attributes.orderable.urls.update_url || element.attributes.orderable.name"
class="grow-1 text-ellipsis whitespace-nowrap grow my-1 font-bold">
class="grow-1 text-ellipsis whitespace-nowrap grow my-1 font-bold"
:class="{'pointer-events-none': !element.attributes.orderable.urls.update_url}"
>
<InlineEdit
:value="element.attributes.orderable.name"
:characterLimit="255"

View file

@ -11,6 +11,12 @@ Canaid::Permissions.register_for(Result) do
result.my_module.permission_granted?(user, MyModulePermissions::RESULTS_MANAGE)
end
can :restore_result do |user, result|
result.archived? &&
!result.my_module.archived_branch? &&
result.my_module.permission_granted?(user, MyModulePermissions::RESULTS_MANAGE)
end
can :delete_result do |user, result|
result.archived? &&
result.unlocked?(result) &&

View file

@ -8,8 +8,8 @@ class ResultSerializer < ActiveModel::Serializer
include InputSanitizeHelper
attributes :name, :id, :urls, :updated_at, :created_at_formatted, :updated_at_formatted, :user,
:my_module_id, :attachments_manageble, :marvinjs_enabled, :type, :marvinjs_context,
:wopi_enabled, :wopi_context, :created_at, :created_by
:my_module_id, :attachments_manageble, :marvinjs_enabled, :marvinjs_context, :type,
:wopi_enabled, :wopi_context, :created_at, :created_by, :archived
def marvinjs_enabled
MarvinJsService.enabled?
@ -19,6 +19,18 @@ class ResultSerializer < ActiveModel::Serializer
'Result'
end
def name
if archived
"(A) #{object.name}"
else
object.name
end
end
def archived
object.archived?
end
def current_user
scope
end
@ -76,21 +88,26 @@ class ResultSerializer < ActiveModel::Serializer
if can_manage_result?(object)
urls_list.merge!({
delete_url: result_path(object),
archive_url: my_module_result_archive_path(object.my_module, object),
update_url: my_module_result_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),
update_asset_view_mode_url: update_asset_view_mode_my_module_result_path(object.my_module, object),
update_view_state_url: update_view_state_my_module_result_path(object.my_module, object),
direct_upload_url: rails_direct_uploads_url,
upload_attachment_url: upload_attachment_my_module_result_path(object.my_module, object),
reorder_elements_url: reorder_result_result_orderable_elements_path(result_id: object.id)
})
archive_url: archive_my_module_result_path(object.my_module, object),
update_url: my_module_result_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),
update_asset_view_mode_url: update_asset_view_mode_my_module_result_path(object.my_module,
object),
update_view_state_url: update_view_state_my_module_result_path(object.my_module, object),
direct_upload_url: rails_direct_uploads_url,
upload_attachment_url: upload_attachment_my_module_result_path(object.my_module, object),
reorder_elements_url: reorder_my_module_result_result_orderable_elements_path(
object.my_module, object
)
})
end
urls_list[:restore_url] = restore_my_module_result_path(object.my_module, object) if can_restore_result?(object)
urls_list[:delete_url] = my_module_result_path(object.my_module, object) if can_delete_result?(object)
if can_create_results?(object.my_module)
urls_list[:duplicate_url] = duplicate_my_module_result_url(object.my_module, object)
urls_list[:duplicate_url] =
duplicate_my_module_result_url(object.my_module, object)
end
urls_list

View file

@ -28,7 +28,7 @@
<div data-hook="secondary-navigation-tabs"></div>
<% if can_read_experiment?(@my_module.experiment) && !@my_module.archived_branch? %>
<a class="p-3 border-b-4 border-transparent hover:no-underline uppercase text-bold capitalize <%= is_module_archive? ? "text-sn-blue" : "text-sn-grey" %>"
href="<%= archive_my_module_url(@my_module) %>"
href="<%= my_module_results_path(@my_module, view_mode: :archived) %>"
title="<%= t'nav2.modules.archive' %>"
>
<%= t("nav2.modules.archive") %>

View file

@ -18,7 +18,8 @@
<%= render partial: 'my_modules/header_actions' %>
<div id="results" data-behaviour="vue">
<results url="<%= my_module_results_url(@my_module) %>">
<results url="<%= my_module_results_url(@my_module, view_mode: params[:view_mode]) %>"
can-create=<%= can_create_results?(@my_module) && params[:view_mode].blank? %>>
</div>
</div>

View file

@ -253,7 +253,7 @@ en:
full_name: "Full name"
initials: "Initials"
avatar: "Avatar"
activejob:
failure_notifiable_job:
general_notification_title: "Your export failed. Please contact support."
@ -1312,6 +1312,8 @@ en:
rearrange: "Rearrange"
archive: "Archive"
duplicate: "Duplicate"
restore: "Restore"
delete: "Delete"
move_modal:
search_placeholder: "Enter result name"
no_options_placeholder: "No results available to select"

View file

@ -539,6 +539,12 @@ Rails.application.routes.draw do
post :update_view_state
post :update_asset_view_mode
post :duplicate
post :archive
post :restore
end
resources :result_orderable_elements do
post :reorder, on: :collection
end
resources :tables, controller: 'result_elements/tables', only: %i(create destroy update) do
@ -555,7 +561,6 @@ Rails.application.routes.draw do
post :duplicate
end
end
post 'archive', to: 'results#archive'
end
end
@ -614,15 +619,6 @@ Rails.application.routes.draw do
end
end
resources :results, only: [:update, :destroy] do
resources :result_orderable_elements do
post :reorder, on: :collection
end
resources :result_comments,
path: '/comments',
only: %i(create index update destroy)
end
resources :result_texts, only: [:edit, :update, :destroy]
get 'result_texts/:id/download' => 'result_texts#download',
as: :result_text_download