From 0401eabcc7b9bebc9921aa3419ac499f1e250857 Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Tue, 14 Apr 2026 16:54:41 +0000 Subject: [PATCH 1/4] feat: enhance course staff requests index and table usability - Relocate export buttons below the table for better layout flow. - Add a "Batch Edit" toggle to control selection column visibility. - Update action buttons with specific labels and remove nested groups. - Add checkmark indicators and improved alignment to column visibility menu. - Remove redundant navigation links from the actions column. Co-authored-by: Claude Code --- app/assets/stylesheets/_custom_bootstrap.scss | 27 ++++++++++ .../controllers/requests_controller.js | 50 ++++++++++++++++--- app/views/requests/instructor_index.html.erb | 45 +++++++---------- 3 files changed, 88 insertions(+), 34 deletions(-) diff --git a/app/assets/stylesheets/_custom_bootstrap.scss b/app/assets/stylesheets/_custom_bootstrap.scss index 42f26e39..f8443f6b 100644 --- a/app/assets/stylesheets/_custom_bootstrap.scss +++ b/app/assets/stylesheets/_custom_bootstrap.scss @@ -471,6 +471,33 @@ a.btn-outline-danger.disable:hover { // BS-type table-responsive +// Column visibility dropdown - checkmarks for visible columns +.dt-button-collection { + .dt-button { + text-align: left !important; + padding-left: 2.2em !important; + position: relative; + + &.active, + &.dt-button-active { + background-color: transparent !important; + color: var(--bs-dropdown-link-color, inherit) !important; + + &:hover { + background-color: var(--bs-dropdown-link-hover-bg) !important; + color: var(--bs-dropdown-link-hover-color) !important; + } + + &::before { + content: '✓'; + position: absolute; + left: 0.75em; + font-weight: bold; + } + } + } +} + // Request Table desktop @media (min-width: 768px) { #requests-table #assignment { diff --git a/app/javascript/controllers/requests_controller.js b/app/javascript/controllers/requests_controller.js index 4b6d7278..c1092263 100644 --- a/app/javascript/controllers/requests_controller.js +++ b/app/javascript/controllers/requests_controller.js @@ -19,6 +19,7 @@ export default class extends Controller { const searchQuery = this.element.dataset.searchQuery; const readonlyToken = this.element.dataset.readonlyToken; const courseId = this.element.dataset.courseId; + const controller = this; this.table = new DataTable('#requests-table', { paging: true, @@ -28,11 +29,45 @@ export default class extends Controller { responsive: true, columnDefs: [ { orderable: false, targets: 'no-sort' }, - { type: "date", targets: [5, 6, 7] } + { type: "date", targets: [5, 6, 7] }, + { visible: false, targets: [0] } ], order: [[5, "asc"]], layout: { topStart: { + buttons: [ + { + extend: 'colvis', + text: 'Columns', + columns: ':not(.no-sort)' + }, + { + text: 'Batch Edit', + action: function (e, dt, node, config) { + const col = dt.column(0); + const willShow = !col.visible(); + col.visible(willShow); + + const batchActions = controller.element.querySelector('.batch-actions'); + if (batchActions) { + batchActions.classList.toggle('d-none', !willShow); + } + + if (!willShow) { + controller._selectableCheckboxes().forEach((cb) => { cb.checked = false; }); + controller._syncSelectionControls(); + } + + const btnEl = node.nodeType === 1 ? node : (node[0] || node); + btnEl.classList.toggle('active', willShow); + btnEl.innerHTML = willShow + ? 'Exit Batch Edit' + : 'Batch Edit'; + } + } + ] + }, + bottom2Start: { buttons: [ { extend: 'collection', @@ -92,9 +127,8 @@ export default class extends Controller { } } } - }, - 'colvis' - ], + } + ] } } }); @@ -137,8 +171,8 @@ export default class extends Controller { async _submitSingleAction(button) { const url = button.dataset.url; - const btnGroup = button.closest('.btn-group'); - const allBtns = btnGroup ? btnGroup.querySelectorAll('button') : [button]; + const container = button.closest('.request-actions'); + const allBtns = container ? container.querySelectorAll('button') : [button]; allBtns.forEach((btn) => { btn.disabled = true; }); try { @@ -235,8 +269,8 @@ export default class extends Controller { statusTd.innerHTML = `${label}`; } - const btnGroup = tr.querySelector('.btn-group'); - if (btnGroup) btnGroup.remove(); + const requestActions = tr.querySelector('.request-actions'); + if (requestActions) requestActions.remove(); const checkbox = tr.querySelector('input[data-request-id]'); if (checkbox) { diff --git a/app/views/requests/instructor_index.html.erb b/app/views/requests/instructor_index.html.erb index 4274f8ef..affc90b3 100644 --- a/app/views/requests/instructor_index.html.erb +++ b/app/views/requests/instructor_index.html.erb @@ -67,31 +67,24 @@ <% end %> -
- <%= link_to course_request_path(@course, request), class: "btn btn-sm btn-primary", title: "View", aria: { label: "View request" } do %> - - <% end %> - <% if request.status == 'pending' %> -
- - -
- <% end %> -
+ <% if request.status == 'pending' %> +
+ + +
+ <% end %> <%= link_to request.user.try(:name) || 'N/A', course_request_path(@course, request) %> @@ -143,7 +136,7 @@ -
+
+ + <% export_url = export_course_requests_url(@course, format: :csv, readonly_api_token: @course.readonly_api_token) %> + +
+ + + +
+ + <% else %>
There are no current requests.
<% end %> From 583e0c71f171fae01313ed7802f7aff30161fd55 Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Tue, 14 Apr 2026 22:51:18 -0700 Subject: [PATCH 3/4] tidy unused code --- app/javascript/controllers/requests_controller.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/javascript/controllers/requests_controller.js b/app/javascript/controllers/requests_controller.js index 30725b82..21fd2d2d 100644 --- a/app/javascript/controllers/requests_controller.js +++ b/app/javascript/controllers/requests_controller.js @@ -17,8 +17,6 @@ export default class extends Controller { if (!DataTable.isDataTable('#requests-table')) { const searchQuery = this.element.dataset.searchQuery; - const readonlyToken = this.element.dataset.readonlyToken; - const courseId = this.element.dataset.courseId; const controller = this; this.table = new DataTable('#requests-table', { From fffc29944a0aab1747c1bb243cd20f82e3a2d22b Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Tue, 14 Apr 2026 23:06:27 -0700 Subject: [PATCH 4/4] More tidying of the HTML table --- app/helpers/requests_helper.rb | 4 ++ app/views/requests/instructor_index.html.erb | 40 ++++++++++---------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/app/helpers/requests_helper.rb b/app/helpers/requests_helper.rb index d57b8fd5..79cb39d9 100644 --- a/app/helpers/requests_helper.rb +++ b/app/helpers/requests_helper.rb @@ -1,4 +1,8 @@ module RequestsHelper + def text_label_for(request) + "Request for #{request.user.try(:name) || 'N/A'} - #{request.assignment&.name || 'N/A'}" + end + def status_export_string(request) case request.status when 'pending' diff --git a/app/views/requests/instructor_index.html.erb b/app/views/requests/instructor_index.html.erb index c88a2f18..92b8f4b8 100644 --- a/app/views/requests/instructor_index.html.erb +++ b/app/views/requests/instructor_index.html.erb @@ -28,8 +28,8 @@
- - + + - + - - - - - - + + + + + + @@ -67,20 +67,20 @@
ActionsActions Name AssignmentStudent IDRequested AtOriginal Due DateRequested Due Date# of DaysStatusStudent IDRequested AtOriginal Due DateRequested Due Date# of DaysStatus
<% if request.status == 'pending' %> -
+
<% else %>