django-smartbase-admin 0.2.78__py3-none-any.whl → 0.2.79__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,7 +28,8 @@ from django.utils.safestring import mark_safe
28
28
  from django.utils.text import capfirst
29
29
  from django.utils.translation import gettext_lazy as _
30
30
  from django_admin_inline_paginator.admin import TabularInlinePaginated
31
- from filer.fields.image import AdminImageFormField
31
+ from filer.fields.file import FilerFileField
32
+ from filer.fields.image import AdminImageFormField, FilerImageField
32
33
  from nested_admin.nested import (
33
34
  NestedModelAdmin,
34
35
  NestedTabularInline,
@@ -74,6 +75,15 @@ except ImportError:
74
75
  pass
75
76
 
76
77
 
78
+ color_field_enabled = None
79
+ try:
80
+ from colorfield.fields import ColorField
81
+
82
+ color_field_enabled = True
83
+ except ImportError:
84
+ pass
85
+
86
+
77
87
  from django_smartbase_admin.admin.widgets import (
78
88
  SBAdminTextInputWidget,
79
89
  SBAdminTextareaWidget,
@@ -97,6 +107,8 @@ from django_smartbase_admin.admin.widgets import (
97
107
  SBAdminCKEditorUploadingWidget,
98
108
  SBAdminAttributesWidget,
99
109
  SBAdminMultipleChoiceInlineWidget,
110
+ SBAdminColorWidget,
111
+ SBAdminFilerFileWidget,
100
112
  )
101
113
  from django_smartbase_admin.engine.admin_base_view import (
102
114
  SBAdminBaseListView,
@@ -142,10 +154,16 @@ class SBAdminFormFieldWidgetsMixin:
142
154
  ReadOnlyPasswordHashWidget: SBAdminReadOnlyPasswordHashWidget,
143
155
  forms.HiddenInput: SBAdminHiddenWidget,
144
156
  }
157
+ db_field_widgets = {
158
+ FilerImageField: SBAdminFilerFileWidget,
159
+ FilerFileField: SBAdminFilerFileWidget,
160
+ }
145
161
  if postrgres_enabled:
146
162
  formfield_widgets[SimpleArrayField] = SBAdminArrayWidget
147
163
  if django_cms_attributes:
148
164
  formfield_widgets[AttributesFormField] = SBAdminAttributesWidget
165
+ if color_field_enabled:
166
+ db_field_widgets[ColorField] = SBAdminColorWidget
149
167
 
150
168
  django_widget_to_widget = {
151
169
  forms.PasswordInput: SBAdminPasswordInputWidget,
@@ -153,7 +171,9 @@ class SBAdminFormFieldWidgetsMixin:
153
171
  }
154
172
 
155
173
  def get_form_field_widget_class(self, form_field, db_field, request):
156
- default_widget_class = self.formfield_widgets.get(form_field.__class__)
174
+ default_widget_class = self.db_field_widgets.get(
175
+ db_field.__class__, self.formfield_widgets.get(form_field.__class__)
176
+ )
157
177
  if not hasattr(request, "request_data"):
158
178
  # in case of login the view is not wrapped and we have no request_data present
159
179
  return default_widget_class
@@ -1,4 +1,5 @@
1
1
  import json
2
+ import logging
2
3
 
3
4
  from ckeditor.widgets import CKEditorWidget
4
5
  from ckeditor_uploader.widgets import CKEditorUploadingWidget
@@ -6,12 +7,19 @@ from django import forms
6
7
  from django.conf import settings
7
8
  from django.contrib.admin.widgets import (
8
9
  AdminURLFieldWidget,
10
+ ForeignKeyRawIdWidget,
9
11
  )
10
12
  from django.contrib.auth.forms import ReadOnlyPasswordHashWidget
13
+ from django.template.loader import render_to_string
14
+ from django.urls import reverse
11
15
  from django.utils.formats import get_format
16
+ from django.utils.http import urlencode
17
+ from django.utils.safestring import mark_safe
12
18
  from django.utils.translation import gettext_lazy as _
13
19
  from django.views.generic.base import ContextMixin
20
+ from filer.fields.file import AdminFileWidget as FilerAdminFileWidget
14
21
  from filer.fields.image import AdminImageWidget
22
+ from filer.models import File
15
23
 
16
24
  from django_smartbase_admin.engine.filter_widgets import (
17
25
  AutocompleteFilterWidget,
@@ -19,6 +27,8 @@ from django_smartbase_admin.engine.filter_widgets import (
19
27
  from django_smartbase_admin.services.thread_local import SBAdminThreadLocalService
20
28
  from django_smartbase_admin.templatetags.sb_admin_tags import SBAdminJSONEncoder
21
29
 
30
+ logger = logging.getLogger(__name__)
31
+
22
32
 
23
33
  class SBAdminBaseWidget(ContextMixin):
24
34
  sb_admin_widget = True
@@ -379,6 +389,75 @@ class SBAdminImageWidget(SBAdminBaseWidget, AdminImageWidget):
379
389
  )
380
390
 
381
391
 
392
+ class SBAdminFilerFileWidget(SBAdminBaseWidget, FilerAdminFileWidget):
393
+ template_name = "sb_admin/widgets/filer_file.html"
394
+
395
+ def __init__(self, form_field=None, *args, **kwargs):
396
+ self.form_field = form_field
397
+ super(FilerAdminFileWidget, self).__init__(
398
+ form_field.rel, form_field.view.admin_site
399
+ )
400
+
401
+ def render(self, name, value, attrs=None, renderer=None):
402
+ obj = self.obj_for_value(value)
403
+ css_id = attrs.get("id", "id_image_x")
404
+ related_url = None
405
+ change_url = ""
406
+ if value:
407
+ try:
408
+ file_obj = File.objects.get(pk=value)
409
+ if file_obj.logical_folder.is_root:
410
+ related_url = reverse("sb_admin:filer-directory_listing-root")
411
+ else:
412
+ related_url = reverse(
413
+ "sb_admin:filer-directory_listing",
414
+ args=(file_obj.logical_folder.id,),
415
+ )
416
+ change_url = reverse(
417
+ "sb_admin:{}_{}_change".format(
418
+ file_obj._meta.app_label,
419
+ file_obj._meta.model_name,
420
+ ),
421
+ args=(file_obj.pk,),
422
+ )
423
+ except Exception as e:
424
+ # catch exception and manage it. We can re-raise it for debugging
425
+ # purposes and/or just logging it, provided user configured
426
+ # proper logging configuration
427
+ if settings.FILER_ENABLE_LOGGING:
428
+ logger.error("Error while rendering file widget: %s", e)
429
+ if settings.FILER_DEBUG:
430
+ raise
431
+ if not related_url:
432
+ related_url = reverse("sb_admin:filer-directory_listing-last")
433
+ params = self.url_parameters()
434
+ params["_pick"] = "file"
435
+ if params:
436
+ lookup_url = "?" + urlencode(sorted(params.items()))
437
+ else:
438
+ lookup_url = ""
439
+ if "class" not in attrs:
440
+ # The JavaScript looks for this hook.
441
+ attrs["class"] = "vForeignKeyRawIdAdminField"
442
+ # rendering the super for ForeignKeyRawIdWidget on purpose here because
443
+ # we only need the input and none of the other stuff that
444
+ # ForeignKeyRawIdWidget adds
445
+ hidden_input = super(ForeignKeyRawIdWidget, self).render(
446
+ name, value, attrs
447
+ ) # grandparent super
448
+ context = {
449
+ "hidden_input": hidden_input,
450
+ "lookup_url": "{}{}".format(related_url, lookup_url),
451
+ "change_url": change_url,
452
+ "object": obj,
453
+ "lookup_name": name,
454
+ "id": css_id,
455
+ "admin_icon_delete": "admin/img/icon-deletelink.svg",
456
+ }
457
+ html = render_to_string(self.template_name, context)
458
+ return mark_safe(html)
459
+
460
+
382
461
  class SBAdminReadOnlyPasswordHashWidget(SBAdminBaseWidget, ReadOnlyPasswordHashWidget):
383
462
  template_name = "sb_admin/widgets/read_only_password_hash.html"
384
463
 
@@ -423,3 +502,41 @@ class SBAdminCodeWidget(SBAdminBaseWidget, forms.Widget):
423
502
 
424
503
  class SBAdminHTMLWidget(SBAdminBaseWidget, forms.Widget):
425
504
  template_name = "sb_admin/widgets/html_read_only.html"
505
+
506
+
507
+ class SBAdminColorWidget(SBAdminTextInputWidget):
508
+ template_name = "sb_admin/widgets/color_field.html"
509
+ color_swatches = getattr(
510
+ settings,
511
+ "SB_ADMIN_COLOR_SWATCHES",
512
+ [
513
+ "#ffbe76",
514
+ "#f9ca24",
515
+ "#f0932b",
516
+ "#ff7979",
517
+ "#eb4d4b",
518
+ "#badc58",
519
+ "#6ab04c",
520
+ "#c7ecee",
521
+ "#7ed6df",
522
+ "#22a6b3",
523
+ "#e056fd",
524
+ "#be2edd",
525
+ "#686de0",
526
+ "#4834d4",
527
+ "#30336b",
528
+ "#130f40",
529
+ "#95afc0",
530
+ "#535c68",
531
+ ],
532
+ )
533
+
534
+ class Media:
535
+ css = {
536
+ "all": [
537
+ "sb_admin/css/coloris/coloris.min.css",
538
+ ],
539
+ }
540
+ js = [
541
+ "sb_admin/js/coloris/coloris.min.js",
542
+ ]
@@ -8,6 +8,8 @@ from django.template.loader import render_to_string
8
8
  from django.utils.html import conditional_escape
9
9
  from django.utils.safestring import mark_safe
10
10
 
11
+ from django_smartbase_admin.admin.site import sb_admin_site
12
+
11
13
 
12
14
  class SBAdminReadonlyField(django.contrib.admin.helpers.AdminReadonlyField):
13
15
  readonly_template = "sb_admin/includes/readonly_field.html"
@@ -26,7 +28,7 @@ class SBAdminReadonlyField(django.contrib.admin.helpers.AdminReadonlyField):
26
28
  )
27
29
 
28
30
  def contents(self, request=None):
29
- if self.model_admin.admin_site.name != "sb_admin":
31
+ if self.model_admin.admin_site.name != sb_admin_site.name:
30
32
  return super().contents()
31
33
 
32
34
  field, obj, model_admin = (
@@ -2,6 +2,7 @@ import json
2
2
  import pickle
3
3
  import urllib
4
4
 
5
+ from django.conf import settings
5
6
  from django.db.models import Q, FilteredRelation, F, Value, CharField
6
7
  from django.shortcuts import redirect
7
8
  from django_smartbase_admin.templatetags.sb_admin_tags import SBAdminJSONEncoder
@@ -105,7 +106,9 @@ class SBAdminViewService(object):
105
106
  response.render()
106
107
  response.content = (
107
108
  response.content.decode()
108
- .replace('href="/admin/', 'href="/sb-admin/')
109
+ .replace(
110
+ f'href="/{settings.ADMIN_PATH}', f'href="/{settings.SB_ADMIN_PATH}'
111
+ )
109
112
  .encode()
110
113
  )
111
114
  return response
@@ -0,0 +1,4 @@
1
+ from django.conf import settings
2
+
3
+ SB_ADMIN_PATH = getattr(settings, "SB_ADMIN_PATH", "sb-admin/")
4
+ setattr(settings, "SB_ADMIN_PATH", SB_ADMIN_PATH)
@@ -0,0 +1 @@
1
+ .clr-picker{display:none;flex-wrap:wrap;position:absolute;width:200px;z-index:1000;border-radius:10px;background-color:#fff;justify-content:flex-end;direction:ltr;box-shadow:0 0 5px rgba(0,0,0,.05),0 5px 20px rgba(0,0,0,.1);-moz-user-select:none;-webkit-user-select:none;user-select:none}.clr-picker.clr-open,.clr-picker[data-inline=true]{display:flex}.clr-picker[data-inline=true]{position:relative}.clr-gradient{position:relative;width:100%;height:100px;margin-bottom:15px;border-radius:3px 3px 0 0;background-image:linear-gradient(rgba(0,0,0,0),#000),linear-gradient(90deg,#fff,currentColor);cursor:pointer}.clr-marker{position:absolute;width:12px;height:12px;margin:-6px 0 0 -6px;border:1px solid #fff;border-radius:50%;background-color:currentColor;cursor:pointer}.clr-picker input[type=range]::-webkit-slider-runnable-track{width:100%;height:16px}.clr-picker input[type=range]::-webkit-slider-thumb{width:16px;height:16px;-webkit-appearance:none}.clr-picker input[type=range]::-moz-range-track{width:100%;height:16px;border:0}.clr-picker input[type=range]::-moz-range-thumb{width:16px;height:16px;border:0}.clr-hue{background-image:linear-gradient(to right,red 0,#ff0 16.66%,#0f0 33.33%,#0ff 50%,#00f 66.66%,#f0f 83.33%,red 100%)}.clr-alpha,.clr-hue{position:relative;width:calc(100% - 40px);height:8px;margin:5px 20px;border-radius:4px}.clr-alpha span{display:block;height:100%;width:100%;border-radius:inherit;background-image:linear-gradient(90deg,rgba(0,0,0,0),currentColor)}.clr-alpha input[type=range],.clr-hue input[type=range]{position:absolute;width:calc(100% + 32px);height:16px;left:-16px;top:-4px;margin:0;background-color:transparent;opacity:0;cursor:pointer;appearance:none;-webkit-appearance:none}.clr-alpha div,.clr-hue div{position:absolute;width:16px;height:16px;left:0;top:50%;margin-left:-8px;transform:translateY(-50%);border:2px solid #fff;border-radius:50%;background-color:currentColor;box-shadow:0 0 1px #888;pointer-events:none}.clr-alpha div:before{content:'';position:absolute;height:100%;width:100%;left:0;top:0;border-radius:50%;background-color:currentColor}.clr-format{display:none;order:1;width:calc(100% - 40px);margin:0 20px 20px}.clr-segmented{display:flex;position:relative;width:100%;margin:0;padding:0;border:1px solid #ddd;border-radius:15px;box-sizing:border-box;color:#999;font-size:12px}.clr-segmented input,.clr-segmented legend{position:absolute;width:100%;height:100%;margin:0;padding:0;border:0;left:0;top:0;opacity:0;pointer-events:none}.clr-segmented label{flex-grow:1;margin:0;padding:4px 0;font-size:inherit;font-weight:400;line-height:initial;text-align:center;cursor:pointer}.clr-segmented label:first-of-type{border-radius:10px 0 0 10px}.clr-segmented label:last-of-type{border-radius:0 10px 10px 0}.clr-segmented input:checked+label{color:#fff;background-color:#666}.clr-swatches{order:2;width:calc(100% - 32px);margin:0 16px}.clr-swatches div{display:flex;flex-wrap:wrap;padding-bottom:12px;justify-content:center}.clr-swatches button{position:relative;width:20px;height:20px;margin:0 4px 6px 4px;padding:0;border:0;border-radius:50%;color:inherit;text-indent:-1000px;white-space:nowrap;overflow:hidden;cursor:pointer}.clr-swatches button:after{content:'';display:block;position:absolute;width:100%;height:100%;left:0;top:0;border-radius:inherit;background-color:currentColor;box-shadow:inset 0 0 0 1px rgba(0,0,0,.1)}input.clr-color{order:1;width:calc(100% - 80px);height:32px;margin:15px 20px 20px auto;padding:0 10px;border:1px solid #ddd;border-radius:16px;color:#444;background-color:#fff;font-family:sans-serif;font-size:14px;text-align:center;box-shadow:none}input.clr-color:focus{outline:0;border:1px solid #1e90ff}.clr-clear,.clr-close{display:none;order:2;height:24px;margin:0 20px 20px;padding:0 20px;border:0;border-radius:12px;color:#fff;background-color:#666;font-family:inherit;font-size:12px;font-weight:400;cursor:pointer}.clr-close{display:block;margin:0 20px 20px auto}.clr-preview{position:relative;width:32px;height:32px;margin:15px 0 20px 20px;border-radius:50%;overflow:hidden}.clr-preview:after,.clr-preview:before{content:'';position:absolute;height:100%;width:100%;left:0;top:0;border:1px solid #fff;border-radius:50%}.clr-preview:after{border:0;background-color:currentColor;box-shadow:inset 0 0 0 1px rgba(0,0,0,.1)}.clr-preview button{position:absolute;width:100%;height:100%;z-index:1;margin:0;padding:0;border:0;border-radius:50%;outline-offset:-2px;background-color:transparent;text-indent:-9999px;cursor:pointer;overflow:hidden}.clr-alpha div,.clr-color,.clr-hue div,.clr-marker{box-sizing:border-box}.clr-field{display:inline-block;position:relative;color:transparent}.clr-field input{margin:0;direction:ltr}.clr-field.clr-rtl input{text-align:right}.clr-field button{position:absolute;width:30px;height:100%;right:0;top:50%;transform:translateY(-50%);margin:0;padding:0;border:0;color:inherit;text-indent:-1000px;white-space:nowrap;overflow:hidden;pointer-events:none}.clr-field.clr-rtl button{right:auto;left:0}.clr-field button:after{content:'';display:block;position:absolute;width:100%;height:100%;left:0;top:0;border-radius:inherit;background-color:currentColor;box-shadow:inset 0 0 1px rgba(0,0,0,.5)}.clr-alpha,.clr-alpha div,.clr-field button,.clr-preview:before,.clr-swatches button{background-image:repeating-linear-gradient(45deg,#aaa 25%,transparent 25%,transparent 75%,#aaa 75%,#aaa),repeating-linear-gradient(45deg,#aaa 25%,#fff 25%,#fff 75%,#aaa 75%,#aaa);background-position:0 0,4px 4px;background-size:8px 8px}.clr-marker:focus{outline:0}.clr-keyboard-nav .clr-alpha input:focus+div,.clr-keyboard-nav .clr-hue input:focus+div,.clr-keyboard-nav .clr-marker:focus,.clr-keyboard-nav .clr-segmented input:focus+label{outline:0;box-shadow:0 0 0 2px #1e90ff,0 0 2px 2px #fff}.clr-picker[data-alpha=false] .clr-alpha{display:none}.clr-picker[data-minimal=true]{padding-top:16px}.clr-picker[data-minimal=true] .clr-alpha,.clr-picker[data-minimal=true] .clr-color,.clr-picker[data-minimal=true] .clr-gradient,.clr-picker[data-minimal=true] .clr-hue,.clr-picker[data-minimal=true] .clr-preview{display:none}.clr-dark{background-color:#444}.clr-dark .clr-segmented{border-color:#777}.clr-dark .clr-swatches button:after{box-shadow:inset 0 0 0 1px rgba(255,255,255,.3)}.clr-dark input.clr-color{color:#fff;border-color:#777;background-color:#555}.clr-dark input.clr-color:focus{border-color:#1e90ff}.clr-dark .clr-preview:after{box-shadow:inset 0 0 0 1px rgba(255,255,255,.5)}.clr-dark .clr-alpha,.clr-dark .clr-alpha div,.clr-dark .clr-preview:before,.clr-dark .clr-swatches button{background-image:repeating-linear-gradient(45deg,#666 25%,transparent 25%,transparent 75%,#888 75%,#888),repeating-linear-gradient(45deg,#888 25%,#444 25%,#444 75%,#888 75%,#888)}.clr-picker.clr-polaroid{border-radius:6px;box-shadow:0 0 5px rgba(0,0,0,.1),0 5px 30px rgba(0,0,0,.2)}.clr-picker.clr-polaroid:before{content:'';display:block;position:absolute;width:16px;height:10px;left:20px;top:-10px;border:solid transparent;border-width:0 8px 10px 8px;border-bottom-color:currentColor;box-sizing:border-box;color:#fff;filter:drop-shadow(0 -4px 3px rgba(0,0,0,.1));pointer-events:none}.clr-picker.clr-polaroid.clr-dark:before{color:#444}.clr-picker.clr-polaroid.clr-left:before{left:auto;right:20px}.clr-picker.clr-polaroid.clr-top:before{top:auto;bottom:-10px;transform:rotateZ(180deg)}.clr-polaroid .clr-gradient{width:calc(100% - 20px);height:120px;margin:10px;border-radius:3px}.clr-polaroid .clr-alpha,.clr-polaroid .clr-hue{width:calc(100% - 30px);height:10px;margin:6px 15px;border-radius:5px}.clr-polaroid .clr-alpha div,.clr-polaroid .clr-hue div{box-shadow:0 0 5px rgba(0,0,0,.2)}.clr-polaroid .clr-format{width:calc(100% - 20px);margin:0 10px 15px}.clr-polaroid .clr-swatches{width:calc(100% - 12px);margin:0 6px}.clr-polaroid .clr-swatches div{padding-bottom:10px}.clr-polaroid .clr-swatches button{width:22px;height:22px}.clr-polaroid input.clr-color{width:calc(100% - 60px);margin:10px 10px 15px auto}.clr-polaroid .clr-clear{margin:0 10px 15px 10px}.clr-polaroid .clr-close{margin:0 10px 15px auto}.clr-polaroid .clr-preview{margin:10px 0 15px 10px}.clr-picker.clr-large{width:275px}.clr-large .clr-gradient{height:150px}.clr-large .clr-swatches button{width:22px;height:22px}.clr-picker.clr-pill{width:380px;padding-left:180px;box-sizing:border-box}.clr-pill .clr-gradient{position:absolute;width:180px;height:100%;left:0;top:0;margin-bottom:0;border-radius:3px 0 0 3px}.clr-pill .clr-hue{margin-top:20px}