Description:
manage
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r877:93c4562b9761 - - The requested commit is too big and content was truncated. 14 files changed. Show full diff

new file 100644
@@ -1,1 +1,5
1 $font-size-base: 0.875rem;
1 $font-size-base: 0.875rem;
2 +
3 + $primary: #0074d9;
4 + //$danger: #ff4136;
5 +
@@ -1,85 +1,86
1 require 'csv'
1 require 'csv'
2
2
3 class UserAdminController < ApplicationController
3 class UserAdminController < ApplicationController
4
4
5 include MailHelperMethods
5 include MailHelperMethods
6
6
7 before_action :admin_authorization
7 before_action :admin_authorization
8
8
9 def index
9 def index
10 @user_count = User.count
10 @user_count = User.count
11 @users = User.all
11 @users = User.all
12 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
12 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
13 @contests = Contest.enabled
13 @contests = Contest.enabled
14 @user = User.new
14 @user = User.new
15 end
15 end
16
16
17 def active
17 def active
18 sessions = ActiveRecord::SessionStore::Session.where("updated_at >= ?", 60.minutes.ago)
18 sessions = ActiveRecord::SessionStore::Session.where("updated_at >= ?", 60.minutes.ago)
19 @users = []
19 @users = []
20 sessions.each do |session|
20 sessions.each do |session|
21 if session.data[:user_id]
21 if session.data[:user_id]
22 @users << User.find(session.data[:user_id])
22 @users << User.find(session.data[:user_id])
23 end
23 end
24 end
24 end
25 end
25 end
26
26
27 def show
27 def show
28 @user = User.find(params[:id])
28 @user = User.find(params[:id])
29 end
29 end
30
30
31 def new
31 def new
32 @user = User.new
32 @user = User.new
33 end
33 end
34
34
35 def create
35 def create
36 @user = User.new(user_params)
36 @user = User.new(user_params)
37 @user.activated = true
37 @user.activated = true
38 + byebug
38 if @user.save
39 if @user.save
39 flash[:notice] = 'User was successfully created.'
40 flash[:notice] = 'User was successfully created.'
40 redirect_to :action => 'index'
41 redirect_to :action => 'index'
41 else
42 else
42 render :action => 'new'
43 render :action => 'new'
43 end
44 end
44 end
45 end
45
46
46 def clear_last_ip
47 def clear_last_ip
47 @user = User.find(params[:id])
48 @user = User.find(params[:id])
48 @user.last_ip = nil
49 @user.last_ip = nil
49 @user.save
50 @user.save
50 redirect_to action: 'index', page: params[:page]
51 redirect_to action: 'index', page: params[:page]
51 end
52 end
52
53
53 def create_from_list
54 def create_from_list
54 lines = params[:user_list]
55 lines = params[:user_list]
55
56
56
57
57 res = User.create_from_list(lines)
58 res = User.create_from_list(lines)
58 error_logins = res[:error_logins]
59 error_logins = res[:error_logins]
59 error_msg = res[:first_error]
60 error_msg = res[:first_error]
60 ok_user = res[:created_users]
61 ok_user = res[:created_users]
61
62
62
63
63 #add to group
64 #add to group
64 if params[:add_to_group]
65 if params[:add_to_group]
65 group = Group.find_by(id: params[:group_id])&.add_users_skip_existing(ok_user)
66 group = Group.find_by(id: params[:group_id])&.add_users_skip_existing(ok_user)
66 end
67 end
67
68
68 # show flash
69 # show flash
69 if ok_user.count > 0
70 if ok_user.count > 0
70 flash[:success] = "#{ok_user.count} user(s) was created or updated successfully"
71 flash[:success] = "#{ok_user.count} user(s) was created or updated successfully"
71 end
72 end
72 if error_logins.size > 0
73 if error_logins.size > 0
73 flash[:error] = "Following user(s) failed to be created: " + error_logins.join(', ') + ". The error of the first failed one are: " + error_msg;
74 flash[:error] = "Following user(s) failed to be created: " + error_logins.join(', ') + ". The error of the first failed one are: " + error_msg;
74 end
75 end
75 redirect_to :action => 'index'
76 redirect_to :action => 'index'
76 end
77 end
77
78
78 def edit
79 def edit
79 @user = User.find(params[:id])
80 @user = User.find(params[:id])
80 end
81 end
81
82
82 def update
83 def update
83 @user = User.find(params[:id])
84 @user = User.find(params[:id])
84 if @user.update_attributes(user_params)
85 if @user.update_attributes(user_params)
85 flash[:notice] = 'User was successfully updated.'
86 flash[:notice] = 'User was successfully updated.'
@@ -1,56 +1,57
1 // Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
1 // Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
2 //import "@hotwired/turbo-rails"
2 //import "@hotwired/turbo-rails"
3 //import "controllers"
3 //import "controllers"
4 //
4 //
5
5
6
6
7 //bootstrap
7 //bootstrap
8 //import "bootstrap"
8 //import "bootstrap"
9 //window.bootstrap = bootstrap
9 //window.bootstrap = bootstrap
10
10
11 //datatable
11 //datatable
12 //import 'datatables-bundle'
12 //import 'datatables-bundle'
13 import "pdfmake"
13 import "pdfmake"
14 import "pdfmake-vfs"
14 import "pdfmake-vfs"
15 import "jszip"
15 import "jszip"
16 import "datatables"
16 import "datatables"
17 import "datatables-bs5"
17 import "datatables-bs5"
18 import "datatables-editor"
18 import "datatables-editor"
19 import "datatables-editor-bs5"
19 import "datatables-editor-bs5"
20 import "datatables-autofill"
20 import "datatables-autofill"
21 import "datatables-autofill-bs5"
21 import "datatables-autofill-bs5"
22 import "datatables-button"
22 import "datatables-button"
23 import "datatables-button-bs5"
23 import "datatables-button-bs5"
24 import "datatables-button-colvis"
24 import "datatables-button-colvis"
25 import "datatables-button-html5"
25 import "datatables-button-html5"
26 import "datatables-button-print"
26 import "datatables-button-print"
27 import "datatables-colrecorder"
27 import "datatables-colrecorder"
28 import "datatables-datetime"
28 import "datatables-datetime"
29 import "datatables-fixedcolumns"
29 import "datatables-fixedcolumns"
30 import "datatables-fixedheader"
30 import "datatables-fixedheader"
31 import "datatables-keytable"
31 import "datatables-keytable"
32 import "datatables-responsive"
32 import "datatables-responsive"
33 import "datatables-responsive-bs5"
33 import "datatables-responsive-bs5"
34 import "datatables-rowgroup"
34 import "datatables-rowgroup"
35 import "datatables-rowreorder"
35 import "datatables-rowreorder"
36 import "datatables-scroller"
36 import "datatables-scroller"
37 import "datatables-searchbuilder"
37 import "datatables-searchbuilder"
38 import "datatables-searchbuilder-bs5"
38 import "datatables-searchbuilder-bs5"
39 import "datatables-searchpanes"
39 import "datatables-searchpanes"
40 import "datatables-searchpanes-bs5"
40 import "datatables-searchpanes-bs5"
41 import "datatables-select"
41 import "datatables-select"
42 import "datatables-staterestore"
42 import "datatables-staterestore"
43 import "datatables-staterestore-bs5"
43 import "datatables-staterestore-bs5"
44 /* */
44 /* */
45
45
46 import "select2"
46 import "select2"
47 + import "chart"
47
48
48 //my own customization
49 //my own customization
49 import 'custom'
50 import 'custom'
50
51
51
52
52 //trigger import map ready
53 //trigger import map ready
53 console.log('application.js ready')
54 console.log('application.js ready')
54 window.importmapScriptsLoaded = true
55 window.importmapScriptsLoaded = true
55 const import_map_loaded = new CustomEvent('import-map-loaded', { });
56 const import_map_loaded = new CustomEvent('import-map-loaded', { });
56 document.dispatchEvent(import_map_loaded);
57 document.dispatchEvent(import_map_loaded);
@@ -1,48 +1,45
1 $(document).on('change', '.btn-file :file', function() {
1 $(document).on('change', '.btn-file :file', function() {
2 var input, label, numFiles;
2 var input, label, numFiles;
3 input = $(this);
3 input = $(this);
4 numFiles = input.get(0).files ? input.get(0).files.length : 1;
4 numFiles = input.get(0).files ? input.get(0).files.length : 1;
5 label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
5 label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
6 input.trigger('fileselect', [numFiles, label]);
6 input.trigger('fileselect', [numFiles, label]);
7 });
7 });
8
8
9 $(function() {
9 $(function() {
10 var e;
10 var e;
11 $(".select2").select2({
11 $(".select2").select2({
12 theme: "bootstrap-5",
12 theme: "bootstrap-5",
13 //selectionCssClass: "select2--small",
13 //selectionCssClass: "select2--small",
14 //dropdownCssClass: "select2--small",
14 //dropdownCssClass: "select2--small",
15 });
15 });
16
16
17 $('.btn-file :file').on('fileselect', function(event, numFiles, label) {
17 $('.btn-file :file').on('fileselect', function(event, numFiles, label) {
18 var input, log;
18 var input, log;
19 input = $(this).parents('.input-group').find(':text');
19 input = $(this).parents('.input-group').find(':text');
20 log = numFiles > 1 ? numFiles + ' files selected' : label;
20 log = numFiles > 1 ? numFiles + ' files selected' : label;
21 if (input.length) {
21 if (input.length) {
22 input.val(log);
22 input.val(log);
23 } else {
23 } else {
24 if (log) {
24 if (log) {
25 alert(log);
25 alert(log);
26 }
26 }
27 }
27 }
28 });
28 });
29 $('.ajax-toggle').on('click', function(event) {
29 $('.ajax-toggle').on('click', function(event) {
30 var target;
30 var target;
31 target = $(event.target);
31 target = $(event.target);
32 target.removeClass('btn-default');
32 target.removeClass('btn-default');
33 target.removeClass('btn-success');
33 target.removeClass('btn-success');
34 target.addClass('btn-warning');
34 target.addClass('btn-warning');
35 target.text('...');
35 target.text('...');
36 });
36 });
37 if ($("#editor").length > 0) {
37 if ($("#editor").length > 0) {
38 e = ace.edit("editor");
38 e = ace.edit("editor");
39 e.setTheme('ace/theme/merbivore');
39 e.setTheme('ace/theme/merbivore');
40 e.getSession().setTabSize(2);
40 e.getSession().setTabSize(2);
41 e.getSession().setUseSoftTabs(true);
41 e.getSession().setUseSoftTabs(true);
42 }
42 }
43
43
44 //jQuery(".best_in_place").best_in_place();
44 //jQuery(".best_in_place").best_in_place();
45 });
45 });
46 -
47 - // ---
48 - // generated by coffee-script 1.9.2
@@ -1,78 +1,78
1 require 'digest/sha1'
1 require 'digest/sha1'
2 require 'net/pop'
2 require 'net/pop'
3 require 'net/https'
3 require 'net/https'
4 require 'net/http'
4 require 'net/http'
5 require 'json'
5 require 'json'
6
6
7 class User < ActiveRecord::Base
7 class User < ActiveRecord::Base
8
8
9 has_and_belongs_to_many :roles
9 has_and_belongs_to_many :roles
10
10
11 #has_and_belongs_to_many :groups
11 #has_and_belongs_to_many :groups
12 has_many :groups_users, class_name: 'GroupUser'
12 has_many :groups_users, class_name: 'GroupUser'
13 has_many :groups, :through => :groups_users
13 has_many :groups, :through => :groups_users
14
14
15 has_many :test_requests, -> {order(submitted_at: :desc)}
15 has_many :test_requests, -> {order(submitted_at: :desc)}
16
16
17 has_many :messages, -> { order(created_at: :desc) },
17 has_many :messages, -> { order(created_at: :desc) },
18 :class_name => "Message",
18 :class_name => "Message",
19 :foreign_key => "sender_id"
19 :foreign_key => "sender_id"
20
20
21 has_many :replied_messages, -> { order(created_at: :desc) },
21 has_many :replied_messages, -> { order(created_at: :desc) },
22 :class_name => "Message",
22 :class_name => "Message",
23 :foreign_key => "receiver_id"
23 :foreign_key => "receiver_id"
24
24
25 has_many :logins
25 has_many :logins
26
26
27 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
27 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
28
28
29 - belongs_to :site
29 + belongs_to :site, optional: true
30 - belongs_to :country
30 + belongs_to :country, optional: true
31
31
32 has_and_belongs_to_many :contests, -> { order(:name)}
32 has_and_belongs_to_many :contests, -> { order(:name)}
33
33
34 scope :activated_users, -> {where activated: true}
34 scope :activated_users, -> {where activated: true}
35
35
36 validates_presence_of :login
36 validates_presence_of :login
37 validates_uniqueness_of :login
37 validates_uniqueness_of :login
38 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
38 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
39 validates_length_of :login, :within => 3..30
39 validates_length_of :login, :within => 3..30
40
40
41 validates_presence_of :full_name
41 validates_presence_of :full_name
42 validates_length_of :full_name, :minimum => 1
42 validates_length_of :full_name, :minimum => 1
43
43
44 validates_presence_of :password, :if => :password_required?
44 validates_presence_of :password, :if => :password_required?
45 validates_length_of :password, :within => 4..50, :if => :password_required?
45 validates_length_of :password, :within => 4..50, :if => :password_required?
46 validates_confirmation_of :password, :if => :password_required?
46 validates_confirmation_of :password, :if => :password_required?
47
47
48 validates_format_of :email,
48 validates_format_of :email,
49 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
49 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
50 :if => :email_validation?
50 :if => :email_validation?
51 validate :uniqueness_of_email_from_activated_users,
51 validate :uniqueness_of_email_from_activated_users,
52 :if => :email_validation?
52 :if => :email_validation?
53 validate :enough_time_interval_between_same_email_registrations,
53 validate :enough_time_interval_between_same_email_registrations,
54 :if => :email_validation?
54 :if => :email_validation?
55
55
56 # these are for ytopc
56 # these are for ytopc
57 # disable for now
57 # disable for now
58 #validates_presence_of :province
58 #validates_presence_of :province
59
59
60 attr_accessor :password
60 attr_accessor :password
61
61
62 before_save :encrypt_new_password
62 before_save :encrypt_new_password
63 before_save :assign_default_site
63 before_save :assign_default_site
64 before_save :assign_default_contest
64 before_save :assign_default_contest
65
65
66 # this is for will_paginate
66 # this is for will_paginate
67 cattr_reader :per_page
67 cattr_reader :per_page
68 @@per_page = 50
68 @@per_page = 50
69
69
70 def self.authenticate(login, password)
70 def self.authenticate(login, password)
71 user = find_by_login(login)
71 user = find_by_login(login)
72 if user
72 if user
73 return user if user.authenticated?(password)
73 return user if user.authenticated?(password)
74 end
74 end
75 end
75 end
76
76
77 def authenticated?(password)
77 def authenticated?(password)
78 if self.activated
78 if self.activated
@@ -1,64 +1,64
1 - content_for :head do
1 - content_for :head do
2 <meta http-equiv ="refresh" content="60"/>
2 <meta http-equiv ="refresh" content="60"/>
3
3
4 %h1 Grader information
4 %h1 Grader information
5
5
6 %p
6 %p
7 = link_to 'Refresh', { :action => 'list' }, class: 'btn btn-info'
7 = link_to 'Refresh', { :action => 'list' }, class: 'btn btn-info'
8
8
9 .panel.panel-primary
9 .panel.panel-primary
10 .panel-heading
10 .panel-heading
11 Grader control:
11 Grader control:
12 .panel-body
12 .panel-body
13 - =link_to 'Start Graders in grading env', { action: 'start_grading'}, class: 'btn btn-default'
13 + =link_to 'Start Graders in grading env', { action: 'start_grading'}, class: 'btn btn-secondary'
14 - =link_to 'Start Graders in exam env', { action: 'start_exam'}, class: 'btn btn-default'
14 + =link_to 'Start Graders in exam env', { action: 'start_exam'}, class: 'btn btn-secondary'
15 - =link_to 'Stop all running Graders', { action: 'stop_all'}, class: 'btn btn-default'
15 + =link_to 'Stop all running Graders', { action: 'stop_all'}, class: 'btn btn-secondary'
16 - =link_to 'Clear all data', { action: 'clear_all'}, class: 'btn btn-default'
16 + =link_to 'Clear all data', { action: 'clear_all'}, class: 'btn btn-secondary'
17
17
18 .row
18 .row
19 .col-md-6
19 .col-md-6
20 - if @last_task
20 - if @last_task
21 Last task:
21 Last task:
22 = link_to "#{@last_task.id}", :action => 'view', :id => @last_task.id, :type => 'Task'
22 = link_to "#{@last_task.id}", :action => 'view', :id => @last_task.id, :type => 'Task'
23
23
24 %br/
24 %br/
25
25
26 - if @last_test_request
26 - if @last_test_request
27 Last test_request:
27 Last test_request:
28 = link_to "#{@last_test_request.id}", :action => 'view', :id => @last_test_request.id, :type => 'TestRequest'
28 = link_to "#{@last_test_request.id}", :action => 'view', :id => @last_test_request.id, :type => 'TestRequest'
29
29
30 %h2 Current graders
30 %h2 Current graders
31
31
32 = render :partial => 'grader_list', :locals => {:grader_list => @grader_processes}
32 = render :partial => 'grader_list', :locals => {:grader_list => @grader_processes}
33
33
34 %h2 Stalled graders
34 %h2 Stalled graders
35
35
36 = render :partial => 'grader_list', :locals => {:grader_list => @stalled_processes}
36 = render :partial => 'grader_list', :locals => {:grader_list => @stalled_processes}
37
37
38 %h2 Terminated graders
38 %h2 Terminated graders
39
39
40 %p= link_to 'Clear data for terminated graders', { action: 'clear_terminated'}, class: 'btn btn-default', method: 'post'
40 %p= link_to 'Clear data for terminated graders', { action: 'clear_terminated'}, class: 'btn btn-default', method: 'post'
41
41
42 = render :partial => 'grader_list', :locals => {:grader_list => @terminated_processes}
42 = render :partial => 'grader_list', :locals => {:grader_list => @terminated_processes}
43 .col-md-6
43 .col-md-6
44 %h2 Last 20 submissions
44 %h2 Last 20 submissions
45 %table.table.table-striped.table-condensed
45 %table.table.table-striped.table-condensed
46 %thead
46 %thead
47 %th ID
47 %th ID
48 %th User
48 %th User
49 %th Problem
49 %th Problem
50 %th Submitted
50 %th Submitted
51 %th Graded
51 %th Graded
52 %th Result
52 %th Result
53 %tbody
53 %tbody
54 - @submission.each do |sub|
54 - @submission.each do |sub|
55 %tr.inactive
55 %tr.inactive
56 %td= link_to sub.id, submission_path(sub.id)
56 %td= link_to sub.id, submission_path(sub.id)
57 %td= ("" unless sub.user) || link_to(sub.try(:user).try(:full_name), stat_user_path(sub.user.id))
57 %td= ("" unless sub.user) || link_to(sub.try(:user).try(:full_name), stat_user_path(sub.user.id))
58 %td= ("" unless sub.problem) || link_to(sub.try(:problem).try(:full_name), stat_problem_path(sub.problem.id))
58 %td= ("" unless sub.problem) || link_to(sub.try(:problem).try(:full_name), stat_problem_path(sub.problem.id))
59 %td= "#{time_ago_in_words(sub.submitted_at)} ago"
59 %td= "#{time_ago_in_words(sub.submitted_at)} ago"
60 %td= sub.graded_at ? "#{time_ago_in_words(sub.graded_at)} ago" : " "
60 %td= sub.graded_at ? "#{time_ago_in_words(sub.graded_at)} ago" : " "
61 %td= sub.grader_comment
61 %td= sub.grader_comment
62 %h2 Ungraded submission
62 %h2 Ungraded submission
63 %table.table.table-striped.table-condensed
63 %table.table.table-striped.table-condensed
64 %thead
64 %thead
@@ -1,27 +1,7
1 - = form_for @group do |f|
2 - - if @group.errors.any?
3 - #error_explanation
4 - %h2= "#{pluralize(@group.errors.count, "error")} prohibited this group from being saved:"
5 - %ul
6 - - @group.errors.full_messages.each do |msg|
7 - %li= msg
8 - .row
9 - .col-md-6
10 - .form-group.field
11 - = f.label :name
12 - = f.text_field :name, class: 'form-control'
13 .row
1 .row
14 .col-md-6
2 .col-md-6
15 - .form-group.field
3 + = simple_form_for @group do |f|
16 - = f.label :description
4 + = f.input :name
17 - = f.text_field :description, class: 'form-control'
5 + = f.input :description
18 - .row
6 + = f.input :enabled
19 - .col-md-6
7 + = f.button :submit, class: 'btn btn-primary'
20 - .checkbox
21 - = f.label :enabled do
22 - = f.check_box :enabled
23 - Enabled
24 - .row
25 - .col-md-6
26 - .form-group.actions
27 - = f.submit 'Save', class: 'btn btn-primary'
@@ -1,7 +1,9
1 %h1 Editing group
1 %h1 Editing group
2
2
3 = render 'form'
3 = render 'form'
4
4
5 - = link_to 'Show', @group
5 + .row.my-3
6 - \|
6 + .col-auto
7 - = link_to 'Back', groups_path
7 + = link_to 'Edit members and problems', @group, class: 'btn btn-info'
8 + .col-auto
9 + = link_to 'Back', groups_path, class: 'btn btn-secondary'
@@ -1,24 +1,23
1 %h1 Groups
1 %h1 Groups
2
2
3 %p
3 %p
4 - = link_to 'New Group', new_group_path, class: 'btn btn-primary'
4 + = link_to 'New Group', new_group_path, class: 'btn btn-success'
5 %table.table.table-hover
5 %table.table.table-hover
6 %thead
6 %thead
7 %tr
7 %tr
8 %th Name
8 %th Name
9 %th Description
9 %th Description
10 %th Enabled?
10 %th Enabled?
11 %th
11 %th
12 - %th
13 -
14 %tbody
12 %tbody
15 - @groups.each do |group|
13 - @groups.each do |group|
16 %tr{:class => "#{(group.enabled?) ? "success" : "danger"}", id: "group-#{group.id}"}
14 %tr{:class => "#{(group.enabled?) ? "success" : "danger"}", id: "group-#{group.id}"}
17 %td= group.name
15 %td= group.name
18 %td= group.description
16 %td= group.description
19 - %td= toggle_button(group.enabled?, toggle_group_path(group), "group-enabled-#{group.id}", size: ' ', block: ' ')
17 + %td= toggle_button(group.enabled?, toggle_group_path(group), "group-enabled-#{group.id}", block: ' ')
20 - %td= link_to 'View', group, class: 'btn btn-default'
18 + %td
21 - %td= link_to 'Destroy', group, :method => :delete, :data => { :confirm => 'Are you sure?' }, class: 'btn btn-danger'
19 + = link_to 'Edit members and problems', group, class: 'btn btn-secondary btn-sm'
20 + = link_to 'Destroy', group, :method => :delete, :data => { :confirm => 'Are you sure?' }, class: 'btn btn-danger btn-sm'
22
21
23 %br
22 %br
24
23
@@ -1,82 +1,92
1 - .container-fluid
1 + .row.mb-3
2 - .row
3 .col-md-6
2 .col-md-6
4 - %h1 Group #{@group.name}
3 + %h1 Editing Group members and problems
5 - .row
4 + .row.mb-3
5 + .col-md-6
6 + %b Name:
7 + = @group.name
8 + .row.mb-3
6 .col-md-6
9 .col-md-6
7 %b Description:
10 %b Description:
8 = @group.description
11 = @group.description
9 - %br
12 + .row.mb-3
13 + .col-md-6
10 = link_to 'Edit', edit_group_path(@group), class: 'btn btn-primary'
14 = link_to 'Edit', edit_group_path(@group), class: 'btn btn-primary'
11 - .row
15 + .row.mb-3
12 .col-md-12
16 .col-md-12
13 %h1 Group details
17 %h1 Group details
14 .row
18 .row
15 .col-md-6
19 .col-md-6
16 - .panel.panel-default
20 + .card
17 - .panel-heading
21 + .card-header
18 - .panel-title Users in this group
22 + Users in this group
19 - .panel-body
23 + .card-body
20 %ul
24 %ul
21 %li
25 %li
22 If you want to add several users to a group, it may be easier to just re-import those users in
26 If you want to add several users to a group, it may be easier to just re-import those users in
23 = link_to 'New list of users', new_list_user_admin_index_path
27 = link_to 'New list of users', new_list_user_admin_index_path
24 page. You can also use
28 page. You can also use
25 = link_to 'Bulk Manage User', bulk_manage_user_admin_index_path
29 = link_to 'Bulk Manage User', bulk_manage_user_admin_index_path
26 page.
30 page.
27 =form_tag add_user_group_path(@group), class: 'form-inline' do
31 =form_tag add_user_group_path(@group), class: 'form-inline' do
28 - .form-group
32 + .row
29 - =label_tag :user_id, "User"
33 + .col-auto
34 + =label_tag :user_id, "User", class: 'col-form-label'
35 + .col-auto
30 =select_tag :user_id, options_from_collection_for_select(User.all,'id','login_with_name'), class: 'select2', style: 'width: 25em';
36 =select_tag :user_id, options_from_collection_for_select(User.all,'id','login_with_name'), class: 'select2', style: 'width: 25em';
37 + .col-auto
31 =submit_tag "Add",class: 'btn btn-primary'
38 =submit_tag "Add",class: 'btn btn-primary'
32
39
33
40
34 %table.table.table-hover
41 %table.table.table-hover
35 %thead
42 %thead
36 %tr
43 %tr
37 %th Login
44 %th Login
38 %th Full name
45 %th Full name
39 %th Remark
46 %th Remark
40 %th= link_to 'Remove All', remove_all_user_group_path(@group), method: :delete, :data => { :confirm => "Remove ALL USERS from group?" }, class: 'btn btn-danger btn-sm'
47 %th= link_to 'Remove All', remove_all_user_group_path(@group), method: :delete, :data => { :confirm => "Remove ALL USERS from group?" }, class: 'btn btn-danger btn-sm'
41
48
42 %tbody
49 %tbody
43 - @group.users.each do |user|
50 - @group.users.each do |user|
44 %tr
51 %tr
45 %td= user.login
52 %td= user.login
46 %td= user.full_name
53 %td= user.full_name
47 %td= user.remark
54 %td= user.remark
48 %td= link_to 'Remove', remove_user_group_path(@group,user), :method => :delete, :data => { :confirm => "Remove #{user.full_name}?" }, class: 'btn btn-danger btn-sm'
55 %td= link_to 'Remove', remove_user_group_path(@group,user), :method => :delete, :data => { :confirm => "Remove #{user.full_name}?" }, class: 'btn btn-danger btn-sm'
49 .col-md-6
56 .col-md-6
50 - .panel.panel-default
57 + .card
51 - .panel-heading
58 + .card-header
52 - .panel-title Problems
59 + Problems
53 - .panel-body
60 + .card-body
54 %ul
61 %ul
55 %li
62 %li
56 If you want to add several problem to a group, it may be easier to bulk manage them in the
63 If you want to add several problem to a group, it may be easier to bulk manage them in the
57 = link_to 'Bulk Manage Problems', manage_problems_path
64 = link_to 'Bulk Manage Problems', manage_problems_path
58 page
65 page
59 - =form_tag add_problem_group_path(@group), class: 'form-inline' do
66 + =form_tag add_problem_group_path(@group) do
60 - .form-group
67 + .row
61 - =label_tag :problem_id, "Problem"
68 + .col-auto
69 + =label_tag :problem_id, "Problem",class: 'col-form-label'
70 + .col-auto
62 =select_tag :problem_id, options_from_collection_for_select(Problem.all,'id','long_name'), class: 'select2', style: 'width: 25em';
71 =select_tag :problem_id, options_from_collection_for_select(Problem.all,'id','long_name'), class: 'select2', style: 'width: 25em';
72 + .col-auto
63 =submit_tag "Add",class: 'btn btn-primary'
73 =submit_tag "Add",class: 'btn btn-primary'
64
74
65
75
66 %table.table.table-hover
76 %table.table.table-hover
67 %thead
77 %thead
68 %tr
78 %tr
69 %th name
79 %th name
70 %th Full name
80 %th Full name
71 %th Full score
81 %th Full score
72 %th= link_to 'Remove All', remove_all_problem_group_path(@group), method: :delete, :data => { :confirm => "Remove ALL PROBLEMS from group?" }, class: 'btn btn-danger btn-sm'
82 %th= link_to 'Remove All', remove_all_problem_group_path(@group), method: :delete, :data => { :confirm => "Remove ALL PROBLEMS from group?" }, class: 'btn btn-danger btn-sm'
73
83
74 %tbody
84 %tbody
75 - @group.problems.each do |problem|
85 - @group.problems.each do |problem|
76 %tr
86 %tr
77 %td= problem.name
87 %td= problem.name
78 %td= problem.full_name
88 %td= problem.full_name
79 %td= problem.full_score
89 %td= problem.full_score
80 %td= link_to 'Remove', remove_problem_group_path(@group,problem), :method => :delete, :data => { :confirm => "Remove #{problem.full_name}?" }, class: 'btn btn-danger btn-sm'
90 %td= link_to 'Remove', remove_problem_group_path(@group,problem), :method => :delete, :data => { :confirm => "Remove #{problem.full_name}?" }, class: 'btn btn-danger btn-sm'
81
91
82
92
@@ -90,66 +90,67
90 by #{link_to @best[:memory][:user], stat_user_path(@best[:memory][:user_id])}
90 by #{link_to @best[:memory][:user], stat_user_path(@best[:memory][:user_id])}
91 %br
91 %br
92 using <span class="text-success">#{@best[:memory][:lang]}</span>
92 using <span class="text-success">#{@best[:memory][:lang]}</span>
93 %br
93 %br
94 with <span class="text-success">#{number_with_delimiter(@best[:memory][:value])} kbytes </span>
94 with <span class="text-success">#{number_with_delimiter(@best[:memory][:value])} kbytes </span>
95 %br= link_to "#" + @best[:memory][:sub_id].to_s, submission_path(@best[:memory][:sub_id])
95 %br= link_to "#" + @best[:memory][:sub_id].to_s, submission_path(@best[:memory][:sub_id])
96 %td
96 %td
97 by #{link_to @best[:length][:user], stat_user_path(@best[:length][:user_id])}
97 by #{link_to @best[:length][:user], stat_user_path(@best[:length][:user_id])}
98 %br
98 %br
99 using <span class="text-success">#{@best[:length][:lang]}</span>
99 using <span class="text-success">#{@best[:length][:lang]}</span>
100 %br
100 %br
101 with <span class="text-success">#{@best[:length][:value]} bytes</span>
101 with <span class="text-success">#{@best[:length][:value]} bytes</span>
102 %br= link_to "#" + @best[:length][:sub_id].to_s, submission_path(@best[:length][:sub_id])
102 %br= link_to "#" + @best[:length][:sub_id].to_s, submission_path(@best[:length][:sub_id])
103 %td
103 %td
104 - if @best[:first][:user] != '(NULL)'
104 - if @best[:first][:user] != '(NULL)'
105 #{link_to @best[:first][:user], stat_user_path(@best[:first][:user_id])} is the first solver
105 #{link_to @best[:first][:user], stat_user_path(@best[:first][:user_id])} is the first solver
106 %br
106 %br
107 using <span class="text-success">#{@best[:first][:lang]}</span>
107 using <span class="text-success">#{@best[:first][:lang]}</span>
108 %br
108 %br
109 on <span class="text-success">#{@best[:first][:value]}</span>
109 on <span class="text-success">#{@best[:first][:value]}</span>
110 %br= link_to "#" + @best[:first][:sub_id].to_s, submission_path( @best[:first][:sub_id])
110 %br= link_to "#" + @best[:first][:sub_id].to_s, submission_path( @best[:first][:sub_id])
111 - else
111 - else
112 no first solver
112 no first solver
113 - @by_lang.each do |lang,value|
113 - @by_lang.each do |lang,value|
114 %tr
114 %tr
115 %td= lang
115 %td= lang
116 %td
116 %td
117 = link_to value[:runtime][:user], stat_user_path(value[:runtime][:user_id])
117 = link_to value[:runtime][:user], stat_user_path(value[:runtime][:user_id])
118 %br
118 %br
119 = "#{(value[:runtime][:value] * 1000).to_i} @"
119 = "#{(value[:runtime][:value] * 1000).to_i} @"
120 = link_to "#" + value[:runtime][:sub_id].to_s, submission_path( value[:runtime][:sub_id])
120 = link_to "#" + value[:runtime][:sub_id].to_s, submission_path( value[:runtime][:sub_id])
121 %td
121 %td
122 = link_to value[:memory][:user], stat_user_path( value[:memory][:user_id])
122 = link_to value[:memory][:user], stat_user_path( value[:memory][:user_id])
123 %br
123 %br
124 = "#{number_with_delimiter(value[:memory][:value])} @"
124 = "#{number_with_delimiter(value[:memory][:value])} @"
125 = link_to "#" + value[:memory][:sub_id].to_s, submission_path(value[:memory][:sub_id])
125 = link_to "#" + value[:memory][:sub_id].to_s, submission_path(value[:memory][:sub_id])
126 %td
126 %td
127 = link_to value[:length][:user], stat_user_path(value[:length][:user_id])
127 = link_to value[:length][:user], stat_user_path(value[:length][:user_id])
128 %br
128 %br
129 = "#{value[:length][:value]} @"
129 = "#{value[:length][:value]} @"
130 = link_to "#" + value[:length][:sub_id].to_s, submission_path(value[:length][:sub_id])
130 = link_to "#" + value[:length][:sub_id].to_s, submission_path(value[:length][:sub_id])
131 %td
131 %td
132 - if value[:first][:user] != '(NULL)' #TODO: i know... this is wrong...
132 - if value[:first][:user] != '(NULL)' #TODO: i know... this is wrong...
133 = link_to value[:first][:user], stat_user_path(value[:first][:user_id])
133 = link_to value[:first][:user], stat_user_path(value[:first][:user_id])
134 %br
134 %br
135 = "#{value[:first][:value]} @"
135 = "#{value[:first][:value]} @"
136 = link_to "#" + value[:first][:sub_id].to_s, submission_path( value[:first][:sub_id])
136 = link_to "#" + value[:first][:sub_id].to_s, submission_path( value[:first][:sub_id])
137
137
138 - %script{src:"https://cdn.jsdelivr.net/npm/chart.js"}
139 :javascript
138 :javascript
139 + $(document).on('import-map-loaded',(e) => {
140 data = #{@chart_dataset}
140 data = #{@chart_dataset}
141 config = {
141 config = {
142 type: 'bar',
142 type: 'bar',
143 data: data,
143 data: data,
144 options: {
144 options: {
145 plugins: {
145 plugins: {
146 legend: {
146 legend: {
147 display: false
147 display: false
148 },
148 },
149 },
149 },
150 }
150 }
151 }
151 }
152 Chart.defaults.font.size = 15
152 Chart.defaults.font.size = 15
153 //Chart.defaults.font.family = 'Sarabun Light'
153 //Chart.defaults.font.family = 'Sarabun Light'
154 chart = new Chart($('#chart'),config)
154 chart = new Chart($('#chart'),config)
155 + });
155
156
@@ -4,98 +4,88
4 .card-header.text-bg-success.border-success
4 .card-header.text-bg-success.border-success
5 Quick Add
5 Quick Add
6 .card-body
6 .card-body
7 = form_with url: user_admin_index_path, scope: :user, class: 'row row-cols-lg-auto g-3 align-items-center' do |f|
7 = form_with url: user_admin_index_path, scope: :user, class: 'row row-cols-lg-auto g-3 align-items-center' do |f|
8 .col-12
8 .col-12
9 = f.text_field 'login', :size => 10,class: 'form-control', placeholder: 'login'
9 = f.text_field 'login', :size => 10,class: 'form-control', placeholder: 'login'
10 .form-group
10 .form-group
11 = f.text_field 'full_name', :size => 10,class: 'form-control', placeholder: 'full name'
11 = f.text_field 'full_name', :size => 10,class: 'form-control', placeholder: 'full name'
12 .form-group
12 .form-group
13 = f.password_field 'password', :size => 10,class: 'form-control', placeholder: 'password'
13 = f.password_field 'password', :size => 10,class: 'form-control', placeholder: 'password'
14 .form-group
14 .form-group
15 = f.password_field 'password_confirmation', :size => 10,class: 'form-control', placeholder: 'password confirmation'
15 = f.password_field 'password_confirmation', :size => 10,class: 'form-control', placeholder: 'password confirmation'
16 .form-group
16 .form-group
17 = f.text_field 'email', :size => 10,class: 'form-control', placeholder: 'email'
17 = f.text_field 'email', :size => 10,class: 'form-control', placeholder: 'email'
18 =submit_tag "Create", class: 'btn btn-success align-items-bottom'
18 =submit_tag "Create", class: 'btn btn-success align-items-bottom'
19
19
20 .card.border-success.mb-3
20 .card.border-success.mb-3
21 .card-header.text-bg-success.border-success
21 .card-header.text-bg-success.border-success
22 Import from site management
22 Import from site management
23 .card-body
23 .card-body
24 = form_with url: import_user_admin_index_path, :multipart => true do |f|
24 = form_with url: import_user_admin_index_path, :multipart => true do |f|
25 .row
25 .row
26 .col-auto
26 .col-auto
27 = f.label :file, 'File:', class: 'col-form-label'
27 = f.label :file, 'File:', class: 'col-form-label'
28 .col-auto
28 .col-auto
29 = f.file_field :file, class: 'form-control'
29 = f.file_field :file, class: 'form-control'
30 .col-auto
30 .col-auto
31 = f.submit 'Submit', class: 'btn btn-secondary'
31 = f.submit 'Submit', class: 'btn btn-secondary'
32
32
33
33
34 %p
34 %p
35 = link_to '+ New user', { :action => 'new' }, { class: 'btn btn-success '}
35 = link_to '+ New user', { :action => 'new' }, { class: 'btn btn-success '}
36 = link_to '+ New list of users', { :action => 'new_list' }, { class: 'btn btn-success '}
36 = link_to '+ New list of users', { :action => 'new_list' }, { class: 'btn btn-success '}
37 = link_to 'Bulk Manage', { action: :bulk_manage} , { class: 'btn btn-secondary btn-info'}
37 = link_to 'Bulk Manage', { action: :bulk_manage} , { class: 'btn btn-secondary btn-info'}
38 = link_to 'View administrators',{ :action => 'admin'}, { class: 'btn btn-secondary '}
38 = link_to 'View administrators',{ :action => 'admin'}, { class: 'btn btn-secondary '}
39 = link_to 'Random passwords',{ :action => 'random_all_passwords'}, { class: 'btn btn-secondary '}
39 = link_to 'Random passwords',{ :action => 'random_all_passwords'}, { class: 'btn btn-secondary '}
40 = link_to 'View active users',{ :action => 'active'}, { class: 'btn btn-secondary '}
40 = link_to 'View active users',{ :action => 'active'}, { class: 'btn btn-secondary '}
41 = link_to 'Mass mailing',{ :action => 'mass_mailing'}, { class: 'btn btn-secondary '}
41 = link_to 'Mass mailing',{ :action => 'mass_mailing'}, { class: 'btn btn-secondary '}
42
42
43 - if GraderConfiguration.multicontests?
43 - if GraderConfiguration.multicontests?
44 %br/
44 %br/
45 %b Multi-contest:
45 %b Multi-contest:
46 = link_to '[Manage bulk users in contests]', :action => 'contest_management'
46 = link_to '[Manage bulk users in contests]', :action => 'contest_management'
47 View users in:
47 View users in:
48 - @contests.each do |contest|
48 - @contests.each do |contest|
49 = link_to "[#{contest.name}]", :action => 'contests', :id => contest.id
49 = link_to "[#{contest.name}]", :action => 'contests', :id => contest.id
50 = link_to "[no contest]", :action => 'contests', :id => 'none'
50 = link_to "[no contest]", :action => 'contests', :id => 'none'
51
51
52 - -# Total #{@user_count} users |
53 - -# - if !@paginated
54 - -# Display all users.
55 - -# \#{link_to '[show in pages]', :action => 'index', :page => '1'}
56 - -# - else
57 - -# Display in pages.
58 - -# \#{link_to '[display all]', :action => 'index', :page => 'all'} |
59 - -# \#{will_paginate @users, :container => false}
60 -
61 -
62 %table.table.table-hover.table-condense.datatable
52 %table.table.table-hover.table-condense.datatable
63 %thead
53 %thead
64 %th Login
54 %th Login
65 %th Full name
55 %th Full name
66 %th email
56 %th email
67 %th Remark
57 %th Remark
68 %th
58 %th
69 Activated
59 Activated
70 %sup{class: 'text-primary',data: {toggle: 'tooltip', placement: 'top'}, title: 'User has already confirmed the email?' } [?]
60 %sup{class: 'text-primary',data: {toggle: 'tooltip', placement: 'top'}, title: 'User has already confirmed the email?' } [?]
71 %th
61 %th
72 Enabled
62 Enabled
73 %sup{class: 'text-primary',data: {toggle: 'tooltip', placement: 'top'}, title: 'Allow the user to login?' } [?]
63 %sup{class: 'text-primary',data: {toggle: 'tooltip', placement: 'top'}, title: 'Allow the user to login?' } [?]
74 %th Last IP
64 %th Last IP
75 %th
65 %th
76 %th
66 %th
77 %th
67 %th
78 %th
68 %th
79 - for user in @users
69 - for user in @users
80 %tr
70 %tr
81 %td= link_to user.login, stat_user_path(user)
71 %td= link_to user.login, stat_user_path(user)
82 %td= user.full_name
72 %td= user.full_name
83 %td= user.email
73 %td= user.email
84 %td= user.remark
74 %td= user.remark
85 %td= toggle_button(user.activated?, toggle_activate_user_path(user),"toggle_activate_user_#{user.id}")
75 %td= toggle_button(user.activated?, toggle_activate_user_path(user),"toggle_activate_user_#{user.id}")
86 %td= toggle_button(user.enabled?, toggle_enable_user_path(user),"toggle_enable_user_#{user.id}")
76 %td= toggle_button(user.enabled?, toggle_enable_user_path(user),"toggle_enable_user_#{user.id}")
87 %td= user.last_ip
77 %td= user.last_ip
88 - %td= link_to 'Clear IP', {:action => 'clear_last_ip', :id => user, :page=>params[:page]}, :confirm => 'This will reset last logging in ip of the user, are you sure?', class: 'btn btn-default btn-xs btn-block'
78 + %td= link_to 'Clear IP', {:action => 'clear_last_ip', :id => user, :page=>params[:page]}, :confirm => 'This will reset last logging in ip of the user, are you sure?', class: 'btn btn-secondary btn-sm btn-block'
89 - %td= link_to 'Show', {:action => 'show', :id => user}, class: 'btn btn-default btn-xs btn-block'
79 + %td= link_to 'Show', {:action => 'show', :id => user}, class: 'btn btn-secondary btn-sm btn-block'
90 - %td= link_to 'Edit', {:action => 'edit', :id => user}, class: 'btn btn-default btn-xs btn-block'
80 + %td= link_to 'Edit', {:action => 'edit', :id => user}, class: 'btn btn-secondary btn-sm btn-block'
91 - %td= link_to 'Destroy', {action: :destroy, id: user}, data: {confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-danger btn-xs btn-block'
81 + %td= link_to 'Destroy', {action: :destroy, id: user}, data: {confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-danger btn-sm btn-block'
92 %br/
82 %br/
93 = link_to '+ New user', { :action => 'new' }, { class: 'btn btn-success '}
83 = link_to '+ New user', { :action => 'new' }, { class: 'btn btn-success '}
94 = link_to '+ New list of users', { :action => 'new_list' }, { class: 'btn btn-success '}
84 = link_to '+ New list of users', { :action => 'new_list' }, { class: 'btn btn-success '}
95
85
96 :javascript
86 :javascript
97 $(document).on('import-map-loaded',(e) => {
87 $(document).on('import-map-loaded',(e) => {
98 $('.datatable').DataTable({
88 $('.datatable').DataTable({
99 'pageLength': 50
89 'pageLength': 50
100 });
90 });
101 })
91 })
@@ -10,48 +10,49
10 #pin "jquery", to: 'my_jquery.js', preload: true
10 #pin "jquery", to: 'my_jquery.js', preload: true
11 #pin "bootstrap", to: "bootstrap.bundle.min.js", preload: true
11 #pin "bootstrap", to: "bootstrap.bundle.min.js", preload: true
12 #no need popper, because bundled already in bootstrap
12 #no need popper, because bundled already in bootstrap
13 #pin "@popperjs/core", to: "https://ga.jspm.io/npm:@popperjs/core@2.11.6/lib/index.js"
13 #pin "@popperjs/core", to: "https://ga.jspm.io/npm:@popperjs/core@2.11.6/lib/index.js"
14
14
15 # datatable
15 # datatable
16 # I have to fix vfs_font.js for this to work
16 # I have to fix vfs_font.js for this to work
17 pin "jszip", to: "jszip.min.js"
17 pin "jszip", to: "jszip.min.js"
18 pin "pdfmake"
18 pin "pdfmake"
19 pin "pdfmake-vfs", to: 'datatables/pdfmake-0.1.36/vfs_fonts.js'
19 pin "pdfmake-vfs", to: 'datatables/pdfmake-0.1.36/vfs_fonts.js'
20
20
21 pin "datatables-bundle", to: 'datatables/datatables.js'
21 pin "datatables-bundle", to: 'datatables/datatables.js'
22 pin "datatables", to: "datatables/DataTables-1.12.1/js/jquery.dataTables.js"
22 pin "datatables", to: "datatables/DataTables-1.12.1/js/jquery.dataTables.js"
23 pin "datatables-bs5", to: "datatables/DataTables-1.12.1/js/dataTables.bootstrap5.js"
23 pin "datatables-bs5", to: "datatables/DataTables-1.12.1/js/dataTables.bootstrap5.js"
24 pin "datatables-editor", to: "datatables/Editor-2.0.9/js/dataTables.editor.js"
24 pin "datatables-editor", to: "datatables/Editor-2.0.9/js/dataTables.editor.js"
25 pin "datatables-editor-bs5", to: "datatables/Editor-2.0.9/js/editor.bootstrap5.min.js"
25 pin "datatables-editor-bs5", to: "datatables/Editor-2.0.9/js/editor.bootstrap5.min.js"
26 pin "datatables-autofill", to: "datatables/AutoFill-2.4.0/js/dataTables.autoFill.js"
26 pin "datatables-autofill", to: "datatables/AutoFill-2.4.0/js/dataTables.autoFill.js"
27 pin "datatables-autofill-bs5", to: "datatables/AutoFill-2.4.0/js/autoFill.bootstrap5.js"
27 pin "datatables-autofill-bs5", to: "datatables/AutoFill-2.4.0/js/autoFill.bootstrap5.js"
28 pin "datatables-button", to: "datatables/Buttons-2.2.3/js/dataTables.buttons.js"
28 pin "datatables-button", to: "datatables/Buttons-2.2.3/js/dataTables.buttons.js"
29 pin "datatables-button-bs5", to: "datatables/Buttons-2.2.3/js/buttons.bootstrap5.js"
29 pin "datatables-button-bs5", to: "datatables/Buttons-2.2.3/js/buttons.bootstrap5.js"
30 pin "datatables-button-colvis", to: "datatables/Buttons-2.2.3/js/buttons.colVis.js"
30 pin "datatables-button-colvis", to: "datatables/Buttons-2.2.3/js/buttons.colVis.js"
31 pin "datatables-button-html5", to: "datatables/Buttons-2.2.3/js/buttons.html5.js"
31 pin "datatables-button-html5", to: "datatables/Buttons-2.2.3/js/buttons.html5.js"
32 pin "datatables-button-print", to: "datatables/Buttons-2.2.3/js/buttons.print.js"
32 pin "datatables-button-print", to: "datatables/Buttons-2.2.3/js/buttons.print.js"
33 pin "datatables-colrecorder", to: "datatables/ColReorder-1.5.6/js/dataTables.colReorder.js"
33 pin "datatables-colrecorder", to: "datatables/ColReorder-1.5.6/js/dataTables.colReorder.js"
34 pin "datatables-datetime", to: "datatables/DateTime-1.1.2/js/dataTables.dateTime.js"
34 pin "datatables-datetime", to: "datatables/DateTime-1.1.2/js/dataTables.dateTime.js"
35 pin "datatables-fixedcolumns", to: "datatables/FixedColumns-4.1.0/js/dataTables.fixedColumns.js"
35 pin "datatables-fixedcolumns", to: "datatables/FixedColumns-4.1.0/js/dataTables.fixedColumns.js"
36 pin "datatables-fixedheader", to: "datatables/FixedHeader-3.2.4/js/dataTables.fixedHeader.js"
36 pin "datatables-fixedheader", to: "datatables/FixedHeader-3.2.4/js/dataTables.fixedHeader.js"
37 pin "datatables-keytable", to: "datatables/KeyTable-2.7.0/js/dataTables.keyTable.js"
37 pin "datatables-keytable", to: "datatables/KeyTable-2.7.0/js/dataTables.keyTable.js"
38 pin "datatables-responsive", to: "datatables/Responsive-2.3.0/js/dataTables.responsive.js"
38 pin "datatables-responsive", to: "datatables/Responsive-2.3.0/js/dataTables.responsive.js"
39 pin "datatables-responsive-bs5", to: "datatables/Responsive-2.3.0/js/responsive.bootstrap5.js"
39 pin "datatables-responsive-bs5", to: "datatables/Responsive-2.3.0/js/responsive.bootstrap5.js"
40 pin "datatables-rowgroup", to: "datatables/RowGroup-1.2.0/js/dataTables.rowGroup.js"
40 pin "datatables-rowgroup", to: "datatables/RowGroup-1.2.0/js/dataTables.rowGroup.js"
41 pin "datatables-rowreorder", to: "datatables/RowReorder-1.2.8/js/dataTables.rowReorder.js"
41 pin "datatables-rowreorder", to: "datatables/RowReorder-1.2.8/js/dataTables.rowReorder.js"
42 pin "datatables-scroller", to: "datatables/Scroller-2.0.7/js/dataTables.scroller.js"
42 pin "datatables-scroller", to: "datatables/Scroller-2.0.7/js/dataTables.scroller.js"
43 pin "datatables-searchbuilder", to: "datatables/SearchBuilder-1.3.4/js/dataTables.searchBuilder.js"
43 pin "datatables-searchbuilder", to: "datatables/SearchBuilder-1.3.4/js/dataTables.searchBuilder.js"
44 pin "datatables-searchbuilder-bs5", to: "datatables/SearchBuilder-1.3.4/js/searchBuilder.bootstrap5.js"
44 pin "datatables-searchbuilder-bs5", to: "datatables/SearchBuilder-1.3.4/js/searchBuilder.bootstrap5.js"
45 pin "datatables-searchpanes", to: "datatables/SearchPanes-2.0.2/js/dataTables.searchPanes.js"
45 pin "datatables-searchpanes", to: "datatables/SearchPanes-2.0.2/js/dataTables.searchPanes.js"
46 pin "datatables-searchpanes-bs5", to: "datatables/SearchPanes-2.0.2/js/searchPanes.bootstrap5.js"
46 pin "datatables-searchpanes-bs5", to: "datatables/SearchPanes-2.0.2/js/searchPanes.bootstrap5.js"
47 pin "datatables-select", to: "datatables/Select-1.4.0/js/dataTables.select.js"
47 pin "datatables-select", to: "datatables/Select-1.4.0/js/dataTables.select.js"
48 pin "datatables-staterestore", to: "datatables/StateRestore-1.1.1/js/dataTables.stateRestore.js"
48 pin "datatables-staterestore", to: "datatables/StateRestore-1.1.1/js/dataTables.stateRestore.js"
49 pin "datatables-staterestore-bs5", to: "datatables/StateRestore-1.1.1/js/stateRestore.bootstrap5.js"
49 pin "datatables-staterestore-bs5", to: "datatables/StateRestore-1.1.1/js/stateRestore.bootstrap5.js"
50
50
51 #select2
51 #select2
52 pin "select2", to: "select2.min.js"
52 pin "select2", to: "select2.min.js"
53
53
54 #my local js
54 #my local js
55 pin "custom", to: "custom.js"
55 pin "custom", to: "custom.js"
56
56
57 #pin "ace-rails-ap"
57 #pin "ace-rails-ap"
58 + pin "chart", to: 'chart.js' # @3.9.1
You need to be logged in to leave comments. Login now