From d46d7ff62646704ee463de8e7a155dfd4ccebc4e Mon Sep 17 00:00:00 2001 From: Tom O'Dwyer Date: Thu, 12 Sep 2024 11:36:58 +0100 Subject: [PATCH 1/9] Install simple-datatables dependency --- package-lock.json | 25 ++++++++++++++++++++++++- package.json | 3 ++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 23c45707..efad8ef8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,8 @@ "version": "1.0.0", "dependencies": { "@fontsource-variable/public-sans": "^5.0.19", - "htmx.org": "^1.9.12" + "htmx.org": "^1.9.12", + "simple-datatables": "^9.1.0" }, "devDependencies": { "@tailwindcss/forms": "^0.5.7", @@ -1119,6 +1120,12 @@ "node": ">=4" } }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "license": "MIT" + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -1126,6 +1133,12 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/diff-dom": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/diff-dom/-/diff-dom-5.1.4.tgz", + "integrity": "sha512-TSEaVdVGictY1KHg7VpVw2nuM02YKC9C8/qBkGiCnkiAybVbu1zQTMj2/dnVLRO7Z62UsqzHGpXweiOj5/jaZg==", + "license": "LGPL-3.0" + }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -2066,6 +2079,16 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simple-datatables": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/simple-datatables/-/simple-datatables-9.1.0.tgz", + "integrity": "sha512-0k5x8+71P1Hnn37VcdM/FpRxKLqBM+T32jqRgJiezbijUg6LbpepufkIDEpf8RtGmA6ftoz+FnAcn0Wj9yOQuA==", + "license": "LGPL-3.0", + "dependencies": { + "dayjs": "^1.11.10", + "diff-dom": "^5.1.3" + } + }, "node_modules/source-map-js": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", diff --git a/package.json b/package.json index 4d203fc1..59e27881 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ }, "dependencies": { "@fontsource-variable/public-sans": "^5.0.19", - "htmx.org": "^1.9.12" + "htmx.org": "^1.9.12", + "simple-datatables": "^9.1.0" } } From 678f70f555aecbab152325522a8c750a43609355 Mon Sep 17 00:00:00 2001 From: Tom O'Dwyer Date: Thu, 12 Sep 2024 11:38:20 +0100 Subject: [PATCH 2/9] Create datatable component styles and scripts --- airlock/templates/_components/datatable.html | 13 +++ airlock/templatetags/airlock_components.py | 1 + assets/src/scripts/datatable.js | 112 +++++++++++++++++++ assets/src/styles/datatable.css | 42 +++++++ vite.config.js | 1 + 5 files changed, 169 insertions(+) create mode 100644 airlock/templates/_components/datatable.html create mode 100644 assets/src/scripts/datatable.js create mode 100644 assets/src/styles/datatable.css diff --git a/airlock/templates/_components/datatable.html b/airlock/templates/_components/datatable.html new file mode 100644 index 00000000..85fb719a --- /dev/null +++ b/airlock/templates/_components/datatable.html @@ -0,0 +1,13 @@ +
+

Loading table data...

+ + {{ children }} + +
diff --git a/airlock/templatetags/airlock_components.py b/airlock/templatetags/airlock_components.py index b2e5e5b7..1793f989 100644 --- a/airlock/templatetags/airlock_components.py +++ b/airlock/templatetags/airlock_components.py @@ -11,6 +11,7 @@ "airlock_workspace_header": "_components/header/workspace/header.html", "airlock_request_header": "_components/header/request/header.html", "airlock_repo_header": "_components/header/repo/header.html", + "datatable": "_components/datatable.html", }, register, ) diff --git a/assets/src/scripts/datatable.js b/assets/src/scripts/datatable.js new file mode 100644 index 00000000..856ad3bc --- /dev/null +++ b/assets/src/scripts/datatable.js @@ -0,0 +1,112 @@ +import { DataTable } from "simple-datatables"; +import "../styles/datatable.css"; + +/** + * @param {string} value + */ +function hasOnlyDigits(value) { + return /^\d+$/.test(value); +} + +function buildTables() { + /** @type {NodeListOf | null} */ + const datatableEls = document.querySelectorAll("[data-datatable]"); + + datatableEls?.forEach((table) => { + const columnFilter = table.hasAttribute("data-column-filter"); + const paging = table.hasAttribute("data-paging"); + const searchable = table.hasAttribute("data-searchable"); + const sortable = table.hasAttribute("data-sortable"); + + let perPage = undefined; + if (table.hasAttribute("data-per-page")) { + const dataPerPage = table.getAttribute("data-per-page"); + if (dataPerPage !== null && hasOnlyDigits(dataPerPage)) { + perPage = parseInt(dataPerPage); + } + } + + let dataTable = new DataTable(table, { + classes: { + sorter: "datatable-sorter p-2 relative text-left w-full", + table: ` + datatable-table min-w-full divide-y divide-slate-300 + [&_th]:bg-slate-200 [&_th]:text-slate-900 [&_th]:text-sm [&_th]:font-semibold [&_th]:leading-5 [&_th]:text-left [&_th]:whitespace-nowrap [&_th]:w-auto + [&_td]:text-slate-700 [&_td]:text-sm [&_td]:p-2 + [&_tr]:border-t [&_tr]:border-slate-200 first:[&_tr]:border-t-0 [&_tr]:bg-white even:[&_tr]:bg-slate-50 + `, + top: "hidden", + bottom: paging + ? "datatable-bottom flex flex-col items-center gap-1 py-3 px-4 border-t border-slate-200 w-full text-sm" + : "hidden", + pagination: paging ? "datatable-pagination" : "hidden", + paginationList: paging + ? "datatable-pagination-list flex flex-row gap-4 mx-auto" + : "hidden", + paginationListItemLink: paging + ? ` + font-semibold text-oxford-600 underline underline-offset-2 decoration-oxford-300 transition-colors duration-200 + hover:decoration-transparent hover:text-oxford + focus:decoration-transparent focus:text-oxford focus:bg-bn-sun-300 + ` + : "hidden", + }, + paging, + perPage, + searchable, + sortable, + tableRender: columnFilter + ? (_data, table) => { + const tHead = table.childNodes?.[0]; + const filterHeaders = { + nodeName: "TR", + childNodes: tHead?.childNodes?.[0].childNodes?.map( + (_th, index) => { + const showSearch = + // @ts-ignore + _th.attributes["data-searchable"] !== "false"; + + return { + nodeName: "TH", + childNodes: showSearch + ? [ + { + nodeName: "INPUT", + attributes: { + class: + "datatable-input block w-full border-slate-300 font-normal shadow-sm rounded-md mb-1 sm:text-sm sm:leading-5 focus:border-oxford-500 focus:outline-oxford-500 focus:-outline-offset-1", + "data-columns": `[${index}]`, + // @ts-ignore + placeholder: `Filter ${_data.headings[index].text + .trim() + .toLowerCase()}`, + type: "search", + }, + }, + ] + : [], + }; + } + ), + }; + tHead?.childNodes?.push(filterHeaders); + return table; + } + : (_data, table) => table, + }); + + dataTable.on("datatable.init", () => { + const container = table.closest(".table-container"); + + if (container) { + const spinner = container.querySelector("[data-datatable-spinner]"); + spinner?.classList.toggle("hidden"); + table.classList.toggle("hidden"); + } + }); + }); +} + +buildTables(); + +document.body.addEventListener("htmx:afterSettle", () => buildTables()); diff --git a/assets/src/styles/datatable.css b/assets/src/styles/datatable.css new file mode 100644 index 00000000..b59f6c16 --- /dev/null +++ b/assets/src/styles/datatable.css @@ -0,0 +1,42 @@ +[data-datatable] { + .datatable-sorter { + & .datatable-icon--descending, + & .datatable-icon--ascending { + @apply hidden; + } + + & .datatable-icon--no-sort { + @apply block; + } + } + .datatable-ascending { + & .datatable-icon--no-sort, + & .datatable-icon--descending { + @apply hidden; + } + + & .datatable-icon--ascending { + @apply block; + } + } + + .datatable-descending { + & .datatable-icon--no-sort, + & .datatable-icon--ascending { + @apply hidden; + } + + & .datatable-icon--descending { + @apply block; + } + } + + & a { + @apply text-oxford-600 font-semibold underline decoration-oxford-300 underline-offset-2 duration-200 transition-colors ease-in-out focus:bg-bn-sun-300; + + &:hover, + &:focus { + @apply text-oxford-800 decoration-transparent; + } + } +} diff --git a/vite.config.js b/vite.config.js index c2b6c5d8..7ebb8122 100644 --- a/vite.config.js +++ b/vite.config.js @@ -7,6 +7,7 @@ export default defineConfig({ outDir: "./assets/out", rollupOptions: { input: { + datatable: "assets/src/scripts/datatable.js", htmx: "assets/src/scripts/htmx.js", main: "assets/src/scripts/main.js", resizer: "assets/src/scripts/resizer.js", From 78a875f8030b72b4fa18f71ed7024dfab7918cb9 Mon Sep 17 00:00:00 2001 From: Tom O'Dwyer Date: Thu, 12 Sep 2024 11:38:47 +0100 Subject: [PATCH 3/9] Replace tables with datatable component --- airlock/templates/activity.html | 130 ++++++++---------- .../file_browser/file_content/csv.html | 88 +++++++----- airlock/templates/file_browser/repo/dir.html | 29 ++-- .../templates/file_browser/request/dir.html | 53 ++++--- .../templates/file_browser/workspace/dir.html | 54 +++++--- 5 files changed, 188 insertions(+), 166 deletions(-) diff --git a/airlock/templates/activity.html b/airlock/templates/activity.html index 4a1e5ff1..12d12afa 100644 --- a/airlock/templates/activity.html +++ b/airlock/templates/activity.html @@ -1,81 +1,63 @@ {% load airlock %} {% load django_vite %} -{% load static %} - - -{% #card title="Recent activity" %} +{% #card title="Recent activity" class="mt-5" %} {% if activity %} -
-

Loading table data...

- - + {% #datatable paging per_page="25" column_filter searchable sortable %} + + + + + + + + + + {% for log in activity %} - - - - + + + + - - - {% for log in activity %} - - - - - - - {% endfor %} - - - - - -
+ {% endfor %} + + {% /datatable %} {% else %} {% #list_group %} {% list_group_empty title="No activity" description="There has been no recent activity on this workspace" %} @@ -83,6 +65,4 @@ {% endif %} {% /card %} -{% vite_asset "assets/src/scripts/components.js" app="job_server" %} - - +{% vite_asset "assets/src/scripts/datatable.js" %} diff --git a/airlock/templates/file_browser/file_content/csv.html b/airlock/templates/file_browser/file_content/csv.html index 0c5427ab..cd9db5e4 100644 --- a/airlock/templates/file_browser/file_content/csv.html +++ b/airlock/templates/file_browser/file_content/csv.html @@ -3,52 +3,70 @@ {% load static %} - + + + + + {% vite_hmr_client %} - {% vite_asset "assets/src/scripts/base.js" app="job_server" %} - {% vite_asset "assets/src/scripts/components.js" app="job_server" %} - - + {% vite_asset "assets/src/scripts/main.js" %} + {% vite_asset "assets/src/scripts/datatable.js" %}
{% if use_datatables %} -

Loading table data...

- + {% #datatable column_filter searchable sortable %} + + + {% for header in headers %} + + {% endfor %} + + + + {% for row in rows %} + + {% for cell in row %} + + {% endfor %} + + {% endfor %} + + {% /datatable %} {% else %} - {% endif %} - - - {% for header in headers %} - - {% endfor %} - - - - {% for row in rows %} - - {% for cell in row %} - + + + {% for header in headers %} + + {% endfor %} + + + + {% for row in rows %} + + {% for cell in row %} + + {% endfor %} + {% endfor %} - - {% endfor %} - -
-
- {{ header }} - {% if use_datatables %} - {% datatable_sort_icon %} - {% endif %} - -
{{ cell }}
+ {{ header }} +
{{ cell }}
- -
+ + + {% endif %} - - + + diff --git a/airlock/templates/file_browser/repo/dir.html b/airlock/templates/file_browser/repo/dir.html index fdde65c3..394f48de 100644 --- a/airlock/templates/file_browser/repo/dir.html +++ b/airlock/templates/file_browser/repo/dir.html @@ -2,20 +2,20 @@ {% load static %} {% load airlock %} -{% block extra_styles %} - -{% endblock %} - {% #card title=path_item.name container=True %} - - {% #table class="dir_table" id="customTable" %} - {% #table_head %} + {% #datatable column_filter searchable sortable %} + -
File{% datatable_sort_icon %}
+
+ File + + {% datatable_sort_icon %} + +
- {% /table_head %} + {% for path in path_item.children %} @@ -23,10 +23,9 @@ {% endfor %} - {% /table %} - - {% vite_asset "assets/src/scripts/components.js" app="job_server" %} - - - + {% /datatable %} {% /card %} + +{% vite_hmr_client %} +{% vite_asset "assets/src/scripts/datatable.js" %} + diff --git a/airlock/templates/file_browser/request/dir.html b/airlock/templates/file_browser/request/dir.html index a9ad19f4..e62e35fd 100644 --- a/airlock/templates/file_browser/request/dir.html +++ b/airlock/templates/file_browser/request/dir.html @@ -2,10 +2,6 @@ {% load static %} {% load airlock %} -{% block extra_styles %} - -{% endblock %} - {% fragment as buttons %} {% if content_buttons.multiselect_withdraw.show %}
@@ -17,7 +13,6 @@ {% endif %} {% endfragment %} - {% #card title=path_item.name container=False custom_button=buttons %}
- {% #table class="dir_table" id="customTable" %} - {% #table_head %} + {% #datatable column_filter searchable sortable %} + -
File{% datatable_sort_icon %}
+
+ File + + {% datatable_sort_icon %} + +
-
File Type{% datatable_sort_icon %}
+
+ File Type + + {% datatable_sort_icon %} + +
-
Size{% datatable_sort_icon %}
+
+ Size + + {% datatable_sort_icon %} + +
-
Modified{% datatable_sort_icon %}
+
+ Modified + + {% datatable_sort_icon %} + +
{% if content_buttons.multiselect_withdraw.show %} - + {% endif %} - {% /table_head %} + {% for path in path_item.children %} @@ -68,12 +83,10 @@ {% endfor %} - {% /table %} - + {% /datatable %}
- - {% vite_asset "assets/src/scripts/components.js" app="job_server" %} - - - {% /card %} + +{% vite_hmr_client %} +{% vite_asset "assets/src/scripts/datatable.js" %} + diff --git a/airlock/templates/file_browser/workspace/dir.html b/airlock/templates/file_browser/workspace/dir.html index 57fadd38..56f7bf35 100644 --- a/airlock/templates/file_browser/workspace/dir.html +++ b/airlock/templates/file_browser/workspace/dir.html @@ -2,12 +2,7 @@ {% load static %} {% load airlock %} -{% block extra_styles %} - -{% endblock %} - {% fragment as buttons %} - {% if content_buttons.multiselect_add.show %} {% if content_buttons.multiselect_add.disabled %} {% #button type="button" disabled=True tooltip=content_buttons.multiselect_add.tooltip id="add-file-modal-button" %} @@ -44,28 +39,48 @@ {% csrf_token %} - {% #table class="dir_table" id="customTable" %} - {% #table_head %} + {% #datatable column_filter searchable sortable %} + -
File{% datatable_sort_icon %}
+
+ File + + {% datatable_sort_icon %} + +
-
Review State{% datatable_sort_icon %}
+
+ Review State + + {% datatable_sort_icon %} + +
-
Size{% datatable_sort_icon %}
+
+ Size + + {% datatable_sort_icon %} + +
-
Modified{% datatable_sort_icon %}
+
+ Modified + + {% datatable_sort_icon %} + +
{% if not content_buttons.multiselect_add.disabled %} - + {% endif %} - {% /table_head %} + {% for path in path_item.children %} @@ -83,14 +98,11 @@ {% endfor %} - {% /table %} - - + {% /datatable %} - - {% vite_asset "assets/src/scripts/components.js" app="job_server" %} - - - {% endif %} {% /card %} + +{% vite_hmr_client %} +{% vite_asset "assets/src/scripts/datatable.js" %} + From 3e920c918a6e6a7ceeeb054806c83f9259344489 Mon Sep 17 00:00:00 2001 From: Tom O'Dwyer Date: Thu, 12 Sep 2024 11:39:02 +0100 Subject: [PATCH 4/9] Remove unused styles and scripts --- airlock/static/assets/activity.js | 1 - airlock/static/assets/datatable-loader.js | 41 ---------------------- airlock/static/assets/datatable.css | 26 -------------- airlock/static/assets/file_browser/dir.css | 14 -------- 4 files changed, 82 deletions(-) delete mode 100644 airlock/static/assets/activity.js delete mode 100644 airlock/static/assets/datatable-loader.js delete mode 100644 airlock/static/assets/datatable.css delete mode 100644 airlock/static/assets/file_browser/dir.css diff --git a/airlock/static/assets/activity.js b/airlock/static/assets/activity.js deleted file mode 100644 index 2eb2e375..00000000 --- a/airlock/static/assets/activity.js +++ /dev/null @@ -1 +0,0 @@ -window.initCustomTable(10); diff --git a/airlock/static/assets/datatable-loader.js b/airlock/static/assets/datatable-loader.js deleted file mode 100644 index d6ac3262..00000000 --- a/airlock/static/assets/datatable-loader.js +++ /dev/null @@ -1,41 +0,0 @@ -var observer = new MutationObserver((mutations, obs) => { - const sorterButton = document.querySelector( - "button.datatable-sorter" - ); - const paginationEl = document.querySelector("#pagination-nav") - if (sorterButton) { - document.querySelector("#airlock-table p.spinner").style.display = "none"; - document.querySelector("#airlock-table table.datatable").style.display = "table"; - // If we have paginationEl, display it - // The upstream code hides the pagination until the page numbers have been populated - if (paginationEl !== null) { - document.querySelector("#pagination-nav").classList.remove("hidden") - }; - obs.disconnect(); - clearTimeout(); - return; - } -}); - -observer.observe(document, { - childList: true, - subtree: true, -}); - -// If the datatable hasn't loaded within 5 seconds, it's likely something's gone -// wrong; unhide the table to show the non-datatable table -// Also hide the datatable sort icons as they'll be unformatted without the -// datatable, and they won't work anyway -setTimeout(() => { - const sorterButton = document.querySelector( - "button.datatable-sorter" - ); - if (!sorterButton) { - document.querySelector("#airlock-table p.spinner").style.display = "none"; - document.querySelector("#airlock-table table.datatable").style.display = "table"; - const sortIcons = document.getElementsByClassName("sort-icon"); - for (let i = 0; i < sortIcons.length; i++) { - sortIcons.item(i).style.display = "none";; - } - } -}, 5000); diff --git a/airlock/static/assets/datatable.css b/airlock/static/assets/datatable.css deleted file mode 100644 index 9842177a..00000000 --- a/airlock/static/assets/datatable.css +++ /dev/null @@ -1,26 +0,0 @@ -.datatable thead { - position: sticky; - top: 0; - text-align: left; - background-color: rgba(248, 250, 252); -} - -#customTable.datatable-table th:first-child, -#customTable.datatable-table td:first-child { - padding-inline-start: 1.25rem; -} - -#customTable.datatable-table th:first-child button, -#customTable.datatable-table td:first-child button { - padding-inline-start: 0; -} - -#customTable.datatable-table th:last-child, -#customTable.datatable-table td:last-child { - padding-inline-end: 1.25rem; -} - -#customTable.datatable-table th:last-child button, -#customTable.datatable-table td:last-child button { - padding-inline-end: 0; -} diff --git a/airlock/static/assets/file_browser/dir.css b/airlock/static/assets/file_browser/dir.css deleted file mode 100644 index 903a8056..00000000 --- a/airlock/static/assets/file_browser/dir.css +++ /dev/null @@ -1,14 +0,0 @@ -#customTable thead { -position: sticky; -top: 0; -text-align: left; -background-color: rgba(248,250,252); -} - -#customTable td.name a.directory { -background-image: url(/static/folder.png); -background-repeat: no-repeat; -background-size: 1.4rem; -background-position: left -0.2rem top 0; -padding-left: 1.1rem; -} From c0cbe5c59b3fc4a2f7d7e0fbfd011a28ca94278a Mon Sep 17 00:00:00 2001 From: Tom O'Dwyer Date: Thu, 12 Sep 2024 11:39:38 +0100 Subject: [PATCH 5/9] Simplify dir script for based on datatables --- airlock/static/assets/file_browser/dir.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/airlock/static/assets/file_browser/dir.js b/airlock/static/assets/file_browser/dir.js index 3d4f8578..3a3655aa 100644 --- a/airlock/static/assets/file_browser/dir.js +++ b/airlock/static/assets/file_browser/dir.js @@ -1,13 +1,11 @@ -// ensure datatable is initialised when loading over HTMX -window.initCustomTable ? window.initCustomTable() : null; - // implement select all checkbox -function toggleSelectAll(elem, event) { +function toggleSelectAll(elem) { const form = document.querySelector("#multiselect_form"); - const checkboxes = form.querySelectorAll('input[type="checkbox"]'); + /** @type {NodeListOf|undefined} */ + const checkboxes = form?.querySelectorAll('input[type="checkbox"]'); - checkboxes.forEach(function(checkbox) { + checkboxes?.forEach(function(checkbox) { checkbox.checked = elem.checked; }); } From a13ab3d8ba497e928fba3d753c0b36a608032ed5 Mon Sep 17 00:00:00 2001 From: Tom O'Dwyer Date: Thu, 12 Sep 2024 12:03:23 +0100 Subject: [PATCH 6/9] Update CSS selector for datatables in tests --- tests/functional/test_docs_screenshots.py | 2 +- tests/functional/test_e2e.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/functional/test_docs_screenshots.py b/tests/functional/test_docs_screenshots.py index 99293c9e..68cb9058 100644 --- a/tests/functional/test_docs_screenshots.py +++ b/tests/functional/test_docs_screenshots.py @@ -82,7 +82,7 @@ def test_screenshot_from_creation_to_release( # Directory view page.goto(live_server.url + workspace.get_url(UrlPath("outputs"))) # let the data table load - expect(page.locator("#customTable.datatable-table")).to_be_visible() + expect(page.locator(".datatable-table")).to_be_visible() page.screenshot(path=settings.SCREENSHOT_DIR / "workspace_directory_view.png") # Content only in directory view content = page.locator("#selected-contents") diff --git a/tests/functional/test_e2e.py b/tests/functional/test_e2e.py index 1200063d..6f0559b9 100644 --- a/tests/functional/test_e2e.py +++ b/tests/functional/test_e2e.py @@ -542,7 +542,7 @@ def test_e2e_withdraw_and_readd_file(page, live_server, dev_users): # Withdraw file2 from the directory page page.goto(live_server.url + release_request.get_url("default/subdir")) - expect(page.locator("#customTable.datatable-table")).to_be_visible() + expect(page.locator(".datatable-table")).to_be_visible() find_and_click( page.locator('input[name="selected"][value="default/subdir/file2.txt"]') ) @@ -563,7 +563,7 @@ def test_e2e_withdraw_and_readd_file(page, live_server, dev_users): page.goto(live_server.url + workspace.get_url(UrlPath("subdir/"))) # We have to wait for the datatable to finish rendering before we interact with the # checkboxes otherwise the wrong thing gets selected - expect(page.locator("#customTable.datatable-table")).to_be_visible() + expect(page.locator(".datatable-table")).to_be_visible() find_and_click(page.locator(f'input[name="selected"][value="{path1}"]')) find_and_click(page.locator("button[value=add_files]")) From 63b3cb84d3d1acafc1b90eabc37862e7f5f3d6b7 Mon Sep 17 00:00:00 2001 From: Tom O'Dwyer Date: Thu, 12 Sep 2024 12:13:42 +0100 Subject: [PATCH 7/9] Fix paging props on datatable --- airlock/templates/_components/datatable.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/airlock/templates/_components/datatable.html b/airlock/templates/_components/datatable.html index 85fb719a..4f1fe401 100644 --- a/airlock/templates/_components/datatable.html +++ b/airlock/templates/_components/datatable.html @@ -3,10 +3,10 @@ {{ children }} From 217f72fd2b3d9abc0ae743e2deab29a9756905bf Mon Sep 17 00:00:00 2001 From: Tom O'Dwyer Date: Thu, 12 Sep 2024 12:18:32 +0100 Subject: [PATCH 8/9] Show 10 items per page in the activity log --- airlock/templates/activity.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/airlock/templates/activity.html b/airlock/templates/activity.html index 12d12afa..a49859fa 100644 --- a/airlock/templates/activity.html +++ b/airlock/templates/activity.html @@ -3,7 +3,7 @@ {% #card title="Recent activity" class="mt-5" %} {% if activity %} - {% #datatable paging per_page="25" column_filter searchable sortable %} + {% #datatable paging per_page="10" column_filter searchable sortable %} From 8ac805adbf76f9282508f87bb8e805a26554002d Mon Sep 17 00:00:00 2001 From: Tom O'Dwyer Date: Thu, 12 Sep 2024 12:49:46 +0100 Subject: [PATCH 9/9] Only paginate datatable if per_page is supplied --- airlock/templates/_components/datatable.html | 4 ++-- airlock/templates/activity.html | 2 +- assets/src/scripts/datatable.js | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/airlock/templates/_components/datatable.html b/airlock/templates/_components/datatable.html index 4f1fe401..2acc5d9b 100644 --- a/airlock/templates/_components/datatable.html +++ b/airlock/templates/_components/datatable.html @@ -3,10 +3,10 @@ {{ children }} diff --git a/airlock/templates/activity.html b/airlock/templates/activity.html index a49859fa..313e3f1c 100644 --- a/airlock/templates/activity.html +++ b/airlock/templates/activity.html @@ -3,7 +3,7 @@ {% #card title="Recent activity" class="mt-5" %} {% if activity %} - {% #datatable paging per_page="10" column_filter searchable sortable %} + {% #datatable per_page="10" column_filter searchable sortable %} diff --git a/assets/src/scripts/datatable.js b/assets/src/scripts/datatable.js index 856ad3bc..35204ea3 100644 --- a/assets/src/scripts/datatable.js +++ b/assets/src/scripts/datatable.js @@ -14,14 +14,15 @@ function buildTables() { datatableEls?.forEach((table) => { const columnFilter = table.hasAttribute("data-column-filter"); - const paging = table.hasAttribute("data-paging"); const searchable = table.hasAttribute("data-searchable"); const sortable = table.hasAttribute("data-sortable"); + let paging = false; let perPage = undefined; if (table.hasAttribute("data-per-page")) { const dataPerPage = table.getAttribute("data-per-page"); if (dataPerPage !== null && hasOnlyDigits(dataPerPage)) { + paging = true; perPage = parseInt(dataPerPage); } }