mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-01-01 13:13:22 +08:00
Merge pull request #1321 from okriuchykhin/ok_SCI_2731
Add Projects view - list/table view [SCI-2731]
This commit is contained in:
commit
16b29b50a5
12 changed files with 454 additions and 124 deletions
|
@ -7,7 +7,8 @@
|
|||
// - refresh project users tab after manage user modal is closed
|
||||
// - refactor view handling using library, ex. backbone.js
|
||||
|
||||
/* global Comments CounterBadge animateSpinner initFormSubmitLinks HelperModule */
|
||||
/* global Comments CounterBadge animateSpinner initFormSubmitLinks HelperModule
|
||||
I18n */
|
||||
|
||||
//= require comments
|
||||
(function() {
|
||||
|
@ -28,8 +29,15 @@
|
|||
|
||||
var projectsViewMode = 'cards';
|
||||
var projectsViewFilter = $('.projects-view-filter.active').data('filter');
|
||||
var projectsViewFilterChanged = false;
|
||||
var projectsChanged = false;
|
||||
var projectsViewSort = 'new';
|
||||
|
||||
var TABLE;
|
||||
|
||||
// Array with selected project IDs shared between both views
|
||||
var selectedProjects = [];
|
||||
|
||||
/**
|
||||
* Initialize the JS for new project modal to work.
|
||||
*/
|
||||
|
@ -61,9 +69,11 @@
|
|||
.on('ajax:beforeSend', function() {
|
||||
animateSpinner(newProjectModalBody);
|
||||
})
|
||||
.on('ajax:success', function(data, status) {
|
||||
// Redirect to response page
|
||||
$(location).attr('href', status.url);
|
||||
.on('ajax:success', function(ev, data) {
|
||||
projectsChanged = true;
|
||||
refreshCurrentView();
|
||||
newProjectModal.modal('hide');
|
||||
HelperModule.flashAlertMsg(data.message, 'success');
|
||||
})
|
||||
.on('ajax:error', function(jqxhr, status) {
|
||||
$(this).renderFormErrors('project', status.responseJSON);
|
||||
|
@ -79,6 +89,65 @@
|
|||
});
|
||||
}
|
||||
|
||||
// init project archive/restore function
|
||||
function initArchiveRestoreButton(el) {
|
||||
el.find('form.edit_project')
|
||||
.on('ajax:beforeSend', function() {
|
||||
animateSpinner($('#projects-cards-view').closest('.tab-content'));
|
||||
})
|
||||
.on('ajax:success', function(ev, data) {
|
||||
projectsChanged = true;
|
||||
HelperModule.flashAlertMsg(data.message, 'success');
|
||||
// Project saved, reload view
|
||||
refreshCurrentView();
|
||||
})
|
||||
.on('ajax:error', function(ev, data) {
|
||||
HelperModule.flashAlertMsg(data.responseJSON.message, 'danger');
|
||||
})
|
||||
.on('ajax:complete', function() {
|
||||
animateSpinner($('#projects-cards-view').closest('.tab-content'), false);
|
||||
});
|
||||
}
|
||||
|
||||
function initEditProjectButton(el) {
|
||||
el.find(".dropdown-menu a[data-action='edit']")
|
||||
.on('ajax:success', function(ev, data) {
|
||||
// Update modal title
|
||||
editProjectModalTitle.html(data.title);
|
||||
|
||||
// Set modal body
|
||||
editProjectModalBody.html(data.html);
|
||||
|
||||
// Add modal body's submit handler
|
||||
editProjectModal.find('form')
|
||||
.on('ajax:beforeSend', function() {
|
||||
animateSpinner(this);
|
||||
})
|
||||
.on('ajax:success', function(ev2, data2) {
|
||||
projectsChanged = true;
|
||||
// Hide modal
|
||||
editProjectModal.modal('hide');
|
||||
|
||||
HelperModule.flashAlertMsg(data2.message, 'success');
|
||||
|
||||
// Project saved, reload view
|
||||
refreshCurrentView();
|
||||
})
|
||||
.on('ajax:error', function(ev2, data2) {
|
||||
$(this).renderFormErrors('project', data2.responseJSON.errors);
|
||||
})
|
||||
.on('ajax:complete', function() {
|
||||
animateSpinner(this, false);
|
||||
});
|
||||
|
||||
// Show the modal
|
||||
editProjectModal.modal('show');
|
||||
})
|
||||
.on('ajax:error', function() {
|
||||
// TODO
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the JS for edit project modal to work.
|
||||
*/
|
||||
|
@ -93,42 +162,6 @@
|
|||
editProjectModal.on('hidden.bs.modal', function() {
|
||||
editProjectModalBody.html('');
|
||||
});
|
||||
|
||||
$(".panel-project a[data-action='edit']")
|
||||
.on('ajax:success', function(ev, data) {
|
||||
// Update modal title
|
||||
editProjectModalTitle.html(data.title);
|
||||
|
||||
// Set modal body
|
||||
editProjectModalBody.html(data.html);
|
||||
|
||||
// Add modal body's submit handler
|
||||
editProjectModal.find('form')
|
||||
.on('ajax:beforeSend', function() {
|
||||
animateSpinner(this);
|
||||
})
|
||||
.on('ajax:success', function(ev2, data2) {
|
||||
// Hide modal
|
||||
editProjectModal.modal('hide');
|
||||
|
||||
HelperModule.flashAlertMsg(data2.message, 'success');
|
||||
|
||||
// Project saved, reload cards view
|
||||
loadCardsView();
|
||||
})
|
||||
.on('ajax:error', function(ev2, data2) {
|
||||
$(this).renderFormErrors('project', data2.responseJSON.errors);
|
||||
})
|
||||
.on('ajax:complete', function() {
|
||||
animateSpinner(this, false);
|
||||
});
|
||||
|
||||
// Show the modal
|
||||
editProjectModal.modal('show');
|
||||
})
|
||||
.on('ajax:error', function() {
|
||||
// TODO
|
||||
});
|
||||
}
|
||||
|
||||
function initManageUsersModal() {
|
||||
|
@ -147,6 +180,7 @@
|
|||
data.counter, data.project_id, 'users'
|
||||
);
|
||||
initUsersEditLink(projectEl);
|
||||
projectsChanged = true;
|
||||
},
|
||||
error: function() {
|
||||
// TODO
|
||||
|
@ -232,8 +266,18 @@
|
|||
initUserRoleForms();
|
||||
}
|
||||
|
||||
function updateSelectedCards() {
|
||||
$('.panel-project').removeClass('selected');
|
||||
$('.project-card-selector').prop('checked', false);
|
||||
$.each(selectedProjects, function(index, value) {
|
||||
var selectedCard = $('.panel-project[id=' + value + ']');
|
||||
selectedCard.addClass('selected');
|
||||
selectedCard.find('.project-card-selector').prop('checked', true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes page
|
||||
* Initializes cards view
|
||||
*/
|
||||
function init() {
|
||||
newProjectModal = $('#new-project-modal');
|
||||
|
@ -251,6 +295,7 @@
|
|||
projectActionsModalBody = projectActionsModal.find('.modal-body');
|
||||
projectActionsModalFooter = projectActionsModal.find('.modal-footer');
|
||||
|
||||
updateSelectedCards();
|
||||
initNewProjectModal();
|
||||
initEditProjectModal();
|
||||
initManageUsersModal();
|
||||
|
@ -258,31 +303,25 @@
|
|||
Comments.initEditComments('.panel-project .tab-content');
|
||||
Comments.initDeleteComments('.panel-project .tab-content');
|
||||
|
||||
initEditProjectButton($('.panel-project'));
|
||||
initArchiveRestoreButton($('.panel-project'));
|
||||
|
||||
$('.project-card-selector').click(function() {
|
||||
if (this.checked) {
|
||||
var projectId = $(this).closest('.panel-project').data('id');
|
||||
// Determine whether ID is in the list of selected project IDs
|
||||
var index = $.inArray(projectId, selectedProjects);
|
||||
|
||||
// If checkbox is checked and row ID is not in list of selected project IDs
|
||||
if (this.checked && index === -1) {
|
||||
$(this).closest('.panel-project').addClass('selected');
|
||||
} else {
|
||||
selectedProjects.push(projectId);
|
||||
// Otherwise, if checkbox is not checked and ID is in list of selected IDs
|
||||
} else if (!this.checked && index !== -1) {
|
||||
$(this).closest('.panel-project').removeClass('selected');
|
||||
selectedProjects.splice(index, 1);
|
||||
}
|
||||
});
|
||||
|
||||
// init project archive/restore function
|
||||
$('.panel-project .panel-heading form')
|
||||
.on('ajax:beforeSend', function() {
|
||||
animateSpinner($('#projects-cards-view'));
|
||||
})
|
||||
.on('ajax:success', function(ev, data) {
|
||||
HelperModule.flashAlertMsg(data.message, 'success');
|
||||
// Project saved, reload cards view
|
||||
loadCardsView();
|
||||
})
|
||||
.on('ajax:error', function(ev, data) {
|
||||
HelperModule.flashAlertMsg(data.responseJSON.message, 'danger');
|
||||
})
|
||||
.on('ajax:complete', function() {
|
||||
animateSpinner($('#projects-cards-view'), false);
|
||||
});
|
||||
|
||||
// initialize project tab remote loading
|
||||
$('.panel-project .active').removeClass('active');
|
||||
$('.panel-project .panel-footer [role=tab]')
|
||||
|
@ -322,6 +361,14 @@
|
|||
});
|
||||
}
|
||||
|
||||
function refreshCurrentView() {
|
||||
if (projectsViewMode === 'cards') {
|
||||
loadCardsView();
|
||||
} else {
|
||||
TABLE.draw();
|
||||
}
|
||||
}
|
||||
|
||||
function loadCardsView() {
|
||||
// Load HTML with projects list
|
||||
var viewContainer = $('#projects-cards-view');
|
||||
|
@ -349,14 +396,18 @@
|
|||
$('.projects-view-filter').click(function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
$('.projects-view-filter').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
if ($(this).data('filter') === projectsViewFilter) {
|
||||
return;
|
||||
}
|
||||
$('.projects-view-filter').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
selectedProjects = [];
|
||||
projectsViewFilter = $(this).data('filter');
|
||||
projectsViewFilterChanged = true;
|
||||
if ($('#projects-cards-view').hasClass('active')) {
|
||||
loadCardsView();
|
||||
} else if (!$.isEmptyObject(TABLE)) {
|
||||
TABLE.draw();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -367,6 +418,10 @@
|
|||
return;
|
||||
}
|
||||
projectsViewMode = $(this).val();
|
||||
if (projectsChanged) {
|
||||
refreshCurrentView();
|
||||
}
|
||||
projectsChanged = false;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -384,6 +439,218 @@
|
|||
});
|
||||
}
|
||||
|
||||
// Updates "Select all" control in a data table
|
||||
function updateDataTableSelectAllCtrl() {
|
||||
var $table = TABLE.table().node();
|
||||
var $header = TABLE.table().header();
|
||||
var $chkboxAll = $('.project-row-selector', $table);
|
||||
var $chkboxChecked = $('.project-row-selector:checked', $table);
|
||||
var chkboxSelectAll = $('input[name="select_all"]', $header).get(0);
|
||||
|
||||
// If none of the checkboxes are checked
|
||||
if ($chkboxChecked.length === 0) {
|
||||
chkboxSelectAll.checked = false;
|
||||
if ('indeterminate' in chkboxSelectAll) {
|
||||
chkboxSelectAll.indeterminate = false;
|
||||
}
|
||||
|
||||
// If all of the checkboxes are checked
|
||||
} else if ($chkboxChecked.length === $chkboxAll.length) {
|
||||
chkboxSelectAll.checked = true;
|
||||
if ('indeterminate' in chkboxSelectAll) {
|
||||
chkboxSelectAll.indeterminate = false;
|
||||
}
|
||||
|
||||
// If some of the checkboxes are checked
|
||||
} else {
|
||||
chkboxSelectAll.checked = true;
|
||||
if ('indeterminate' in chkboxSelectAll) {
|
||||
chkboxSelectAll.indeterminate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initRowSelection() {
|
||||
// Handle clicks on checkbox
|
||||
$('.dt-body-center .project-row-selector').change(function(e) {
|
||||
// Get row ID
|
||||
var $row = $(this).closest('tr');
|
||||
var data = TABLE.row($row).data();
|
||||
var rowId = data.DT_RowId;
|
||||
|
||||
// Determine whether row ID is in the list of selected project IDs
|
||||
var index = $.inArray(rowId, selectedProjects);
|
||||
|
||||
// If checkbox is checked and row ID is not in list of selected project IDs
|
||||
if (this.checked && index === -1) {
|
||||
selectedProjects.push(rowId);
|
||||
// Otherwise, if checkbox is not checked and ID is in list of selected IDs
|
||||
} else if (!this.checked && index !== -1) {
|
||||
selectedProjects.splice(index, 1);
|
||||
}
|
||||
|
||||
updateDataTableSelectAllCtrl();
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
// Handle click on "Select all" control
|
||||
$('.dataTables_scrollHead input[name="select_all"]').change(function(e) {
|
||||
if (this.checked) {
|
||||
$('.project-row-selector:not(:checked)').trigger('click');
|
||||
} else {
|
||||
$('.project-row-selector:checked').trigger('click');
|
||||
}
|
||||
// Prevent click event from propagating to parent
|
||||
e.stopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
function updateSelectedRows() {
|
||||
TABLE.rows().every(function() {
|
||||
var rowSelector = $(this.node()).find('input[type="checkbox"]');
|
||||
var rowId = this.data().DT_RowId;
|
||||
|
||||
if ($.inArray(rowId, selectedProjects) !== -1) {
|
||||
rowSelector.prop('checked', true);
|
||||
} else {
|
||||
rowSelector.prop('checked', false);
|
||||
}
|
||||
});
|
||||
|
||||
updateDataTableSelectAllCtrl();
|
||||
}
|
||||
|
||||
function dataTableInit() {
|
||||
var TABLE_ID = '#projects-overview-table';
|
||||
TABLE = $(TABLE_ID).DataTable({
|
||||
dom: "R<'row'<'col-sm-9-custom toolbar'l><'col-sm-3-custom'f>>tpi",
|
||||
stateSave: false,
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
scrollY: '64vh',
|
||||
scrollCollapse: true,
|
||||
destroy: true,
|
||||
ajax: {
|
||||
url: $(TABLE_ID).data('source'),
|
||||
global: false,
|
||||
type: 'POST',
|
||||
data: function(params) {
|
||||
params.filter = projectsViewFilter;
|
||||
// return { ...params, ...{ filter: projectsViewFilter } };
|
||||
}
|
||||
},
|
||||
colReorder: {
|
||||
fixedColumnsLeft: 9
|
||||
},
|
||||
columnDefs: [{
|
||||
// Checkbox column needs special handling
|
||||
targets: 0,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
className: 'dt-body-center',
|
||||
sWidth: '1%',
|
||||
render: function() {
|
||||
return "<input class='project-row-selector' type='checkbox'>";
|
||||
}
|
||||
}, {
|
||||
targets: 8,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
className: 'dt-body-center',
|
||||
sWidth: '1%'
|
||||
}],
|
||||
oLanguage: {
|
||||
sSearch: I18n.t('general.filter')
|
||||
},
|
||||
rowCallback: function(row, data) {
|
||||
// Get row ID
|
||||
var rowId = data.DT_RowId;
|
||||
var dropdown = $(row).find('.dropdown');
|
||||
var dropdownCell = dropdown.closest('td');
|
||||
// If row ID is in the list of selected row IDs
|
||||
if ($.inArray(rowId, selectedProjects) !== -1) {
|
||||
$(row).find('input[type="checkbox"]').prop('checked', true);
|
||||
}
|
||||
|
||||
initEditProjectButton($(row));
|
||||
initArchiveRestoreButton($(row));
|
||||
|
||||
dropdown.on('show.bs.dropdown', function() {
|
||||
$('body').append(dropdown.css({
|
||||
left: dropdown.offset().left,
|
||||
position: 'absolute',
|
||||
top: dropdown.offset().top
|
||||
}).detach());
|
||||
});
|
||||
dropdown.on('hidden.bs.dropdown', function() {
|
||||
dropdownCell.append(dropdown.removeAttr('style').detach());
|
||||
});
|
||||
},
|
||||
order: [[2, 'asc']],
|
||||
columns: [
|
||||
{ data: 'checkbox' },
|
||||
{ data: 'status' },
|
||||
{ data: 'name' },
|
||||
{ data: 'start' },
|
||||
{ data: 'visibility' },
|
||||
{ data: 'users' },
|
||||
{ data: 'experiments' },
|
||||
{ data: 'tasks' },
|
||||
{ data: 'actions' }
|
||||
],
|
||||
fnDrawCallback: function() {
|
||||
animateSpinner(this, false);
|
||||
updateDataTableSelectAllCtrl();
|
||||
initRowSelection();
|
||||
initFormSubmitLinks($(this));
|
||||
},
|
||||
stateLoadCallback: function() {
|
||||
// to be implemented
|
||||
},
|
||||
stateSaveCallback: function(settings, data) {
|
||||
// to be implemented
|
||||
},
|
||||
fnInitComplete: function() {
|
||||
// to be implemented
|
||||
}
|
||||
});
|
||||
|
||||
// Handle click on table cells with checkboxes
|
||||
$(TABLE_ID).on('click', 'tbody td', function(e) {
|
||||
if ($(e.target).is(
|
||||
'.project-row-selector, .active-project-link, button, span'
|
||||
)) {
|
||||
// Skip if clicking on selector checkbox, links and buttons
|
||||
return;
|
||||
}
|
||||
$(this).parent().find('.project-row-selector').trigger('click');
|
||||
});
|
||||
|
||||
return TABLE;
|
||||
}
|
||||
|
||||
$('.projects-view-mode-switch a').on('shown.bs.tab', function(event) {
|
||||
if ($(event.target).data('mode') === 'table') {
|
||||
// table tab
|
||||
$('#sortMenu').hide();
|
||||
if ($.isEmptyObject(TABLE)) {
|
||||
dataTableInit();
|
||||
} else if (projectsViewFilterChanged) {
|
||||
TABLE.draw();
|
||||
} else {
|
||||
updateSelectedRows();
|
||||
}
|
||||
} else {
|
||||
// cards tab
|
||||
$('#sortMenu').show();
|
||||
if (projectsViewFilterChanged) {
|
||||
loadCardsView();
|
||||
}
|
||||
updateSelectedCards();
|
||||
}
|
||||
projectsViewFilterChanged = false;
|
||||
});
|
||||
|
||||
initProjectsViewFilter();
|
||||
initProjectsViewModeSwitch();
|
||||
initSorting();
|
||||
|
|
14
app/assets/stylesheets/themes/projects.scss
Normal file
14
app/assets/stylesheets/themes/projects.scss
Normal file
|
@ -0,0 +1,14 @@
|
|||
@import "constants";
|
||||
|
||||
// Projects overview table
|
||||
|
||||
.projects-overview-table {
|
||||
.fas {
|
||||
color: $color-silver-chalice;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.archived {
|
||||
background-color: $color-concrete;
|
||||
}
|
||||
}
|
|
@ -49,6 +49,7 @@ class ProjectsController < ApplicationController
|
|||
end
|
||||
|
||||
def index_dt
|
||||
@draw = params[:draw].to_i
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
@current_team = current_team if current_team
|
||||
|
@ -93,10 +94,10 @@ class ProjectsController < ApplicationController
|
|||
)
|
||||
)
|
||||
|
||||
flash[:success] = t("projects.create.success_flash", name: @project.name)
|
||||
message = t('projects.create.success_flash', name: @project.name)
|
||||
respond_to do |format|
|
||||
format.json {
|
||||
render json: { url: projects_path }, status: :ok
|
||||
render json: { message: message }, status: :ok
|
||||
}
|
||||
end
|
||||
else
|
||||
|
|
|
@ -121,7 +121,7 @@ class ProjectsOverviewService
|
|||
def sort(records, params)
|
||||
order = params[:order]&.values&.first
|
||||
if order
|
||||
dir = order[:dir] == 'DESC' ? 'DESC' : 'ASC'
|
||||
dir = order[:dir] == 'desc' ? 'DESC' : 'ASC'
|
||||
column_index = order[:column]
|
||||
else
|
||||
dir = 'ASC'
|
||||
|
|
|
@ -121,7 +121,9 @@
|
|||
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="projects-cards-view" data-projects-url="<%= projects_path %>"></div>
|
||||
<div class="tab-pane" id="projects-table-view">Table view</div>
|
||||
<div class="tab-pane" id="projects-table-view">
|
||||
<%= render partial: "projects/index/team_projects_table" %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
|
|
@ -5,41 +5,7 @@
|
|||
data-project-users-tab-url="<%= url_for project_user_projects_path(project_id: project.id, format: :json) %>">
|
||||
<div class="panel-heading">
|
||||
|
||||
<% if (active && (can_manage_project?(project) || can_archive_project?(project))) || (!active && can_restore_project?(project)) %>
|
||||
<div class="dropdown pull-right">
|
||||
<button class="btn btn-link dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<% project_form = nil %>
|
||||
<%= form_for project, format: :json, method: :put, remote: true do |f| %>
|
||||
<% project_form = f %>
|
||||
<%= f.hidden_field :archived, value: active %>
|
||||
<% end %>
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenu1" style="top: 105%;">
|
||||
<li class="dropdown-header"><%= t('projects.index.options_header') %></li>
|
||||
<% if active && can_manage_project?(project) %>
|
||||
<li>
|
||||
<%= link_to t("projects.index.edit_option"), edit_project_path(project, format: :json), remote: true, "data-action" => "edit" %>
|
||||
</li>
|
||||
<% elsif active && can_archive_project?(project) %>
|
||||
<li>
|
||||
<a href="#"
|
||||
class="form-submit-link"
|
||||
data-turbolinks="false"
|
||||
data-submit-form="<%= project_form.options[:html][:id] %>"
|
||||
data-confirm-form="<%= t("projects.index.archive_confirm") %>"><%= t 'projects.index.archive_option' %></a>
|
||||
</li>
|
||||
<% else %>
|
||||
<li>
|
||||
<a href="#"
|
||||
class="form-submit-link"
|
||||
data-turbolinks="false"
|
||||
data-submit-form="<%= project_form.options[:html][:id] %>"><%= t 'projects.index.restore_option' %></a>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= render partial: "projects/index/project_actions_dropdown.html.erb", locals: { project: project } %>
|
||||
|
||||
<div class="pull-right">
|
||||
<input class="project-card-selector" type="checkbox" name="project-<%= project.id %>">
|
||||
|
|
39
app/views/projects/index/_project_actions_dropdown.html.erb
Normal file
39
app/views/projects/index/_project_actions_dropdown.html.erb
Normal file
|
@ -0,0 +1,39 @@
|
|||
<% cache project do %>
|
||||
<% active = !project.archived %>
|
||||
<% if (active && (can_manage_project?(project) || can_archive_project?(project))) || (!active && can_restore_project?(project)) %>
|
||||
<div class="dropdown pull-right">
|
||||
<button class="btn btn-link dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<% project_form = nil %>
|
||||
<%= form_for project, format: :json, method: :put, remote: true do |f| %>
|
||||
<% project_form = f %>
|
||||
<%= f.hidden_field :archived, value: active %>
|
||||
<% end %>
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenu1" style="top: 105%;">
|
||||
<li class="dropdown-header"><%= t('projects.index.options_header') %></li>
|
||||
<% if active && can_manage_project?(project) %>
|
||||
<li>
|
||||
<%= link_to t("projects.index.edit_option"), edit_project_path(project, format: :json), remote: true, "data-action" => "edit" %>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if active && can_archive_project?(project) %>
|
||||
<li>
|
||||
<a href="#"
|
||||
class="form-submit-link"
|
||||
data-turbolinks="false"
|
||||
data-submit-form="<%= project_form.options[:html][:id] %>"
|
||||
data-confirm-form="<%= t("projects.index.archive_confirm") %>"><%= t 'projects.index.archive_option' %></a>
|
||||
</li>
|
||||
<% elsif !active %>
|
||||
<li>
|
||||
<a href="#"
|
||||
class="form-submit-link"
|
||||
data-turbolinks="false"
|
||||
data-submit-form="<%= project_form.options[:html][:id] %>"><%= t 'projects.index.restore_option' %></a>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
21
app/views/projects/index/_team_projects_table.html.erb
Normal file
21
app/views/projects/index/_team_projects_table.html.erb
Normal file
|
@ -0,0 +1,21 @@
|
|||
<div class="projects-overview-table">
|
||||
<table id="projects-overview-table" class="table"
|
||||
data-source="<%= projects_index_dt_path %>">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><input name="select_all" value="1" type="checkbox"></th>
|
||||
<th><%= t("projects.table.status") %></th>
|
||||
<th><%= t("projects.table.name") %></th>
|
||||
<th><%= t("projects.table.start") %></th>
|
||||
<th><%= t("projects.table.visibility") %></th>
|
||||
<th><%= t("projects.table.users") %></th>
|
||||
<th><%= t("projects.table.experiments") %></th>
|
||||
<th><%= t("projects.table.tasks") %></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<%= stylesheet_link_tag 'datatables' %>
|
|
@ -1,28 +1,40 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
json.draw @draw
|
||||
json.recordsTotal @projects.total_count
|
||||
json.recordsFiltered @projects.length
|
||||
json.recordsFiltered @projects.total_count
|
||||
json.data do
|
||||
json.array! @projects do |project|
|
||||
json.set! 'DT_RowId', project.id
|
||||
json.set! '1', if project.archived
|
||||
'<i class="fas fa-archive"></i>' +
|
||||
I18n.t('projects.index.archived')
|
||||
else
|
||||
'<i class="fas fa-arrow-alt-circle-right"></i>' +
|
||||
I18n.t('projects.index.active')
|
||||
end
|
||||
json.set! '2', project.name
|
||||
json.set! '3', I18n.l(project.created_at, format: :full)
|
||||
json.set! '4', if project.visibility == 'hidden'
|
||||
'<i class="fas fa-eye-slash"></i>' +
|
||||
I18n.t('projects.index.hidden')
|
||||
else
|
||||
'<i class="fas fa-eye"></i>' +
|
||||
I18n.t('projects.index.visible')
|
||||
end
|
||||
json.set! '5', project.user_count
|
||||
json.set! '6', project.experiment_count
|
||||
json.set! '7', project.task_count
|
||||
json.set! 'DT_RowClass', project.archived ? 'archived' : ''
|
||||
json.set! 'status', if project.archived
|
||||
'<i class="fas fa-archive"></i>' +
|
||||
I18n.t('projects.index.archived')
|
||||
else
|
||||
'<i class="fas fa-arrow-alt-circle-right"></i>' +
|
||||
I18n.t('projects.index.active')
|
||||
end
|
||||
json.set! 'name', if project.archived
|
||||
escape_input(project.name)
|
||||
else
|
||||
link_to(escape_input(project.name),
|
||||
project_path(project),
|
||||
class: 'active-project-link')
|
||||
end
|
||||
json.set! 'start', I18n.l(project.created_at, format: :full)
|
||||
json.set! 'visibility', if project.visibility == 'hidden'
|
||||
'<i class="fas fa-eye-slash"></i>' +
|
||||
I18n.t('projects.index.hidden')
|
||||
else
|
||||
'<i class="fas fa-eye"></i>' +
|
||||
I18n.t('projects.index.visible')
|
||||
end
|
||||
json.set! 'users', project.user_count
|
||||
json.set! 'experiments', project.experiment_count
|
||||
json.set! 'tasks', project.task_count
|
||||
json.set! 'actions', render(
|
||||
partial: 'projects/index/project_actions_dropdown.html.erb',
|
||||
locals: { project: project }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -38,11 +38,11 @@
|
|||
<ul class="list-unstyled">
|
||||
<li>
|
||||
<div class="btn-group projects-view-mode-switch" data-toggle="buttons">
|
||||
<a class="btn btn-toggle active" href="#projects-cards-view" data-toggle="tab">
|
||||
<a class="btn btn-toggle active" href="#projects-cards-view" data-toggle="tab" data-mode="cards">
|
||||
<input type="radio" name="projects-view-mode-selector" value="cards">
|
||||
<i class="fas fa-th-large"></i>
|
||||
</a>
|
||||
<a class="btn btn-toggle" href="#projects-table-view" data-toggle="tab">
|
||||
<a class="btn btn-toggle" href="#projects-table-view" data-toggle="tab" data-mode="table">
|
||||
<input type="radio" name="projects-view-mode-selector" value="table">
|
||||
<i class="fas fa-th-list"></i>
|
||||
</a>
|
||||
|
|
|
@ -283,6 +283,14 @@ en:
|
|||
invite_users_link: "Invite users"
|
||||
invite_users_details: "to team %{team}."
|
||||
contact_admins: "To invite additional users to team %{team}, contact its administrator/s."
|
||||
table:
|
||||
status: "Status"
|
||||
name: "Project name"
|
||||
start: "Start date"
|
||||
visibility: "Visible to"
|
||||
users: "Users"
|
||||
experiments: "Experiments"
|
||||
tasks: "Tasks"
|
||||
create:
|
||||
success_flash: "Project <strong>%{name}</strong> successfully created."
|
||||
update:
|
||||
|
|
|
@ -193,7 +193,7 @@ Rails.application.routes.draw do
|
|||
end
|
||||
|
||||
get 'projects/archive', to: 'projects#archive', as: 'projects_archive'
|
||||
get 'projects/index_dt', to: 'projects#index_dt', as: 'projects_index_dt'
|
||||
post 'projects/index_dt', to: 'projects#index_dt', as: 'projects_index_dt'
|
||||
|
||||
resources :reports, only: :index
|
||||
get 'reports/datatable', to: 'reports#datatable'
|
||||
|
|
Loading…
Reference in a new issue