Upgrade Bulma and begin drug info screen and favourites
This commit is contained in:
parent
4c8411b863
commit
46b1858897
@ -61,4 +61,5 @@ DRUGS_DEFAULT_PARAMS = {
|
||||
"size": "15",
|
||||
"sorting": "desc",
|
||||
"source": "substances",
|
||||
"index": "main",
|
||||
}
|
||||
|
31
app/urls.py
31
app/urls.py
@ -20,7 +20,7 @@ from django.contrib.auth.views import LogoutView
|
||||
from django.urls import include, path
|
||||
from two_factor.urls import urlpatterns as tf_urls
|
||||
|
||||
from core.views import base, demo, drugs, notifications, search
|
||||
from core.views import base, demo, drugs, favourites, notifications, search
|
||||
|
||||
urlpatterns = [
|
||||
path("__debug__/", include("debug_toolbar.urls")),
|
||||
@ -57,6 +57,11 @@ urlpatterns = [
|
||||
drugs.DrugDelete.as_view(),
|
||||
name="drug_delete",
|
||||
),
|
||||
path(
|
||||
"drugs/<str:type>/detail/<str:pk>/",
|
||||
drugs.DrugDetail.as_view(),
|
||||
name="drug_detail",
|
||||
),
|
||||
path(
|
||||
"drugs/clear/all/",
|
||||
drugs.DrugClear.as_view(),
|
||||
@ -70,4 +75,28 @@ urlpatterns = [
|
||||
# Drug search
|
||||
path("search/", search.DrugsTableView.as_view(), name="search"),
|
||||
path("search/partial/", search.DrugsTableView.as_view(), name="search_partial"),
|
||||
# Favourites
|
||||
path(
|
||||
"favourites/<str:type>/", favourites.FavouriteList.as_view(), name="favourites"
|
||||
),
|
||||
path(
|
||||
"favourites/<str:type>/create/",
|
||||
favourites.FavouriteCreate.as_view(),
|
||||
name="favourite_create",
|
||||
),
|
||||
path(
|
||||
"favourites/<str:type>/update/<str:pk>/",
|
||||
favourites.FavouriteUpdate.as_view(),
|
||||
name="favourite_update",
|
||||
),
|
||||
path(
|
||||
"favourites/<str:type>/delete/<str:pk>/",
|
||||
favourites.FavouriteDelete.as_view(),
|
||||
name="favourite_delete",
|
||||
),
|
||||
path(
|
||||
"favourites/<str:type>/detail/<str:pk>/",
|
||||
favourites.FavouriteDetail.as_view(),
|
||||
name="favourite_detail",
|
||||
),
|
||||
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||
|
@ -11,6 +11,7 @@ from .models import (
|
||||
Entry,
|
||||
Experience,
|
||||
ExperienceDose,
|
||||
Favourite,
|
||||
NotificationSettings,
|
||||
Source,
|
||||
Timing,
|
||||
@ -57,3 +58,4 @@ admin.site.register(Experience)
|
||||
admin.site.register(Source)
|
||||
admin.site.register(SEI)
|
||||
admin.site.register(ExperienceDose)
|
||||
admin.site.register(Favourite)
|
||||
|
@ -21,6 +21,7 @@ class PsychWikiClient(GraphQLClient, BaseClient):
|
||||
Store the data in the database.
|
||||
"""
|
||||
for drug in data["substances"]:
|
||||
print("DRUG ITER", drug)
|
||||
try:
|
||||
drug_obj = Drug.objects.get(name=drug["name"])
|
||||
except Drug.DoesNotExist:
|
||||
@ -89,6 +90,7 @@ class PsychWikiClient(GraphQLClient, BaseClient):
|
||||
)
|
||||
if created or dosage not in drug_obj.dosages.all():
|
||||
drug_obj.dosages.add(dosage)
|
||||
print("YES DOSAGE", drug_obj.dosages)
|
||||
|
||||
# Parsing timing information
|
||||
timing = roa["duration"]
|
||||
|
@ -89,6 +89,8 @@ def drug_query(request, query_params, size=None, tags=None):
|
||||
|
||||
# Q/T - Query/Tags
|
||||
result = run_query(query_params, tags, size, sources, ranges, sort)
|
||||
for x in result:
|
||||
print(x.dosages)
|
||||
rtrn = {
|
||||
"object_list": result,
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ from mixins.restrictions import RestrictedFormMixin
|
||||
|
||||
from mxs.restrictions import RestrictedFormMixinStaff
|
||||
|
||||
from .models import Drug, NotificationSettings, User
|
||||
from .models import Drug, Favourite, NotificationSettings, User
|
||||
|
||||
# Create your forms here.
|
||||
|
||||
@ -78,3 +78,20 @@ class DrugForm(RestrictedFormMixinStaff, ModelForm):
|
||||
"actions": "Actions, what does it do on an objective level?",
|
||||
"experiences": "Experiences, what do people experience?",
|
||||
}
|
||||
|
||||
|
||||
class FavouriteForm(RestrictedFormMixin, ModelForm):
|
||||
class Meta:
|
||||
model = Favourite
|
||||
fields = (
|
||||
"nickname",
|
||||
"name",
|
||||
"drug_class",
|
||||
"common_name",
|
||||
)
|
||||
help_texts = {
|
||||
"nickname": "Call it whatever you like.",
|
||||
"name": "Lysergic acid diethylamide, Phenibut",
|
||||
"drug_class": "Psychedelic, Sedative, Stimulant",
|
||||
"common_name": "LSD",
|
||||
}
|
||||
|
44
core/migrations/0010_price_favouritedrug.py
Normal file
44
core/migrations/0010_price_favouritedrug.py
Normal file
@ -0,0 +1,44 @@
|
||||
# Generated by Django 5.0.3 on 2024-05-17 19:01
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0009_alter_drug_common_name_alter_drug_drug_class'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Price',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('amount_mg', models.IntegerField()),
|
||||
('price_gbp', models.FloatField()),
|
||||
('note', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FavouriteDrug',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('nickname', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('drug_class', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('common_name', models.CharField(blank=True, max_length=1024, null=True)),
|
||||
('actions', models.ManyToManyField(blank=True, to='core.action')),
|
||||
('dosages', models.ManyToManyField(blank=True, to='core.dosage')),
|
||||
('effects', models.ManyToManyField(blank=True, to='core.effect')),
|
||||
('experiences', models.ManyToManyField(blank=True, to='core.experience')),
|
||||
('links', models.ManyToManyField(blank=True, to='core.entry')),
|
||||
('original', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.drug')),
|
||||
('timings', models.ManyToManyField(blank=True, to='core.timing')),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
('prices', models.ManyToManyField(blank=True, null=True, to='core.price')),
|
||||
],
|
||||
),
|
||||
]
|
17
core/migrations/0011_rename_favouritedrug_favourite.py
Normal file
17
core/migrations/0011_rename_favouritedrug_favourite.py
Normal file
@ -0,0 +1,17 @@
|
||||
# Generated by Django 5.0.3 on 2024-05-17 19:02
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0010_price_favouritedrug'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameModel(
|
||||
old_name='FavouriteDrug',
|
||||
new_name='Favourite',
|
||||
),
|
||||
]
|
@ -188,7 +188,7 @@ class Dosage(models.Model):
|
||||
def __str__(self):
|
||||
text = (
|
||||
f"{self.threshold_lower} {self.light_lower} {self.common_lower} "
|
||||
"{self.strong_lower} {self.heavy_lower}"
|
||||
f"{self.strong_lower} {self.heavy_lower}"
|
||||
)
|
||||
return f"{self.roa} {text} ({self.unit})"
|
||||
|
||||
@ -409,6 +409,69 @@ class Drug(models.Model):
|
||||
return f"{self.name} ({self.common_name})"
|
||||
|
||||
|
||||
class Price(models.Model):
|
||||
"""
|
||||
Price of a drug.
|
||||
"""
|
||||
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
||||
amount_mg = models.IntegerField()
|
||||
price_gbp = models.FloatField()
|
||||
note = models.CharField(max_length=255, blank=True, null=True)
|
||||
|
||||
|
||||
# class Stack: references, times
|
||||
# class StackUnit: reference, times, dose_mg
|
||||
|
||||
|
||||
class Favourite(models.Model):
|
||||
"""
|
||||
Model of a drug. Owned by a user and customisable.
|
||||
"""
|
||||
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
||||
|
||||
# Nickname
|
||||
nickname = models.CharField(max_length=255, blank=True, null=True)
|
||||
|
||||
# Prices, how much certain mass of this substance costs
|
||||
prices = models.ManyToManyField(Price, blank=True, null=True)
|
||||
|
||||
# Internals
|
||||
original = models.ForeignKey(Drug, on_delete=models.SET_NULL, blank=True, null=True)
|
||||
|
||||
# Below duplicates Drug
|
||||
# Lysergic acid diethylamide, Phenibut
|
||||
name = models.CharField(max_length=255)
|
||||
|
||||
# Psychedelic, Sedative, Stimulant
|
||||
drug_class = models.CharField(max_length=255, blank=True, null=True)
|
||||
|
||||
# LSD
|
||||
common_name = models.CharField(max_length=1024, blank=True, null=True)
|
||||
|
||||
# Factsheets, posts
|
||||
links = models.ManyToManyField(Entry, blank=True)
|
||||
|
||||
# Dosages, how much to take to get a certain effect
|
||||
dosages = models.ManyToManyField(Dosage, blank=True)
|
||||
|
||||
# Timings, how long to wait to reach maximum intensity (and others)
|
||||
timings = models.ManyToManyField(Timing, blank=True)
|
||||
|
||||
# Effects, what does it do on a subjective level?
|
||||
effects = models.ManyToManyField(Effect, blank=True)
|
||||
|
||||
# Actions, what does it do on an objective level?
|
||||
actions = models.ManyToManyField(Action, blank=True)
|
||||
|
||||
# Experiences, what do people experience?
|
||||
experiences = models.ManyToManyField(Experience, blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} ({self.common_name})"
|
||||
|
||||
|
||||
# class Perms(models.Model):
|
||||
# class Meta:
|
||||
# permissions = (
|
||||
|
File diff suppressed because one or more lines are too long
4
core/static/css/bulma.min.css
vendored
4
core/static/css/bulma.min.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -209,6 +209,12 @@
|
||||
<a class="navbar-item" href="{% url 'home' %}">
|
||||
Home
|
||||
</a>
|
||||
<a class="navbar-item" href="{% url 'home' %}">
|
||||
Search
|
||||
</a>
|
||||
<a class="navbar-item" href="{% url 'favourites' type='page' %}">
|
||||
Favourites
|
||||
</a>
|
||||
{% if user.is_superuser %}
|
||||
<div class="navbar-item has-dropdown is-hoverable">
|
||||
<a class="navbar-link">
|
||||
@ -225,9 +231,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<a class="navbar-item" href="{% url 'home' %}">
|
||||
Search
|
||||
</a>
|
||||
|
||||
{% if user.is_authenticated %}
|
||||
|
||||
<div class="navbar-item has-dropdown is-hoverable">
|
||||
|
76
core/templates/partials/drug-detail.html
Normal file
76
core/templates/partials/drug-detail.html
Normal file
@ -0,0 +1,76 @@
|
||||
{% load pretty %}
|
||||
|
||||
{% load cache %}
|
||||
|
||||
{% cache 600 favourite_detail request.user.id object %}
|
||||
{% include 'mixins/partials/notify.html' %}
|
||||
|
||||
{% if object is not None %}
|
||||
<h1 class="title">{{ object.name }} - {{ object.nickname }} - {{ object.common_name }}</h1>
|
||||
<p class="subtitle"><strong>{{ object.drug_class }}</strong></p>
|
||||
<div class="block">
|
||||
<a class="button is-info" href="#">Prices</a>
|
||||
<a class="button is-info" href="#">More info</a>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<div class="cell">
|
||||
<div class="box">
|
||||
<h2 class="subtitle">Dosage</h2>
|
||||
<ul>
|
||||
{% for dose in object.dosages.all %}
|
||||
<li>{{ dose }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="box">
|
||||
<h2 class="subtitle">Timing</h2>
|
||||
<ul>
|
||||
{% for timing in object.timings.all %}
|
||||
<li>{{ timing }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="box">
|
||||
<h2 class="subtitle">Links</h2>
|
||||
<ul>
|
||||
{% for link in object.links.all %}
|
||||
<li>{{ link }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="cell">
|
||||
<div class="box">
|
||||
<h2 class="subtitle">Actions</h2>
|
||||
<ul>
|
||||
{% for action in object.actions.all %}
|
||||
<li>{{ action }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="box">
|
||||
<h2 class="subtitle">Effects</h2>
|
||||
<ul>
|
||||
{% for effect in object.effects.all %}
|
||||
<li>{{ effect }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="box">
|
||||
<h2 class="subtitle">Experiences</h2>
|
||||
<ul>
|
||||
{% for exp in object.experiences.all %}
|
||||
<li>{{ exp }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endcache %}
|
@ -64,6 +64,15 @@
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<a href="{% url 'drug_detail' type='page' pk=item.id %}"><button
|
||||
class="button">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-eye"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
86
core/templates/partials/favourite-list.html
Normal file
86
core/templates/partials/favourite-list.html
Normal file
@ -0,0 +1,86 @@
|
||||
{% load cache %}
|
||||
{% load cachalot cache %}
|
||||
{% get_last_invalidation 'core.Favourite' as last %}
|
||||
{% include 'mixins/partials/notify.html' %}
|
||||
{% cache 600 objects_favourittes request.user.id object_list last %}
|
||||
<table
|
||||
class="table is-fullwidth is-hoverable"
|
||||
hx-target="#{{ context_object_name }}-table"
|
||||
id="{{ context_object_name }}-table"
|
||||
hx-swap="outerHTML"
|
||||
hx-trigger="{{ context_object_name_singular }}Event from:body"
|
||||
hx-get="{{ list_url }}">
|
||||
<thead>
|
||||
<th>id</th>
|
||||
<th>nickname</th>
|
||||
<th>prices</th>
|
||||
<th>name</th>
|
||||
<th>drug class</th>
|
||||
<th>common name</th>
|
||||
<th>links</th>
|
||||
<th>dosages</th>
|
||||
<th>timings</th>
|
||||
<th>effects</th>
|
||||
<th>actions</th>
|
||||
<th>experiences</th>
|
||||
<th>actions</th>
|
||||
</thead>
|
||||
{% for item in object_list %}
|
||||
<tr>
|
||||
<td>{{ item.id }}</td>
|
||||
<td>{{ item.nickname }}</td>
|
||||
<td>{{ item.prices.count }}</td>
|
||||
<td>{{ item.name }}</td>
|
||||
<td>{{ item.drug_class }}</td>
|
||||
<td>{{ item.common_name }}</td>
|
||||
<td>{{ item.links.count }}</td>
|
||||
<td>{{ item.dosages.count }}</td>
|
||||
<td>{{ item.timings.count }}</td>
|
||||
<td>{{ item.effects.count }}</td>
|
||||
<td>{{ item.actions.count }}</td>
|
||||
<td>{{ item.experiences.count }}</td>
|
||||
<td>
|
||||
<div class="buttons">
|
||||
<button
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-get="{% url 'favourite_update' type=type pk=item.id %}"
|
||||
hx-trigger="click"
|
||||
hx-target="#{{ type }}s-here"
|
||||
hx-swap="innerHTML"
|
||||
class="button">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-pencil"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-delete="{% url 'favourite_delete' type=type pk=item.id %}"
|
||||
hx-trigger="click"
|
||||
hx-target="#modals-here"
|
||||
hx-swap="innerHTML"
|
||||
hx-confirm="Are you sure you wish to delete {{ item.name }}?"
|
||||
class="button">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<a href="{% url 'favourite_detail' type='page' pk=item.id %}"><button
|
||||
class="button">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-eye"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
</table>
|
||||
{% endcache %}
|
@ -5,523 +5,289 @@
|
||||
{% load urlsafe %}
|
||||
{% load cache %}
|
||||
|
||||
{% cache 3600 results_table_full request.user.id table %}
|
||||
{% block table-wrapper %}
|
||||
<script src="{% static 'js/column-shifter.js' %}"></script>
|
||||
<div id="drilldown-table" class="column-shifter-container" style="position:relative; z-index:1;">
|
||||
{% block table %}
|
||||
<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:2;">
|
||||
{% 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>
|
||||
{# cache 3600 results_table_full request.user.id table #}
|
||||
{% block table-wrapper %}
|
||||
<script src="{% static 'js/column-shifter.js' %}"></script>
|
||||
<div id="drilldown-table" class="column-shifter-container" style="position:relative; z-index:1;">
|
||||
{% block table %}
|
||||
<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:2;">
|
||||
{% 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 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');
|
||||
});
|
||||
<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');
|
||||
});
|
||||
|
||||
</script>
|
||||
<div id="table-container" style="display:none;">
|
||||
<table {% render_attrs table.attrs class="table drilldown-results-table 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 %}
|
||||
{% block table.thead.th %}
|
||||
<th class="orderable {{ column.name }}">
|
||||
<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 %}
|
||||
</script>
|
||||
<div id="table-container" style="display:none;">
|
||||
<table {% render_attrs table.attrs class="table drilldown-results-table 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 %}
|
||||
{% block table.thead.th %}
|
||||
<th class="orderable {{ column.name }}">
|
||||
<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.orderable_icon %}<i class="fa-solid fa-sort"></i>{% endblock table.orderable_icon %}</span>
|
||||
<span class="icon" aria-hidden="true">{% block table.asc_icon %}<i class="fa-solid fa-sort-up"></i>{% endblock table.asc_icon %}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="nowrap-child">
|
||||
<a
|
||||
hx-get="search/partial/{% querystring table.prefixed_order_by_field=column.order_by_alias.next %}&{{ uri }}"
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-trigger="click"
|
||||
hx-target="#drilldown-table"
|
||||
hx-swap="outerHTML"
|
||||
hx-indicator="#spinner"
|
||||
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 %}
|
||||
{% if row.cells.type == 'control' %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<span class="icon has-text-grey" data-tooltip="Hidden">
|
||||
<i class="fa-solid fa-file-slash"></i>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<p class="has-text-grey">Hidden {{ row.cells.hidden }} similar result{% if row.cells.hidden > 1%}s{% endif %}</p>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr class="
|
||||
{% if row.cells.exemption == True %}has-background-grey-lighter
|
||||
{% elif cell == 'join' %}has-background-success-light
|
||||
{% elif cell == 'quit' %}has-background-danger-light
|
||||
{% elif cell == 'kick' %}has-background-danger-light
|
||||
{% elif cell == 'part' %}has-background-warning-light
|
||||
{% elif cell == 'mode' %}has-background-info-light
|
||||
{% endif %}">
|
||||
{% for column, cell in row.items %}
|
||||
{% if column.name in show %}
|
||||
{% block table.tbody.td %}
|
||||
{% if 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 }}">
|
||||
{% 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
|
||||
class="has-text-grey"
|
||||
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>
|
||||
{% elif row.cells.src == '4ch' %}
|
||||
<span class="icon" data-tooltip="4chan">
|
||||
<i class="fa-solid fa-leaf" 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' or column.name == 'mtype' %}
|
||||
<td class="{{ column.name }}">
|
||||
<a
|
||||
class="has-text-grey"
|
||||
onclick="populateSearch('{{ column.name }}', '{{ cell|escapejs }}')">
|
||||
{% if cell == 'msg' %}
|
||||
<span class="icon" data-tooltip="Message">
|
||||
<i class="fa-solid fa-message"></i>
|
||||
</span>
|
||||
{% elif cell == 'join' %}
|
||||
<span class="icon" data-tooltip="Join">
|
||||
<i class="fa-solid fa-person-to-portal"></i>
|
||||
</span>
|
||||
{% elif cell == 'part' %}
|
||||
<span class="icon" data-tooltip="Part">
|
||||
<i class="fa-solid fa-person-from-portal"></i>
|
||||
</span>
|
||||
{% elif cell == 'quit' %}
|
||||
<span class="icon" data-tooltip="Quit">
|
||||
<i class="fa-solid fa-circle-xmark"></i>
|
||||
</span>
|
||||
{% elif cell == 'kick' %}
|
||||
<span class="icon" data-tooltip="Kick">
|
||||
<i class="fa-solid fa-user-slash"></i>
|
||||
</span>
|
||||
{% elif cell == 'nick' %}
|
||||
<span class="icon" data-tooltip="Nick">
|
||||
<i class="fa-solid fa-signature"></i>
|
||||
</span>
|
||||
{% elif cell == 'mode' %}
|
||||
<span class="icon" data-tooltip="Mode">
|
||||
<i class="fa-solid fa-gear"></i>
|
||||
</span>
|
||||
{% elif cell == 'action' %}
|
||||
<span class="icon" data-tooltip="Action">
|
||||
<i class="fa-solid fa-exclamation"></i>
|
||||
</span>
|
||||
{% elif cell == 'notice' %}
|
||||
<span class="icon" data-tooltip="Notice">
|
||||
<i class="fa-solid fa-message-code"></i>
|
||||
</span>
|
||||
{% elif cell == 'conn' %}
|
||||
<span class="icon" data-tooltip="Connection">
|
||||
<i class="fa-solid fa-cloud-exclamation"></i>
|
||||
</span>
|
||||
{% elif cell == 'znc' %}
|
||||
<span class="icon" data-tooltip="ZNC">
|
||||
<i class="fa-brands fa-unity"></i>
|
||||
</span>
|
||||
{% elif cell == 'query' %}
|
||||
<span class="icon" data-tooltip="Query">
|
||||
<i class="fa-solid fa-message"></i>
|
||||
</span>
|
||||
{% elif cell == 'highlight' %}
|
||||
<span class="icon" data-tooltip="Highlight">
|
||||
<i class="fa-solid fa-exclamation"></i>
|
||||
</span>
|
||||
{% elif cell == 'who' %}
|
||||
<span class="icon" data-tooltip="Who">
|
||||
<i class="fa-solid fa-passport"></i>
|
||||
</span>
|
||||
{% elif cell == 'topic' %}
|
||||
<span class="icon" data-tooltip="Topic">
|
||||
<i class="fa-solid fa-sign"></i>
|
||||
</span>
|
||||
{% else %}
|
||||
{{ cell }}
|
||||
{% endif %}
|
||||
</a>
|
||||
</td>
|
||||
{% elif column.name == 'msg' %}
|
||||
<td class="{{ column.name }} wrap">
|
||||
<a
|
||||
class="has-text-grey is-underlined"
|
||||
hx-get="search/partial/{% querystring table.prefixed_order_by_field=column.order_by_alias.next %}&{{ uri }}"
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-post="{% url 'modal_context' %}"
|
||||
hx-vals='{"net": "{{ row.cells.net|escapejs }}",
|
||||
"num": "{{ row.cells.num|escapejs }}",
|
||||
"source": "{{ row.cells.src|escapejs }}",
|
||||
"channel": "{{ row.cells.channel|escapejs }}",
|
||||
"time": "{{ row.cells.time|escapejs }}",
|
||||
"date": "{{ row.cells.date|escapejs }}",
|
||||
"index": "{% if row.cells.index != '—' %}{{row.cells.index}}{% else %}{{ params.index }}{% endif %}",
|
||||
"type": "{{ row.cells.type }}",
|
||||
"mtype": "{{ row.cells.mtype }}",
|
||||
"nick": "{{ row.cells.nick|escapejs }}",
|
||||
"dedup": "{{ params.dedup }}"}'
|
||||
hx-target="#modals-here"
|
||||
hx-trigger="click"
|
||||
href="/?modal=context&net={{row.cells.net|escapejs}}&num={{row.cells.num|escapejs}}&source={{row.cells.src|escapejs}}&channel={{row.cells.channel|urlsafe}}&time={{row.cells.time|escapejs}}&date={{row.cells.date|escapejs}}&index={{params.index}}&type={{row.cells.type}}&mtype={{row.cells.mtype}}&nick={{row.cells.mtype|escapejs}}">
|
||||
{{ row.cells.msg }}
|
||||
hx-target="#drilldown-table"
|
||||
hx-swap="outerHTML"
|
||||
hx-indicator="#spinner"
|
||||
style="cursor: pointer;">
|
||||
{{ column.header }}
|
||||
</a>
|
||||
</td>
|
||||
{% elif column.name == 'nick' %}
|
||||
<td class="{{ column.name }}">
|
||||
<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-grey" onclick="populateSearch('nick', '{{ cell|escapejs }}')">
|
||||
{{ cell }}
|
||||
</a>
|
||||
<div class="nowrap-child">
|
||||
{% if row.cells.src == 'irc' %}
|
||||
<a
|
||||
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="has-text-black">
|
||||
<span class="icon" data-tooltip="Open drilldown modal">
|
||||
<i class="fa-solid fa-album"></i>
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-post="{% url 'modal_drilldown' type='window' %}"
|
||||
hx-vals='{"net": "{{ row.cells.net }}", "nick": "{{ row.cells.nick }}", "channel": "{{ row.cells.channel }}"}'
|
||||
hx-target="#windows-here"
|
||||
hx-swap="afterend"
|
||||
hx-trigger="click"
|
||||
class="has-text-black">
|
||||
<span class="icon" data-tooltip="Open drilldown window">
|
||||
<i class="fa-solid fa-album"></i>
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-post="{% url 'modal_drilldown' type='widget' %}"
|
||||
hx-vals='{"net": "{{ row.cells.net }}", "nick": "{{ row.cells.nick }}", "channel": "{{ row.cells.channel }}"}'
|
||||
hx-target="#widgets-here"
|
||||
hx-trigger="click"
|
||||
class="has-text-black">
|
||||
<span class="icon" data-tooltip="Open drilldown widget">
|
||||
<i class="fa-solid fa-album"></i>
|
||||
</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if row.cells.num_chans != '—' %}
|
||||
<div class="nowrap-child">
|
||||
<span class="tag">
|
||||
{{ row.cells.num_chans }}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
{% elif column.name == 'channel' %}
|
||||
<td class="{{ column.name }}">
|
||||
{% if cell != '—' %}
|
||||
<div class="nowrap-parent">
|
||||
<a
|
||||
class="nowrap-child has-text-grey"
|
||||
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 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>
|
||||
{% elif column.name == "tokens" %}
|
||||
<td class="{{ column.name }}">
|
||||
<div class="tags">
|
||||
{% for word in cell %}
|
||||
<a
|
||||
class="tag"
|
||||
onclick="populateSearch('{{ column.name }}', '{{ word }}')">
|
||||
{{ word }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</td>
|
||||
{% elif column.name == "meta" %}
|
||||
<td class="{{ column.name }}">
|
||||
<pre class="small-field" style="cursor: pointer;">{{ cell }}</pre>
|
||||
</td>
|
||||
{% elif 'id' in column.name and column.name != "ident" %}
|
||||
<td class="{{ column.name }}">
|
||||
<div class="buttons">
|
||||
<div class="nowrap-parent">
|
||||
<!-- <input class="input" type="text" value="{{ cell }}" style="width: 50px;" readonly> -->
|
||||
<a
|
||||
class="has-text-grey button nowrap-child"
|
||||
onclick="populateSearch('{{ column.name }}', '{{ cell|escapejs }}')">
|
||||
<span class="icon" data-tooltip="Populate {{ cell }}">
|
||||
<i class="fa-solid fa-arrow-left-long-to-line" aria-hidden="true"></i>
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
class="has-text-grey button nowrap-child"
|
||||
onclick="window.prompt('Copy to clipboard: Ctrl+C, Enter', '{{ cell|escapejs }}');">
|
||||
<span class="icon" data-tooltip="Copy to clipboard">
|
||||
<i class="fa-solid fa-copy" aria-hidden="true"></i>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</div>
|
||||
{% else %}
|
||||
<td class="{{ column.name }}">
|
||||
<a
|
||||
class="has-text-grey"
|
||||
onclick="populateSearch('{{ column.name }}', '{{ cell|escapejs }}')">
|
||||
{{ cell }}
|
||||
</a>
|
||||
</td>
|
||||
<div class="nowrap-child">
|
||||
{{ column.header }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock table.tbody.td %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% 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 %}
|
||||
</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 %}
|
||||
{% if row.cells.type == 'control' %}
|
||||
<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 %}
|
||||
<td></td>
|
||||
<td>
|
||||
<span class="icon has-text-grey" data-tooltip="Hidden">
|
||||
<i class="fa-solid fa-file-slash"></i>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<p class="has-text-grey">Hidden {{ row.cells.hidden }} similar result{% if row.cells.hidden > 1%}s{% endif %}</p>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
{% for column, cell in row.items %}
|
||||
{% if column.name in show %}
|
||||
{% block table.tbody.td %}
|
||||
{% if cell == '—' %}
|
||||
<td class="{{ column.name }}">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-file-slash"></i>
|
||||
</span>
|
||||
</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>
|
||||
{% elif column.name == "dosages" %}
|
||||
<td class="{{ column.name }}">
|
||||
{{ cell.entry }}
|
||||
</td>
|
||||
{% elif column.name == "name" %}
|
||||
<td class="{{ column.name }}">
|
||||
<a href="{% url 'drug_detail' type='page' pk=row.cells.id %}"><button
|
||||
class="button">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-eye"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</a>
|
||||
{{ cell }}
|
||||
</td>
|
||||
|
||||
{% else %}
|
||||
<td class="{{ column.name }}">
|
||||
<a
|
||||
class="has-text-grey"
|
||||
onclick="populateSearch('{{ column.name }}', '{{ cell|escapejs }}')">
|
||||
{{ cell }}
|
||||
</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
{% endblock table.tbody.td %}
|
||||
{% endif %}
|
||||
{% 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 %}
|
||||
<nav class="pagination is-justify-content-flex-end" role="navigation" aria-label="pagination">
|
||||
{% block pagination.previous %}
|
||||
<a
|
||||
class="pagination-previous is-flex-grow-0 {% if not table.page.has_previous %}is-hidden-mobile{% endif %}"
|
||||
{% if table.page.has_previous %}
|
||||
hx-get="search/partial/{% querystring table.prefixed_page_field=table.page.previous_page_number %}&{{ uri }}"
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-trigger="click"
|
||||
hx-target="#drilldown-table"
|
||||
hx-swap="outerHTML"
|
||||
hx-indicator="#spinner"
|
||||
{% else %}
|
||||
href="#"
|
||||
disabled
|
||||
{% endif %}
|
||||
{% 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 %}
|
||||
style="order:1;">
|
||||
{% block pagination.previous.text %}
|
||||
<span aria-hidden="true">«</span>
|
||||
{% endblock pagination.previous.text %}
|
||||
</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/partial/{% querystring table.prefixed_page_field=table.page.next_page_number %}&{{ uri }}"
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-trigger="click"
|
||||
hx-target="#drilldown-table"
|
||||
hx-swap="outerHTML"
|
||||
hx-indicator="#spinner"
|
||||
{% else %}
|
||||
href="#"
|
||||
disabled
|
||||
{% endif %}
|
||||
style="order:3;"
|
||||
>
|
||||
{% block pagination.next.text %}
|
||||
<span aria-hidden="true">»</span>
|
||||
{% endblock pagination.next.text %}
|
||||
</a>
|
||||
{% endblock pagination.next %}
|
||||
{% if table.page.has_previous or table.page.has_next %}
|
||||
{% block pagination.range %}
|
||||
<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/partial/{% querystring table.prefixed_page_field=p %}&{{ uri }}"
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-trigger="click"
|
||||
hx-target="#drilldown-table"
|
||||
hx-swap="outerHTML"
|
||||
hx-indicator="#spinner"
|
||||
{% endif %}
|
||||
>
|
||||
{% if p == '...' %}
|
||||
<span class="pagination-ellipsis">…</span>
|
||||
{% else %}
|
||||
{{ p }}
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock pagination.range %}
|
||||
{% 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 %}
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% endblock pagination %}
|
||||
</div>
|
||||
{% endblock table-wrapper %}
|
||||
{% endcache %}
|
||||
{% endblock table.tfoot %}
|
||||
</table>
|
||||
</div>
|
||||
{% endblock table %}
|
||||
{% block pagination %}
|
||||
{% if table.page and table.paginator.num_pages > 1 %}
|
||||
<nav class="pagination is-justify-content-flex-end" role="navigation" aria-label="pagination">
|
||||
{% block pagination.previous %}
|
||||
<a
|
||||
class="pagination-previous is-flex-grow-0 {% if not table.page.has_previous %}is-hidden-mobile{% endif %}"
|
||||
{% if table.page.has_previous %}
|
||||
hx-get="search/partial/{% querystring table.prefixed_page_field=table.page.previous_page_number %}&{{ uri }}"
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-trigger="click"
|
||||
hx-target="#drilldown-table"
|
||||
hx-swap="outerHTML"
|
||||
hx-indicator="#spinner"
|
||||
{% else %}
|
||||
href="#"
|
||||
disabled
|
||||
{% endif %}
|
||||
style="order:1;">
|
||||
{% block pagination.previous.text %}
|
||||
<span aria-hidden="true">«</span>
|
||||
{% endblock pagination.previous.text %}
|
||||
</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/partial/{% querystring table.prefixed_page_field=table.page.next_page_number %}&{{ uri }}"
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-trigger="click"
|
||||
hx-target="#drilldown-table"
|
||||
hx-swap="outerHTML"
|
||||
hx-indicator="#spinner"
|
||||
{% else %}
|
||||
href="#"
|
||||
disabled
|
||||
{% endif %}
|
||||
style="order:3;"
|
||||
>
|
||||
{% block pagination.next.text %}
|
||||
<span aria-hidden="true">»</span>
|
||||
{% endblock pagination.next.text %}
|
||||
</a>
|
||||
{% endblock pagination.next %}
|
||||
{% if table.page.has_previous or table.page.has_next %}
|
||||
{% block pagination.range %}
|
||||
<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/partial/{% querystring table.prefixed_page_field=p %}&{{ uri }}"
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-trigger="click"
|
||||
hx-target="#drilldown-table"
|
||||
hx-swap="outerHTML"
|
||||
hx-indicator="#spinner"
|
||||
{% endif %}
|
||||
>
|
||||
{% if p == '...' %}
|
||||
<span class="pagination-ellipsis">…</span>
|
||||
{% else %}
|
||||
{{ p }}
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock pagination.range %}
|
||||
{% endif %}
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% endblock pagination %}
|
||||
</div>
|
||||
{% endblock table-wrapper %}
|
||||
{# endcache #}
|
9
core/templatetags/pretty.py
Normal file
9
core/templatetags/pretty.py
Normal file
@ -0,0 +1,9 @@
|
||||
import orjson
|
||||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter
|
||||
def pretty(data):
|
||||
return orjson.dumps(data, option=orjson.OPT_INDENT_2).decode("utf-8")
|
@ -8,7 +8,9 @@ from core.forms import DrugForm
|
||||
from core.models import Drug
|
||||
from core.views.helpers import synchronize_async_helper
|
||||
from mxs.restrictions import StaffMemberRequiredMixin
|
||||
from mxs.views import ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate
|
||||
from mxs.views import ObjectCreate, ObjectDelete, ObjectList, ObjectRead, ObjectUpdate
|
||||
|
||||
# from mixins.views import ObjectRead
|
||||
|
||||
|
||||
class DrugList(LoginRequiredMixin, StaffMemberRequiredMixin, ObjectList):
|
||||
@ -54,6 +56,25 @@ class DrugDelete(LoginRequiredMixin, StaffMemberRequiredMixin, ObjectDelete):
|
||||
model = Drug
|
||||
|
||||
|
||||
class DrugDetail(LoginRequiredMixin, StaffMemberRequiredMixin, ObjectRead):
|
||||
model = Drug
|
||||
form_class = DrugForm
|
||||
detail_template = "partials/drug-detail.html"
|
||||
|
||||
detail_url_name = "drug_detail"
|
||||
detail_url_args = ["type", "pk"]
|
||||
|
||||
def get_object(self, **kwargs):
|
||||
print("GET")
|
||||
pk = kwargs.get("pk")
|
||||
info = Drug.objects.get(pk=pk)
|
||||
|
||||
# self.extra_context = {}
|
||||
print("info", info)
|
||||
# return dictionary
|
||||
return info.__dict__
|
||||
|
||||
|
||||
class DrugClear(LoginRequiredMixin, StaffMemberRequiredMixin, APIView):
|
||||
def delete(self, request):
|
||||
template_name = "mixins/partials/notify.html"
|
||||
|
85
core/views/favourites.py
Normal file
85
core/views/favourites.py
Normal file
@ -0,0 +1,85 @@
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
|
||||
# from mixins.restrictions import StaffMemberRequiredMixin
|
||||
from mixins.views import (
|
||||
ObjectCreate,
|
||||
ObjectDelete,
|
||||
ObjectList,
|
||||
ObjectRead,
|
||||
ObjectUpdate,
|
||||
)
|
||||
|
||||
from core.forms import FavouriteForm
|
||||
from core.models import Favourite
|
||||
|
||||
|
||||
class FavouriteList(LoginRequiredMixin, ObjectList):
|
||||
list_template = "partials/favourite-list.html"
|
||||
model = Favourite
|
||||
page_title = "Global list of favourites"
|
||||
|
||||
list_url_name = "favourites"
|
||||
list_url_args = ["type"]
|
||||
|
||||
submit_url_name = "favourite_create"
|
||||
|
||||
|
||||
class FavouriteCreate(LoginRequiredMixin, ObjectCreate):
|
||||
model = Favourite
|
||||
form_class = FavouriteForm
|
||||
|
||||
submit_url_name = "favourite_create"
|
||||
|
||||
|
||||
class FavouriteUpdate(LoginRequiredMixin, ObjectUpdate):
|
||||
model = Favourite
|
||||
form_class = FavouriteForm
|
||||
|
||||
submit_url_name = "favourite_update"
|
||||
|
||||
|
||||
class FavouriteDelete(LoginRequiredMixin, ObjectDelete):
|
||||
model = Favourite
|
||||
|
||||
|
||||
class FavouriteDetail(LoginRequiredMixin, ObjectRead):
|
||||
model = Favourite
|
||||
form_class = FavouriteForm
|
||||
detail_template = "partials/drug-detail.html"
|
||||
|
||||
detail_url_name = "favourite_detail"
|
||||
detail_url_args = ["type", "pk"]
|
||||
|
||||
def get_object(self, **kwargs):
|
||||
pk = kwargs.get("pk")
|
||||
info = Favourite.objects.get(pk=pk, user=self.request.user)
|
||||
return info.__dict__
|
||||
|
||||
|
||||
# class FavouriteClear(LoginRequiredMixin, APIView):
|
||||
# def delete(self, request):
|
||||
# template_name = "mixins/partials/notify.html"
|
||||
# favourites_all = Favourite.objects.all()
|
||||
# favourites_all.delete()
|
||||
# context = {
|
||||
# "message": "Deleted all favourites",
|
||||
# "class": "success",
|
||||
# }
|
||||
# response = render(request, template_name, context)
|
||||
# response["HX-Trigger"] = "drugEvent"
|
||||
# return response
|
||||
|
||||
|
||||
# class FavouritePullMerge(LoginRequiredMixin, APIView):
|
||||
# def post(self, request):
|
||||
# template_name = "mixins/partials/notify.html"
|
||||
# # Do something
|
||||
# run = synchronize_async_helper(PsychWikiClient())
|
||||
# result = synchronize_async_helper(run.update_favourites())
|
||||
# context = {
|
||||
# "message": f"Favourites fetched: {result}",
|
||||
# "class": "success",
|
||||
# }
|
||||
# response = render(request, template_name, context)
|
||||
# response["HX-Trigger"] = "drugEvent"
|
||||
# return response
|
Loading…
Reference in New Issue
Block a user