Implement toggleable table fields

This commit is contained in:
2022-08-09 07:20:30 +01:00
parent 89b38111cd
commit d1076ca2b5
6 changed files with 574 additions and 308 deletions

View File

@@ -3,6 +3,7 @@
{% load joinsep %}
{% include 'partials/notify.html' %}
{% if table %}
<script src="{% static 'js/column-shifter.js' %}"></script>
<div style="display: none" id="jsonData" data-json="{{ data }}">
</div>
@@ -31,11 +32,7 @@
</div>
<script src="{% static 'chart.js' %}"></script>
</div>
<div class="box">
<div class="table-container">
{% include 'ui/drilldown/table_results_partial.html' %}
</div>
</div>
{% include 'ui/drilldown/table_results_partial.html' %}
{% endif %}
{# Update the tags in case the user changed the query #}
{# Check for focus and refocus #}

View File

@@ -1,297 +1,340 @@
{% load django_tables2 %}
{% load i18n %}
{% load django_tables2_bulma_template %}
{% load static %}
{% block table-wrapper %}
<div class="container">
<div id="drilldown-table" class="container box column-shifter-container" style="position:relative; z-index:1;">
{% block table %}
<table {% render_attrs table.attrs class="table is-striped is-hoverable is-fullwidth" %}>
{% block table.thead %}
{% if table.show_header %}
<thead {% render_attrs table.attrs.thead class="" %}>
{% block table.thead.row %}
<tr>
{% for column in table.columns %}
<div class="nowrap-parent">
<div class="nowrap-child">
<div class="dropdown" id="dropdown">
<div class="dropdown-trigger">
<button id="dropdown-trigger" class="button dropdown-toggle" aria-haspopup="true" aria-controls="dropdown-menu">
<span>Show/hide fields</span>
<span class="icon is-small">
<i class="fas fa-angle-down" aria-hidden="true"></i>
</span>
</button>
</div>
<div class="dropdown-menu" id="dropdown-menu" role="menu">
<div class="dropdown-content" style="position:absolute; z-index:10;">
{% for column in table.columns %}
{% if column.name in show %}
<a class="btn-shift-column dropdown-item"
data-td-class="{{ column.name }}"
data-state="on"
{% if not forloop.last %} style="border-bottom:1px solid #ccc;" {%endif %}
data-table-class-container="drilldown-table">
<span class="check icon" data-tooltip="Visible" style="display:none;">
<i class="fa-solid fa-check"></i>
</span>
<span class="uncheck icon" data-tooltip="Hidden" style="display:none;">
<i class="fa-solid fa-xmark"></i>
</span>
{{ column.header }}
</a>
{% endif %}
{% endfor %}
</div>
</div>
</div>
</div>
<div class="nowrap-child">
<span id="loader" class="button is-light has-text-link is-loading">Static</span>
</div>
</div>
<script>
var dropdown_button = document.getElementById("dropdown-trigger");
var dropdown = document.getElementById("dropdown");
dropdown_button.addEventListener('click', function(e) {
// elements[i].preventDefault();
dropdown.classList.toggle('is-active');
});
{% if column.name in show and not column.name in hide %}
{% block table.thead.th %}
<th {% render_attrs column.attrs.th class="" %}>
<div class="nowrap-parent">
{% if column.orderable %}
<div class="nowrap-child">
{% if column.is_ordered %}
{% is_descending column.order_by as descending %}
{% if descending %}
<span class="icon" aria-hidden="true">{% block table.desc_icon %}<i class="fa-solid fa-sort-down"></i>{% endblock table.desc_icon %}</span>
{% else %}
<span class="icon" aria-hidden="true">{% block table.asc_icon %}<i class="fa-solid fa-sort-up"></i>{% endblock table.asc_icon %}</span>
{% endif %}
{% else %}
<span class="icon" aria-hidden="true">{% block table.orderable_icon %}<i class="fa-solid fa-sort"></i>{% endblock table.orderable_icon %}</span>
{% endif %}
</div>
<div class="nowrap-child">
<a
hx-get="search/{% querystring table.prefixed_order_by_field=column.order_by_alias.next %}&{{ uri }}"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-trigger="click"
hx-target="#results"
hx-swap="innerHTML"
hx-indicator=".progress"
style="cursor: pointer;">
{{ column.header }}
</a>
</div>
{% else %}
<div class="nowrap-child">
{{ column.header }}
</div>
{% endif %}
</div>
</th>
{% endblock table.thead.th %}
{% endif %}
{% endfor %}
</tr>
{% endblock table.thead.row %}
</thead>
{% endif %}
{% endblock table.thead %}
{% block table.tbody %}
<tbody {{ table.attrs.tbody.as_html }}>
{% for row in table.paginated_rows %}
{% block table.tbody.row %}
<tr class="{% if row.cells.exemption == True %}
has-background-grey-lighter
{% elif row.cells.type == 'join' %}
has-background-success-light
{% elif row.cells.type == 'quit' %}
has-background-danger-light
{% elif row.cells.type == 'kick' %}
has-background-danger-light
{% elif row.cells.type == 'part' %}
has-background-warning-light
{% elif row.cells.type == 'mode' %}
has-background-info-light
{% endif %}">
{% for column, cell in row.items %}
{% if column.name in show and not column.name in hide %}
{% block table.tbody.td %}
{% if cell == '—' %}
<td>
<span class="icon">
<i class="fa-solid fa-file-slash"></i>
</span>
</td>
{% elif column.name == 'src' %}
<td>
<a class="has-text-link is-underlined"
onclick="populateSearch('src', '{{ cell|escapejs }}')">
{% if row.cells.src == 'irc' %}
<span class="icon" data-tooltip="IRC">
<i class="fa-solid fa-hashtag" aria-hidden="true"></i>
</span>
{% elif row.cells.src == 'dis' %}
<span class="icon" data-tooltip="Discord">
<i class="fa-brands fa-discord" aria-hidden="true"></i>
</span>
{% endif %}
</a>
</td>
{% elif column.name == 'ts' %}
<td>
<p>{{ row.cells.date }}</p>
<p>{{ row.cells.time }}</p>
</td>
{% elif column.name == 'type' %}
<td>
<a class="has-text-link is-underlined"
onclick="populateSearch('type', '{{ cell|escapejs }}')">
{% if row.cells.type == 'msg' %}
<span class="icon" data-tooltip="Message">
<i class="fa-solid fa-message"></i>
</span>
{% elif row.cells.type == 'join' %}
<span class="icon" data-tooltip="Join">
<i class="fa-solid fa-person-to-portal"></i>
</span>
{% elif row.cells.type == 'part' %}
<span class="icon" data-tooltip="Part">
<i class="fa-solid fa-person-from-portal"></i>
</span>
{% elif row.cells.type == 'quit' %}
<span class="icon" data-tooltip="Quit">
<i class="fa-solid fa-circle-xmark"></i>
</span>
{% elif row.cells.type == 'kick' %}
<span class="icon" data-tooltip="Kick">
<i class="fa-solid fa-user-slash"></i>
</span>
{% elif row.cells.type == 'nick' %}
<span class="icon" data-tooltip="Nick">
<i class="fa-solid fa-signature"></i>
</span>
{% elif row.cells.type == 'mode' %}
<span class="icon" data-tooltip="Mode">
<i class="fa-solid fa-gear"></i>
</span>
{% elif row.cells.type == 'action' %}
<span class="icon" data-tooltip="Action">
<i class="fa-solid fa-exclamation"></i>
</span>
{% else %}
{{ row.cells.type }}
{% endif %}
</a>
</td>
{% elif column.name == 'msg' %}
<td style="max-width: 10em" class="wrap">{{ row.cells.msg }}</td>
{% elif column.name == 'host' %}
<td>
<a class="has-text-link is-underlined"
onclick="populateSearch('host', '{{ cell|escapejs }}')">
{{ cell }}
</a>
</td>
{% elif column.name == 'nick' %}
<td>
</script>
<div class="table-container" style="display:none;">
<table {% render_attrs table.attrs class="table is-striped is-hoverable is-fullwidth" %}>
{% block table.thead %}
{% if table.show_header %}
<thead {% render_attrs table.attrs.thead class="" %}>
{% block table.thead.row %}
<tr>
{% for column in table.columns %}
{% if column.name in show and not column.name in hide %}
{% block table.thead.th %}
<th class="orderable {{ column.name }}"
{% if column.name in invisible %}
style="display:none;"
{% endif %}>
<div class="nowrap-parent">
<div class="nowrap-child">
{% if row.cells.online is True %}
<span class="icon has-text-success has-tooltip-success" data-tooltip="Online">
<i class="fa-solid fa-circle"></i>
</span>
{% elif row.cells.online is False %}
<span class="icon has-text-danger has-tooltip-danger" data-tooltip="Offline">
<i class="fa-solid fa-circle"></i>
</span>
{% else %}
<span class="icon has-text-warning has-tooltip-warning" data-tooltip="Unknown">
<i class="fa-solid fa-circle"></i>
</span>
{% endif %}
</div>
<a class="nowrap-child has-text-link is-underlined" onclick="populateSearch('nick', '{{ cell|escapejs }}')">
{{ cell }}
</a>
<div class="nowrap-child">
{% if row.cells.src == 'irc' %}
<button
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-post="{% url 'modal_drilldown' %}"
hx-vals='{"net": "{{ row.cells.net }}", "nick": "{{ row.cells.nick }}", "channel": "{{ row.cells.channel }}"}'
hx-target="#modals-here"
hx-trigger="click"
class="button is-small">
Information
</button>
{% endif %}
</div>
{% if row.cells.num_chans != '—' %}
{% if column.orderable %}
<div class="nowrap-child">
<span class="tag">
{{ row.cells.num_chans }}
</span>
{% if column.is_ordered %}
{% is_descending column.order_by as descending %}
{% if descending %}
<span class="icon" aria-hidden="true">{% block table.desc_icon %}<i class="fa-solid fa-sort-down"></i>{% endblock table.desc_icon %}</span>
{% else %}
<span class="icon" aria-hidden="true">{% block table.asc_icon %}<i class="fa-solid fa-sort-up"></i>{% endblock table.asc_icon %}</span>
{% endif %}
{% else %}
<span class="icon" aria-hidden="true">{% block table.orderable_icon %}<i class="fa-solid fa-sort"></i>{% endblock table.orderable_icon %}</span>
{% endif %}
</div>
<div class="nowrap-child">
<a
hx-get="search/{% querystring table.prefixed_order_by_field=column.order_by_alias.next %}&{{ uri }}"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-trigger="click"
hx-target="#results"
hx-swap="innerHTML"
hx-indicator="#spinner"
style="cursor: pointer;">
{{ column.header }}
</a>
</div>
{% else %}
<div class="nowrap-child">
{{ column.header }}
</div>
{% endif %}
</div>
</td>
{% elif column.name == 'channel' %}
<td>
{% if cell != '—' %}
</th>
{% endblock table.thead.th %}
{% endif %}
{% endfor %}
</tr>
{% endblock table.thead.row %}
</thead>
{% endif %}
{% endblock table.thead %}
{% block table.tbody %}
<tbody {{ table.attrs.tbody.as_html }}>
{% for row in table.paginated_rows %}
{% block table.tbody.row %}
<tr class="{% if row.cells.exemption == True %}has-background-grey-lighter{% elif row.cells.type == 'join' %}has-background-success-light{% elif row.cells.type == 'quit' %}has-background-danger-light{% elif row.cells.type == 'kick' %}has-background-danger-light{% elif row.cells.type == 'part' %}has-background-warning-light{% elif row.cells.type == 'mode' %}has-background-info-light{% endif %}">
{% for column, cell in row.items %}
{% if column.name in show and not column.name in hide %}
{% block table.tbody.td %}
{% if column.name in invisible %}
<td class="{{ column.name }}" style="display:none;">
{{ cell }}
</td>
{% elif cell == '—' %}
<td class="{{ column.name }}">
<span class="icon">
<i class="fa-solid fa-file-slash"></i>
</span>
</td>
{% elif column.name == 'src' %}
<td class="{{ column.name }}">
<a class="has-text-link is-underlined"
onclick="populateSearch('src', '{{ cell|escapejs }}')">
{% if row.cells.src == 'irc' %}
<span class="icon" data-tooltip="IRC">
<i class="fa-solid fa-hashtag" aria-hidden="true"></i>
</span>
{% elif row.cells.src == 'dis' %}
<span class="icon" data-tooltip="Discord">
<i class="fa-brands fa-discord" aria-hidden="true"></i>
</span>
{% endif %}
</a>
</td>
{% elif column.name == 'ts' %}
<td class="{{ column.name }}">
<p>{{ row.cells.date }}</p>
<p>{{ row.cells.time }}</p>
</td>
{% elif column.name == 'type' %}
<td class="{{ column.name }}">
<a class="has-text-link is-underlined"
onclick="populateSearch('type', '{{ cell|escapejs }}')">
{% if row.cells.type == 'msg' %}
<span class="icon" data-tooltip="Message">
<i class="fa-solid fa-message"></i>
</span>
{% elif row.cells.type == 'join' %}
<span class="icon" data-tooltip="Join">
<i class="fa-solid fa-person-to-portal"></i>
</span>
{% elif row.cells.type == 'part' %}
<span class="icon" data-tooltip="Part">
<i class="fa-solid fa-person-from-portal"></i>
</span>
{% elif row.cells.type == 'quit' %}
<span class="icon" data-tooltip="Quit">
<i class="fa-solid fa-circle-xmark"></i>
</span>
{% elif row.cells.type == 'kick' %}
<span class="icon" data-tooltip="Kick">
<i class="fa-solid fa-user-slash"></i>
</span>
{% elif row.cells.type == 'nick' %}
<span class="icon" data-tooltip="Nick">
<i class="fa-solid fa-signature"></i>
</span>
{% elif row.cells.type == 'mode' %}
<span class="icon" data-tooltip="Mode">
<i class="fa-solid fa-gear"></i>
</span>
{% elif row.cells.type == 'action' %}
<span class="icon" data-tooltip="Action">
<i class="fa-solid fa-exclamation"></i>
</span>
{% else %}
{{ row.cells.type }}
{% endif %}
</a>
</td>
{% elif column.name == 'msg' %}
<td class="{{ column.name }}" style="max-width: 10em" class="wrap">{{ row.cells.msg }}</td>
{% elif column.name == 'host' %}
<td class="{{ column.name }}">
<a class="has-text-link is-underlined"
onclick="populateSearch('host', '{{ cell|escapejs }}')">
{{ cell }}
</a>
</td>
{% elif column.name == 'nick' %}
<td class="{{ column.name }}">
<div class="nowrap-parent">
<a class="nowrap-child has-text-link is-underlined"
onclick="populateSearch('channel', '{{ cell|escapejs }}')">
<div class="nowrap-child">
{% if row.cells.online is True %}
<span class="icon has-text-success has-tooltip-success" data-tooltip="Online">
<i class="fa-solid fa-circle"></i>
</span>
{% elif row.cells.online is False %}
<span class="icon has-text-danger has-tooltip-danger" data-tooltip="Offline">
<i class="fa-solid fa-circle"></i>
</span>
{% else %}
<span class="icon has-text-warning has-tooltip-warning" data-tooltip="Unknown">
<i class="fa-solid fa-circle"></i>
</span>
{% endif %}
</div>
<a class="nowrap-child has-text-link is-underlined" onclick="populateSearch('nick', '{{ cell|escapejs }}')">
{{ cell }}
</a>
{% if row.cells.num_users != '—' %}
<div class="nowrap-child">
{% if row.cells.src == 'irc' %}
<button
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-post="{% url 'modal_drilldown' %}"
hx-vals='{"net": "{{ row.cells.net }}", "nick": "{{ row.cells.nick }}", "channel": "{{ row.cells.channel }}"}'
hx-target="#modals-here"
hx-trigger="click"
class="button is-small">
Information
</button>
{% endif %}
</div>
{% if row.cells.num_chans != '—' %}
<div class="nowrap-child">
<span class="tag">
{{ row.cells.num_users }}
{{ row.cells.num_chans }}
</span>
</div>
{% endif %}
</div>
{% else %}
</td>
{% elif column.name == 'channel' %}
<td class="{{ column.name }}">
{% if cell != '—' %}
<div class="nowrap-parent">
<a class="nowrap-child has-text-link is-underlined"
onclick="populateSearch('channel', '{{ cell|escapejs }}')">
{{ cell }}
</a>
{% if row.cells.num_users != '—' %}
<div class="nowrap-child">
<span class="tag">
{{ row.cells.num_users }}
</span>
</div>
{% endif %}
</div>
{% else %}
{{ cell }}
{% endif %}
</td>
{% elif column.name == 'net' %}
<td class="{{ column.name }}">
<a class="has-text-link is-underlined"
onclick="populateSearch('net', '{{ cell|escapejs }}')">
{{ cell }}
</a>
</td>
{% elif column.name == 'nick_id' %}
<td class="{{ column.name }}">
<a class="has-text-link is-underlined"
onclick="populateSearch('nick_id', '{{ cell|escapejs }}')">
{{ cell }}
</a>
</td>
{% elif column.name == 'user_id' %}
<td class="{{ column.name }}">
<a class="has-text-link is-underlined"
onclick="populateSearch('user_id', '{{ cell|escapejs }}')">
{{ cell }}
</a>
</td>
{% elif column.name == 'channel_id' %}
<td class="{{ column.name }}">
<a class="has-text-link is-underlined"
onclick="populateSearch('channel_id', '{{ cell|escapejs }}')">
{{ cell }}
</a>
</td>
{% elif cell is True or cell is False %}
<td class="{{ column.name }}">
{% if cell is True %}
<span class="icon has-text-success">
<i class="fa-solid fa-check"></i>
</span>
{% else %}
<span class="icon">
<i class="fa-solid fa-xmark"></i>
</span>
{% endif %}
</td>
{% else %}
<td class="{{ column.name }}">
{{ cell }}
{% endif %}
</td>
{% elif column.name == 'net' %}
<td>
<a class="has-text-link is-underlined"
onclick="populateSearch('net', '{{ cell|escapejs }}')">
{{ cell }}
</a>
</td>
{% elif column.name == 'nick_id' %}
<td>
<a class="has-text-link is-underlined"
onclick="populateSearch('nick_id', '{{ cell|escapejs }}')">
{{ cell }}
</a>
</td>
{% elif column.name == 'user_id' %}
<td>
<a class="has-text-link is-underlined"
onclick="populateSearch('user_id', '{{ cell|escapejs }}')">
{{ cell }}
</a>
</td>
{% elif column.name == 'channel_id' %}
<td>
<a class="has-text-link is-underlined"
onclick="populateSearch('channel_id', '{{ cell|escapejs }}')">
{{ cell }}
</a>
</td>
{% elif cell == True or cell == False %}
<td>
{% if cell == True %}
<span class="icon has-text-success">
<i class="fa-solid fa-check"></i>
</span>
{% else %}
<span class="icon">
<i class="fa-solid fa-xmark"></i>
</span>
{% endif %}
</td>
{% else %}
<td>
{{ cell }}
</td>
{% endif %}
{% endblock table.tbody.td %}
{% endif %}
{% endfor %}
</tr>
{% endblock table.tbody.row %}
{% empty %}
{% if table.empty_text %}
{% block table.tbody.empty_text %}
<tr><td colspan="{{ table.columns|length }}">{{ table.empty_text }}</td></tr>
{% endblock table.tbody.empty_text %}
{% endif %}
{% endfor %}
</tbody>
{% endblock table.tbody %}
{% block table.tfoot %}
{% if table.has_footer %}
<tfoot {{ table.attrs.tfoot.as_html }}>
{% block table.tfoot.row %}
<tr>
{% for column in table.columns %}
{% block table.tfoot.td %}
<td {{ column.attrs.tf.as_html }}>{{ column.footer }}</td>
{% endblock table.tfoot.td %}
{% endfor %}
</tr>
{% endblock table.tfoot.row %}
</tfoot>
{% endif %}
{% endblock table.tfoot %}
</table>
</td>
{% endif %}
{% endblock table.tbody.td %}
{% endif %}
{% endfor %}
</tr>
{% endblock table.tbody.row %}
{% empty %}
{% if table.empty_text %}
{% block table.tbody.empty_text %}
<tr><td class="{{ column.name }}" colspan="{{ table.columns|length }}">{{ table.empty_text }}</td></tr>
{% endblock table.tbody.empty_text %}
{% endif %}
{% endfor %}
</tbody>
{% endblock table.tbody %}
{% block table.tfoot %}
{% if table.has_footer %}
<tfoot {{ table.attrs.tfoot.as_html }}>
{% block table.tfoot.row %}
<tr>
{% for column in table.columns %}
{% block table.tfoot.td %}
<td class="{{ column.name }}" {{ column.attrs.tf.as_html }}>{{ column.footer }}</td>
{% endblock table.tfoot.td %}
{% endfor %}
</tr>
{% endblock table.tfoot.row %}
</tfoot>
{% endif %}
{% endblock table.tfoot %}
</table>
</div>
{% endblock table %}
{% block pagination %}
{% if table.page and table.paginator.num_pages > 1 %}
@@ -305,7 +348,7 @@
hx-trigger="click"
hx-target="#results"
hx-swap="innerHTML"
hx-indicator=".progress"
hx-indicator="#spinner"
{% else %}
href="#"
disabled
@@ -317,19 +360,20 @@
</a>
{% endblock pagination.previous %}
{% block pagination.next %}
<a class="pagination-next is-flex-grow-0 {% if not table.page.has_next %}is-hidden-mobile{% endif %}"
{% if table.page.has_next %}
hx-get="search/{% querystring table.prefixed_page_field=table.page.next_page_number %}&{{ uri }}"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-trigger="click"
hx-target="#results"
hx-swap="innerHTML"
hx-indicator=".progress"
{% else %}
href="#"
disabled
{% endif %}
style="order:3;"
<a
class="pagination-next is-flex-grow-0 {% if not table.page.has_next %}is-hidden-mobile{% endif %}"
{% if table.page.has_next %}
hx-get="search/{% querystring table.prefixed_page_field=table.page.next_page_number %}&{{ uri }}"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-trigger="click"
hx-target="#results"
hx-swap="innerHTML"
hx-indicator="#spinner"
{% else %}
href="#"
disabled
{% endif %}
style="order:3;"
>
{% block pagination.next.text %}
<span aria-hidden="true">&raquo;</span>
@@ -341,19 +385,20 @@
<ul class="pagination-list is-flex-grow-0" style="order:2;">
{% for p in table.page|table_page_range:table.paginator %}
<li>
<a class="pagination-link {% if p == table.page.number %}is-current{% endif %}"
aria-label="Page {{ p }}" block
{% if p == table.page.number %}aria-current="page"{% endif %}
{% if p == table.page.number %}
href="#"
{% else %}
hx-get="search/{% querystring table.prefixed_page_field=p %}&{{ uri }}"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-trigger="click"
hx-target="#results"
hx-swap="innerHTML"
hx-indicator=".progress"
{% endif %}
<a
class="pagination-link {% if p == table.page.number %}is-current{% endif %}"
aria-label="Page {{ p }}" block
{% if p == table.page.number %}aria-current="page"{% endif %}
{% if p == table.page.number %}
href="#"
{% else %}
hx-get="search/{% querystring table.prefixed_page_field=p %}&{{ uri }}"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-trigger="click"
hx-target="#results"
hx-swap="innerHTML"
hx-indicator="#spinner"
{% endif %}
>
{% if p == '...' %}
<span class="pagination-ellipsis">&hellip;</span>