mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-06 13:14:29 +08:00
Implement user state saving for projects overview [SCI-2733]
This commit is contained in:
parent
7a591273a3
commit
af02f29fb5
18 changed files with 9348 additions and 89247 deletions
|
@ -30,7 +30,6 @@
|
|||
//= require jsnetworkx
|
||||
//= require bootstrap-select
|
||||
//= require_directory ./sitewide
|
||||
//= require jquery.dataTables.yadcf
|
||||
//= require datatables
|
||||
//= require ajax-bootstrap-select.min
|
||||
//= require underscore
|
||||
|
@ -267,4 +266,4 @@ var HelperModule = (function(){
|
|||
$(document).on('turbolinks:load', function() {
|
||||
$(window).trigger('load.bs.select.data-api');
|
||||
});
|
||||
})();
|
||||
})();
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
var projectsViewFilter = $('.projects-view-filter.active').data('filter');
|
||||
var projectsViewFilterChanged = false;
|
||||
var projectsChanged = false;
|
||||
var projectsViewSort = 'new';
|
||||
var projectsViewSort = $('#sortMenuDropdown a.disabled').data('sort');
|
||||
|
||||
var TABLE;
|
||||
|
||||
|
@ -524,7 +524,7 @@
|
|||
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,
|
||||
stateSave: true,
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
scrollY: '64vh',
|
||||
|
@ -604,14 +604,18 @@
|
|||
initRowSelection();
|
||||
initFormSubmitLinks($(this));
|
||||
},
|
||||
stateLoadCallback: function() {
|
||||
// to be implemented
|
||||
stateLoadCallback: function(settings, callback) {
|
||||
$.ajax({
|
||||
url: $(TABLE_ID).data('state-load-source'),
|
||||
dataType: 'json',
|
||||
type: 'GET',
|
||||
success: function(json) {
|
||||
callback(json.state);
|
||||
}
|
||||
});
|
||||
},
|
||||
stateSaveCallback: function(settings, data) {
|
||||
// to be implemented
|
||||
},
|
||||
fnInitComplete: function() {
|
||||
// to be implemented
|
||||
stateSaveCallback: function() {
|
||||
// Don't do anything, state will be updated at backend, based on params
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -29,8 +29,9 @@ class ProjectsController < ApplicationController
|
|||
format.json do
|
||||
@current_team = current_team if current_team
|
||||
@current_team ||= current_user.teams.first
|
||||
@projects = ProjectsOverviewService.new(@current_team, current_user)
|
||||
.project_cards(params)
|
||||
@projects = ProjectsOverviewService
|
||||
.new(@current_team, current_user, params)
|
||||
.project_cards
|
||||
render json: {
|
||||
html: render_to_string(
|
||||
partial: 'projects/index/team_projects.html.erb',
|
||||
|
@ -43,6 +44,10 @@ class ProjectsController < ApplicationController
|
|||
@teams = current_user.teams
|
||||
# New project for create new project modal
|
||||
@project = Project.new
|
||||
view_state =
|
||||
current_team.current_view_state(current_user)
|
||||
@current_filter = view_state.state['filter']
|
||||
@current_sort = view_state.state.dig('cards', 'sort')
|
||||
load_projects_tree
|
||||
end
|
||||
end
|
||||
|
@ -54,8 +59,9 @@ class ProjectsController < ApplicationController
|
|||
format.json do
|
||||
@current_team = current_team if current_team
|
||||
@current_team ||= current_user.teams.first
|
||||
@projects = ProjectsOverviewService.new(@current_team, current_user)
|
||||
.projects_datatable(params)
|
||||
@projects = ProjectsOverviewService
|
||||
.new(@current_team, current_user, params)
|
||||
.projects_datatable
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -313,6 +319,16 @@ class ProjectsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def dt_state_load
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
render json: {
|
||||
state: current_team.current_view_state(current_user).state['table']
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
include FirstTimeDataGenerator
|
||||
|
@ -338,9 +354,8 @@ class ProjectsController < ApplicationController
|
|||
def load_projects_tree
|
||||
if current_user.teams.any?
|
||||
@current_team = current_team if current_team
|
||||
|
||||
@current_team ||= current_user.teams.first
|
||||
@current_sort = params[:sort].to_s
|
||||
@current_sort ||= 'new'
|
||||
@projects_tree = current_user.projects_tree(@current_team, @current_sort)
|
||||
else
|
||||
@projects_tree = []
|
||||
|
|
|
@ -35,11 +35,28 @@ class Team < ApplicationRecord
|
|||
has_many :reports, inverse_of: :team, dependent: :destroy
|
||||
has_many :datatables_reports,
|
||||
class_name: 'Views::Datatables::DatatablesReport'
|
||||
has_many :view_states, as: :viewable, dependent: :destroy
|
||||
|
||||
after_commit do
|
||||
Views::Datatables::DatatablesReport.refresh_materialized_view
|
||||
end
|
||||
|
||||
def current_view_state(user)
|
||||
state = view_states.where(user: user).take
|
||||
state || view_states.create!(user: user, state: default_view_state)
|
||||
end
|
||||
|
||||
def default_view_state
|
||||
{ filter: 'active',
|
||||
cards: { sort: 'new' },
|
||||
table: {
|
||||
'start': 0,
|
||||
'length': 10,
|
||||
'order' => [2, 'asc'],
|
||||
'time': Time.new.to_i
|
||||
} }
|
||||
end
|
||||
|
||||
def search_users(query = nil)
|
||||
a_query = "%#{query}%"
|
||||
users.where.not(confirmed_at: nil)
|
||||
|
|
11
app/models/view_state.rb
Normal file
11
app/models/view_state.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal:true
|
||||
|
||||
class ViewState < ApplicationRecord
|
||||
belongs_to :user
|
||||
belongs_to :viewable, polymorphic: true
|
||||
|
||||
validates :viewable_id, uniqueness: {
|
||||
scope: %i(viewable_type user_id),
|
||||
message: :not_unique
|
||||
}
|
||||
end
|
|
@ -1,17 +1,30 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ProjectsOverviewService
|
||||
def initialize(team, user)
|
||||
def initialize(team, user, params)
|
||||
@team = team
|
||||
@user = user
|
||||
@params = params
|
||||
@view_state = @team.current_view_state(@user)
|
||||
if @view_state.state['filter'] != @params[:filter] &&
|
||||
%w(active archived all).include?(@params[:filter])
|
||||
@view_state.state['filter'] = @params[:filter]
|
||||
end
|
||||
end
|
||||
|
||||
def project_cards(params)
|
||||
def project_cards
|
||||
cards_state = @view_state.state['cards']
|
||||
records = fetch_records
|
||||
records = records.where(archived: true) if params[:filter] == 'archived'
|
||||
records = records.where(archived: false) if params[:filter] == 'active'
|
||||
return records unless params[:sort]
|
||||
case params[:sort]
|
||||
records = records.where(archived: true) if @params[:filter] == 'archived'
|
||||
records = records.where(archived: false) if @params[:filter] == 'active'
|
||||
if @params[:sort] &&
|
||||
cards_state['sort'] != @params[:sort] &&
|
||||
%w(new old atoz ztoa).include?(@params[:sort])
|
||||
cards_state['sort'] = @params[:sort]
|
||||
@view_state.state['cards'] = cards_state
|
||||
end
|
||||
@view_state.save! if @view_state.changed?
|
||||
case cards_state['sort']
|
||||
when 'new'
|
||||
records.order(created_at: :desc)
|
||||
when 'old'
|
||||
|
@ -25,15 +38,19 @@ class ProjectsOverviewService
|
|||
end
|
||||
end
|
||||
|
||||
def projects_datatable(params)
|
||||
per_page = params[:length] == '-1' ? 10 : params[:length].to_i
|
||||
page = params[:start] ? (params[:start].to_i / per_page) + 1 : 1
|
||||
def projects_datatable
|
||||
table_state = @view_state.state['table']
|
||||
per_page = @params[:length] == '-1' ? 10 : @params[:length].to_i
|
||||
table_state['length'] = per_page if table_state['length'] != per_page
|
||||
page = @params[:start] ? (@params[:start].to_i / per_page) + 1 : 1
|
||||
records = fetch_dt_records
|
||||
records = records.where(archived: true) if params[:filter] == 'archived'
|
||||
records = records.where(archived: false) if params[:filter] == 'active'
|
||||
search_value = params.dig(:search, :value)
|
||||
records = records.where(archived: true) if @params[:filter] == 'archived'
|
||||
records = records.where(archived: false) if @params[:filter] == 'active'
|
||||
search_value = @params.dig(:search, :value)
|
||||
records = search(records, search_value) if search_value.present?
|
||||
sort(records, params).page(page).per(per_page)
|
||||
records = sort(records).page(page).per(per_page)
|
||||
@view_state.save! if @view_state.changed?
|
||||
records
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -118,8 +135,9 @@ class ProjectsOverviewService
|
|||
}
|
||||
end
|
||||
|
||||
def sort(records, params)
|
||||
order = params[:order]&.values&.first
|
||||
def sort(records)
|
||||
order_state = @view_state.state['table']['order'][0]
|
||||
order = @params[:order]&.values&.first
|
||||
if order
|
||||
dir = order[:dir] == 'desc' ? 'DESC' : 'ASC'
|
||||
column_index = order[:column]
|
||||
|
@ -127,6 +145,9 @@ class ProjectsOverviewService
|
|||
dir = 'ASC'
|
||||
column_index = '1'
|
||||
end
|
||||
if order_state != [column_index.to_i, dir.downcase]
|
||||
@view_state.state['table']['order'][0] = [column_index.to_i, dir.downcase]
|
||||
end
|
||||
sort_column = sortable_columns[column_index]
|
||||
sort_column ||= sortable_columns['1']
|
||||
records.order("#{sort_column} #{dir}")
|
||||
|
|
|
@ -100,17 +100,13 @@
|
|||
</button>
|
||||
<ul id="sortMenuDropdown" class="dropdown-menu" aria-labelledby="sortMenu">
|
||||
<% ["new", "old", "atoz", "ztoa"].each do |sort| %>
|
||||
<% if @current_sort != sort %>
|
||||
<li>
|
||||
<a class="<%= 'disabled' if sort == 'new' %>" href="#" data-sort="<%= sort %>">
|
||||
<%= t('projects.index.sort_' + sort) %>
|
||||
</a>
|
||||
</li>
|
||||
<% else %>
|
||||
<li >
|
||||
<a class="disabled" href="#"><%= t('projects.index.sort_' + sort) %></a>
|
||||
</li>
|
||||
<% end %>
|
||||
<li>
|
||||
<% if @current_sort != sort %>
|
||||
<a href="#" data-sort="<%= sort %>"><%= t('projects.index.sort_' + sort) %></a>
|
||||
<% else %>
|
||||
<a class="disabled" href="#" data-sort="<%= sort %>"><%= t('projects.index.sort_' + sort) %></a>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<div class="projects-overview-table">
|
||||
<table id="projects-overview-table" class="table"
|
||||
data-source="<%= projects_index_dt_path %>">
|
||||
data-source="<%= projects_index_dt_path %>"
|
||||
data-state-load-source="<%= projects_dt_state_load_path %>">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><input name="select_all" value="1" type="checkbox"></th>
|
||||
|
|
|
@ -19,17 +19,23 @@
|
|||
<ul class="nav navbar-nav navbar-right" style="vertical-align: bottom">
|
||||
<% if all_projects_page? %>
|
||||
<% if can_read_team?(current_team) %>
|
||||
<li id="projects-active-nav-tab" class="active projects-view-filter" data-filter="active">
|
||||
<li id="projects-active-nav-tab"
|
||||
class="<%= 'active' if @current_filter == 'active' %> projects-view-filter"
|
||||
data-filter="active">
|
||||
<a href="#" title="<%=t "nav2.all_projects.index" %>">
|
||||
<span><%=t "nav2.all_projects.index" %></span>
|
||||
</a>
|
||||
</li>
|
||||
<li id="projects-archive-nav-tab" class="projects-view-filter" data-filter="archived">
|
||||
<li id="projects-archive-nav-tab"
|
||||
class="<%= 'active' if @current_filter == 'archived' %> projects-view-filter"
|
||||
data-filter="archived">
|
||||
<a href="#" title="<%=t "nav2.all_projects.archive" %>">
|
||||
<span><%=t "nav2.all_projects.archive" %></span>
|
||||
</a>
|
||||
</li>
|
||||
<li id="projects-all-nav-tab" class="projects-view-filter" data-filter="all">
|
||||
<li id="projects-all-nav-tab"
|
||||
class="<%= 'active' if @current_filter == 'all' %> projects-view-filter"
|
||||
data-filter="all">
|
||||
<a href="#" title="<%=t "nav2.all_projects.all" %>">
|
||||
<span><%=t "nav2.all_projects.all" %></span>
|
||||
</a>
|
||||
|
|
|
@ -59,6 +59,11 @@ en:
|
|||
attributes:
|
||||
name:
|
||||
taken: "This project name has to be unique inside a team (this includes the archive)."
|
||||
view_state:
|
||||
attributes:
|
||||
viewable_id:
|
||||
not_unique: "State already exists for this user and parent object"
|
||||
|
||||
helpers:
|
||||
label:
|
||||
team:
|
||||
|
|
|
@ -189,6 +189,8 @@ Rails.application.routes.draw do
|
|||
|
||||
get 'projects/archive', to: 'projects#archive', as: 'projects_archive'
|
||||
post 'projects/index_dt', to: 'projects#index_dt', as: 'projects_index_dt'
|
||||
get 'projects/dt_state_load', to: 'projects#dt_state_load',
|
||||
as: 'projects_dt_state_load'
|
||||
|
||||
resources :reports, only: :index
|
||||
get 'reports/datatable', to: 'reports#datatable'
|
||||
|
|
13
db/migrate/20181008130519_create_view_states.rb
Normal file
13
db/migrate/20181008130519_create_view_states.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal:true
|
||||
|
||||
class CreateViewStates < ActiveRecord::Migration[5.1]
|
||||
def change
|
||||
create_table :view_states do |t|
|
||||
t.jsonb :state
|
||||
t.references :user, foreign_key: true
|
||||
t.references :viewable, polymorphic: true
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
14
db/schema.rb
14
db/schema.rb
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20180524091143) do
|
||||
ActiveRecord::Schema.define(version: 20181008130519) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -796,6 +796,17 @@ ActiveRecord::Schema.define(version: 20180524091143) do
|
|||
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
|
||||
end
|
||||
|
||||
create_table "view_states", force: :cascade do |t|
|
||||
t.jsonb "state"
|
||||
t.bigint "user_id"
|
||||
t.string "viewable_type"
|
||||
t.bigint "viewable_id"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["user_id"], name: "index_view_states_on_user_id"
|
||||
t.index ["viewable_type", "viewable_id"], name: "index_view_states_on_viewable_type_and_viewable_id"
|
||||
end
|
||||
|
||||
create_table "wopi_actions", id: :serial, force: :cascade do |t|
|
||||
t.string "action", null: false
|
||||
t.string "extension", null: false
|
||||
|
@ -959,6 +970,7 @@ ActiveRecord::Schema.define(version: 20180524091143) do
|
|||
add_foreign_key "user_teams", "users"
|
||||
add_foreign_key "user_teams", "users", column: "assigned_by_id"
|
||||
add_foreign_key "users", "teams", column: "current_team_id"
|
||||
add_foreign_key "view_states", "users"
|
||||
add_foreign_key "wopi_actions", "wopi_apps"
|
||||
add_foreign_key "wopi_apps", "wopi_discoveries"
|
||||
add_foreign_key "zip_exports", "users"
|
||||
|
|
9
spec/factories/view_states.rb
Normal file
9
spec/factories/view_states.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :view_state do
|
||||
state {}
|
||||
user { User.first || create(:user) }
|
||||
viewable { Team.first || create(:team) }
|
||||
end
|
||||
end
|
28
spec/models/view_state_spec.rb
Normal file
28
spec/models/view_state_spec.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ViewState, type: :model do
|
||||
it 'should be of class ViewState' do
|
||||
expect(subject.class).to eq ViewState
|
||||
end
|
||||
|
||||
describe 'Database table' do
|
||||
it { should have_db_column :state }
|
||||
it { should have_db_column :user_id }
|
||||
it { should have_db_column :viewable_type }
|
||||
it { should have_db_column :viewable_id }
|
||||
it { should have_db_column :created_at }
|
||||
it { should have_db_column :updated_at }
|
||||
end
|
||||
|
||||
describe 'Relations' do
|
||||
it { should belong_to :user }
|
||||
it { should belong_to :viewable }
|
||||
end
|
||||
|
||||
describe 'Should be a valid object' do
|
||||
it { should validate_presence_of :user }
|
||||
it { should validate_presence_of :viewable }
|
||||
end
|
||||
end
|
93577
vendor/assets/javascripts/datatables.js
vendored
93577
vendor/assets/javascripts/datatables.js
vendored
File diff suppressed because one or more lines are too long
4409
vendor/assets/javascripts/jquery.dataTables.yadcf.js
vendored
4409
vendor/assets/javascripts/jquery.dataTables.yadcf.js
vendored
File diff suppressed because it is too large
Load diff
374
vendor/assets/stylesheets/datatables.css
vendored
374
vendor/assets/stylesheets/datatables.css
vendored
|
@ -4,10 +4,10 @@
|
|||
*
|
||||
* To rebuild or modify this file with the latest versions of the included
|
||||
* software please visit:
|
||||
* https://datatables.net/download/#bs/jszip-2.5.0,pdfmake-0.1.18,dt-1.10.8,b-1.0.1,b-colvis-1.0.1,b-flash-1.0.1,b-html5-1.0.1,b-print-1.0.1,cr-1.2.0,r-1.0.7,rr-1.0.0,se-1.0.0
|
||||
* https://datatables.net/download/#bs/dt-1.10.18/b-1.5.4/b-colvis-1.5.4/b-html5-1.5.4/b-print-1.5.4/cr-1.5.0/r-2.2.2
|
||||
*
|
||||
* Included libraries:
|
||||
* JSZip 2.5.0, pdfmake 0.1.18, DataTables 1.10.8, Buttons 1.0.1, Column visibility 1.0.1, Flash export 1.0.1, HTML5 export 1.0.1, Print view 1.0.1, ColReorder 1.2.0, Responsive 1.0.7, RowReorder 1.0.0, Select 1.0.0
|
||||
* DataTables 1.10.18, Buttons 1.5.4, Column visibility 1.5.4, HTML5 export 1.5.4, Print view 1.5.4, ColReorder 1.5.0, Responsive 2.2.2
|
||||
*/
|
||||
|
||||
table.dataTable {
|
||||
|
@ -15,13 +15,17 @@ table.dataTable {
|
|||
margin-top: 6px !important;
|
||||
margin-bottom: 6px !important;
|
||||
max-width: none !important;
|
||||
border-collapse: separate !important;
|
||||
}
|
||||
table.dataTable td,
|
||||
table.dataTable th {
|
||||
-webkit-box-sizing: content-box;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
table.dataTable td.dataTables_empty,
|
||||
table.dataTable th.dataTables_empty {
|
||||
text-align: center;
|
||||
}
|
||||
table.dataTable.nowrap th,
|
||||
table.dataTable.nowrap td {
|
||||
white-space: nowrap;
|
||||
|
@ -62,9 +66,21 @@ div.dataTables_wrapper div.dataTables_paginate ul.pagination {
|
|||
margin: 2px 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_processing {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 200px;
|
||||
margin-left: -100px;
|
||||
margin-top: -26px;
|
||||
text-align: center;
|
||||
padding: 1em 0;
|
||||
}
|
||||
|
||||
table.dataTable thead > tr > th,
|
||||
table.dataTable thead > tr > td {
|
||||
table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting,
|
||||
table.dataTable thead > tr > td.sorting_asc,
|
||||
table.dataTable thead > tr > td.sorting_desc,
|
||||
table.dataTable thead > tr > td.sorting {
|
||||
padding-right: 30px;
|
||||
}
|
||||
table.dataTable thead > tr > th:active,
|
||||
|
@ -113,22 +129,25 @@ div.dataTables_scrollHead table.dataTable {
|
|||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
div.dataTables_scrollBody table {
|
||||
div.dataTables_scrollBody > table {
|
||||
border-top: none;
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
div.dataTables_scrollBody table thead .sorting:after,
|
||||
div.dataTables_scrollBody table thead .sorting_asc:after,
|
||||
div.dataTables_scrollBody table thead .sorting_desc:after {
|
||||
div.dataTables_scrollBody > table > thead .sorting:after,
|
||||
div.dataTables_scrollBody > table > thead .sorting_asc:after,
|
||||
div.dataTables_scrollBody > table > thead .sorting_desc:after {
|
||||
display: none;
|
||||
}
|
||||
div.dataTables_scrollBody table tbody tr:first-child th,
|
||||
div.dataTables_scrollBody table tbody tr:first-child td {
|
||||
div.dataTables_scrollBody > table > tbody > tr:first-child > th,
|
||||
div.dataTables_scrollBody > table > tbody > tr:first-child > td {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
div.dataTables_scrollFoot table {
|
||||
div.dataTables_scrollFoot > .dataTables_scrollFootInner {
|
||||
box-sizing: content-box;
|
||||
}
|
||||
div.dataTables_scrollFoot > .dataTables_scrollFootInner > table {
|
||||
margin-top: 0 !important;
|
||||
border-top: none;
|
||||
}
|
||||
|
@ -151,9 +170,6 @@ table.dataTable.table-condensed .sorting_desc:after {
|
|||
right: 6px;
|
||||
}
|
||||
|
||||
table.table-bordered.dataTable {
|
||||
border-collapse: separate !important;
|
||||
}
|
||||
table.table-bordered.dataTable th,
|
||||
table.table-bordered.dataTable td {
|
||||
border-left-width: 0;
|
||||
|
@ -172,7 +188,46 @@ div.dataTables_scrollHead table.table-bordered {
|
|||
border-bottom-width: 0;
|
||||
}
|
||||
|
||||
div.table-responsive > div.dataTables_wrapper > div.row {
|
||||
margin: 0;
|
||||
}
|
||||
div.table-responsive > div.dataTables_wrapper > div.row > div[class^="col-"]:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
div.table-responsive > div.dataTables_wrapper > div.row > div[class^="col-"]:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
|
||||
@keyframes dtb-spinner {
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@-o-keyframes dtb-spinner {
|
||||
100% {
|
||||
-o-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@-ms-keyframes dtb-spinner {
|
||||
100% {
|
||||
-ms-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes dtb-spinner {
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@-moz-keyframes dtb-spinner {
|
||||
100% {
|
||||
-moz-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
div.dt-button-info {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
|
@ -198,6 +253,12 @@ div.dt-button-info > div {
|
|||
padding: 1em;
|
||||
}
|
||||
|
||||
div.dt-button-collection-title {
|
||||
text-align: center;
|
||||
padding: 0.3em 0 0.5em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
ul.dt-button-collection.dropdown-menu {
|
||||
display: block;
|
||||
z-index: 2002;
|
||||
|
@ -212,6 +273,7 @@ ul.dt-button-collection.dropdown-menu.fixed {
|
|||
top: 50%;
|
||||
left: 50%;
|
||||
margin-left: -75px;
|
||||
border-radius: 0;
|
||||
}
|
||||
ul.dt-button-collection.dropdown-menu.fixed.two-column {
|
||||
margin-left: -150px;
|
||||
|
@ -253,6 +315,9 @@ ul.dt-button-collection.dropdown-menu.four-column {
|
|||
-o-column-count: 4;
|
||||
column-count: 4;
|
||||
}
|
||||
ul.dt-button-collection.dropdown-menu .dt-button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
div.dt-button-background {
|
||||
position: fixed;
|
||||
|
@ -263,8 +328,48 @@ div.dt-button-background {
|
|||
z-index: 2001;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
div.dt-buttons {
|
||||
float: none;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
div.dt-buttons a.btn {
|
||||
float: none;
|
||||
}
|
||||
}
|
||||
div.dt-buttons button.btn.processing,
|
||||
div.dt-buttons div.btn.processing,
|
||||
div.dt-buttons a.btn.processing {
|
||||
color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
div.dt-buttons button.btn.processing:after,
|
||||
div.dt-buttons div.btn.processing:after,
|
||||
div.dt-buttons a.btn.processing:after {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: -8px 0 0 -8px;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
content: ' ';
|
||||
border: 2px solid #282828;
|
||||
border-radius: 50%;
|
||||
border-left-color: transparent;
|
||||
border-right-color: transparent;
|
||||
animation: dtb-spinner 1500ms infinite linear;
|
||||
-o-animation: dtb-spinner 1500ms infinite linear;
|
||||
-ms-animation: dtb-spinner 1500ms infinite linear;
|
||||
-webkit-animation: dtb-spinner 1500ms infinite linear;
|
||||
-moz-animation: dtb-spinner 1500ms infinite linear;
|
||||
}
|
||||
|
||||
table.DTCR_clonedTable {
|
||||
|
||||
table.DTCR_clonedTable.dataTable {
|
||||
position: absolute !important;
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
z-index: 202;
|
||||
}
|
||||
|
@ -276,42 +381,47 @@ div.DTCR_pointer {
|
|||
}
|
||||
|
||||
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child,
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child {
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > td.child,
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > th.child,
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty {
|
||||
cursor: default !important;
|
||||
}
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before,
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before,
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before {
|
||||
display: none !important;
|
||||
}
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr[role="row"] > td:first-child,
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr[role="row"] > th:first-child {
|
||||
position: relative;
|
||||
padding-left: 30px;
|
||||
cursor: pointer;
|
||||
}
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child:before,
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child:before {
|
||||
top: 8px;
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr[role="row"] > td:first-child:before,
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr[role="row"] > th:first-child:before {
|
||||
top: 9px;
|
||||
left: 4px;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
display: block;
|
||||
position: absolute;
|
||||
color: white;
|
||||
border: 2px solid white;
|
||||
border-radius: 16px;
|
||||
text-align: center;
|
||||
line-height: 14px;
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 0 3px #444;
|
||||
box-sizing: content-box;
|
||||
text-align: center;
|
||||
text-indent: 0 !important;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
line-height: 14px;
|
||||
content: '+';
|
||||
background-color: #337ab7;
|
||||
}
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child.dataTables_empty:before,
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child.dataTables_empty:before {
|
||||
display: none;
|
||||
}
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before,
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child:before {
|
||||
content: '-';
|
||||
background-color: #d33333;
|
||||
}
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr.child td:before {
|
||||
display: none;
|
||||
}
|
||||
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child,
|
||||
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child {
|
||||
padding-left: 27px;
|
||||
|
@ -323,7 +433,8 @@ table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child:befor
|
|||
height: 14px;
|
||||
width: 14px;
|
||||
border-radius: 14px;
|
||||
line-height: 12px;
|
||||
line-height: 14px;
|
||||
text-indent: 3px;
|
||||
}
|
||||
table.dataTable.dtr-column > tbody > tr > td.control,
|
||||
table.dataTable.dtr-column > tbody > tr > th.control {
|
||||
|
@ -342,11 +453,13 @@ table.dataTable.dtr-column > tbody > tr > th.control:before {
|
|||
position: absolute;
|
||||
color: white;
|
||||
border: 2px solid white;
|
||||
border-radius: 16px;
|
||||
text-align: center;
|
||||
line-height: 14px;
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 0 3px #444;
|
||||
box-sizing: content-box;
|
||||
text-align: center;
|
||||
text-indent: 0 !important;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
line-height: 14px;
|
||||
content: '+';
|
||||
background-color: #337ab7;
|
||||
}
|
||||
|
@ -361,20 +474,20 @@ table.dataTable > tbody > tr.child {
|
|||
table.dataTable > tbody > tr.child:hover {
|
||||
background: transparent !important;
|
||||
}
|
||||
table.dataTable > tbody > tr.child ul {
|
||||
table.dataTable > tbody > tr.child ul.dtr-details {
|
||||
display: inline-block;
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
table.dataTable > tbody > tr.child ul li {
|
||||
table.dataTable > tbody > tr.child ul.dtr-details > li {
|
||||
border-bottom: 1px solid #efefef;
|
||||
padding: 0.5em 0;
|
||||
}
|
||||
table.dataTable > tbody > tr.child ul li:first-child {
|
||||
table.dataTable > tbody > tr.child ul.dtr-details > li:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
table.dataTable > tbody > tr.child ul li:last-child {
|
||||
table.dataTable > tbody > tr.child ul.dtr-details > li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
table.dataTable > tbody > tr.child span.dtr-title {
|
||||
|
@ -383,139 +496,70 @@ table.dataTable > tbody > tr.child span.dtr-title {
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
table.dt-rowReorder-float {
|
||||
position: absolute !important;
|
||||
opacity: 0.8;
|
||||
table-layout: static;
|
||||
outline: 2px solid #337ab7;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
tr.dt-rowReorder-moving {
|
||||
outline: 2px solid #888;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
body.dt-rowReorder-noOverflow {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
table.dataTable td.reorder {
|
||||
text-align: center;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
|
||||
table.dataTable tbody > tr.selected,
|
||||
table.dataTable tbody > tr > .selected {
|
||||
background-color: #08C;
|
||||
}
|
||||
table.dataTable.stripe tbody > tr.odd.selected,
|
||||
table.dataTable.stripe tbody > tr.odd > .selected, table.dataTable.display tbody > tr.odd.selected,
|
||||
table.dataTable.display tbody > tr.odd > .selected {
|
||||
background-color: #0085c7;
|
||||
}
|
||||
table.dataTable.hover tbody > tr.selected:hover,
|
||||
table.dataTable.hover tbody > tr > .selected:hover, table.dataTable.display tbody > tr.selected:hover,
|
||||
table.dataTable.display tbody > tr > .selected:hover {
|
||||
background-color: #0083c5;
|
||||
}
|
||||
table.dataTable.order-column tbody > tr.selected > .sorting_1,
|
||||
table.dataTable.order-column tbody > tr.selected > .sorting_2,
|
||||
table.dataTable.order-column tbody > tr.selected > .sorting_3,
|
||||
table.dataTable.order-column tbody > tr > .selected, table.dataTable.display tbody > tr.selected > .sorting_1,
|
||||
table.dataTable.display tbody > tr.selected > .sorting_2,
|
||||
table.dataTable.display tbody > tr.selected > .sorting_3,
|
||||
table.dataTable.display tbody > tr > .selected {
|
||||
background-color: #0085c8;
|
||||
}
|
||||
table.dataTable.display tbody > tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_1 {
|
||||
background-color: #0081c1;
|
||||
}
|
||||
table.dataTable.display tbody > tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_2 {
|
||||
background-color: #0082c2;
|
||||
}
|
||||
table.dataTable.display tbody > tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_3 {
|
||||
background-color: #0083c4;
|
||||
}
|
||||
table.dataTable.display tbody > tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_1 {
|
||||
background-color: #0085c8;
|
||||
}
|
||||
table.dataTable.display tbody > tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_2 {
|
||||
background-color: #0086ca;
|
||||
}
|
||||
table.dataTable.display tbody > tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_3 {
|
||||
background-color: #0087cb;
|
||||
}
|
||||
table.dataTable.display tbody > tr.odd > .selected, table.dataTable.order-column.stripe tbody > tr.odd > .selected {
|
||||
background-color: #0081c1;
|
||||
}
|
||||
table.dataTable.display tbody > tr.even > .selected, table.dataTable.order-column.stripe tbody > tr.even > .selected {
|
||||
background-color: #0085c8;
|
||||
}
|
||||
table.dataTable.display tbody > tr.selected:hover > .sorting_1, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_1 {
|
||||
background-color: #007dbb;
|
||||
}
|
||||
table.dataTable.display tbody > tr.selected:hover > .sorting_2, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_2 {
|
||||
background-color: #007ebd;
|
||||
}
|
||||
table.dataTable.display tbody > tr.selected:hover > .sorting_3, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_3 {
|
||||
background-color: #007fbf;
|
||||
}
|
||||
table.dataTable.display tbody > tr:hover > .selected,
|
||||
table.dataTable.display tbody > tr > .selected:hover, table.dataTable.order-column.hover tbody > tr:hover > .selected,
|
||||
table.dataTable.order-column.hover tbody > tr > .selected:hover {
|
||||
background-color: #007dbb;
|
||||
}
|
||||
table.dataTable td.select-checkbox {
|
||||
position: relative;
|
||||
}
|
||||
table.dataTable td.select-checkbox:before, table.dataTable td.select-checkbox:after {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 1.2em;
|
||||
left: 50%;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
div.dtr-modal {
|
||||
position: fixed;
|
||||
box-sizing: border-box;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
z-index: 100;
|
||||
padding: 10em 1em;
|
||||
}
|
||||
table.dataTable td.select-checkbox:before {
|
||||
content: ' ';
|
||||
margin-top: -6px;
|
||||
margin-left: -6px;
|
||||
div.dtr-modal div.dtr-modal-display {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
overflow: auto;
|
||||
margin: auto;
|
||||
z-index: 102;
|
||||
overflow: auto;
|
||||
background-color: #f5f5f7;
|
||||
border: 1px solid black;
|
||||
border-radius: 3px;
|
||||
border-radius: 0.5em;
|
||||
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
table.dataTable tr.selected td.select-checkbox:after {
|
||||
content: '\2714';
|
||||
margin-top: -11px;
|
||||
margin-left: -4px;
|
||||
div.dtr-modal div.dtr-modal-content {
|
||||
position: relative;
|
||||
padding: 1em;
|
||||
}
|
||||
div.dtr-modal div.dtr-modal-close {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 6px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border: 1px solid #eaeaea;
|
||||
background-color: #f9f9f9;
|
||||
text-align: center;
|
||||
text-shadow: 1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
z-index: 12;
|
||||
}
|
||||
div.dtr-modal div.dtr-modal-close:hover {
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
div.dtr-modal div.dtr-modal-background {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 101;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
div.dataTables_wrapper span.select-info,
|
||||
div.dataTables_wrapper span.select-item {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 640px) {
|
||||
div.dataTables_wrapper span.select-info,
|
||||
div.dataTables_wrapper span.select-item {
|
||||
margin-left: 0;
|
||||
display: block;
|
||||
@media screen and (max-width: 767px) {
|
||||
div.dtr-modal div.dtr-modal-display {
|
||||
width: 95%;
|
||||
}
|
||||
}
|
||||
table.dataTable tbody tr.selected,
|
||||
table.dataTable tbody th.selected,
|
||||
table.dataTable tbody td.selected {
|
||||
color: white;
|
||||
}
|
||||
table.dataTable tbody tr.selected a,
|
||||
table.dataTable tbody th.selected a,
|
||||
table.dataTable tbody td.selected a {
|
||||
color: #a2d4ed;
|
||||
div.dtr-bs-modal table.table tr:first-child td {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue