Implement Insights page
This commit is contained in:
@@ -65,7 +65,7 @@
|
||||
{% if user.is_authenticated %}
|
||||
<div class="navbar-item has-dropdown is-hoverable">
|
||||
<a class="navbar-link">
|
||||
Plans
|
||||
Tools
|
||||
</a>
|
||||
|
||||
<div class="navbar-dropdown">
|
||||
@@ -73,6 +73,9 @@
|
||||
<a class="navbar-item" href="{% url 'drilldown' %}">
|
||||
Drilldown
|
||||
</a>
|
||||
<a class="navbar-item" href="{% url 'insights' %}">
|
||||
Insights
|
||||
</a>
|
||||
{% endif %}
|
||||
<hr class="navbar-divider">
|
||||
<a class="navbar-item" href="mailto:help@pathogen.is">
|
||||
|
||||
132
core/templates/modals/insights.html
Normal file
132
core/templates/modals/insights.html
Normal file
@@ -0,0 +1,132 @@
|
||||
{% 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>
|
||||
@@ -56,43 +56,6 @@
|
||||
</div>
|
||||
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<label class="label">Timescale</label>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div class="control is-expanded has-icons-left">
|
||||
<div class="select is-fullwidth">
|
||||
<select name="timescale">
|
||||
{% for timescale in timescales %}
|
||||
<option value="{{ timescale }}">{{ timescale }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fas fa-magnifying-glass"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<label class="label">Fields</label>
|
||||
|
||||
<div class="field">
|
||||
<div class="control is-expanded has-icons-left">
|
||||
<div class="select is-fullwidth is-multiple">
|
||||
<select multiple name="fields">
|
||||
{% for field in fields %}
|
||||
<option value="{{ field }}">{{ field }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fas fa-magnifying-glass"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<label class="label">Results</label>
|
||||
<div class="field">
|
||||
@@ -114,7 +77,7 @@
|
||||
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<button class="button is-primary is-fullwidth" hx-post="{% url 'search' %}" hx-trigger="click" hx-target="#results" hx-swap="outerHTML">
|
||||
<button class="button is-primary is-fullwidth" hx-post="{% url 'search_drilldown' %}" hx-trigger="click" hx-target="#results" hx-swap="outerHTML">
|
||||
Search
|
||||
</button>
|
||||
</div>
|
||||
@@ -1,4 +1,5 @@
|
||||
{% load static %}
|
||||
{% load index %}
|
||||
|
||||
<div id="results">
|
||||
{% if results is not None %}
|
||||
@@ -106,7 +107,7 @@
|
||||
{% if item.src == 'irc' %}
|
||||
<button
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-post="{% url 'modal_info' %}"
|
||||
hx-post="{% url 'modal_drilldown' %}"
|
||||
hx-vals='{"net": "{{ item.net }}", "nick": "{{ item.nick }}", "channel": "{{ item.channel }}"}'
|
||||
hx-target="#modals-here"
|
||||
hx-trigger="click"
|
||||
85
core/templates/ui/insights/insights.html
Normal file
85
core/templates/ui/insights/insights.html
Normal file
@@ -0,0 +1,85 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% block content %}
|
||||
<script>
|
||||
// tabbed browsing for the modal
|
||||
function initTabs() {
|
||||
TABS.forEach((tab) => {
|
||||
tab.addEventListener('click', (e) => {
|
||||
let selected = tab.getAttribute('data-tab');
|
||||
updateActiveTab(tab);
|
||||
updateActiveContent(selected);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function updateActiveTab(selected) {
|
||||
TABS.forEach((tab) => {
|
||||
if (tab && tab.classList.contains(ACTIVE_CLASS)) {
|
||||
tab.classList.remove(ACTIVE_CLASS);
|
||||
}
|
||||
});
|
||||
selected.classList.add(ACTIVE_CLASS);
|
||||
}
|
||||
|
||||
function updateActiveContent(selected) {
|
||||
CONTENT.forEach((item) => {
|
||||
if (item && item.classList.contains(ACTIVE_CLASS)) {
|
||||
item.classList.remove(ACTIVE_CLASS);
|
||||
}
|
||||
let data = item.getAttribute('data-content');
|
||||
if (data === selected) {
|
||||
item.classList.add(ACTIVE_CLASS);
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.icon { border-bottom: 0px !important;}
|
||||
</style>
|
||||
<div class="tile is-ancestor">
|
||||
|
||||
<div class="tile is-parent is-vertical">
|
||||
<div class="tile is-child box">
|
||||
<form method="POST">
|
||||
{% csrf_token %}
|
||||
<div class="field">
|
||||
<label class="label">Search</label>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div class="control is-expanded has-icons-left">
|
||||
<input name="query" class="input" type="text" placeholder="nickname">
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fas fa-magnifying-glass"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<button class="button is-primary is-fullwidth" hx-post="{% url 'search_insights' %}" hx-trigger="click" hx-target="#results" hx-swap="outerHTML">
|
||||
Search
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="results">
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tile is-parent">
|
||||
<p> 2</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
||||
79
core/templates/ui/insights/results.html
Normal file
79
core/templates/ui/insights/results.html
Normal file
@@ -0,0 +1,79 @@
|
||||
{% load static %}
|
||||
{% load index %}
|
||||
|
||||
<div class="tile is-child box">
|
||||
<div id="results">
|
||||
{% if item is not None %}
|
||||
<div class="table-container">
|
||||
<table class="table is-hoverable is-fullwidth">
|
||||
<tr>
|
||||
<th>src</th>
|
||||
<td>
|
||||
{% if item|index:'src' == 'irc' %}
|
||||
<span class="icon" data-tooltip="IRC">
|
||||
<i class="fa-solid fa-hashtag" aria-hidden="true"></i>
|
||||
</span>
|
||||
{% elif item|index:'src' == 'dis' %}
|
||||
<span class="icon" data-tooltip="Discord">
|
||||
<i class="fa-brands fa-discord" aria-hidden="true"></i>
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>nick</th>
|
||||
<td>
|
||||
{% if item|index:'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|index:'online' is False %}
|
||||
<span class="icon has-text-danger has-tooltip-danger" data-tooltip="Offline">
|
||||
<i class="fa-solid fa-circle"></i>
|
||||
</span>
|
||||
{{ item|index:'nick' }}
|
||||
{% else %}
|
||||
<span class="icon has-text-warning has-tooltip-warning" data-tooltip="Unknown">
|
||||
<i class="fa-solid fa-circle"></i>
|
||||
</span>
|
||||
{{ item|index:'nick'}}
|
||||
{% endif %}
|
||||
{% if item|index:'num_chans' is not None %}
|
||||
<span class="tag">
|
||||
{{ item|index:'num_chans' }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>host</th>
|
||||
<td>{{ item.host }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>actions</th>
|
||||
<td>
|
||||
{% if item.src == 'irc' %}
|
||||
<button
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-post="{% url 'modal_insights' %}"
|
||||
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>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>net</th>
|
||||
<td>{{ item.net }}</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user