Merge branch 'release/3.0.12'
This commit is contained in:
commit
1772d63bfc
@ -19,7 +19,7 @@
|
||||
<h3>{{ category }}</h3>
|
||||
<a href="{% url 'dashboard:category-detail' category.pk %}" class="btn">View category →</a>
|
||||
</header>
|
||||
{% include 'dashboard/product/_table.html' with product_list=category.product_set.all %}
|
||||
{% include 'dashboard/product/_table.html' with product_list=category.product_set.all category=category %}
|
||||
</section>
|
||||
{% endfor %}
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
<h3>{{ category }}</h3>
|
||||
<a href="{% url 'dashboard:category-detail' category.pk %}" class="btn">View category →</a>
|
||||
</header>
|
||||
{% include 'dashboard/product/_table.html' with product_list=category.product_set.all %}
|
||||
{% include 'dashboard/product/_table.html' with product_list=category.product_set.all category=category %}
|
||||
</section>
|
||||
{% endfor %}
|
||||
</article>
|
||||
|
||||
@ -6,10 +6,10 @@
|
||||
<th>Visible in listings</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody class="sortable" data-model="product" data-filter="category" data-fid="{{ category.pk }}">
|
||||
{% for product in product_list %}
|
||||
<tr class="is-link" onclick="window.location='{% url 'dashboard:product-detail' product.pk %}'">
|
||||
<td>{{ product.sorting }}</td>
|
||||
<tr class="is-link" data-id="{{ product.pk }}" onclick="window.location='{% url 'dashboard:product-detail' product.pk %}'">
|
||||
<td class="handle">☰</td>
|
||||
<td>
|
||||
<figure class="product-figure">
|
||||
<img class="product-image" src="{{ product.get_first_img.image.url }}" alt="{{ product.get_first_img.image }}">
|
||||
|
||||
@ -80,10 +80,10 @@
|
||||
<th colspan="2">Stock</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody class="sortable" data-model="productvariant" data-filter="product" data-fid="{{ product.pk }}">
|
||||
{% for variant in product.variants.all %}
|
||||
<tr>
|
||||
<td>{{ variant.sorting }}</td>
|
||||
<tr data-id="{{ variant.pk }}">
|
||||
<td class="handle">☰</td>
|
||||
<td>
|
||||
<h3>{{ variant.name }}</h3>
|
||||
</td>
|
||||
@ -124,18 +124,18 @@
|
||||
<h4>Photos</h4>
|
||||
<a href="{% url 'dashboard:prodphoto-create' product.pk %}" class="btn">+ Upload new photo</a>
|
||||
</header>
|
||||
<div class="gallery panel-section">
|
||||
{% for photo in product.productphoto_set.all %}
|
||||
<figure class="gallery-item">
|
||||
<img src="{{ photo.image.url }}">
|
||||
<figcaption>
|
||||
<form action="{% url 'dashboard:prodphoto-delete' product.pk photo.pk %}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" class="btn btn-warning" value="Delete photo">
|
||||
</form>
|
||||
</figcaption>
|
||||
</figure>
|
||||
{% endfor %}
|
||||
<div class="gallery panel-section sortable" data-model="productphoto" data-filter="product" data-fid="{{ product.pk }}">
|
||||
{% for photo in product.productphoto_set.all %}
|
||||
<figure class="gallery-item handle" data-id="{{ photo.pk }}">
|
||||
<img src="{{ photo.image.url }}">
|
||||
<figcaption>
|
||||
<form action="{% url 'dashboard:prodphoto-delete' product.pk photo.pk %}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" class="btn btn-warning" value="Delete photo">
|
||||
</form>
|
||||
</figcaption>
|
||||
</figure>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
|
||||
@ -3,6 +3,11 @@
|
||||
|
||||
{% block head_title %}Products | {% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
|
||||
<script type="module" src="{% static 'scripts/sorting.js' %}" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<article>
|
||||
<header class="object-header">
|
||||
|
||||
@ -231,6 +231,12 @@ urlpatterns = [
|
||||
])),
|
||||
])),
|
||||
|
||||
path(
|
||||
'update-sorting/',
|
||||
views.update_sorting,
|
||||
name='update-sorting'
|
||||
),
|
||||
|
||||
path(
|
||||
'customers/',
|
||||
views.CustomerListView.as_view(),
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
import logging
|
||||
import json
|
||||
from datetime import datetime
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
from django import forms
|
||||
from django.apps import apps
|
||||
from django.shortcuts import render, reverse, redirect, get_object_or_404
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.http import JsonResponse, HttpResponseRedirect
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.views.generic.base import RedirectView, TemplateView
|
||||
from django.views.generic.edit import (
|
||||
@ -13,6 +15,7 @@ from django.views.generic.edit import (
|
||||
from django.views.generic.detail import DetailView, SingleObjectMixin
|
||||
from django.views.generic.list import ListView
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.views.decorators.http import require_POST
|
||||
from django.contrib.auth.mixins import (
|
||||
LoginRequiredMixin, PermissionRequiredMixin
|
||||
)
|
||||
@ -616,6 +619,27 @@ class ProductOptionDeleteView(
|
||||
success_url = reverse_lazy('dashboard:catalog')
|
||||
|
||||
|
||||
def sort(objs, order):
|
||||
for i, pk in enumerate(order):
|
||||
m = objs.get(pk=pk)
|
||||
m.sorting = i+1
|
||||
yield m
|
||||
|
||||
|
||||
@require_POST
|
||||
def update_sorting(request):
|
||||
data = json.loads(request.body)
|
||||
model = apps.get_model('core', data['model_name'])
|
||||
objs = model.objects.filter(
|
||||
Q((data['filter'], data['filter_id']))
|
||||
).order_by('sorting')
|
||||
|
||||
updated_objs = sort(objs, data['order'])
|
||||
|
||||
model.objects.bulk_update(updated_objs, ['sorting'])
|
||||
return JsonResponse({'message': 'Sorting updated'})
|
||||
|
||||
|
||||
class CustomerListView(LoginRequiredMixin, ListView):
|
||||
model = User
|
||||
template_name = 'dashboard/customer/list.html'
|
||||
|
||||
51
static/scripts/sorting.js
Normal file
51
static/scripts/sorting.js
Normal file
@ -0,0 +1,51 @@
|
||||
import { getCookie } from './cookie.js'
|
||||
const sorting_url = JSON.parse(document.querySelector('#sorting-url').textContent);
|
||||
|
||||
document.querySelectorAll('.sortable').forEach(el => {
|
||||
const options = {
|
||||
animation: 150,
|
||||
store: {
|
||||
/**
|
||||
* Save the order of elements. Called onEnd (when the item is dropped).
|
||||
* @param {Sortable} sortable
|
||||
*/
|
||||
set: (sortable) => {
|
||||
const order = sortable.toArray()
|
||||
const csrftoken = getCookie('csrftoken')
|
||||
const data = {
|
||||
model_name: el.dataset.model,
|
||||
filter: el.dataset.filter,
|
||||
filter_id: el.dataset.fid,
|
||||
order: order
|
||||
}
|
||||
|
||||
const options = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
mode: 'same-origin',
|
||||
};
|
||||
|
||||
// construct a new Request passing in the csrftoken
|
||||
const request = new Request(sorting_url, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': csrftoken
|
||||
},
|
||||
})
|
||||
|
||||
return fetch(request, options)
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
console.log('Success:', data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error:', error);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if (el.querySelector('.handle')) {
|
||||
options.handle = '.handle'
|
||||
}
|
||||
new Sortable(el, options)
|
||||
})
|
||||
@ -643,3 +643,7 @@ main > article > header {
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.handle {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
@ -22,6 +22,8 @@
|
||||
{% endcompress %}
|
||||
|
||||
<script type="module" defer src="{% static 'scripts/initializers/timezone.js' %}"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
|
||||
<script type="module" src="{% static 'scripts/sorting.js' %}" defer></script>
|
||||
|
||||
{% block head %}
|
||||
{% endblock %}
|
||||
@ -84,6 +86,9 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% url 'dashboard:update-sorting' as sorting_url %}
|
||||
{{ sorting_url|json_script:"sorting-url" }}
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
document.querySelectorAll('.message-dissmiss').forEach(dissmissEl => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user