diff --git a/app/assets/javascripts/osem-datatables.js b/app/assets/javascripts/osem-datatables.js
index 0248275f..f9bdb008 100644
--- a/app/assets/javascripts/osem-datatables.js
+++ b/app/assets/javascripts/osem-datatables.js
@@ -30,3 +30,18 @@ $(function () {
});
});
});
+
+function truncatify(selector) {
+ $(selector).each(function(){
+ var text = $(this).text()
+ $(this).html('' + text + ' ')
+ });
+}
+
+function iconize(selector, value, icon, title) {
+ $(selector).each(function(){
+ if ($(this).text() == value) {
+ $(this).html("");
+ }
+ });
+}
diff --git a/app/controllers/admin/registrations_controller.rb b/app/controllers/admin/registrations_controller.rb
index fb427d25..3f19ed39 100644
--- a/app/controllers/admin/registrations_controller.rb
+++ b/app/controllers/admin/registrations_controller.rb
@@ -15,6 +15,13 @@ module Admin
@registration_distribution = @conference.registration_distribution
@affiliation_distribution = @conference.affiliation_distribution
@code_of_conduct = @conference.code_of_conduct.present?
+
+ respond_to do |format|
+ format.html
+ format.json do
+ render json: RegistrationDatatable.new(view_context, conference: @conference)
+ end
+ end
end
def edit; end
diff --git a/app/datatables/registration_datatable.rb b/app/datatables/registration_datatable.rb
new file mode 100644
index 00000000..bdd97e72
--- /dev/null
+++ b/app/datatables/registration_datatable.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+class RegistrationDatatable < AjaxDatatablesRails::Base
+ def_delegator :@view, :edit_admin_conference_registration_path
+
+ def view_columns
+ @view_columns ||= {
+ id: { source: 'Registration.id', cond: :eq },
+ name: { source: 'User.name' },
+ roles: { source: 'Role.name' },
+ email: { source: 'User.email' },
+ accepted_code_of_conduct: { source: 'Registration.accepted_code_of_conduct', searchable: false },
+ arrival: { source: 'Registration.arrival', searchable: false },
+ departure: { source: 'Registration.departure', searchable: false },
+ actions: { source: 'Registration.id', searchable: false, orderable: false }
+ }
+ end
+
+ private
+
+ def conference
+ @conference ||= options[:conference]
+ end
+
+ def conference_role_titles(record)
+ record.roles.collect do |role|
+ role.name.titleize if role.resource == conference
+ end.compact
+ end
+
+ def data
+ records.map do |record|
+ {
+ id: record.id,
+ name: record.user.name,
+ roles: conference_role_titles(record.user),
+ email: record.email,
+ accepted_code_of_conduct: !!record.accepted_code_of_conduct, # rubocop:disable Style/DoubleNegation
+ arrival: record.arrival&.utc,
+ departure: record.departure&.utc,
+ questions: {},
+ edit_url: edit_admin_conference_registration_path(conference, record),
+ DT_RowId: record.id
+ }
+ end
+ end
+
+ def get_raw_records # rubocop:disable Naming/AccessorMethodName
+ conference.registrations.includes(user: :roles).references(:users, :roles).distinct
+ end
+
+ # override upstream santitation, which converts everything to strings
+ def sanitize(records)
+ records
+ end
+end
diff --git a/app/views/admin/registrations/index.html.haml b/app/views/admin/registrations/index.html.haml
index 212763ca..699d5a9f 100644
--- a/app/views/admin/registrations/index.html.haml
+++ b/app/views/admin/registrations/index.html.haml
@@ -21,70 +21,96 @@
.row
.col-md-12
%div.margin-event-table
- %table.datatable#registrations
+ %table.datatable#registrations{ data: { source: admin_conference_registrations_path(conference_id: @conference, format: :json) } }
%thead
%tr
- %th ID#
- %th Name
- %th E-Mail
- - if @code_of_conduct
- %th
- %abbr{ title: 'Code of Conduct' } CoC
- %th Arrival
- %th Departure
- - if @conference.questions.any?
- %th Questions
- %th Actions
+ %th{ width: '0' } ID#
+ %th{ width: '25%' } Name
+ %th{ width: '0' } Roles
+ %th{ width: '0' } E-Mail
+ %th{ width: '0' }
+ %abbr{ title: 'Code of Conduct' } CoC
+ %th{ width: '0' } Arrival
+ %th{ width: '0' } Departure
+ %th{ width: '0' } Actions
%tbody
- - @registrations.each_with_index do |registration, index|
- %tr
- %td
- = registration.id
- %td
- = registration.name.present? ? registration.name : registration.username
- %br
- - registration.user.roles.where(resource: @conference).each do |role|
- %span.label.label-info
- = role.name.titleize
- %td
- = registration.email
- - if @code_of_conduct
- - if registration.accepted_code_of_conduct
- %td.text-success.text-center= fa_icon('check', title: 'accepted')
- - else
- %td.text-center.text-warning
- = fa_icon('exclamation-circle',
- title: 'Has not accepted Code of Conduct')
- %td
- - if registration.arrival
- = registration.arrival.strftime('%d %b %H:%M')
- - else
- n/a
- %td
- - if registration.departure
- = registration.departure.strftime('%d %b %H:%M')
- - else
- n/a
- -if @conference.questions.any?
- %td
- = link_to 'Questions','#', class: 'btn btn-success question-btn', 'data-id' => index, 'data-name' => registration.name
- %td{ 'data-order' => registration.attended.to_s }
- = check_box_tag "#{@conference.short_title}_#{registration.id}", registration.id, registration.attended,
- class: 'switch-checkbox',
- url: toggle_attendance_admin_conference_registration_path(@conference.short_title, id: registration.id)+"?attended="
- .btn-group
- = link_to 'Edit', edit_admin_conference_registration_path(@conference.short_title, id: registration),
- method: :get, class: 'btn btn-primary'
- = link_to 'Delete', admin_conference_registration_path(@conference.short_title, registration),
- method: :delete, class: 'btn btn-danger', data: { confirm: "Do you really want to delete the Registration for #{registration.name}?" }
- - @registrations.each_with_index do |registration, index|
- .questions{class: "question#{index}", style: 'display:none;'}
- = render partial: 'questions', locals: { registration: registration }
-.modal.fade{ id: 'questions', 'role' => 'dialog', 'aria-hidden' => 'true' }
- .modal-dialog
- .modal-content
- .modal-header
- %h3{id: 'question-modal-header'}
- Questions for Foobar
- .modal-body#question-modal-body
+:javascript
+ $(function () {
+ var codeOfConductPresent = #{@code_of_conduct ? 'true' : 'false'};
+ var registrationsDataTable = $('#registrations.datatable').DataTable({
+ "processing": true,
+ "serverSide": true,
+ "ajax": $('#registrations.datatable').data('source'),
+ "drawCallback": function(settings) {
+ checkboxSwitch("[class='switch-checkbox']");
+ if (codeOfConductPresent) {
+ iconize("td.code-of-conduct", "true", "check", "accepted");
+ iconize("td.code-of-conduct", "false", "exclamation-circle", "Has not accepted Code of Conduct");
+ };
+ // truncatify("td.truncate");
+ },
+ "columns": [
+ {
+ "data": "id"
+ },
+ {
+ "data": "name",
+ "className": "truncate",
+ "render": function(data, type, row) {
+ var content = '' + data + '
';
+ $.each(row.roles, function(index, role){
+ content += ' ' + role + ''
+ });
+ return content;
+ }
+ },
+ {
+ "name": "roles",
+ "data": "roles",
+ "className": "truncate",
+ "render": function(data, type, row) {
+ return data.join(', ');
+ }
+ },
+ {
+ "data": "email"
+ },
+ {
+ "data": "accepted_code_of_conduct",
+ "className": "code-of-conduct text-center",
+ "searchable": false
+ },
+ {
+ "data": "arrival",
+ "searchable": false,
+ "render": function(data, type, row) {
+ if (data) { return moment(data).format('ll LT'); }
+ return '';
+ }
+ },
+ {
+ "data": "departure",
+ "searchable": false,
+ "render": function(data, type, row) {
+ if (data) { return moment(data).format('ll LT'); }
+ return '';
+ }
+ },
+ {
+ "data": null,
+ "className": "actions",
+ "searchable": false,
+ "sortable": false,
+ "render": function (data, type, row, meta) {
+ return '