Add create actions [SCI-8953]

This commit is contained in:
Anton 2023-08-11 14:48:20 +02:00
parent f6191dbb67
commit 6e5fa5ccd7
22 changed files with 261 additions and 80 deletions

View file

@ -55,7 +55,7 @@ $(document).on('click', '.asset .delete-asset', function(e) {
$(document).on('turbolinks:before-visit', (e) => {
if ($('.uploading-attachment-container:not(.error)').length) {
if (confirm(I18n.t('protocols.steps.attachments.new.leaving_warning'))) {
if (confirm(I18n.t('attachments.new.leaving_warning'))) {
return true;
}
e.preventDefault();

View file

@ -8,10 +8,10 @@ module ResultElements
predefined_table_dimensions = create_table_params[:tableDimensions].map(&:to_i)
name = if predefined_table_dimensions[0] == predefined_table_dimensions[1]
t('protocols.steps.table.default_name',
position: @step.step_tables.length + 1)
position: @result.result_tables.length + 1)
else
t('protocols.steps.plate.default_name',
position: @step.step_tables.length + 1)
position: @result.result_tables.length + 1)
end
result_table = @result.result_tables.new(table:
Table.new(
@ -24,11 +24,11 @@ module ResultElements
))
ActiveRecord::Base.transaction do
create_in_step!(@step, step_table)
create_in_result!(@result, result_table)
# log_step_activity(:table_added, { table_name: step_table.table.name })
end
render_result_orderable_element(step_table)
render_result_orderable_element(result_table)
rescue ActiveRecord::RecordInvalid
head :unprocessable_entity
end

View file

@ -13,7 +13,7 @@ module ResultElements
result_text = @result.result_texts.build
ActiveRecord::Base.transaction do
create_in_step!(@result, result_text)
create_in_result!(@result, result_text)
#log_step_activity(:text_added, { text_name: step_text.name })
end

View file

@ -4,7 +4,7 @@ class ResultsController < ApplicationController
skip_before_action :verify_authenticity_token, only: %i(create destroy)
before_action :load_my_module
before_action :load_vars, only: %i(destroy elements assets)
before_action :load_vars, only: %i(destroy elements assets upload_attachment update_view_state update_asset_view_mode )
before_action :check_destroy_permissions, only: :destroy
def index
@ -44,6 +44,44 @@ class ResultsController < ApplicationController
user: current_user
end
def upload_attachment
@result.transaction do
@asset = @result.assets.create!(
created_by: current_user,
last_modified_by: current_user,
team: @my_module.team,
view_mode: @result.assets_view_mode
)
@asset.file.attach(params[:signed_blob_id])
@asset.post_process_file(@my_module.team)
end
render json: @asset,
serializer: AssetSerializer,
user: current_user
end
def update_view_state
view_state = @result.current_view_state(current_user)
view_state.state['result_assets']['sort'] = params.require(:assets).require(:order)
view_state.save! if view_state.changed?
render json: {}, status: :ok
end
def update_asset_view_mode
html = ''
ActiveRecord::Base.transaction do
@result.assets_view_mode = params[:assets_view_mode]
@result.save!(touch: false)
@result.assets.update_all(view_mode: @result.assets_view_mode)
end
render json: { view_mode: @result.assets_view_mode }, status: :ok
rescue ActiveRecord::RecordInvalid => e
Rails.logger.error(e.message)
render json: { errors: e.message }, status: :unprocessable_entity
end
def destroy
result_type = if @result.is_text
t('activities.result_type.text')

View file

@ -5,14 +5,14 @@
<button @click="openReorderModal">
Open Rearrange Modal
</button>
<div>
<div class="inline-block">
<input type="file" class="hidden" ref="fileSelector" @change="loadFromComputer" multiple />
<div ref="elementsDropdownButton" v-if="urls.update_url" class="dropdown">
<button class="btn btn-light dropdown-toggle insert-button" type="button" :id="'stepInserMenu_' + step.id" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<button class="btn btn-light dropdown-toggle insert-button" type="button" :id="'resultInsertMenu_' + result.id" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
{{ i18n.t('protocols.steps.insert.button') }}
<span class="sn-icon sn-icon-down"></span>
</button>
<ul ref="elementsDropdown" class="dropdown-menu insert-element-dropdown dropdown-menu-right" :aria-labelledby="'stepInserMenu_' + step.id">
<ul ref="elementsDropdown" class="dropdown-menu insert-element-dropdown dropdown-menu-right" :aria-labelledby="'resultInsertMenu_' + result.id">
<li class="title">
{{ i18n.t('protocols.steps.insert.title') }}
</li>
@ -31,10 +31,6 @@
</li>
</ul>
</li>
<li class="action" @click="createElement('checklist')">
<i class="sn-icon sn-icon-activities"></i>
{{ i18n.t('protocols.steps.insert.checklist') }}
</li>
<li class="action" @click="createElement('text')">
<i class="sn-icon sn-icon-result-text"></i>
{{ i18n.t('protocols.steps.insert.text') }}
@ -47,16 +43,16 @@
<li class="action" @click="openLoadFromComputer">
{{ i18n.t('protocols.steps.insert.add_file') }}
</li>
<li class="action" v-if="step.attributes.wopi_enabled" @click="openWopiFileModal">
<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="step.attributes.marvinjs_enabled" @click="openMarvinJsModal($refs.marvinJsButton)">
<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="step.id"
:data-object-id="result.id"
ref="marvinJsButton"
:data-marvin-url="step.attributes.marvinjs_context.marvin_js_asset_url"
:data-object-type="step.attributes.type"
:data-marvin-url="result.attributes.marvinjs_context.marvin_js_asset_url"
:data-object-type="result.attributes.type"
tabindex="0"
>
{{ i18n.t('marvinjs.new_button') }}
@ -97,9 +93,9 @@
@attachments:openFileModal="showFileModal = true"
@attachment:deleted="attachmentDeleted"
@attachment:uploaded="loadAttachments"
@attachments:order="() => {}"
@attachments:viewMode="() => {}"
@attachment:viewMode="() => {}"/>
@attachments:order="changeAttachmentsOrder"
@attachments:viewMode="changeAttachmentsViewMode"
@attachment:viewMode="updateAttachmentViewMode"/>
</div>
</div>
</template>
@ -126,7 +122,15 @@
elements: [],
attachments: [],
attachmentsReady: false,
showFileModal: false
showFileModal: false,
wellPlateOptions: [
{ label: 'protocols.steps.insert.well_plate_options.32_x_48', dimensions: [32, 48] },
{ label: 'protocols.steps.insert.well_plate_options.16_x_24', dimensions: [16, 24] },
{ label: 'protocols.steps.insert.well_plate_options.8_x_12', dimensions: [8, 12] },
{ 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.2_x_3', dimensions: [2, 3] }
]
}
},
mixins: [UtilsMixin, AttachmentsMixin, WopiFileModal],
@ -177,17 +181,57 @@
}
})
.then(() => {
this.$emit('stepUpdated');
this.$emit('resultUpdated');
})
.catch(() => {
HelperModule.flashAlertMsg(this.i18n.t('errors.general'), 'danger');
});
},
deleteElement(element) {
deleteElement(position) {
this.elements.splice(position, 1)
let unorderedElements = this.elements.map( e => {
if (e.attributes.position >= position) {
e.attributes.position -= 1;
}
return e;
})
this.$emit('resultUpdated')
},
updateElement(element) {
updateElement(element, skipRequest=false, callback) {
let index = this.elements.findIndex((e) => e.id === element.id);
this.elements[index].isNew = false;
if (skipRequest) {
this.elements[index].attributes.orderable = element.attributes.orderable;
this.$emit('resultUpdated');
} else {
$.ajax({
url: element.attributes.orderable.urls.update_url,
method: 'PUT',
data: element.attributes.orderable,
success: (result) => {
this.elements[index].attributes.orderable = result.data.attributes;
this.$emit('resultUpdated');
// optional callback after successful update
if(typeof callback === 'function') {
callback();
}
}
}).fail(() => {
HelperModule.flashAlertMsg(this.i18n.t('errors.general'), 'danger');
})
}
},
insertElement(element) {
let position = element.attributes.position;
this.elements = this.elements.map( s => {
if (s.attributes.position >= position) {
s.attributes.position += 1;
}
return s;
})
this.elements.push(element);
},
loadElements() {
$.get(this.urls.elements_url, (result) => {
@ -214,6 +258,25 @@
this.attachments = this.attachments.filter((a) => a.id !== id );
this.$emit('resultUpdated');
},
createElement(elementType, tableDimensions = [5,5], plateTemplate = false) {
$.post(this.urls[`create_${elementType}_url`], { tableDimensions: tableDimensions, plateTemplate: plateTemplate }, (result) => {
result.data.isNew = true;
this.elements.push(result.data)
this.$emit('stepUpdated')
}).fail(() => {
HelperModule.flashAlertMsg(this.i18n.t('errors.general'), 'danger');
}).done(() => {
this.$parent.$nextTick(() => {
const children = this.$children
const lastChild = children[children.length - 1]
lastChild.$el.scrollIntoView(false)
window.scrollBy({
top: 200,
behavior: 'smooth'
});
})
});
},
}
}
</script>

View file

@ -7,7 +7,7 @@
<div class="flex items-center gap-2" v-if="parent.attributes.attachments_manageble && attachmentsReady">
<div ref="actionsDropdownButton" class="dropdown sci-dropdown">
<button class="btn btn-light dropdown-toggle" type="button" id="dropdownAttachmentsOptions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<span>{{ i18n.t("protocols.steps.attachments.preview_menu") }}</span>
<span>{{ i18n.t("attachments.preview_menu") }}</span>
<span class="sn-icon sn-icon-down"></span>
</button>
<ul ref="actionsDropdown" class="dropdown-menu dropdown-menu-right dropdown-attachment-options"
@ -20,7 +20,7 @@
class="attachments-view-mode action-link"
:class="viewMode == parent.attributes.assets_view_mode ? 'selected' : ''"
@click="changeAttachmentsViewMode(viewMode)"
v-html="i18n.t(`protocols.steps.attachments.view_mode.${viewMode}_html`)"
v-html="i18n.t(`attachments.view_mode.${viewMode}_html`)"
></a>
</li>
</template>

View file

@ -19,7 +19,7 @@
</span>
</a>
<span v-if="attachment.isNewUpload" class="attachment-label-new">
{{ i18n.t('protocols.steps.attachments.new.description') }}
{{ i18n.t('attachments.new.description') }}
</span>
<div class="file-metadata">
<span>

View file

@ -18,7 +18,7 @@
</span>
</a>
<span v-if="attachment.isNewUpload" class="attachment-label-new">
{{ i18n.t('protocols.steps.attachments.new.description') }}
{{ i18n.t('attachments.new.description') }}
</span>
<div class="file-metadata">
<span>

View file

@ -24,7 +24,7 @@
:title="`${ attachment.attributes.file_name }`">
{{ attachment.attributes.file_name }}
<span v-if="attachment.isNewUpload" class="attachment-label-new">
{{ i18n.t('protocols.steps.attachments.new.description') }}
{{ i18n.t('attachments.new.description') }}
</span>
</div>
<div class="attachment-metadata">

View file

@ -7,7 +7,7 @@
<i v-if="attachment.error" class="fas fa-exclamation-triangle"></i>
</div>
<div class="file-name" :class="{'one-line': attachmentViewMode == 'list-attachment-container' }">
<div v-if="!attachment.error">{{ i18n.t("protocols.steps.attachments.new.uploading") }}</div>
<div v-if="!attachment.error">{{ i18n.t("attachments.new.uploading") }}</div>
<div class="file-name-text">{{ attachment.attributes.file_name }}</div>
</div>
<div v-if="!attachment.error" class="progress-container">

View file

@ -71,7 +71,7 @@ export default {
}
};
if (file.size > GLOBAL_CONSTANTS.FILE_MAX_SIZE_MB * 1024 * 1024) {
fileObject.error = I18n.t('protocols.steps.attachments.new.file_too_big');
fileObject.error = I18n.t('attachments.new.file_too_big');
this.attachments.push(fileObject);
return;
}
@ -80,7 +80,7 @@ export default {
this.attachmentsParent.attributes.storage_limit.total > 0 &&
this.attachmentsParent.attributes.storage_limit.used >= this.attachmentsParent.attributes.storage_limit.total;
if (storageLimit) {
fileObject.error = I18n.t('protocols.steps.attachments.new.no_more_space');
fileObject.error = I18n.t('attachments.new.no_more_space');
this.attachments.push(fileObject);
return;
}
@ -93,7 +93,7 @@ export default {
upload.create((error, blob) => {
if (error) {
fileObject.error = I18n.t('protocols.steps.attachments.new.general_error');
fileObject.error = I18n.t('attachments.new.general_error');
this.attachments.splice(filePosition, 1);
setTimeout(() => {
this.attachments.push(fileObject);
@ -107,7 +107,7 @@ export default {
fileObject.id = result.data.id;
fileObject.attributes = result.data.attributes;
}).fail(() => {
fileObject.error = I18n.t('protocols.steps.attachments.new.general_error');
fileObject.error = I18n.t('attachments.new.general_error');
this.attachments.splice(filePosition, 1);
setTimeout(() => {
this.attachments.push(fileObject);

View file

@ -4,10 +4,13 @@ class Result < ApplicationRecord
include ArchivableModel
include SearchableModel
include SearchableByNameModel
include ViewableModel
auto_strip_attributes :name, nullify: false
validates :name, length: { maximum: Constants::NAME_MAX_LENGTH }
enum assets_view_mode: { thumbnail: 0, list: 1, inline: 2 }
belongs_to :user, inverse_of: :results
belongs_to :last_modified_by, class_name: 'User', optional: true
belongs_to :archived_by, class_name: 'User', optional: true
@ -51,6 +54,16 @@ class Result < ApplicationRecord
end
end
def default_view_state
{ 'assets' => { 'sort' => 'new' } }
end
def validate_view_state(view_state)
unless %w(new old atoz ztoa).include?(view_state.state.dig('assets', 'sort'))
view_state.errors.add(:state, :wrong_state)
end
end
def self.viewable_by_user(user, teams)
where(my_module: MyModule.viewable_by_user(user, teams))
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
class ResultOrderableElement < ApplicationRecord
validates :position, uniqueness: { scope: :step }
validates :position, uniqueness: { scope: :result }
validate :check_result_relations
around_destroy :decrement_following_elements_positions
@ -11,8 +11,8 @@ class ResultOrderableElement < ApplicationRecord
private
def check_step_relations
if step != orderable.step
def check_result_relations
if result != orderable.result
errors.add(
:step_orderable_element,
I18n.t('activerecord.errors.models.result_orderable_element.attributes.result.wrong_result')

View file

@ -2,10 +2,17 @@
class ResultText < ApplicationRecord
include TinyMceImages
include ActionView::Helpers::TextHelper
auto_strip_attributes :text, nullify: false
validates :text, length: { maximum: Constants::RICH_TEXT_MAX_LENGTH }
belongs_to :result, inverse_of: :result_texts, touch: true
has_one :result_orderable_element, as: :orderable, dependent: :destroy
def name
return if text.blank?
strip_tags(text.truncate(64))
end
end

View file

@ -22,7 +22,7 @@ class Table < ApplicationRecord
has_one :step_table, inverse_of: :table, dependent: :destroy
has_one :step, through: :step_table
has_one :result_table, inverse_of: :table
has_one :result_table, inverse_of: :table, dependent: :destroy
has_one :result, through: :result_table
has_many :report_elements, inverse_of: :table, dependent: :destroy

View file

@ -7,7 +7,27 @@ class ResultSerializer < ActiveModel::Serializer
include ActionView::Helpers::TextHelper
include InputSanitizeHelper
attributes :name, :id, :urls, :updated_at, :created_at_formatted, :updated_at_formatted, :user, :my_module_id
attributes :name, :id, :urls, :updated_at, :created_at_formatted, :updated_at_formatted, :user,
:my_module_id, :attachments_manageble, :marvinjs_enabled, :marvinjs_context,
:wopi_enabled, :wopi_context
def marvinjs_enabled
MarvinJsService.enabled?
end
def type
'Result'
end
def marvinjs_context
if marvinjs_enabled
{
marvin_js_asset_url: marvin_js_assets_path,
icon: image_path('icon_small/marvinjs.svg')
}
end
end
def updated_at
object.updated_at.to_i
@ -20,6 +40,23 @@ class ResultSerializer < ActiveModel::Serializer
}
end
def attachments_manageble
can_manage_result?(object)
end
def wopi_enabled
wopi_enabled?
end
def wopi_context
if wopi_enabled
{
create_wopi: create_wopi_file_path,
icon: image_path('office/office.svg')
}
end
end
def created_at_formatted
I18n.l(object.created_at, format: :full)
end
@ -29,9 +66,24 @@ class ResultSerializer < ActiveModel::Serializer
end
def urls
{
urls_list = {
elements_url: elements_my_module_result_path(object.my_module, object),
attachments_url: assets_my_module_result_path(object.my_module, object)
}
if can_manage_result?(object)
urls_list.merge!({
delete_url: result_path(object),
update_url: result_path(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)
})
end
urls_list
end
end

View file

@ -6,7 +6,7 @@ class ResultTextSerializer < ActiveModel::Serializer
include ApplicationHelper
include ActionView::Helpers::TextHelper
attributes :id, :text, :urls, :text_view, :icon, :placeholder
attributes :id, :text, :urls, :text_view, :icon, :placeholder, :name
def updated_at
object.updated_at.to_i

View file

@ -15,7 +15,7 @@
<div class="actions">
<div class="dropdown sci-dropdown">
<button class="btn btn-light dropdown-toggle" type="button" id="dropdownAttachmentsOptions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<span><%= t("protocols.steps.attachments.manage") %></span>
<span><%= t("attachments.manage") %></span>
<span class="caret pull-right"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right dropdown-attachment-options"
@ -23,7 +23,7 @@
data-view-mode-url="<%= update_asset_view_mode_step_path(step) %>"
data-step-id="<%= step.id %>"
data-state-save-url="<%= update_view_state_step_path(step.id) %>">
<li class="divider-label"><%= t("protocols.steps.attachments.add") %></li>
<li class="divider-label"><%= t("attachments.add") %></li>
<%= render partial: '/assets/marvinjs/create_marvin_sketch_li',
locals: { element_id: step.id, element_type: 'Step', sketch_container: ".attachments[data-step-id=#{step.id}]" },
formats: :html %>
@ -33,7 +33,7 @@
locals: { element_id: step.id, element_type: 'Step' } %>
</li>
<li role="separator" class="divider"></li>
<li class="divider-label"><%= t("protocols.steps.attachments.sort_by") %></li>
<li class="divider-label"><%= t("attachments.sort_by") %></li>
<% ['new', 'old', 'atoz', 'ztoa'].each do |sort| %>
<li>
<a data-order="<%= sort %>" class="action-link change-order <%= 'selected' if current_order == sort %>">
@ -42,11 +42,11 @@
</li>
<% end %>
<li role="separator" class="divider"></li>
<li class="divider-label"><%= t("protocols.steps.attachments.attachments_view_mode") %></li>
<li class="divider-label"><%= t("attachments.attachments_view_mode") %></li>
<% ['inline', 'thumbnail', 'list'].each do |view_mode| %>
<li>
<a class="attachments-view-mode action-link <%= 'selected' if view_mode == step.assets_view_mode %>" data-assets-view-mode="<%= view_mode %>">
<%= t("protocols.steps.attachments.view_mode.#{view_mode}_html") %>
<%= t("attachments.view_mode.#{view_mode}_html") %>
</a>
</li>
<% end %>

View file

@ -377,6 +377,34 @@ en:
activities: "Activity"
archive: "Archived results"
attachments:
menu:
office_file: "New Office file"
chemical_drawing: "New chemical drawing"
file_from_pc: "File from your PC"
modified_label: "Modified:"
preview_menu: "Preview size"
add: "ADD"
sort_by: "SORT BY"
attachments_view_mode: "ALL ATTACHMENTS VIEW SIZE"
new:
description: 'New'
uploading: 'Uploading'
file_too_big: 'Failed to upload: File size is too big'
no_more_space: 'Failed to upload: You ran out of space'
general_error: 'Failed to upload: Something went wrong, please try again'
leaving_warning: 'Your changes will be lost if you navigate away'
sort:
new_html: "Newest first &#8595;"
old_html: "Oldest first &#8593;"
atoz_html: "Name &#8595;"
ztoa_html: "Name &#8593;"
view_mode:
inline_html: "Large"
thumbnail_html: "Medium"
list_html: "List"
search:
whole_word: "Match any whole word"
whole_phrase: "Match whole phrase"
@ -3095,33 +3123,6 @@ en:
duplicate_title: "Duplicate step"
complete_title: "Complete step"
uncomplete_title: "Restart step"
attachments:
menu:
office_file: "New Office file"
chemical_drawing: "New chemical drawing"
file_from_pc: "File from your PC"
modified_label: "Modified:"
preview_menu: "Preview size"
add: "ADD"
sort_by: "SORT BY"
attachments_view_mode: "ALL ATTACHMENTS VIEW SIZE"
new:
description: 'New'
uploading: 'Uploading'
file_too_big: 'Failed to upload: File size is too big'
no_more_space: 'Failed to upload: You ran out of space'
general_error: 'Failed to upload: Something went wrong, please try again'
leaving_warning: 'Your changes will be lost if you navigate away'
sort:
new_html: "Newest first &#8595;"
old_html: "Oldest first &#8593;"
atoz_html: "Name &#8595;"
ztoa_html: "Name &#8593;"
view_mode:
inline_html: "Large"
thumbnail_html: "Medium"
list_html: "List"
new:
add_step_title: "Add new step"
tab_checklists: "Checklists"

View file

@ -503,9 +503,6 @@ Rails.application.routes.draw do
post :select_default_snapshot, to: 'my_module_repository_snapshots#select'
resources :result_texts, only: [:new, :create]
resources :result_assets, only: [:new, :create]
resources :result_tables, only: [:new, :create]
member do
# AJAX popup accessed from full-zoom canvas for single module,
# as well as full activities view (HTML) for single module
@ -538,6 +535,9 @@ Rails.application.routes.draw do
member do
get :elements
get :assets
post :upload_attachment
post :update_view_state
post :update_asset_view_mode
end
resources :tables, controller: 'result_elements/tables', only: %i(create destroy update) do

View file

@ -0,0 +1,6 @@
class AddAssetsViewModeToResult < ActiveRecord::Migration[7.0]
def change
add_column :results, :assets_view_mode, :integer, default: 0
change_column_null :result_texts, :text, true
end
end

View file

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.0].define(version: 2023_07_25_120831) do
ActiveRecord::Schema[7.0].define(version: 2023_08_11_115859) do
# These are extensions that must be enabled in order to support this database
enable_extension "btree_gist"
enable_extension "pg_trgm"
@ -921,7 +921,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_07_25_120831) do
end
create_table "result_texts", force: :cascade do |t|
t.string "text", null: false
t.string "text"
t.bigint "result_id", null: false
t.index "trim_html_tags((text)::text) gin_trgm_ops", name: "index_result_texts_on_text", using: :gin
t.index ["result_id"], name: "index_result_texts_on_result_id"
@ -939,6 +939,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_07_25_120831) do
t.bigint "archived_by_id"
t.bigint "restored_by_id"
t.datetime "restored_on", precision: nil
t.integer "assets_view_mode", default: 0
t.index "trim_html_tags((name)::text) gin_trgm_ops", name: "index_results_on_name", using: :gin
t.index ["archived"], name: "index_results_on_archived"
t.index ["archived_by_id"], name: "index_results_on_archived_by_id"