kopia lustrzana https://github.com/jedie/PyInventory
Merge pull request #63 from jedie/optional-grouping
Group item: default "automatic" mode and can be disabled by filter actionpull/67/head
commit
7a609c5931
|
@ -157,6 +157,7 @@ Files are separated into: "/src/" and "/development/"
|
||||||
== history
|
== history
|
||||||
|
|
||||||
* [[https://github.com/jedie/PyInventory/compare/v0.9.4...master|compare v0.9.4...master]] **dev**
|
* [[https://github.com/jedie/PyInventory/compare/v0.9.4...master|compare v0.9.4...master]] **dev**
|
||||||
|
** Group item: default "automatic" mode and can be disabled by filter action
|
||||||
** tbc
|
** tbc
|
||||||
* [[https://github.com/jedie/PyInventory/compare/v0.9.3...v0.9.4|v0.9.4 - 15.09.2021]]
|
* [[https://github.com/jedie/PyInventory/compare/v0.9.3...v0.9.4|v0.9.4 - 15.09.2021]]
|
||||||
** Pin {{{psycopg < 2.9}}} because of https://github.com/psycopg/psycopg2/issues/1293
|
** Pin {{{psycopg < 2.9}}} because of https://github.com/psycopg/psycopg2/issues/1293
|
||||||
|
|
|
@ -220,6 +220,8 @@ history
|
||||||
|
|
||||||
* `compare v0.9.4...master <https://github.com/jedie/PyInventory/compare/v0.9.4...master>`_ **dev**
|
* `compare v0.9.4...master <https://github.com/jedie/PyInventory/compare/v0.9.4...master>`_ **dev**
|
||||||
|
|
||||||
|
* Group item: default "automatic" mode and can be disabled by filter action
|
||||||
|
|
||||||
* tbc
|
* tbc
|
||||||
|
|
||||||
* `v0.9.4 - 15.09.2021 <https://github.com/jedie/PyInventory/compare/v0.9.3...v0.9.4>`_
|
* `v0.9.4 - 15.09.2021 <https://github.com/jedie/PyInventory/compare/v0.9.3...v0.9.4>`_
|
||||||
|
@ -401,4 +403,4 @@ donation
|
||||||
|
|
||||||
------------
|
------------
|
||||||
|
|
||||||
``Note: this file is generated from README.creole 2021-09-15 21:28:39 with "python-creole"``
|
``Note: this file is generated from README.creole 2021-09-29 19:16:20 with "python-creole"``
|
|
@ -3,6 +3,7 @@ from reversion_compare.admin import CompareVersionAdmin
|
||||||
|
|
||||||
class BaseUserAdmin(CompareVersionAdmin):
|
class BaseUserAdmin(CompareVersionAdmin):
|
||||||
def get_changelist(self, request, **kwargs):
|
def get_changelist(self, request, **kwargs):
|
||||||
|
self.request = request
|
||||||
self.user = request.user
|
self.user = request.user
|
||||||
return super().get_changelist(request, **kwargs)
|
return super().get_changelist(request, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
import tagulous
|
import tagulous
|
||||||
from adminsortable2.admin import SortableInlineAdminMixin
|
from adminsortable2.admin import SortableInlineAdminMixin
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.admin.views.main import ChangeList
|
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
@ -14,6 +15,9 @@ from inventory.models import ItemLinkModel, ItemModel
|
||||||
from inventory.models.item import ItemFileModel, ItemImageModel
|
from inventory.models.item import ItemFileModel, ItemImageModel
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class UserInlineMixin:
|
class UserInlineMixin:
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
qs = super().get_queryset(request)
|
qs = super().get_queryset(request)
|
||||||
|
@ -62,14 +66,48 @@ class ItemModelResource(ModelResource):
|
||||||
model = ItemModel
|
model = ItemModel
|
||||||
|
|
||||||
|
|
||||||
class ItemModelChangeList(ChangeList):
|
class GroupItemsListFilter(admin.SimpleListFilter):
|
||||||
def get_queryset(self, request):
|
title = _('Group Items')
|
||||||
"""
|
parameter_name = 'grouping'
|
||||||
List always the base instances
|
|
||||||
"""
|
GET_KEY_AUTO = 'auto'
|
||||||
qs = super().get_queryset(request)
|
GET_KEY_NO = 'no'
|
||||||
qs = qs.filter(parent__isnull=True)
|
|
||||||
return qs
|
def lookups(self, request, model_admin):
|
||||||
|
return (
|
||||||
|
(self.GET_KEY_AUTO, _('Automatic')),
|
||||||
|
(self.GET_KEY_NO, _('No')),
|
||||||
|
)
|
||||||
|
|
||||||
|
def value(self):
|
||||||
|
return super().value() or self.GET_KEY_AUTO
|
||||||
|
|
||||||
|
def queryset(self, request, queryset):
|
||||||
|
auto_mode = self.value() == self.GET_KEY_AUTO
|
||||||
|
if auto_mode:
|
||||||
|
request.group_items = not request.GET.keys()
|
||||||
|
else:
|
||||||
|
request.group_items = self.value() != self.GET_KEY_NO
|
||||||
|
|
||||||
|
logger.info('Group items: %r (auto mode: %r)', request.group_items, auto_mode)
|
||||||
|
|
||||||
|
if request.group_items:
|
||||||
|
queryset = queryset.filter(parent__isnull=True)
|
||||||
|
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
def choices(self, changelist):
|
||||||
|
for lookup, title in self.lookup_choices:
|
||||||
|
if lookup == self.GET_KEY_AUTO:
|
||||||
|
query_string = changelist.get_query_string(remove=[self.parameter_name])
|
||||||
|
else:
|
||||||
|
query_string = changelist.get_query_string({self.parameter_name: lookup})
|
||||||
|
|
||||||
|
yield {
|
||||||
|
'selected': self.value() == lookup,
|
||||||
|
'query_string': query_string,
|
||||||
|
'display': title,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@admin.register(ItemModel)
|
@admin.register(ItemModel)
|
||||||
|
@ -88,13 +126,19 @@ class ItemModelAdmin(ImportExportMixin, BaseUserAdmin):
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
def column_item(self, obj):
|
def column_item(self, obj):
|
||||||
# TODO: annotate "sub_items" !
|
|
||||||
qs = ItemModel.objects.filter(user=self.user)
|
|
||||||
qs = qs.filter(parent=obj).sort()
|
|
||||||
context = {
|
context = {
|
||||||
'base_item': obj,
|
'base_item': obj,
|
||||||
'sub_items': qs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.request.group_items: # Attribute added in GroupItemsListFilter.queryset()
|
||||||
|
logger.debug('Display sub items inline')
|
||||||
|
# TODO: annotate "sub_items" !
|
||||||
|
qs = ItemModel.objects.filter(
|
||||||
|
user=self.user # user added in BaseUserAdmin.get_changelist()
|
||||||
|
)
|
||||||
|
qs = qs.filter(parent=obj).sort()
|
||||||
|
context['sub_items'] = qs
|
||||||
|
|
||||||
return render_to_string(
|
return render_to_string(
|
||||||
template_name='admin/inventory/item/column_item.html',
|
template_name='admin/inventory/item/column_item.html',
|
||||||
context=context,
|
context=context,
|
||||||
|
@ -111,7 +155,7 @@ class ItemModelAdmin(ImportExportMixin, BaseUserAdmin):
|
||||||
)
|
)
|
||||||
ordering = ('kind', 'producer', 'name')
|
ordering = ('kind', 'producer', 'name')
|
||||||
list_display_links = None
|
list_display_links = None
|
||||||
list_filter = ('kind', 'location', 'producer', 'tags')
|
list_filter = (GroupItemsListFilter, 'kind', 'location', 'producer', 'tags')
|
||||||
search_fields = ('name', 'description', 'kind__name', 'tags__name')
|
search_fields = ('name', 'description', 'kind__name', 'tags__name')
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(_('Internals'), {
|
(_('Internals'), {
|
||||||
|
@ -156,9 +200,5 @@ class ItemModelAdmin(ImportExportMixin, BaseUserAdmin):
|
||||||
readonly_fields = ('id', 'create_dt', 'update_dt', 'user')
|
readonly_fields = ('id', 'create_dt', 'update_dt', 'user')
|
||||||
inlines = (ItemImageModelInline, ItemFileModelInline, ItemLinkModelInline)
|
inlines = (ItemImageModelInline, ItemFileModelInline, ItemLinkModelInline)
|
||||||
|
|
||||||
def get_changelist(self, request, **kwargs):
|
|
||||||
self.user = request.user
|
|
||||||
return ItemModelChangeList
|
|
||||||
|
|
||||||
|
|
||||||
tagulous.admin.enhance(ItemModel, ItemModelAdmin)
|
tagulous.admin.enhance(ItemModel, ItemModelAdmin)
|
||||||
|
|
Plik binarny nie jest wyświetlany.
|
@ -7,8 +7,8 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: \n"
|
"Project-Id-Version: \n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-04-28 18:31+0200\n"
|
"POT-Creation-Date: 2021-09-29 19:19+0200\n"
|
||||||
"PO-Revision-Date: 2021-04-28 18:29+0200\n"
|
"PO-Revision-Date: 2021-09-29 19:19+0200\n"
|
||||||
"Last-Translator: Jens Diemer\n"
|
"Last-Translator: Jens Diemer\n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"Language: de\n"
|
"Language: de\n"
|
||||||
|
@ -18,6 +18,15 @@ msgstr ""
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Generator: Poedit 2.3\n"
|
"X-Generator: Poedit 2.3\n"
|
||||||
|
|
||||||
|
msgid "Group Items"
|
||||||
|
msgstr "Gegenstände Gruppieren"
|
||||||
|
|
||||||
|
msgid "Automatic"
|
||||||
|
msgstr "Automatisch"
|
||||||
|
|
||||||
|
msgid "No"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "ItemModel.verbose_name_plural"
|
msgid "ItemModel.verbose_name_plural"
|
||||||
msgstr "Gegenstände"
|
msgstr "Gegenstände"
|
||||||
|
|
||||||
|
@ -188,7 +197,7 @@ msgid "ItemFileModel.file.verbose_name"
|
||||||
msgstr "Datei"
|
msgstr "Datei"
|
||||||
|
|
||||||
msgid "ItemFileModel.file.help_text"
|
msgid "ItemFileModel.file.help_text"
|
||||||
msgstr ""
|
msgstr " "
|
||||||
|
|
||||||
msgid "ItemFileModel.verbose_name"
|
msgid "ItemFileModel.verbose_name"
|
||||||
msgstr "Datei"
|
msgstr "Datei"
|
||||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: \n"
|
"Project-Id-Version: \n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-04-28 18:31+0200\n"
|
"POT-Creation-Date: 2021-09-29 19:19+0200\n"
|
||||||
"PO-Revision-Date: 2021-04-28 18:30+0200\n"
|
"PO-Revision-Date: 2021-04-28 18:30+0200\n"
|
||||||
"Last-Translator: Jens Diemer\n"
|
"Last-Translator: Jens Diemer\n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
|
@ -18,6 +18,15 @@ msgstr ""
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Generator: Poedit 2.3\n"
|
"X-Generator: Poedit 2.3\n"
|
||||||
|
|
||||||
|
msgid "Group Items"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Automatic"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "No"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "ItemModel.verbose_name_plural"
|
msgid "ItemModel.verbose_name_plural"
|
||||||
msgstr "Items"
|
msgstr "Items"
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
from inventory_project.settings.base import * # noqa
|
# flake8: noqa: E405, F403
|
||||||
|
|
||||||
|
from inventory_project.settings.base import *
|
||||||
|
|
||||||
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
|
@ -11,3 +13,7 @@ DATABASES = {
|
||||||
SECRET_KEY = 'No individual secret for tests ;)'
|
SECRET_KEY = 'No individual secret for tests ;)'
|
||||||
|
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
|
|
||||||
|
LOGGING['formatters']['colored']['format'] = (
|
||||||
|
'%(log_color)s%(name)s %(levelname)8s %(cut_path)s:%(lineno)-3s %(message)s'
|
||||||
|
)
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
from bx_django_utils.test_utils.html_assertion import HtmlAssertionMixin
|
import datetime
|
||||||
|
import logging
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
from bx_django_utils.test_utils.datetime import MockDatetimeGenerator
|
||||||
|
from bx_django_utils.test_utils.html_assertion import HtmlAssertionMixin, assert_html_response_snapshot
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.template.defaulttags import CsrfTokenNode
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
from django.utils import timezone
|
||||||
from django_tools.unittest_utils.mockup import ImageDummy
|
from django_tools.unittest_utils.mockup import ImageDummy
|
||||||
from model_bakery import baker
|
from model_bakery import baker
|
||||||
|
|
||||||
|
@ -22,7 +29,8 @@ class AdminTestCase(HtmlAssertionMixin, TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
cls.normaluser = baker.make(
|
cls.normaluser = baker.make(
|
||||||
User, is_staff=True, is_active=True, is_superuser=False
|
User, username='NormalUser',
|
||||||
|
is_staff=True, is_active=True, is_superuser=False
|
||||||
)
|
)
|
||||||
assert cls.normaluser.user_permissions.count() == 0
|
assert cls.normaluser.user_permissions.count() == 0
|
||||||
group = get_or_create_normal_user_group()[0]
|
group = get_or_create_normal_user_group()[0]
|
||||||
|
@ -136,3 +144,78 @@ class AdminTestCase(HtmlAssertionMixin, TestCase):
|
||||||
assert image.name == 'test.png'
|
assert image.name == 'test.png'
|
||||||
assert image.item == item
|
assert image.item == item
|
||||||
assert image.user_id == self.normaluser.pk
|
assert image.user_id == self.normaluser.pk
|
||||||
|
|
||||||
|
def test_auto_group_items(self):
|
||||||
|
self.client.force_login(self.normaluser)
|
||||||
|
|
||||||
|
offset = datetime.timedelta(minutes=1)
|
||||||
|
with mock.patch.object(timezone, 'now', MockDatetimeGenerator(offset=offset)):
|
||||||
|
for main_item_no in range(1, 3):
|
||||||
|
main_item = ItemModel.objects.create(
|
||||||
|
id=f'00000000-000{main_item_no}-0000-0000-000000000000',
|
||||||
|
user=self.normaluser,
|
||||||
|
name=f'main item {main_item_no}'
|
||||||
|
)
|
||||||
|
main_item.full_clean()
|
||||||
|
for sub_item_no in range(1, 3):
|
||||||
|
sub_item = ItemModel.objects.create(
|
||||||
|
id=f'00000000-000{main_item_no}-000{sub_item_no}-0000-000000000000',
|
||||||
|
user=self.normaluser,
|
||||||
|
parent=main_item,
|
||||||
|
name=f'sub item {main_item_no}.{sub_item_no}'
|
||||||
|
)
|
||||||
|
sub_item.full_clean()
|
||||||
|
|
||||||
|
names = list(ItemModel.objects.order_by('id').values_list('name', flat=True))
|
||||||
|
assert names == [
|
||||||
|
'main item 1', 'sub item 1.1', 'sub item 1.2',
|
||||||
|
'main item 2', 'sub item 2.1', 'sub item 2.2',
|
||||||
|
]
|
||||||
|
|
||||||
|
# Default mode, without any GET parameter -> group "automatic":
|
||||||
|
|
||||||
|
with mock.patch.object(CsrfTokenNode, 'render', return_value='MockedCsrfTokenNode'), \
|
||||||
|
self.assertLogs(logger='inventory', level=logging.DEBUG) as logs:
|
||||||
|
response = self.client.get(
|
||||||
|
path='/admin/inventory/itemmodel/',
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
self.assert_html_parts(response, parts=(
|
||||||
|
f'<title>Select Item to change | PyInventory v{__version__}</title>',
|
||||||
|
|
||||||
|
'<a href="/admin/inventory/itemmodel/00000000-0001-0000-0000-000000000000/change/">'
|
||||||
|
'main item 1</a>',
|
||||||
|
|
||||||
|
'<li><a href="/admin/inventory/itemmodel/00000000-0001-0001-0000-000000000000/change/">'
|
||||||
|
'sub item 1.1</a></li>',
|
||||||
|
))
|
||||||
|
assert logs.output == [
|
||||||
|
'INFO:inventory.admin.item:Group items: True (auto mode: True)',
|
||||||
|
'DEBUG:inventory.admin.item:Display sub items inline',
|
||||||
|
'DEBUG:inventory.admin.item:Display sub items inline'
|
||||||
|
]
|
||||||
|
assert_html_response_snapshot(response=response)
|
||||||
|
|
||||||
|
# Search should disable grouping:
|
||||||
|
|
||||||
|
with mock.patch.object(CsrfTokenNode, 'render', return_value='MockedCsrfTokenNode'), \
|
||||||
|
self.assertLogs(logger='inventory', level=logging.DEBUG) as logs:
|
||||||
|
response = self.client.get(
|
||||||
|
path='/admin/inventory/itemmodel/?q=sub+item+2.',
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
self.assert_html_parts(response, parts=(
|
||||||
|
'<input type="text" size="40" name="q" value="sub item 2." id="searchbar" autofocus>',
|
||||||
|
'2 results (<a href="?">6 total</a>)',
|
||||||
|
|
||||||
|
'<a href="/admin/inventory/itemmodel/00000000-0002-0001-0000-000000000000/change/">'
|
||||||
|
'sub item 2.1</a>',
|
||||||
|
|
||||||
|
'<a href="/admin/inventory/itemmodel/00000000-0002-0002-0000-000000000000/change/">'
|
||||||
|
'sub item 2.2</a>',
|
||||||
|
))
|
||||||
|
assert logs.output == [
|
||||||
|
# grouping disabled?
|
||||||
|
'INFO:inventory.admin.item:Group items: False (auto mode: True)'
|
||||||
|
]
|
||||||
|
assert_html_response_snapshot(response=response)
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" >
|
||||||
|
<head>
|
||||||
|
<title>Select Item to change | PyInventory v0.9.4</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/static/admin/css/base.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="/static/admin/css/changelists.css">
|
||||||
|
<script type="text/javascript" src="/admin/jsi18n/"></script>
|
||||||
|
<meta name="google" content="notranslate">
|
||||||
|
<meta name="robots" content="noindex,nofollow" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="/static/inventory.css">
|
||||||
|
<script type="text/javascript" src="/static/admin/js/vendor/jquery/jquery.min.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/admin/js/jquery.init.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/admin/js/core.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/admin/js/admin/RelatedObjectLookups.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/admin/js/actions.min.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/admin/js/urlify.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/admin/js/prepopulate.min.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/admin/js/vendor/xregexp/xregexp.min.js"></script>
|
||||||
|
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0">
|
||||||
|
<link rel="stylesheet" type="text/css" href="/static/admin/css/responsive.css">
|
||||||
|
<meta name="robots" content="NONE,NOARCHIVE">
|
||||||
|
</head>
|
||||||
|
<body class=" app-inventory model-itemmodel change-list"
|
||||||
|
data-admin-utc-offset="7200">
|
||||||
|
<!-- Container -->
|
||||||
|
<div id="container">
|
||||||
|
<!-- Header -->
|
||||||
|
<div id="header">
|
||||||
|
<div id="branding">
|
||||||
|
<h1 id="site-name">
|
||||||
|
<a href="/admin/">PyInventory v0.9.4</a>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div id="user-tools">
|
||||||
|
Welcome,
|
||||||
|
<strong>NormalUser</strong>.
|
||||||
|
<a href="/">View site</a> /
|
||||||
|
<a href="/admin/password_change/">Change password</a> /
|
||||||
|
<a href="/admin/logout/">Log out</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- END Header -->
|
||||||
|
<div class="breadcrumbs">
|
||||||
|
<a href="/admin/">Home</a>
|
||||||
|
› <a href="/admin/inventory/">Inventory</a>
|
||||||
|
› Items
|
||||||
|
</div>
|
||||||
|
<!-- Content -->
|
||||||
|
<div id="content" class="flex">
|
||||||
|
<h1>Select Item to change</h1>
|
||||||
|
<div id="content-main">
|
||||||
|
<ul class="object-tools">
|
||||||
|
<li><a href='/admin/inventory/itemmodel/import/' class="import_link">Import</a></li>
|
||||||
|
<li><a href="/admin/inventory/itemmodel/export/?" class="export_link">Export</a></li>
|
||||||
|
<li>
|
||||||
|
<a href="/admin/inventory/itemmodel/add/" class="addlink">
|
||||||
|
Add Item
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="module filtered" id="changelist">
|
||||||
|
<div id="toolbar"><form id="changelist-search" method="get">
|
||||||
|
<div><!-- DIV needed for valid HTML -->
|
||||||
|
<label for="searchbar"><img src="/static/admin/img/search.svg" alt="Search"></label>
|
||||||
|
<input type="text" size="40" name="q" value="" id="searchbar" autofocus>
|
||||||
|
<input type="submit" value="Search">
|
||||||
|
<span class="small quiet">2 results (<a href="?">6 total</a>)</span>
|
||||||
|
</div>
|
||||||
|
</form></div>
|
||||||
|
<div class="xfull">
|
||||||
|
<ul class="toplinks">
|
||||||
|
<li class="date-back"><a href="?create_dt__year=2000">‹ 2000</a></li>
|
||||||
|
<li> <a href="?create_dt__day=1&create_dt__month=1&create_dt__year=2000">January 1</a></li>
|
||||||
|
</ul><br class="clear">
|
||||||
|
</div>
|
||||||
|
<div id="changelist-filter">
|
||||||
|
<h2>Filter</h2>
|
||||||
|
<h3> By Group Items </h3>
|
||||||
|
<ul>
|
||||||
|
<li class="selected">
|
||||||
|
<a href="?" title="Automatic">Automatic</a></li>
|
||||||
|
<li>
|
||||||
|
<a href="?grouping=no" title="No">No</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<form id="changelist-form" method="post" novalidate>MockedCsrfTokenNode
|
||||||
|
<div class="actions">
|
||||||
|
<label>Action: <select name="action" required>
|
||||||
|
<option value="" selected>---------</option>
|
||||||
|
<option value="delete_selected">Delete selected Items</option>
|
||||||
|
</select></label><input type="hidden" name="select_across" value="0" class="select-across">
|
||||||
|
<button type="submit" class="button" title="Run the selected action" name="index" value="0">Go</button>
|
||||||
|
<span class="action-counter" data-actions-icnt="2">0 of 2 selected</span>
|
||||||
|
</div>
|
||||||
|
<div class="results">
|
||||||
|
<table id="result_list">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="action-checkbox-column">
|
||||||
|
<div class="text"><span><input type="checkbox" id="action-toggle"></span></div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</th>
|
||||||
|
<th scope="col" class="column-_tagulous_display_kind">
|
||||||
|
<div class="text"><span>Kind</span></div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</th>
|
||||||
|
<th scope="col" class="column-_tagulous_display_producer">
|
||||||
|
<div class="text"><span>Producer</span></div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</th>
|
||||||
|
<th scope="col" class="column-column_item">
|
||||||
|
<div class="text"><span>Items</span></div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</th>
|
||||||
|
<th scope="col" class="sortable column-location">
|
||||||
|
<div class="text"><a href="?o=4">Location</a></div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</th>
|
||||||
|
<th scope="col" class="sortable column-received_date">
|
||||||
|
<div class="text"><a href="?o=5">Received date</a></div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</th>
|
||||||
|
<th scope="col" class="sortable column-update_dt">
|
||||||
|
<div class="text"><a href="?o=6">Last update</a></div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr class="row1"><td class="action-checkbox"><input type="checkbox" name="_selected_action" value="00000000-0001-0000-0000-000000000000" class="action-select"></td><td class="field-_tagulous_display_kind"> </td><td class="field-_tagulous_display_producer"> </td><td class="field-column_item"><strong><a href="/admin/inventory/itemmodel/00000000-0001-0000-0000-000000000000/change/">main item 1</a></strong>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/admin/inventory/itemmodel/00000000-0001-0001-0000-000000000000/change/">sub item 1.1</a></li>
|
||||||
|
<li><a href="/admin/inventory/itemmodel/00000000-0001-0002-0000-000000000000/change/">sub item 1.2</a></li>
|
||||||
|
</ul>
|
||||||
|
</td><td class="field-location nowrap">-</td><td class="field-received_date nowrap">-</td><td class="field-update_dt nowrap">Jan. 1, 2000, 1:01 a.m.</td></tr>
|
||||||
|
<tr class="row2"><td class="action-checkbox"><input type="checkbox" name="_selected_action" value="00000000-0002-0000-0000-000000000000" class="action-select"></td><td class="field-_tagulous_display_kind"> </td><td class="field-_tagulous_display_producer"> </td><td class="field-column_item"><strong><a href="/admin/inventory/itemmodel/00000000-0002-0000-0000-000000000000/change/">main item 2</a></strong>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/admin/inventory/itemmodel/00000000-0002-0001-0000-000000000000/change/">sub item 2.1</a></li>
|
||||||
|
<li><a href="/admin/inventory/itemmodel/00000000-0002-0002-0000-000000000000/change/">sub item 2.2</a></li>
|
||||||
|
</ul>
|
||||||
|
</td><td class="field-location nowrap">-</td><td class="field-received_date nowrap">-</td><td class="field-update_dt nowrap">Jan. 1, 2000, 1:04 a.m.</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<p class="paginator">
|
||||||
|
2 Items
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br class="clear">
|
||||||
|
</div>
|
||||||
|
<!-- END Content -->
|
||||||
|
<div id="footer">
|
||||||
|
<a href="https://github.com/jedie/PyInventory">https://github.com/jedie/PyInventory</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- END Container -->
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,152 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" >
|
||||||
|
<head>
|
||||||
|
<title>Select Item to change | PyInventory v0.9.4</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/static/admin/css/base.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="/static/admin/css/changelists.css">
|
||||||
|
<script type="text/javascript" src="/admin/jsi18n/"></script>
|
||||||
|
<meta name="google" content="notranslate">
|
||||||
|
<meta name="robots" content="noindex,nofollow" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="/static/inventory.css">
|
||||||
|
<script type="text/javascript" src="/static/admin/js/vendor/jquery/jquery.min.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/admin/js/jquery.init.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/admin/js/core.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/admin/js/admin/RelatedObjectLookups.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/admin/js/actions.min.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/admin/js/urlify.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/admin/js/prepopulate.min.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/admin/js/vendor/xregexp/xregexp.min.js"></script>
|
||||||
|
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0">
|
||||||
|
<link rel="stylesheet" type="text/css" href="/static/admin/css/responsive.css">
|
||||||
|
<meta name="robots" content="NONE,NOARCHIVE">
|
||||||
|
</head>
|
||||||
|
<body class=" app-inventory model-itemmodel change-list"
|
||||||
|
data-admin-utc-offset="7200">
|
||||||
|
<!-- Container -->
|
||||||
|
<div id="container">
|
||||||
|
<!-- Header -->
|
||||||
|
<div id="header">
|
||||||
|
<div id="branding">
|
||||||
|
<h1 id="site-name">
|
||||||
|
<a href="/admin/">PyInventory v0.9.4</a>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div id="user-tools">
|
||||||
|
Welcome,
|
||||||
|
<strong>NormalUser</strong>.
|
||||||
|
<a href="/">View site</a> /
|
||||||
|
<a href="/admin/password_change/">Change password</a> /
|
||||||
|
<a href="/admin/logout/">Log out</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- END Header -->
|
||||||
|
<div class="breadcrumbs">
|
||||||
|
<a href="/admin/">Home</a>
|
||||||
|
› <a href="/admin/inventory/">Inventory</a>
|
||||||
|
› Items
|
||||||
|
</div>
|
||||||
|
<!-- Content -->
|
||||||
|
<div id="content" class="flex">
|
||||||
|
<h1>Select Item to change</h1>
|
||||||
|
<div id="content-main">
|
||||||
|
<ul class="object-tools">
|
||||||
|
<li><a href='/admin/inventory/itemmodel/import/' class="import_link">Import</a></li>
|
||||||
|
<li><a href="/admin/inventory/itemmodel/export/?q=sub+item+2." class="export_link">Export</a></li>
|
||||||
|
<li>
|
||||||
|
<a href="/admin/inventory/itemmodel/add/?_changelist_filters=q%3Dsub%2Bitem%2B2." class="addlink">
|
||||||
|
Add Item
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="module filtered" id="changelist">
|
||||||
|
<div id="toolbar"><form id="changelist-search" method="get">
|
||||||
|
<div><!-- DIV needed for valid HTML -->
|
||||||
|
<label for="searchbar"><img src="/static/admin/img/search.svg" alt="Search"></label>
|
||||||
|
<input type="text" size="40" name="q" value="sub item 2." id="searchbar" autofocus>
|
||||||
|
<input type="submit" value="Search">
|
||||||
|
<span class="small quiet">2 results (<a href="?">6 total</a>)</span>
|
||||||
|
</div>
|
||||||
|
</form></div>
|
||||||
|
<div class="xfull">
|
||||||
|
<ul class="toplinks">
|
||||||
|
<li class="date-back"><a href="?create_dt__year=2000&q=sub+item+2.">‹ 2000</a></li>
|
||||||
|
<li> <a href="?create_dt__day=1&create_dt__month=1&create_dt__year=2000&q=sub+item+2.">January 1</a></li>
|
||||||
|
</ul><br class="clear">
|
||||||
|
</div>
|
||||||
|
<div id="changelist-filter">
|
||||||
|
<h2>Filter</h2>
|
||||||
|
<h3> By Group Items </h3>
|
||||||
|
<ul>
|
||||||
|
<li class="selected">
|
||||||
|
<a href="?q=sub+item+2." title="Automatic">Automatic</a></li>
|
||||||
|
<li>
|
||||||
|
<a href="?grouping=no&q=sub+item+2." title="No">No</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<form id="changelist-form" method="post" novalidate>MockedCsrfTokenNode
|
||||||
|
<div class="actions">
|
||||||
|
<label>Action: <select name="action" required>
|
||||||
|
<option value="" selected>---------</option>
|
||||||
|
<option value="delete_selected">Delete selected Items</option>
|
||||||
|
</select></label><input type="hidden" name="select_across" value="0" class="select-across">
|
||||||
|
<button type="submit" class="button" title="Run the selected action" name="index" value="0">Go</button>
|
||||||
|
<span class="action-counter" data-actions-icnt="2">0 of 2 selected</span>
|
||||||
|
</div>
|
||||||
|
<div class="results">
|
||||||
|
<table id="result_list">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="action-checkbox-column">
|
||||||
|
<div class="text"><span><input type="checkbox" id="action-toggle"></span></div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</th>
|
||||||
|
<th scope="col" class="column-_tagulous_display_kind">
|
||||||
|
<div class="text"><span>Kind</span></div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</th>
|
||||||
|
<th scope="col" class="column-_tagulous_display_producer">
|
||||||
|
<div class="text"><span>Producer</span></div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</th>
|
||||||
|
<th scope="col" class="column-column_item">
|
||||||
|
<div class="text"><span>Items</span></div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</th>
|
||||||
|
<th scope="col" class="sortable column-location">
|
||||||
|
<div class="text"><a href="?o=4&q=sub+item+2.">Location</a></div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</th>
|
||||||
|
<th scope="col" class="sortable column-received_date">
|
||||||
|
<div class="text"><a href="?o=5&q=sub+item+2.">Received date</a></div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</th>
|
||||||
|
<th scope="col" class="sortable column-update_dt">
|
||||||
|
<div class="text"><a href="?o=6&q=sub+item+2.">Last update</a></div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr class="row1"><td class="action-checkbox"><input type="checkbox" name="_selected_action" value="00000000-0002-0001-0000-000000000000" class="action-select"></td><td class="field-_tagulous_display_kind"> </td><td class="field-_tagulous_display_producer"> </td><td class="field-column_item"><strong><a href="/admin/inventory/itemmodel/00000000-0002-0001-0000-000000000000/change/">sub item 2.1</a></strong>
|
||||||
|
</td><td class="field-location nowrap">-</td><td class="field-received_date nowrap">-</td><td class="field-update_dt nowrap">Jan. 1, 2000, 1:05 a.m.</td></tr>
|
||||||
|
<tr class="row2"><td class="action-checkbox"><input type="checkbox" name="_selected_action" value="00000000-0002-0002-0000-000000000000" class="action-select"></td><td class="field-_tagulous_display_kind"> </td><td class="field-_tagulous_display_producer"> </td><td class="field-column_item"><strong><a href="/admin/inventory/itemmodel/00000000-0002-0002-0000-000000000000/change/">sub item 2.2</a></strong>
|
||||||
|
</td><td class="field-location nowrap">-</td><td class="field-received_date nowrap">-</td><td class="field-update_dt nowrap">Jan. 1, 2000, 1:06 a.m.</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<p class="paginator">
|
||||||
|
2 Items
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br class="clear">
|
||||||
|
</div>
|
||||||
|
<!-- END Content -->
|
||||||
|
<div id="footer">
|
||||||
|
<a href="https://github.com/jedie/PyInventory">https://github.com/jedie/PyInventory</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- END Container -->
|
||||||
|
</body>
|
||||||
|
</html>
|
Ładowanie…
Reference in New Issue