Implement channel pane for insights

This commit is contained in:
Mark Veidemanis 2022-07-21 13:52:06 +01:00
parent 20d513bef1
commit 9de9ddff6f
Signed by: m
GPG Key ID: 5ACFCEED46C0904F
8 changed files with 299 additions and 377 deletions

View File

@ -21,7 +21,7 @@
</script> </script>
<style> <style>
#tab-content div { #tab-content div {
display: none; display: none;
} }
#tab-content div.is-active { #tab-content div.is-active {
@ -32,7 +32,7 @@
<div class="modal-background"></div> <div class="modal-background"></div>
<div class="modal-content"> <div class="modal-content">
<div class="box"> <div class="box">
<div class="tabs is-toggle is-fullwidth" id="tabs"> <div class="tabs is-toggle is-fullwidth is-primary" id="tabs">
<ul> <ul>
<li class="is-active" data-tab="1"> <li class="is-active" data-tab="1">
<a> <a>
@ -64,7 +64,7 @@
<div class="is-active" data-content="1"> <div class="is-active" data-content="1">
<h4 class="subtitle is-4">Channels for {{ nick }} on {{ net }}</h4> <h4 class="subtitle is-4">Channels for {{ nick }} on {{ net }}</h4>
{% for channel in chans %} {% for channel in chans %}
<a class="panel-block"> <a class="panel-block is-active">
<span class="panel-icon"> <span class="panel-icon">
<i class="fa-solid fa-hashtag" aria-hidden="true"></i> <i class="fa-solid fa-hashtag" aria-hidden="true"></i>
</span> </span>
@ -80,7 +80,7 @@
<div data-content="2"> <div data-content="2">
<h4 class="subtitle is-4">Users on {{ channel }} for {{ net }}</h4> <h4 class="subtitle is-4">Users on {{ channel }} for {{ net }}</h4>
{% for user in users %} {% for user in users %}
<a class="panel-block"> <a class="panel-block is-active">
<span class="panel-icon"> <span class="panel-icon">
<i class="fa-solid fa-user" aria-hidden="true"></i> <i class="fa-solid fa-user" aria-hidden="true"></i>
</span> </span>
@ -96,7 +96,7 @@
<div data-content="3"> <div data-content="3">
<h4 class="subtitle is-4">Users sharing channels with {{ nick }} on {{ net }}</h4> <h4 class="subtitle is-4">Users sharing channels with {{ nick }} on {{ net }}</h4>
{% for user in inter_users %} {% for user in inter_users %}
<a class="panel-block"> <a class="panel-block is-active">
<span class="panel-icon"> <span class="panel-icon">
<i class="fa-solid fa-user" aria-hidden="true"></i> <i class="fa-solid fa-user" aria-hidden="true"></i>
</span> </span>
@ -112,7 +112,7 @@
<div data-content="4"> <div data-content="4">
<h4 class="subtitle is-4">Channels sharing users with {{ channel }} on {{ net }}</h4> <h4 class="subtitle is-4">Channels sharing users with {{ channel }} on {{ net }}</h4>
{% for channel in inter_chans %} {% for channel in inter_chans %}
<a class="panel-block"> <a class="panel-block is-active">
<span class="panel-icon"> <span class="panel-icon">
<i class="fa-solid fa-hashtag" aria-hidden="true"></i> <i class="fa-solid fa-hashtag" aria-hidden="true"></i>
</span> </span>

View File

@ -1,132 +0,0 @@
{% load index %}
<script>
var modal = document.querySelector('.modal'); // assuming you have only 1
var html = document.querySelector('html');
modal.querySelector('.modal-background').addEventListener('click', function(e) {
e.preventDefault();
modal.classList.remove('is-active');
html.classList.remove('is-clipped');
});
modal.querySelector('.modal-close').addEventListener('click', function(e) {
e.preventDefault();
modal.classList.remove('is-active');
html.classList.remove('is-clipped');
});
var TABS = [...document.querySelectorAll('#tabs li')];
var CONTENT = [...document.querySelectorAll('#tab-content div')];
var ACTIVE_CLASS = 'is-active';
initTabs();
</script>
<style>
#tab-content div {
display: none;
}
#tab-content div.is-active {
display: block;
}
</style>
<div class="modal is-active is-clipped">
<div class="modal-background"></div>
<div class="modal-content">
<div class="box">
<div class="tabs is-toggle is-fullwidth" id="tabs">
<ul>
<li class="is-active" data-tab="1">
<a>
<span class="icon is-small"><i class="fa-solid fa-user"></i></span>
<span>Channels</span>
</a>
</li>
<li data-tab="2">
<a>
<span class="icon is-small"><i class="fa-solid fa-hashtag"></i></span>
<span>Users</span>
</a>
</li>
<li data-tab="3">
<a>
<span class="icon is-small"><i class="fa-solid fa-people"></i></span>
<span>Intersection</span>
</a>
</li>
<li data-tab="4">
<a>
<span class="icon is-small"><i class="fa-solid fa-hashtag"></i></span>
<span>Intersection</span>
</a>
</li>
</ul>
</div>
<div id="tab-content">
<div class="is-active" data-content="1">
<h4 class="subtitle is-4">Channels for {{ nick }} on {{ net }}</h4>
{% for channel in chans %}
<a class="panel-block">
<span class="panel-icon">
<i class="fa-solid fa-hashtag" aria-hidden="true"></i>
</span>
{{ channel }}
{% if nick in num_chans %}
<span class="tag">
{{ num_users|index:channel }}
</span>
{% endif %}
</a>
{% endfor %}
</div>
<div data-content="2">
<h4 class="subtitle is-4">Users on {{ channel }} for {{ net }}</h4>
{% for user in users %}
<a class="panel-block">
<span class="panel-icon">
<i class="fa-solid fa-user" aria-hidden="true"></i>
</span>
{{ user }}
{% if channel in num_users %}
<span class="tag">
{{ num_chans|index:user }}
</span>
{% endif %}
</a>
{% endfor %}
</div>
<div data-content="3">
<h4 class="subtitle is-4">Users sharing channels with {{ nick }} on {{ net }}</h4>
{% for user in inter_users %}
<a class="panel-block">
<span class="panel-icon">
<i class="fa-solid fa-user" aria-hidden="true"></i>
</span>
{{ user }}
{% if channel in num_users %}
<span class="tag">
{{ num_chans|index:user }}
</span>
{% endif %}
</a>
{% endfor %}
</div>
<div data-content="4">
<h4 class="subtitle is-4">Channels sharing users with {{ channel }} on {{ net }}</h4>
{% for channel in inter_chans %}
<a class="panel-block">
<span class="panel-icon">
<i class="fa-solid fa-hashtag" aria-hidden="true"></i>
</span>
{{ channel }}
{% if nick in num_chans %}
<span class="tag">
{{ num_users|index:channel }}
</span>
{% endif %}
</a>
{% endfor %}
</div>
</div>
</div>
<button class="modal-close is-large" aria-label="close"></button>
</div>
</div>

View File

@ -79,7 +79,7 @@
hx-post="{% url 'search_drilldown' %}" hx-post="{% url 'search_drilldown' %}"
hx-trigger="click" hx-trigger="click"
hx-target="#results" hx-target="#results"
hx-swap="outerHTML"> hx-swap="innerHTML">
Search Search
</button> </button>
</div> </div>
@ -90,5 +90,6 @@
<div id="results"> <div id="results">
</div> </div>
<div id="modals-here">
</div>
{% endblock %} {% endblock %}

View File

@ -1,157 +1,154 @@
{% load static %} {% load static %}
{% load index %} {% load index %}
<div id="results"> {% if results is not None %}
{% if results is not None %} <div style="display: none" id="jsonData" data-json="{{ data }}">
<div style="display: none" id="jsonData" data-json="{{ data }}"> </div>
<div class="box">
<div style="height: 30rem">
<canvas id="volume"></canvas>
</div> </div>
<div class="box"> <script src="{% static 'chart.js' %}"></script>
<div style="height: 30rem"> </div>
<canvas id="volume"></canvas> <div class="box">
</div> <div class="table-container">
<script src="{% static 'chart.js' %}"></script> <table class="table is-striped is-hoverable is-fullwidth">
</div> <thead>
<div class="box"> <tr>
<div class="table-container"> <th>src</th>
<table class="table is-striped is-hoverable is-fullwidth"> <th>type</th>
<thead> <th>ts</th>
<th>msg</th>
<th>host</th>
<th>nick</th>
<th>actions</th>
<th>channel</th>
<th>net</th>
</tr>
</thead>
<tbody>
{% for item in results %}
<tr> <tr>
<th>src</th> <td>
<th>type</th> {% if item.src == 'irc' %}
<th>ts</th> <span class="icon" data-tooltip="IRC">
<th>msg</th> <i class="fa-solid fa-hashtag" aria-hidden="true"></i>
<th>host</th> </span>
<th>nick</th> {% elif item.src == 'dis' %}
<th>actions</th> <span class="icon" data-tooltip="Discord">
<th>channel</th> <i class="fa-brands fa-discord" aria-hidden="true"></i>
<th>net</th> </span>
{% endif %}
</td>
<td>
{% if item.type == 'msg' %}
<span class="icon" data-tooltip="Message">
<i class="fa-solid fa-message"></i>
</span>
{% elif item.type == 'join' %}
<span class="icon" data-tooltip="Join">
<i class="fa-solid fa-person-to-portal"></i>
</span>
{% elif item.type == 'part' %}
<span class="icon" data-tooltip="Part">
<i class="fa-solid fa-person-from-portal"></i>
</span>
{% elif item.type == 'quit' %}
<span class="icon" data-tooltip="Quit">
<i class="fa-solid fa-circle-xmark"></i>
</span>
{% elif item.type == 'kick' %}
<span class="icon" data-tooltip="Kick">
<i class="fa-solid fa-user-slash"></i>
</span>
{% elif item.type == 'nick' %}
<span class="icon" data-tooltip="Nick">
<i class="fa-solid fa-signature"></i>
</span>
{% elif item.type == 'mode' %}
<span class="icon" data-tooltip="Mode">
<i class="fa-solid fa-gear"></i>
</span>
{% else %}
{{ item.type }}
{% endif %}
</td>
<td>
<p>{{ item.date }}</p>
<p>{{ item.time }}</p>
</td>
<td style="max-width: 10em">{{ item.msg }}</td>
<td>{{ item.host }}</td>
<td>
{% if item.online is True %}
<span class="icon has-text-success has-tooltip-success" data-tooltip="Online">
<i class="fa-solid fa-circle"></i>
</span>
{{ item.nick }}
{% elif item.online is False %}
<span class="icon has-text-danger has-tooltip-danger" data-tooltip="Offline">
<i class="fa-solid fa-circle"></i>
</span>
{{ item.nick }}
{% else %}
<span class="icon has-text-warning has-tooltip-warning" data-tooltip="Unknown">
<i class="fa-solid fa-circle"></i>
</span>
{{ item.nick }}
{% endif %}
{% if item.num_chans is not None %}
<span class="tag">
{{ item.num_chans }}
</span>
{% endif %}
</td>
<td>
{% if item.src == 'irc' %}
<button
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-post="{% url 'modal_drilldown' %}"
hx-vals='{"net": "{{ item.net }}", "nick": "{{ item.nick }}", "channel": "{{ item.channel }}"}'
hx-target="#modals-here"
hx-trigger="click"
class="button is-small">
Information
</button>
{% endif %}
</td>
<td>
{{ item.channel }}
{% if item.num_users is not None %}
<span class="tag">
{{ item.num_users }}
</span>
{% endif %}
</td>
<td>{{ item.net }}</td>
</tr> </tr>
</thead> {% endfor %}
<tbody> </tbody>
{% for item in results %} </table>
<tr>
<td>
{% if item.src == 'irc' %}
<span class="icon" data-tooltip="IRC">
<i class="fa-solid fa-hashtag" aria-hidden="true"></i>
</span>
{% elif item.src == 'dis' %}
<span class="icon" data-tooltip="Discord">
<i class="fa-brands fa-discord" aria-hidden="true"></i>
</span>
{% endif %}
</td>
<td>
{% if item.type == 'msg' %}
<span class="icon" data-tooltip="Message">
<i class="fa-solid fa-message"></i>
</span>
{% elif item.type == 'join' %}
<span class="icon" data-tooltip="Join">
<i class="fa-solid fa-person-to-portal"></i>
</span>
{% elif item.type == 'part' %}
<span class="icon" data-tooltip="Part">
<i class="fa-solid fa-person-from-portal"></i>
</span>
{% elif item.type == 'quit' %}
<span class="icon" data-tooltip="Quit">
<i class="fa-solid fa-circle-xmark"></i>
</span>
{% elif item.type == 'kick' %}
<span class="icon" data-tooltip="Kick">
<i class="fa-solid fa-user-slash"></i>
</span>
{% elif item.type == 'nick' %}
<span class="icon" data-tooltip="Nick">
<i class="fa-solid fa-signature"></i>
</span>
{% elif item.type == 'mode' %}
<span class="icon" data-tooltip="Mode">
<i class="fa-solid fa-gear"></i>
</span>
{% else %}
{{ item.type }}
{% endif %}
</td>
<td>
<p>{{ item.date }}</p>
<p>{{ item.time }}</p>
</td>
<td style="max-width: 10em">{{ item.msg }}</td>
<td>{{ item.host }}</td>
<td>
{% if item.online is True %}
<span class="icon has-text-success has-tooltip-success" data-tooltip="Online">
<i class="fa-solid fa-circle"></i>
</span>
{{ item.nick }}
{% elif item.online is False %}
<span class="icon has-text-danger has-tooltip-danger" data-tooltip="Offline">
<i class="fa-solid fa-circle"></i>
</span>
{{ item.nick }}
{% else %}
<span class="icon has-text-warning has-tooltip-warning" data-tooltip="Unknown">
<i class="fa-solid fa-circle"></i>
</span>
{{ item.nick }}
{% endif %}
{% if item.num_chans is not None %}
<span class="tag">
{{ item.num_chans }}
</span>
{% endif %}
</td>
<td>
{% if item.src == 'irc' %}
<button
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-post="{% url 'modal_drilldown' %}"
hx-vals='{"net": "{{ item.net }}", "nick": "{{ item.nick }}", "channel": "{{ item.channel }}"}'
hx-target="#modals-here"
hx-trigger="click"
class="button is-small">
Information
</button>
<div id="modals-here"></div>
{% endif %}
</td>
<td>
{{ item.channel }}
{% if item.num_users is not None %}
<span class="tag">
{{ item.num_users }}
</span>
{% endif %}
</td>
<td>{{ item.net }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div> </div>
<div class="box"> </div>
<div class="columns"> <div class="box">
<div class="columns">
<div class="column">
<p>{{ card }} hits</p>
</div>
{% if redacted != 0 %}
<div class="column"> <div class="column">
<p>{{ card }} hits</p> <p>{{ redacted }} redacted</p>
</div> </div>
{% if redacted != 0 %} {% endif %}
<div class="column">
<p>{{ redacted }} redacted</p>
</div>
{% endif %}
{% if exemption is not None %} {% if exemption is not None %}
<div class="column">
<p>god mode</p>
</div>
{% endif %}
<div class="column"> <div class="column">
<p>{{ took }}ms</p> <p>god mode</p>
</div> </div>
{% endif %}
<div class="column">
<p>{{ took }}ms</p>
</div> </div>
</div> </div>
{% endif %} </div>
</div> {% endif %}

View File

@ -0,0 +1,28 @@
<div class="tile is-parent" id="chans1">
<div class="tile is-child ">
<div class="panel is-primary" style="height: 30rem; overflow: auto">
<p class="panel-heading">
Channels
</p>
{% for chan in chans %}
<a class="panel-block is-active">
<span class="panel-icon">
<i class="fa-solid fa-hashtag" aria-hidden="true"></i>
</span>
<span
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-post="{% url 'modal_drilldown' %}"
hx-vals='{"net": "{{ net }}", "nick": "{{ nick }}", "channel": "{{ chan }}"}'
hx-target="#modals-here"
hx-trigger="click"
class="button is-small">
{{ chan }}
</span>
</a>
{% endfor %}
</div>
</div>
</div>

View File

@ -63,7 +63,7 @@
hx-post="{% url 'search_insights' %}" hx-post="{% url 'search_insights' %}"
hx-trigger="click" hx-trigger="click"
hx-target="#results" hx-target="#results"
hx-swap="outerHTML"> hx-swap="innerHTML">
Search Search
</button> </button>
</div> </div>
@ -75,17 +75,9 @@
</div> </div>
</div> </div>
<div class="tile is-parent"> <article id="chans1">
<div class="tile is-child box"> </article>
<p> 2</p>
</div>
</div>
</div> </div>
<div id="modals-here"></div>
{% endblock %}
{% endblock %}

View File

@ -1,83 +1,94 @@
{% load static %} {% load static %}
{% load index %} {% load index %}
<div class="panel is-primary">
<div id="results"> <p class="panel-heading">
<div class="tile is-child box"> Information
{% if item is not None %} </p>
<div class="table-container"> <div class="panel-block is-active">
<table class="table is-fullwidth"> <div class="tile is-child">
<tbody> {% if item is not None %}
<tr> <div class="table-container">
<th>src</th> <table class="table is-fullwidth is-hoverable">
<td> <tbody>
{% if item|index:'src' == 'irc' %} <tr>
<span class="icon" data-tooltip="IRC"> <th>src</th>
<i class="fa-solid fa-hashtag" aria-hidden="true"></i> <td>
</span> {% if item.src == 'irc' %}
IRC <span class="icon" data-tooltip="IRC">
{% elif item|index:'src' == 'dis' %} <i class="fa-solid fa-hashtag" aria-hidden="true"></i>
<span class="icon" data-tooltip="Discord"> </span>
<i class="fa-brands fa-discord" aria-hidden="true"></i> IRC
</span> {% elif item.src == 'dis' %}
Discord <span class="icon" data-tooltip="Discord">
{% endif %} <i class="fa-brands fa-discord" aria-hidden="true"></i>
</td> </span>
</tr> Discord
<tr> {% endif %}
<th>nick</th> </td>
<td> </tr>
{% if item|index:'online' is True %} <tr>
<span class="icon has-text-success has-tooltip-success" data-tooltip="Online"> <th>nick</th>
<i class="fa-solid fa-circle"></i> <td>
</span> {% if item.online is True %}
{{ item.nick }} <span class="icon has-text-success has-tooltip-success" data-tooltip="Online">
{% elif item|index:'online' is False %} <i class="fa-solid fa-circle"></i>
<span class="icon has-text-danger has-tooltip-danger" data-tooltip="Offline"> </span>
<i class="fa-solid fa-circle"></i> {{ item.nick }}
</span> {% elif item.online is False %}
{{ item|index:'nick' }} <span class="icon has-text-danger has-tooltip-danger" data-tooltip="Offline">
{% else %} <i class="fa-solid fa-circle"></i>
<span class="icon has-text-warning has-tooltip-warning" data-tooltip="Unknown"> </span>
<i class="fa-solid fa-circle"></i> {{ item.nick }}
</span> {% else %}
{{ item|index:'nick'}} <span class="icon has-text-warning has-tooltip-warning" data-tooltip="Unknown">
{% endif %} <i class="fa-solid fa-circle"></i>
{% if item|index:'num_chans' is not None %} </span>
<span class="tag"> {{ item.nick }}
{{ item|index:'num_chans' }} {% endif %}
</span> {% if item.num_chans is not None %}
{% endif %} <span class="tag">
</td> {{ item.num_chans }}
</tr> </span>
<tr> {% endif %}
<th>host</th> </td>
<td>{{ item.host }}</td> </tr>
</tr> <tr>
<tr> <th>host</th>
<th>actions</th> <td>{{ item.host }}</td>
<td> </tr>
{% if item.src == 'irc' %} <tr>
<button <th>actions</th>
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}' <td>
hx-post="{% url 'modal_insights' %}" {% if item.src == 'irc' %}
hx-vals='{"net": "{{ item.net }}", "nick": "{{ item.nick }}", "channel": "{{ item.channel }}"}' <button
hx-target="#modals-here" hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-trigger="click" hx-post="{% url 'modal_insights' %}"
class="button is-small"> hx-vals='{"net": "{{ item.net }}", "nick": "{{ item.nick }}", "channel": "{{ item.channel }}"}'
Information hx-target="#modals-here"
</button> hx-trigger="click"
<div id="modals-here"></div> class="button is-small">
{% endif %} Information
</td> </button>
</tr> {% endif %}
<tr> </td>
<th>net</th> </tr>
<td>{{ item.net }}</td> <tr>
</tr> <th>net</th>
</tbody> <td>{{ item.net }}</td>
</table> </tr>
</div> </tbody>
{% endif %} </table>
</div>
{% endif %}
</div>
</div> </div>
</div>
<div
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-vals='{"net": "{{ item.net }}", "nick": "{{ item.nick }}"}'
hx-post="{% url 'chans_insights' %}"
hx-trigger="load"
hx-target="#chans1"
hx-swap="outerHTML">
</div> </div>

View File

@ -22,7 +22,6 @@ class InsightsSearch(LoginRequiredMixin, View):
def post(self, request): def post(self, request):
if not request.user.has_plan(self.plan_name): if not request.user.has_plan(self.plan_name):
return HttpResponseForbidden() return HttpResponseForbidden()
results, context = query_single_result(request) results, context = query_single_result(request)
if not context: if not context:
return HttpResponseForbidden() return HttpResponseForbidden()
@ -32,10 +31,36 @@ class InsightsSearch(LoginRequiredMixin, View):
return HttpResponse("No results") return HttpResponse("No results")
class InsightsChannels(LoginRequiredMixin, APIView):
parser_classes = [FormParser]
template_name = "ui/insights/channels.html"
plan_name = "drilldown"
def post(self, request):
if not request.user.has_plan(self.plan_name):
return HttpResponseForbidden()
if "net" not in request.data:
return HttpResponse("No net")
if "nick" not in request.data:
return HttpResponse("No nick")
net = request.data["net"]
nick = request.data["nick"]
print("Insights channels item", nick)
chans = get_chans(net, [nick])
print("GET CHANS", chans)
if not chans:
return HttpResponseForbidden()
context = {"net": net, "nick": nick, "chans": chans}
if chans:
return render(request, self.template_name, context)
else:
return HttpResponse("No results")
class InsightsInfoModal(LoginRequiredMixin, APIView): class InsightsInfoModal(LoginRequiredMixin, APIView):
parser_classes = [FormParser] parser_classes = [FormParser]
plan_name = "drilldown" plan_name = "drilldown"
template_name = "modals/insights.html" template_name = "modals/drilldown.html"
def post(self, request): def post(self, request):
if not request.user.has_plan(self.plan_name): if not request.user.has_plan(self.plan_name):