Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a custom datatable component for Airlock #665

Merged
merged 9 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion airlock/static/assets/activity.js

This file was deleted.

41 changes: 0 additions & 41 deletions airlock/static/assets/datatable-loader.js

This file was deleted.

26 changes: 0 additions & 26 deletions airlock/static/assets/datatable.css

This file was deleted.

14 changes: 0 additions & 14 deletions airlock/static/assets/file_browser/dir.css

This file was deleted.

10 changes: 4 additions & 6 deletions airlock/static/assets/file_browser/dir.js
Original file line number Diff line number Diff line change
@@ -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<HTMLInputElement>|undefined} */
const checkboxes = form?.querySelectorAll('input[type="checkbox"]');

checkboxes.forEach(function(checkbox) {
checkboxes?.forEach(function(checkbox) {
checkbox.checked = elem.checked;
});
}
13 changes: 13 additions & 0 deletions airlock/templates/_components/datatable.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<div class="table-container">
<p class="spinner p-4" data-datatable-spinner>Loading table data...</p>
<table
class="{{ class }} hidden"
data-datatable
{% if per_page %}
data-per-page="{{ per_page }}"
{% endif %}
{% attrs id data-column-filter=column_filter data-sortable=sortable data-searchable=searchable %}
>
{{ children }}
</table>
</div>
130 changes: 55 additions & 75 deletions airlock/templates/activity.html
Original file line number Diff line number Diff line change
@@ -1,88 +1,68 @@
{% load airlock %}
{% load django_vite %}
{% load static %}

<link rel="stylesheet" href="{% static 'assets/datatable.css' %}">

{% #card title="Recent activity" %}
{% #card title="Recent activity" class="mt-5" %}
{% if activity %}
<div id="airlock-table">
<p class="spinner">Loading table data...</p>
<table class="datatable hidden" id="customTable">
<thead>
{% #datatable per_page="10" column_filter searchable sortable %}
<thead>
<tr>
<th>
<div class="flex flex-row gap-2 items-center">
Time
<span class="sort-icon h-4 w-4 [&_img]:h-4 [&_img]:w-4">
{% datatable_sort_icon %}
</span>
</div>
</th>
<th>
<div class="flex flex-row gap-2 items-center">
User
<span class="sort-icon h-4 w-4 [&_img]:h-4 [&_img]:w-4">
{% datatable_sort_icon %}
</span>
</div>
</th>
<th>
<div class="flex flex-row gap-2 items-center">
Action
<span class="sort-icon h-4 w-4 [&_img]:h-4 [&_img]:w-4">
{% datatable_sort_icon %}
</span>
</div>
</th>
<th>
<div class="flex flex-row gap-2 items-center">
Details
<span class="sort-icon h-4 w-4 [&_img]:h-4 [&_img]:w-4">
{% datatable_sort_icon %}
</span>
</div>
</th>
</tr>
</thead>
<tbody>
{% for log in activity %}
<tr>
<th><div class="flex flex-row gap-2">Time{% datatable_sort_icon %}</div></th>
<th><div class="flex flex-row gap-2">User{% datatable_sort_icon %}</div></th>
<th><div class="flex flex-row gap-2">Action{% datatable_sort_icon %}</div></th>
<th><div class="flex flex-row gap-2">Details{% datatable_sort_icon %}</div></th>
<td>{{ log.created_at|date:'Y-m-d H:i' }}</td>
<td>{{ log.user }}</td>
<td>{{ log.description }}</td>
<td>
<ul>
{% if log.path %}<li><b>path:</b> {{ log.path }}</li>{% endif %}
{% for k,v in log.extra.items %}
<li><b>{{ k }}:</b> {{ v }}</li>
{% endfor %}
</ul>
</td>
</tr>
</thead>
<tbody>
{% for log in activity %}
<tr>
<td>{{ log.created_at|date:'Y-m-d H:i' }}</td>
<td>{{ log.user }}</td>
<td>{{ log.description }}</td>
<td>
<ul>
{% if log.path %}<li><b>path:</b> {{ log.path }}</li>{% endif %}
{% for k,v in log.extra.items %}
<li><b>{{ k }}:</b> {{ v }}</li>
{% endfor %}
</ul>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</table>

<nav id="pagination-nav" class="hidden flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3" aria-label="Pagination">
<div class="sm:block">
<p class="text-sm text-gray-700">
Page
<strong data-table-pagination="page-number">#</strong>
of
<strong data-table-pagination="total-pages">#</strong>
</p>
</div>
<div class="flex flex-1 justify-between gap-4 sm:justify-end">
<button
data-table-pagination="previous-page"
class="
px-4 py-2 text-sm font-medium
inline-flex items-center justify-center border rounded-md shadow-sm transition-buttons duration-200
border border-slate-400/75 text-slate-700 !shadow-none
hover:bg-slate-200
focus:bg-slate-200 focus:ring-slate-500 focus:ring-offset-white
hover:shadow-lg
focus:outline-none focus:ring-2 focus:ring-offset-2"
>
Previous
</button>
<button
data-table-pagination="next-page"
class="
px-4 py-2 text-sm font-medium
inline-flex items-center justify-center border rounded-md shadow-sm transition-buttons duration-200
border border-slate-400/75 text-slate-700 !shadow-none
hover:bg-slate-200
focus:bg-slate-200 focus:ring-slate-500 focus:ring-offset-white
hover:shadow-lg
focus:outline-none focus:ring-2 focus:ring-offset-2"
>
Next
</button>
</div>
</nav>
</div>
{% endfor %}
</tbody>
{% /datatable %}
{% else %}
{% #list_group %}
{% list_group_empty title="No activity" description="There has been no recent activity on this workspace" %}
{% /list_group %}
{% endif %}
{% /card %}

{% vite_asset "assets/src/scripts/components.js" app="job_server" %}
<script defer src="{% static 'assets/activity.js' %}"></script>
<script defer src="{% static 'assets/datatable-loader.js' %}"></script>
{% vite_asset "assets/src/scripts/datatable.js" %}
88 changes: 53 additions & 35 deletions airlock/templates/file_browser/file_content/csv.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,52 +3,70 @@
{% load static %}

<!DOCTYPE html>
<html lang="en">
<html lang="en" class="min-h-screen">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

{% vite_hmr_client %}
{% vite_asset "assets/src/scripts/base.js" app="job_server" %}
{% vite_asset "assets/src/scripts/components.js" app="job_server" %}
<link rel="stylesheet" href="{% static 'assets/datatable.css' %}">
<link rel="stylesheet" href="{% static 'assets/icons.css' %}">
{% vite_asset "assets/src/scripts/main.js" %}
{% vite_asset "assets/src/scripts/datatable.js" %}
</head>

<body>

<div id="airlock-table">
{% if use_datatables %}
<p class="spinner">Loading table data...</p>
<table class="datatable hidden" id="customTable">
{% #datatable column_filter searchable sortable %}
<thead>
<tr>
{% for header in headers %}
<th>
<div class="flex flex-row gap-2 items-center">
{{ header }}
<span class="sort-icon h-4 w-4 [&_img]:h-4 [&_img]:w-4">
{% datatable_sort_icon %}
</span>
</div>
</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in rows %}
<tr>
{% for cell in row %}
<td data-order="{{ cell }}">{{ cell }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
{% /datatable %}
{% else %}
<table>
{% endif %}
<thead>
<tr>
{% for header in headers %}
<th>
<div class="flex flex-row gap-2">
{{ header }}
{% if use_datatables %}
<span class="sort-icon">{% datatable_sort_icon %}</span>
{% endif %}
</dir>
</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in rows %}
<tr>
{% for cell in row %}
<td data-order="{{ cell }}">{{ cell }}</td>
<thead>
<tr>
{% for header in headers %}
<th>
{{ header }}
</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in rows %}
<tr>
{% for cell in row %}
<td>{{ cell }}</td>
{% endfor %}
</tr>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>

</div>
</tbody>
</table>
{% endif %}

<script src="{% static 'assets/datatable-loader.js' %}"></script>
</body>
</div>
</body>

</html>
Loading