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",
|
||||
}
|
||||
|
|
|
@ -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')),
|
||||
],
|
||||
),
|
||||
]
|
|
@ -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
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">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 #}
|
|
@ -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"
|
||||
|
|
|
@ -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