Make snapshots selectable [SCI-4596]

This commit is contained in:
Oleksii Kriuchykhin 2020-05-12 16:26:44 +02:00
parent 76d1196724
commit c74fa3c244
18 changed files with 258 additions and 134 deletions

View file

@ -88,12 +88,12 @@ var MyModuleRepositories = (function() {
function renderSimpleTable(tableContainer) {
if (SIMPLE_TABLE) SIMPLE_TABLE.destroy();
SIMPLE_TABLE = $(tableContainer).DataTable({
dom: "Rt<'pagination-row'<'pagination-actions'p>>",
dom: "Rt<'pagination-row'<'version-label'><'pagination-actions'p>>",
processing: true,
serverSide: true,
responsive: true,
pageLength: 5,
order: [[3, 'asc']],
order: [[1, 'asc']],
sScrollY: '100%',
sScrollX: '100%',
sScrollXInner: '100%',
@ -103,14 +103,16 @@ var MyModuleRepositories = (function() {
data: function(d) {
d.assigned = 'assigned';
d.view_mode = true;
d.skip_custom_columns = true;
d.simple_view = true;
},
global: false,
type: 'POST'
},
columns: tableColumns(tableContainer),
columns: [
{ data: '1' }
],
columnDefs: [{
targets: 3,
targets: 1,
render: function(data, type, row) {
return "<a href='" + row.recordInfoUrl + "'"
+ "class='record-info-link'>" + data + '</a>';
@ -119,6 +121,7 @@ var MyModuleRepositories = (function() {
drawCallback: function() {
var repositoryContainer = $(this).closest('.assigned-repository-container');
repositoryContainer.find('.table.dataTable').removeClass('hidden');
repositoryContainer.find('.version-label').html(tableContainer.data('version-label'));
SIMPLE_TABLE.columns.adjust();
}
});
@ -202,6 +205,12 @@ var MyModuleRepositories = (function() {
let currentId = FULL_VIEW_MODAL.find('.table').data('id');
versionsSidebar.find('.list-group-item').removeClass('active');
versionsSidebar.find(`[data-id="${currentId}"]`).addClass('active');
if (!versionsSidebar.find(`[data-id="${currentId}"]`).data('selected')) {
$('#setDefaultVersionButton').removeClass('hidden');
} else {
$('#setDefaultVersionButton').addClass('hidden');
}
}
function reloadTable(tableUrl) {
@ -259,8 +268,9 @@ var MyModuleRepositories = (function() {
function initSimpleTable() {
$('#assigned-items-container').on('show.bs.collapse', '.assigned-repository-container', function() {
var repositoryContainer = $(this);
var repositoryTemplate = $($('#my-module-repository-simple-template').html());
var repositoryTemplate = $($('#myModuleRepositorySimpleTemplate').html());
repositoryTemplate.attr('data-source', $(this).data('repository-url'));
repositoryTemplate.attr('data-version-label', $(this).data('footer-label'));
repositoryContainer.html(repositoryTemplate);
renderSimpleTable(repositoryTemplate);
});
@ -344,6 +354,32 @@ var MyModuleRepositories = (function() {
FULL_VIEW_TABLE.columns.adjust();
e.stopPropagation();
});
FULL_VIEW_MODAL.on('click', '#setDefaultVersionButton', function(e) {
let data;
animateSpinner(null, true);
if (FULL_VIEW_MODAL.find('.table').data('type') === 'live') {
data = { repository_snapshot_id: -1 };
} else {
data = { repository_snapshot_id: FULL_VIEW_MODAL.find('.table').data('id') };
}
$.ajax({
url: $(this).data('select-path'),
type: 'POST',
dataType: 'json',
data: data,
success: function() {
let versionsList = FULL_VIEW_MODAL.find('.repository-versions-list');
versionsList.find('.list-group-item').data('selected', false);
versionsList.find('.list-group-item.active').data('selected', true);
$('#setDefaultVersionButton').addClass('hidden');
animateSpinner(null, false);
}
});
e.stopPropagation();
});
}
function initRepositoryFullView() {

View file

@ -379,6 +379,10 @@
display: none;
}
.default-version-button {
bottom: 5em;
}
&:hover {
background-color: $color-alto;

View file

@ -17,19 +17,22 @@ class MyModuleRepositoriesController < ApplicationController
@datatable_params = {
view_mode: params[:view_mode],
skip_custom_columns: params[:skip_custom_columns],
my_module: @my_module
}
@all_rows_count = datatable_service.all_count
@columns_mappings = datatable_service.mappings
@repository_rows = datatable_service.repository_rows
.preload(:repository_columns,
:created_by,
repository_cells: @repository.cell_preload_includes)
.page(page)
.per(per_page)
if params[:simple_view]
repository_rows = datatable_service.repository_rows
rows_view = 'repository_rows/simple_view_index.json'
else
repository_rows = datatable_service.repository_rows.preload(:repository_columns,
:created_by,
repository_cells: @repository.cell_preload_includes)
rows_view = 'repository_rows/index.json'
end
@repository_rows = repository_rows.page(page).per(per_page)
render 'repository_rows/index.json'
render rows_view
end
def update

View file

@ -3,9 +3,9 @@
class MyModuleRepositorySnapshotsController < ApplicationController
before_action :load_my_module
before_action :load_repository
before_action :load_repository_snapshot, except: %i(create full_view_versions_sidebar)
before_action :check_view_permissions, except: %i(create destroy)
before_action :check_manage_permissions, only: %i(create destroy)
before_action :load_repository_snapshot, except: %i(create full_view_versions_sidebar select)
before_action :check_view_permissions, except: %i(create destroy select)
before_action :check_manage_permissions, only: %i(create destroy select)
def index_dt
@draw = params[:draw].to_i
@ -13,20 +13,21 @@ class MyModuleRepositorySnapshotsController < ApplicationController
page = (params[:start].to_i / per_page) + 1
datatable_service = RepositorySnapshotDatatableService.new(@repository_snapshot, params, current_user, @my_module)
@datatable_params = {
view_mode: params[:view_mode],
skip_custom_columns: params[:skip_custom_columns]
}
@all_rows_count = datatable_service.all_count
@columns_mappings = datatable_service.mappings
@repository_rows = datatable_service.repository_rows
.preload(:repository_columns,
:created_by,
repository_cells: @repository_snapshot.cell_preload_includes)
.page(page)
.per(per_page)
if params[:simple_view]
repository_rows = datatable_service.repository_rows
rows_view = 'repository_rows/simple_view_index.json'
else
repository_rows = datatable_service.repository_rows
.preload(:repository_columns,
:created_by,
repository_cells: @repository_snapshot.cell_preload_includes)
rows_view = 'repository_rows/snapshot_index.json'
end
@repository_rows = repository_rows.page(page).per(per_page)
render 'repository_rows/snapshot_index.json'
render rows_view
end
def create
@ -75,6 +76,20 @@ class MyModuleRepositorySnapshotsController < ApplicationController
render json: { html: render_to_string(partial: 'my_modules/repositories/full_view_versions_sidebar') }
end
def select
if params[:repository_snapshot_id].to_i == -1
@my_module.repository_snapshots.where(original_repository: @repository).update(selected: nil)
else
repository_snapshot = @my_module.repository_snapshots.find_by(id: params[:repository_snapshot_id])
return render_404 unless repository_snapshot
@my_module.repository_snapshots.where(original_repository: @repository).update(selected: nil)
repository_snapshot.update!(selected: true)
end
render json: {}
end
private
def load_my_module
@ -98,6 +113,6 @@ class MyModuleRepositorySnapshotsController < ApplicationController
end
def check_manage_permissions
render_403 unless can_read_experiment?(@my_module.experiment)
render_403 unless can_manage_module?(@my_module)
end
end

View file

@ -56,21 +56,28 @@ module MyModulesHelper
action_name == 'results'
end
def grouped_by_prj_exp(my_modules)
ungrouped_tasks = my_modules.joins(experiment: :project)
.select('experiments.name as experiment_name,
experiments.archived as experiment_archived,
projects.name as project_name,
projects.archived as project_archived,
my_modules.*')
ungrouped_tasks.group_by { |i| [i[:project_name], i[:experiment_name]] }.map do |group, tasks|
{
project_name: group[0],
project_archived: tasks[0]&.project_archived,
experiment_name: group[1],
experiment_archived: tasks[0]&.experiment_archived,
tasks: tasks
}
def assigned_repository_full_view_table_path(my_module, repository)
if repository.is_a?(RepositorySnapshot)
return full_view_table_my_module_repository_snapshot_path(my_module, repository.original_repository, repository)
end
full_view_table_my_module_repository_path(my_module, repository)
end
def assigned_repository_simple_view_index_path(my_module, repository)
if repository.is_a?(RepositorySnapshot)
return index_dt_my_module_repository_snapshot_path(my_module, repository.original_repository, repository)
end
index_dt_my_module_repository_path(my_module, repository)
end
def assigned_repository_simple_view_footer_label(repository)
if repository.is_a?(RepositorySnapshot)
return t('my_modules.repository.snapshots.simple_view.snapshot_bottom_label',
date_time: l(repository.updated_at, format: :full))
end
t('my_modules.repository.snapshots.simple_view.live_bottom_label')
end
end

View file

@ -34,18 +34,27 @@ module RepositoryDatatableHelper
row['0'] = record[:row_assigned] if options[:my_module]
unless options[:skip_custom_columns]
# Add custom columns
record.repository_cells.each do |cell|
row[columns_mappings[cell.repository_column.id]] =
display_cell_value(cell, team)
end
# Add custom columns
record.repository_cells.each do |cell|
row[columns_mappings[cell.repository_column.id]] =
display_cell_value(cell, team)
end
row
end
end
def prepare_snapshot_row_columns(repository_rows, columns_mappings, team, options = {})
def prepare_simple_view_row_columns(repository_rows)
repository_rows.map do |record|
{
'DT_RowId': record.id,
'1': escape_input(record.name),
'recordInfoUrl': Rails.application.routes.url_helpers.repository_row_path(record.id)
}
end
end
def prepare_snapshot_row_columns(repository_rows, columns_mappings, team)
repository_rows.map do |record|
row = {
'DT_RowId': record.id,
@ -56,12 +65,11 @@ module RepositoryDatatableHelper
'recordInfoUrl': Rails.application.routes.url_helpers.repository_row_path(record.id)
}
unless options[:skip_custom_columns]
# Add custom columns
record.repository_cells.each do |cell|
row[columns_mappings[cell.repository_column.id]] = display_cell_value(cell, team)
end
# Add custom columns
record.repository_cells.each do |cell|
row[columns_mappings[cell.repository_column.id]] = display_cell_value(cell, team)
end
row
end
end

View file

@ -54,7 +54,6 @@ class MyModule < ApplicationRecord
inverse_of: :my_module, dependent: :destroy
has_many :repository_rows, through: :my_module_repository_rows
has_many :repository_snapshots,
class_name: 'RepositorySnapshot',
dependent: :destroy,
inverse_of: :my_module
has_many :user_my_modules, inverse_of: :my_module, dependent: :destroy
@ -201,7 +200,19 @@ class MyModule < ApplicationRecord
end
def assigned_repositories
Repository.where(id: repository_rows.select('DISTINCT(repository_id)'))
team = experiment.project.team
selected_snapshots = repository_snapshots.joins(:repository_rows)
.where(selected: true)
.group(:parent_id, :id)
live_repositories = team.repositories
.joins(repository_rows: :my_module_repository_rows)
.where(my_module_repository_rows: { my_module_id: id })
.where.not(id: selected_snapshots.select(:parent_id))
.group(:id)
selector = 'repositories.*, COUNT(repository_rows.id) AS assigned_rows_count'
live_repositories.select(selector) + selected_snapshots.select(selector)
end
def unassigned_users

View file

@ -8,8 +8,19 @@ class RepositorySnapshot < RepositoryBase
validates :name, presence: true, length: { maximum: Constants::NAME_MAX_LENGTH }
validates :status, presence: true
validate :only_one_selected_for_my_module
def default_columns_count
Constants::REPOSITORY_SNAPSHOT_TABLE_DEFAULT_STATE['length']
end
private
def only_one_selected_for_my_module
return unless selected
if my_module.repository_snapshots.where(original_repository: original_repository, selected: true).any?
errors.add(:selected, I18n.t('activerecord.errors.models.repository_snapshot.attributes.selected.already_taken'))
end
end
end

View file

@ -1,4 +1,6 @@
<div class="list-group-item repository-snapshot-item <%= repository_snapshot.status %>" data-id="<%= repository_snapshot.id %>"
<div class="list-group-item repository-snapshot-item <%= repository_snapshot.status %>"
data-id="<%= repository_snapshot.id %>"
data-selected="<%= repository_snapshot.selected %>"
data-status-url="<%= status_my_module_repository_snapshot_path(@my_module, @repository, repository_snapshot) %>"
data-item-url="<%= my_module_repository_snapshot_path(@my_module, @repository, repository_snapshot) %>">
<div class="row">

View file

@ -6,7 +6,7 @@
</h4>
</div>
<div class="list-group repository-versions-list">
<div class="list-group-item live-version-item" data-id="<%= @repository.id %>">
<div class="list-group-item live-version-item" data-id="<%= @repository.id %>" data-selected="<%= @repository_snapshots.select{ |s| s.selected == true }.blank? %>">
<a id="selectLiveVersionButton" class="version-button" href="#" data-table-url="<%= full_view_table_my_module_repository_path(@my_module, @repository) %>">
<h2 class="list-group-item-heading">
<%= t('my_modules.repository.snapshots.full_view.live') %>
@ -34,4 +34,10 @@
<%= render partial: 'my_modules/repositories/full_view_version', collection: @repository_snapshots, as: :repository_snapshot %>
</div>
</div>
<div class="list-group-item text-center">
<a id="setDefaultVersionButton" class="btn btn-primary default-version-button hidden" data-select-path="<%= select_my_module_repository_snapshots_path(@my_module, @repository) %>">
<%= t('my_modules.repository.snapshots.full_view.set_default_button') %>
</a>
</div>
</div>

View file

@ -7,33 +7,30 @@
data-parent="#assigned-items-container"
>
<i class="fas fa-caret-right"></i>
<span class="assigned-repository-title" data-rows-count="[<%= @my_module.repository_rows_count(repository) %>]">
<span class="assigned-repository-title" data-rows-count="[<%= repository.assigned_rows_count %>]">
<%= repository.name %>
</span>
<div class="action-buttons">
<i class="fas fa-expand full-screen" data-table-url="<%= full_view_table_my_module_repository_path(@my_module, repository) %>">
<i class="fas fa-expand full-screen" data-table-url="<%= assigned_repository_full_view_table_path(@my_module, repository) %>">
</i>
<i class="fas fa-trash unassign-repository"></i>
</div>
</a>
<div class="collapse assigned-repository-container"
id="assigned-repository-items-container-<%= repository.id %>"
data-repository-url="<%= index_dt_my_module_repository_path(@my_module, repository) %>"
data-repository-url="<%= assigned_repository_simple_view_index_path(@my_module, repository) %>"
data-footer-label="<%= assigned_repository_simple_view_footer_label(repository) %>"
>
</div>
</div>
<% end %>
<template id="my-module-repository-simple-template">
<table class="table hidden" data-default-table-columns="<%= default_table_columns %>">
<template id="myModuleRepositorySimpleTemplate">
<table class="table hidden">
<thead>
<tr>
<th class="never"></th>
<th class="never"></th>
<th class="never"></th>
<th class="row-name"><%= t("repositories.table.row_name") %></th>
<th class="never"></th>
<th class="never"></th>
</tr>
</thead>
<tbody></tbody>

View file

@ -13,25 +13,25 @@
</ol>
<p>
<span>
<%=t 'repository_row.modal_info.ID' %>
<%= @repository_row.id %>
<%= t('repository_row.modal_info.ID') %>
<%= @repository_row.parent_id || @repository_row.id %>
</span>
<br>
<span>
<%= t "repository_row.modal_info.added_on" %>:
<%= l @repository_row.created_at, format: :full %>
<%= t('repository_row.modal_info.added_on') %>:
<%= l(@repository_row.created_at, format: :full) %>
</span>
<br>
<span>
<%= t "repository_row.modal_info.added_by" %>:
<%= t('repository_row.modal_info.added_by') %>:
<%= @repository_row.created_by.full_name %>
</span>
<% @repository_row.repository_cells.each do |repository_cell| %>
<br>
<span>
<%= t "repository_row.modal_info.custom_field", cf: repository_cell.repository_column.name %>
<%= t('repository_row.modal_info.custom_field', cf: repository_cell.repository_column.name) %>
<% if repository_cell.value_type == 'RepositoryAssetValue' %>
<%= render partial: "shared/asset_link", locals: { asset: repository_cell.value.asset, display_image_tag: false }, formats: :html %>
<%= render partial: 'shared/asset_link', locals: { asset: repository_cell.value.asset, display_image_tag: false }, formats: :html %>
<% else %>
<%= custom_auto_link(repository_cell.value.formatted, simple_format: false, team: current_team) %>
<% end %>
@ -39,58 +39,60 @@
<% end %>
</p>
<% if @assigned_modules.count > 0 %>
<div>
<%= t("repository_row.modal_info.title", nr: @assigned_modules.count) %>
</div>
<div class="linked-children-datatable">
<table id="repository_row-info-table" class="table dataTable no-footer" role="grid">
<tbody>
<% @assigned_modules.each_with_index do |element, i| %>
<tr role="row">
<td class="sorting_1">
<ol class='breadcrumb'>
<li>
<span class='fas fa-users'></span>&nbsp;
<%= render partial: "search/results/partials/team_text.html.erb",
locals: { team: element.my_module.experiment.project.team } %>
</li>
<li>
<%= image_tag 'icon_small/project.svg' %>
<%= render partial: 'search/results/partials/project_text.html.erb',
locals: { project: element.my_module.experiment.project } %>
</li>
<li>
<%= image_tag 'icon_small/experiment.svg' %>
<%= render partial: 'search/results/partials/experiment_text.html.erb',
locals: { experiment: element.my_module.experiment } %>
</li>
<li>
<%= image_tag 'icon_small/task.svg' %>
<%= render partial: 'search/results/partials/my_module_text.html.erb',
locals: { my_module: element.my_module,
link_to_page: :repositories,
repository: @repository_row.repository } %>
</li>
</ol>
</td>
</tr>
<% end %>
</tbody>
<thead>
<tr>
<th></th>
</tr>
</thead>
</table>
</div>
<% else %>
<em><%=t "repository_row.modal_info.no_tasks" %></em>
<% end %>
<% if @repository_row.repository.is_a?(Repository) %>
<% if @assigned_modules.size > 0 %>
<div>
<%= t('repository_row.modal_info.title', nr: @assigned_modules.size) %>
</div>
<div class="linked-children-datatable">
<table id="repository_row-info-table" class="table dataTable no-footer" role="grid">
<tbody>
<% @assigned_modules.each_with_index do |element, i| %>
<tr role="row">
<td class="sorting_1">
<ol class='breadcrumb'>
<li>
<span class='fas fa-users'></span>&nbsp;
<%= render partial: 'search/results/partials/team_text.html.erb',
locals: { team: element.my_module.experiment.project.team } %>
</li>
<li>
<%= image_tag 'icon_small/project.svg' %>
<%= render partial: 'search/results/partials/project_text.html.erb',
locals: { project: element.my_module.experiment.project } %>
</li>
<li>
<%= image_tag 'icon_small/experiment.svg' %>
<%= render partial: 'search/results/partials/experiment_text.html.erb',
locals: { experiment: element.my_module.experiment } %>
</li>
<li>
<%= image_tag 'icon_small/task.svg' %>
<%= render partial: 'search/results/partials/my_module_text.html.erb',
locals: { my_module: element.my_module,
link_to_page: :repositories,
repository: @repository_row.repository } %>
</li>
</ol>
</td>
</tr>
<% end %>
</tbody>
<thead>
<tr>
<th></th>
</tr>
</thead>
</table>
</div>
<% else %>
<em><%= t('repository_row.modal_info.no_tasks') %></em>
<% end %>
<% end %>
</div>
<script>FilePreviewModal.init()</script>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal"><%= t("general.close")%></button>
<button type="button" class="btn btn-default" data-dismiss="modal"><%= t('general.close')%></button>
</div>
</div>
</div>

View file

@ -0,0 +1,8 @@
# frozen_string_literal: true
json.draw @draw
json.data do
json.array! prepare_simple_view_row_columns(@repository_rows)
end
json.recordsFiltered @repository_rows.first ? @repository_rows.first.filtered_count : 0
json.recordsTotal @all_rows_count

View file

@ -2,10 +2,7 @@
json.draw @draw
json.data do
json.array! prepare_snapshot_row_columns(@repository_rows,
@columns_mappings,
@repository.team,
defined?(@datatable_params) ? @datatable_params : {})
json.array! prepare_snapshot_row_columns(@repository_rows, @columns_mappings, @repository.team)
end
json.recordsFiltered @repository_rows.first ? @repository_rows.first.filtered_count : 0
json.recordsTotal @all_rows_count

View file

@ -100,6 +100,10 @@ en:
attributes:
file:
too_big: "is too big"
repository_snapshot:
attributes:
selected:
already_taken: "Task already has selected snapshot"
repository_list_item:
attributes:
base:
@ -788,6 +792,9 @@ en:
head_title: "%{project} | %{module} | Inventory %{repository}"
export: 'Export'
snapshots:
simple_view:
live_bottom_label: 'Live version'
snapshot_bottom_label: 'Snapshot version %{date_time}'
full_view:
header: 'Versions'
live: 'Live version'
@ -795,6 +802,7 @@ en:
no_snapshots_label: 'You have not created any snapshots yet. To do so click the button bellow.'
versions_sidebar_button: 'View versions'
create_button: 'Create snapshot'
set_default_button: 'Set as default view'
created_by: 'by %{full_name}'
provisioning: 'Provisioning'
flash:

View file

@ -403,6 +403,10 @@ Rails.application.routes.draw do
post :index_dt
get :status
end
collection do
post :select
end
end
get :full_view_versions_sidebar, controller: :my_module_repository_snapshots

View file

@ -6,10 +6,10 @@ class AddRepositorySnapshots < ActiveRecord::Migration[6.0]
t.string :type
t.bigint :parent_id, null: true
t.integer :status, null: true
t.boolean :selected, null: true
t.references :my_module
end
add_reference :repositories, :my_module
execute "UPDATE \"repositories\" SET \"type\" = 'Repository'"
execute "UPDATE \"activities\" SET \"subject_type\" = 'RepositoryBase' WHERE \"subject_type\" = 'Repository'"
@ -31,8 +31,12 @@ class AddRepositorySnapshots < ActiveRecord::Migration[6.0]
execute "UPDATE \"activities\" SET \"subject_type\" = 'Repository' WHERE \"subject_type\" = 'RepositoryBase'"
remove_column :repositories, :parent_id, :bigint, null: true
remove_reference :repositories, :my_module
remove_column :repositories, :type, :string
change_table :repositories, bulk: true do |t|
t.remove :type
t.remove :parent_id
t.remove :status
t.remove :selected
t.remove_references :my_module
end
end
end

View file

@ -1103,6 +1103,7 @@ CREATE TABLE public.repositories (
type character varying,
parent_id bigint,
status integer,
selected boolean,
my_module_id bigint
);