django-whiteneuron 0.3.8.0__tar.gz → 0.4.0.0__tar.gz

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.
Files changed (246) hide show
  1. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/PKG-INFO +115 -8
  2. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/README.md +111 -5
  3. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/django_whiteneuron.egg-info/PKG-INFO +115 -8
  4. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/django_whiteneuron.egg-info/SOURCES.txt +32 -2
  5. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/django_whiteneuron.egg-info/requires.txt +2 -1
  6. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/pyproject.toml +5 -3
  7. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/admin.py +19 -14
  8. django_whiteneuron-0.4.0.0/whiteneuron/base/asgi.py +39 -0
  9. django_whiteneuron-0.4.0.0/whiteneuron/base/filters.py +55 -0
  10. django_whiteneuron-0.4.0.0/whiteneuron/base/html_sanitize.py +65 -0
  11. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/management/commands/cleanup_old_activities.py +3 -0
  12. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/management/commands/update_visit_profiles.py +23 -13
  13. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/middleware.py +212 -77
  14. django_whiteneuron-0.4.0.0/whiteneuron/base/migrations/0028_perf_indexes.py +25 -0
  15. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/modeladmin.py +194 -157
  16. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/models.py +239 -210
  17. django_whiteneuron-0.4.0.0/whiteneuron/base/queue.py +39 -0
  18. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/settings.py +81 -46
  19. django_whiteneuron-0.4.0.0/whiteneuron/base/tasks.py +49 -0
  20. django_whiteneuron-0.4.0.0/whiteneuron/base/templatetags/wn_theme.py +24 -0
  21. django_whiteneuron-0.4.0.0/whiteneuron/base/testing.py +9 -0
  22. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/tests.py +1 -1
  23. django_whiteneuron-0.4.0.0/whiteneuron/base/tests_regressions.py +371 -0
  24. django_whiteneuron-0.4.0.0/whiteneuron/base/themes.py +39 -0
  25. django_whiteneuron-0.4.0.0/whiteneuron/base/urls_testing.py +13 -0
  26. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/utils.py +50 -10
  27. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/contrib/wn_import_export/admin.py +22 -15
  28. django_whiteneuron-0.4.0.0/whiteneuron/contrib/wn_import_export/tasks.py +49 -0
  29. django_whiteneuron-0.4.0.0/whiteneuron/contrib/wn_modeltranslation/admin.py +36 -0
  30. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/contrib/wn_modeltranslation/utils.py +9 -9
  31. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/dashboard/views.py +105 -138
  32. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/admin.py +3 -0
  33. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/urls.py +14 -1
  34. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/admin.py +4 -6
  35. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/models.py +19 -5
  36. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/views.py +12 -9
  37. django_whiteneuron-0.4.0.0/whiteneuron/locale/vi/LC_MESSAGES/django.mo +0 -0
  38. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/locale/vi/LC_MESSAGES/django.po +1225 -516
  39. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/admin.py +161 -0
  40. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/apps.py +8 -0
  41. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/collector.py +157 -0
  42. {django_whiteneuron-0.3.8.0/whiteneuron/notification → django_whiteneuron-0.4.0.0/whiteneuron/monitoring}/management/__init__.py +0 -0
  43. {django_whiteneuron-0.3.8.0/whiteneuron/notification → django_whiteneuron-0.4.0.0/whiteneuron/monitoring}/management/commands/__init__.py +0 -0
  44. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/management/commands/monitoring_collector.py +39 -0
  45. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/migrations/0001_initial.py +123 -0
  46. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/models.py +59 -0
  47. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/permissions.py +3 -0
  48. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/stats.py +218 -0
  49. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/tasks.py +17 -0
  50. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/tests.py +130 -0
  51. django_whiteneuron-0.4.0.0/whiteneuron/notification/__init__.py +0 -0
  52. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/admin.py +92 -67
  53. django_whiteneuron-0.4.0.0/whiteneuron/notification/consumers.py +39 -0
  54. django_whiteneuron-0.4.0.0/whiteneuron/notification/management/__init__.py +0 -0
  55. django_whiteneuron-0.4.0.0/whiteneuron/notification/management/commands/__init__.py +0 -0
  56. django_whiteneuron-0.4.0.0/whiteneuron/notification/migrations/0013_perf_indexes.py +28 -0
  57. django_whiteneuron-0.4.0.0/whiteneuron/notification/migrations/__init__.py +0 -0
  58. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/models.py +40 -5
  59. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/utils.py +9 -4
  60. django_whiteneuron-0.4.0.0/whiteneuron/notification/views.py +29 -0
  61. django_whiteneuron-0.4.0.0/whiteneuron/static/base/css/btn-styles.css +46 -0
  62. django_whiteneuron-0.4.0.0/whiteneuron/static/base/css/loading.css +26 -0
  63. django_whiteneuron-0.4.0.0/whiteneuron/static/base/css/styles.css +2 -0
  64. django_whiteneuron-0.4.0.0/whiteneuron/static/base/images/logo/WhiteNeuron-128.png +0 -0
  65. django_whiteneuron-0.4.0.0/whiteneuron/static/base/images/logo/WhiteNeuron-32.png +0 -0
  66. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/js/loading.js +17 -2
  67. django_whiteneuron-0.4.0.0/whiteneuron/static/base/js/whiteneuron.js +274 -0
  68. django_whiteneuron-0.4.0.0/whiteneuron/static/monitoring/css/dashboard.css +232 -0
  69. django_whiteneuron-0.4.0.0/whiteneuron/static/monitoring/js/dashboard.js +852 -0
  70. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/base.html +3 -3
  71. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/header.html +1 -1
  72. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/index.html +4 -11
  73. django_whiteneuron-0.4.0.0/whiteneuron/templates/admin/monitoring/dashboard.html +153 -0
  74. django_whiteneuron-0.4.0.0/whiteneuron/templates/admin/monitoring/stat.html +9 -0
  75. django_whiteneuron-0.4.0.0/whiteneuron/templates/admin/monitoring/timeseries.html +11 -0
  76. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/search_form.html +13 -8
  77. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/unfold/helpers/account_links.html +1 -1
  78. django_whiteneuron-0.4.0.0/whiteneuron/templates/unfold/helpers/app_list_badge.html +23 -0
  79. django_whiteneuron-0.4.0.0/whiteneuron/templates/unfold/helpers/pagination.html +26 -0
  80. django_whiteneuron-0.4.0.0/whiteneuron/templates/unfold/helpers/theme_switch.html +62 -0
  81. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/unfold/helpers/userlinks.html +8 -2
  82. django_whiteneuron-0.4.0.0/whiteneuron/templates/unfold/helpers/wn_page_button.html +7 -0
  83. django_whiteneuron-0.3.8.0/whiteneuron/base/asgi.py +0 -33
  84. django_whiteneuron-0.3.8.0/whiteneuron/base/filters.py +0 -18
  85. django_whiteneuron-0.3.8.0/whiteneuron/base/tasks.py +0 -4
  86. django_whiteneuron-0.3.8.0/whiteneuron/contrib/wn_import_export/tasks.py +0 -40
  87. django_whiteneuron-0.3.8.0/whiteneuron/contrib/wn_modeltranslation/admin.py +0 -48
  88. django_whiteneuron-0.3.8.0/whiteneuron/locale/vi/LC_MESSAGES/django.mo +0 -0
  89. django_whiteneuron-0.3.8.0/whiteneuron/notification/consumers.py +0 -18
  90. django_whiteneuron-0.3.8.0/whiteneuron/notification/views.py +0 -23
  91. django_whiteneuron-0.3.8.0/whiteneuron/static/base/css/btn-styles.css +0 -62
  92. django_whiteneuron-0.3.8.0/whiteneuron/static/base/css/loading.css +0 -18
  93. django_whiteneuron-0.3.8.0/whiteneuron/static/base/css/styles.css +0 -2
  94. django_whiteneuron-0.3.8.0/whiteneuron/static/base/js/whiteneuron.js +0 -39
  95. django_whiteneuron-0.3.8.0/whiteneuron/templates/unfold/helpers/app_list_badge.html +0 -53
  96. django_whiteneuron-0.3.8.0/whiteneuron/templates/unfold/helpers/navigation_user.html +0 -41
  97. django_whiteneuron-0.3.8.0/whiteneuron/templates/unfold/helpers/pagination.html +0 -14
  98. django_whiteneuron-0.3.8.0/whiteneuron/templates/unfold/helpers/theme_switch.html +0 -26
  99. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/LICENSE +0 -0
  100. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/django_whiteneuron.egg-info/dependency_links.txt +0 -0
  101. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/django_whiteneuron.egg-info/top_level.txt +0 -0
  102. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/setup.cfg +0 -0
  103. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/__init__.py +0 -0
  104. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/__init__.py +0 -0
  105. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/apps.py +0 -0
  106. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/ckeditor.py +0 -0
  107. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/forms.py +0 -0
  108. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/management/__init__.py +0 -0
  109. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/management/commands/__init__.py +0 -0
  110. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/management/commands/init_admin.py +0 -0
  111. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/management/commands/init_groupuser.py +0 -0
  112. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/management/commands/init_guest.py +0 -0
  113. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0001_initial.py +0 -0
  114. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0002_imagemodel_userprofile_user_avatar_user_biography_and_more.py +0 -0
  115. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0003_notification_obj_link.py +0 -0
  116. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0004_delete_notification.py +0 -0
  117. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0005_user_show_softdelete.py +0 -0
  118. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0006_user_is_bot.py +0 -0
  119. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0007_app.py +0 -0
  120. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0008_app_created_at_app_created_by_app_deleted_at_and_more.py +0 -0
  121. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0009_alter_app_table.py +0 -0
  122. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0010_app_category.py +0 -0
  123. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0011_alter_app_options.py +0 -0
  124. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0012_app_permission.py +0 -0
  125. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0013_app_thumbnail_url.py +0 -0
  126. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0014_alter_app_created_at_alter_app_updated_at_and_more.py +0 -0
  127. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0015_ipblacklist.py +0 -0
  128. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0016_uablacklist.py +0 -0
  129. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0017_alter_uablacklist_pattern.py +0 -0
  130. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0018_user_uuid.py +0 -0
  131. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0019_alter_user_uuid.py +0 -0
  132. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0020_add_visit_profile_and_fk_fields.py +0 -0
  133. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0021_populate_visit_profiles.py +0 -0
  134. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0022_remove_duplicate_visit_profiles.py +0 -0
  135. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0023_remove_useractivity_ip_address_and_more.py +0 -0
  136. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0024_alter_visitprofile_user_agent_to_charfield.py +0 -0
  137. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0025_alter_anonymousactivity_options_and_more.py +0 -0
  138. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0026_alter_anonymousactivity_profile_and_more.py +0 -0
  139. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0027_alter_anonymousactivity_method_and_more.py +0 -0
  140. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/__init__.py +0 -0
  141. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/resources.py +0 -0
  142. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/sites.py +0 -0
  143. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/templatetags/__init__.py +0 -0
  144. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/templatetags/unfold_list_custom.py +0 -0
  145. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/templatetags/wn_filters.py +0 -0
  146. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/thread_local.py +0 -0
  147. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/urls.py +0 -0
  148. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/views.py +0 -0
  149. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/base/widgets.py +0 -0
  150. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/contrib/__init__.py +0 -0
  151. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/contrib/wn_import_export/__init__.py +0 -0
  152. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/contrib/wn_import_export/constants.py +0 -0
  153. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/contrib/wn_import_export/mixins.py +0 -0
  154. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/contrib/wn_import_export/utils.py +0 -0
  155. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/contrib/wn_modeltranslation/__init__.py +0 -0
  156. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/dashboard/__init__.py +0 -0
  157. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/dashboard/admin.py +0 -0
  158. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/dashboard/apps.py +0 -0
  159. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/dashboard/migrations/__init__.py +0 -0
  160. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/dashboard/models.py +0 -0
  161. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/dashboard/tests.py +0 -0
  162. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/__init__.py +0 -0
  163. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/apps.py +0 -0
  164. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/migrations/0001_initial.py +0 -0
  165. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/migrations/0002_feedbackdata_created_by_feedbackdata_deleted_at_and_more.py +0 -0
  166. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/migrations/0003_feedbackdata_note.py +0 -0
  167. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/migrations/0004_alter_feedbackdata_object_id.py +0 -0
  168. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/migrations/0005_feedbackdata_field.py +0 -0
  169. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/migrations/0006_alter_feedbackdata_created_at_and_more.py +0 -0
  170. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/migrations/__init__.py +0 -0
  171. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/models.py +0 -0
  172. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/tests.py +0 -0
  173. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/utils.py +0 -0
  174. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/views.py +0 -0
  175. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/__init__.py +0 -0
  176. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/apps.py +0 -0
  177. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/migrations/0001_initial.py +0 -0
  178. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/migrations/0002_alter_excelfile_options_alter_pdffile_options_and_more.py +0 -0
  179. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/migrations/0003_alter_excelfile_created_at_and_more.py +0 -0
  180. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/migrations/0004_excelfile_hash_pdffile_hash.py +0 -0
  181. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/migrations/0005_alter_excelfile_file_alter_excelfile_title_and_more.py +0 -0
  182. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/migrations/0006_excelfile_is_public_pdffile_is_public.py +0 -0
  183. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/migrations/0007_htmlfile.py +0 -0
  184. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/migrations/0008_excelfile_allowed_groups_excelfile_allowed_users_and_more.py +0 -0
  185. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/migrations/__init__.py +0 -0
  186. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/tests.py +0 -0
  187. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/urls.py +0 -0
  188. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/utils.py +0 -0
  189. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/manage.py +0 -0
  190. {django_whiteneuron-0.3.8.0/whiteneuron/notification → django_whiteneuron-0.4.0.0/whiteneuron/monitoring}/__init__.py +0 -0
  191. {django_whiteneuron-0.3.8.0/whiteneuron/notification → django_whiteneuron-0.4.0.0/whiteneuron/monitoring}/migrations/__init__.py +0 -0
  192. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/apps.py +0 -0
  193. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/management/commands/call_demo_noti.py +0 -0
  194. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0001_initial.py +0 -0
  195. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0002_alter_notificationconfig_event_type.py +0 -0
  196. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0003_notification.py +0 -0
  197. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0004_alter_notification_flag.py +0 -0
  198. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0005_notification_keywords.py +0 -0
  199. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0006_remove_notification_keywords.py +0 -0
  200. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0007_notification_changed_data.py +0 -0
  201. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0008_alter_notification_changed_data.py +0 -0
  202. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0009_notification_action_by_alter_notification_user.py +0 -0
  203. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0010_alter_notification_user.py +0 -0
  204. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0011_alter_notification_user.py +0 -0
  205. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0012_alter_notification_action_and_more.py +0 -0
  206. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/routing.py +0 -0
  207. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/tests.py +0 -0
  208. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/css/ckeditor5.css +0 -0
  209. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/forms/js/mdeditor.js +0 -0
  210. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/images/delete.svg +0 -0
  211. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/images/edit.svg +0 -0
  212. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/images/icon-viewlink.svg +0 -0
  213. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/images/loading.gif +0 -0
  214. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/images/login-bg.jpg +0 -0
  215. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/images/login_bg.jpg +0 -0
  216. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/images/logo/LOGO.jpg +0 -0
  217. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/images/logo/WhiteNeuron.png +0 -0
  218. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/js/chart.min.js +0 -0
  219. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/js/d3.v7.min.js +0 -0
  220. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/400.html +0 -0
  221. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/403.html +0 -0
  222. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/404.html +0 -0
  223. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/429.html +0 -0
  224. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/500.html +0 -0
  225. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/auth/user/add_form.html +0 -0
  226. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/base/app_change_list.html +0 -0
  227. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/base/image_change_form.html +0 -0
  228. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/base/userprofile_change_form.html +0 -0
  229. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/change_list.html +0 -0
  230. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/feedbacks/change_form_feedback_list.html +0 -0
  231. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/feedbacks/feedback_change_form.html +0 -0
  232. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/grid_view_results.html +0 -0
  233. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/login.html +0 -0
  234. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/login_after.html +0 -0
  235. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/signature.html +0 -0
  236. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/submit_line.html +0 -0
  237. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/wn_change_form.html +0 -0
  238. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/wn_history_panel.html +0 -0
  239. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/base/announcement.html +0 -0
  240. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/base/forms/helpers/toolbar.html +0 -0
  241. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/base/forms/mdeditor.html +0 -0
  242. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/base/forms/wysiwyg.html +0 -0
  243. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/base.html +0 -0
  244. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/file_management/widgets/clearable_file_input_no_download.html +0 -0
  245. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/unfold/helpers/field_password.html +0 -0
  246. {django_whiteneuron-0.3.8.0 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/unfold/helpers/language_switch.html +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-whiteneuron
3
- Version: 0.3.8.0
3
+ Version: 0.4.0.0
4
4
  Summary: A modern Django Admin extension with enhanced UI/UX, dashboard, feedback, file management, rate limiting, IP blacklisting, and advanced admin integrations built on django-unfold.
5
5
  Author-email: White Neuron <anhnt@whiteneuron.ai>
6
6
  License: MIT License
@@ -34,7 +34,7 @@ Keywords: django,plugin,admin,dashboard,whiteneuron
34
34
  Classifier: Development Status :: 4 - Beta
35
35
  Classifier: Intended Audience :: Developers
36
36
  Classifier: Framework :: Django
37
- Classifier: Framework :: Django :: 5.2
37
+ Classifier: Framework :: Django :: 6.0
38
38
  Classifier: Programming Language :: Python :: 3
39
39
  Classifier: Programming Language :: Python :: 3.13
40
40
  Classifier: License :: OSI Approved :: MIT License
@@ -72,10 +72,11 @@ Requires-Dist: daphne>=4.2.0
72
72
  Requires-Dist: twisted[tls]>=26.4.0rc2
73
73
  Requires-Dist: django-ckeditor-5>=0.2.18
74
74
  Requires-Dist: django-cors-headers>=4.3.0
75
- Requires-Dist: django-unfold>=0.92.0
75
+ Requires-Dist: django-unfold<0.111,>=0.109.0
76
76
  Requires-Dist: djangoql>=0.18.1
77
77
  Requires-Dist: pyopenssl>=26.4.0
78
78
  Requires-Dist: md2html-tailwind4==1.5.3
79
+ Requires-Dist: psutil>=7.0.0
79
80
  Provides-Extra: dev
80
81
  Requires-Dist: pytest; extra == "dev"
81
82
  Requires-Dist: black; extra == "dev"
@@ -95,10 +96,33 @@ A modern Django Admin extension focused on UI/UX, dashboard, feedback, file mana
95
96
  ![django-whiteneuron](https://raw.githubusercontent.com/White-Neuron/django-whiteneuron/main2.0/docs/images/main.png)
96
97
 
97
98
  ## Current Version
98
- v0.3.8.0
99
+ v0.4.0.0
99
100
 
100
101
  ## Changelog
101
102
 
103
+ ### Latest: v0.4.0.0 (2026-10-13)
104
+ **Feature release: daisyUI multi-theme admin, server monitoring dashboard, django-unfold 0.109, security hardening and performance work**
105
+ - **Added**: 35 daisyUI themes selectable from the user menu (**Themes**); each theme also re-colors Unfold and drives its dark mode. `WN_ADMIN_THEMES` limits the picker (`[]` hides it); `WN_THEMES="nord,dracula" bash scripts/tailwind.sh` builds a smaller CSS bundle.
106
+ - **Added**: `whiteneuron.monitoring` — Grafana-style **Server monitoring** dashboard (CPU, memory, disk, load, network, disk I/O, request throughput, p50/p95/p99 latency, error rate, Apdex, slowest endpoints, DB/cache latency) with time ranges, auto-refresh, host selector and shared crosshair. Collect with `manage.py monitoring_collector` or the Celery task `whiteneuron.monitoring.tasks.collect_metrics`; configure with `WN_MONITORING`. New dependency: `psutil`.
107
+ - **Added**: Docker base images `django-whiteneuron-{alpine,debian}:v<version>` built from this repository (`docker/`, moved from WN-Sense); `.github/workflows/docker-base.yml` builds and pushes them on every GitHub Release (secrets `DOCKERHUB_USERNAME` / `DOCKERHUB_TOKEN`).
108
+ - **Changed**: `django-unfold>=0.109.0,<0.111` (the cap is raised after each Unfold release is re-tested against the template overrides); template overrides ported; uses the avatar badge (unread notifications), sidebar sub-navigation (Celery "Schedules"), `SITE_VERSION`, theme-aware dashboard charts.
109
+ - **Security**: escaped notification/grid HTML (stored XSS), whitelisted `?display_fields` (a GET could call `obj.delete()`) and limited the column picker to fields shown on the change form (never `password`; extra exclusions via `ModelAdmin.field_selection_exclude`), staff-only per-user notification WebSocket with origin check, sandboxed uploaded-HTML preview, private exports scoped to the selected rows, `X-Forwarded-For` read from the right (`TRUSTED_PROXY_COUNT`, `IGNORE_X_FORWARDED_FOR`), open-redirect fix in guest login, new-user signal no longer overwrites passwords, `secrets`-based passwords redacted after sending (never passed to the task broker), POST-only feedback resolve, notification IDOR fix.
110
+ - **Security (dependencies)**: locked anyio 4.15.1, urllib3 2.8.0, autobahn 26.7.1, soupsieve 2.10, tablib 3.10.0 (stored XSS in HTML export) and virtualenv 21.14.5 (dev) to patched versions; Tailwind build tooling patched (`npm audit fix`) and the unused `@tailwindcss/typography` removed. `pip-audit` and `npm audit` report no known vulnerabilities.
111
+ - **Performance**: activity logging 1 INSERT per request (was 3–4 queries), dashboard 4 queries (was ~16) + 60s cache, one `bulk_create` + one broadcast per notification, new indexes, atomic rate-limit counters, request-scoped admin state (grid view / page size no longer shared between users), thumbnails built at upload (regenerated if the file is missing), N+1 fixes, 14KB logo instead of 187KB.
112
+ - **Fixed**: dashboard date ranges overlapped by a day, `App.__str__` crash on create, export action signature, `readonly_fields` growing per request, header horizontal overflow on phones, `_(f"…")` strings that could never be translated, Chart.js crash on oklch theme colors, notification WebSocket reconnect loops, monitoring collector stopping when the cache is down, missing site branding (sidebar logo/title) on the monitoring dashboard and admin index, flash messages shown twice on the admin index, changelist toolbar (filter / grid / page-size) hidden for admins without `search_fields`, "Next" enabled on the last page and Previous/Next stuck disabled when Django ignores `?all`, unreadable monitoring colors under several themes, markdown preview styles (md2html_tailwind4 classes were never compiled); Vietnamese translations updated.
113
+ - **Compatibility**: `ModelAdmin.request` still works (now request-scoped, not stored on the shared instance); the *Server monitoring* sidebar link follows the `monitoring.view_metricsample` permission; in the default light/dark modes daisyUI components take their base/primary colors from `UNFOLD["COLORS"]`.
114
+ - **Validation**: 42 package tests pass (`manage.py test whiteneuron`, also under the package's own settings via `whiteneuron.base.testing.package_test_settings`, and from a clean wheel install with django-unfold 0.110.0), `check` clean, `makemigrations` reports no changes, no untranslated Vietnamese strings, Tailwind build and `uv build` succeed; 101 admin URLs swept in a README-style project; changelists, add/change forms, the monitoring dashboard under all 35 themes and the theme picker checked in Chromium (desktop + mobile).
115
+ - **Breaking / behavior changes**:
116
+ - `SECRET_KEY` is required when `DEBUG=False` (build commands such as `collectstatic` are exempt).
117
+ - `WN_ASYNC_TASKS` (Celery for email, export, GPT translation) is opt-in; without it these run inline.
118
+ - Client IP: auto mode uses the right-most public `X-Forwarded-For` hop — set `TRUSTED_PROXY_COUNT`, or `IGNORE_X_FORWARDED_FOR=True` when the app is not behind a proxy.
119
+ - Whole-page cache middleware only with `USE_CACHE_MIDDLEWARE=True`; `EXTENSIONS.modeltranslation` and `compressed_fields` removed (dropped by Unfold); new notifications store plain-text titles and JSON `changed_data`.
120
+ - Project overrides of `unfold/helpers/navigation_user.html` should be compared with Unfold 0.109.
121
+ - **Upgrade Guidance**: `pip install --upgrade django-whiteneuron`, add `"whiteneuron.monitoring"` to `INSTALLED_APPS`, run `migrate` (indexes + monitoring table), `compilemessages`, and start `monitoring_collector` on each host.
122
+ - **Rollback**: revert to v0.3.8.0 after `migrate monitoring zero`, `migrate base 0027` and `migrate notification 0012` (index-only migrations; no data loss).
123
+
124
+ See [CHANGELOG.md](CHANGELOG.md) for the full version history.
125
+
102
126
  ### Latest: v0.3.8.0 (2026-09-25)
103
127
  **Bugfixes: Django 6 format_html crash in Image previews, app mosaic thumbnail URLs, SHOW_FILE_MANAGEMENT sidebar flag**
104
128
  - **Fixed**: `Image.imgThumbnail()` and `Image.imgPreview()` admin methods — replaced f-string interpolation inside `format_html()` with the proper template + args pattern; resolves the rendering crash on Django 6 and ensures interpolated values are HTML-escaped.
@@ -302,15 +326,15 @@ UNFOLD = {
302
326
  "SITE_TITLE": _("White Neuron Admin"),
303
327
  "SITE_SUBHEADER": _("Admin panel"),
304
328
  "SITE_ICON": {
305
- "light": lambda request: static("base/images/logo/WhiteNeuron.png"),
306
- "dark": lambda request: static("base/images/logo/WhiteNeuron.png"),
329
+ "light": lambda request: static("base/images/logo/WhiteNeuron-128.png"),
330
+ "dark": lambda request: static("base/images/logo/WhiteNeuron-128.png"),
307
331
  },
308
332
  "SITE_FAVICONS": [
309
333
  {
310
334
  "rel": "icon",
311
335
  "sizes": "32x32",
312
- "type": "image/svg+xml",
313
- "href": lambda request: static("base/images/logo/WhiteNeuron.png"),
336
+ "type": "image/png",
337
+ "href": lambda request: static("base/images/logo/WhiteNeuron-32.png"),
314
338
  },
315
339
  ],
316
340
  "SHOW_HISTORY": False,
@@ -334,6 +358,52 @@ UNFOLD = {
334
358
  }
335
359
  ```
336
360
 
361
+ ### Server monitoring dashboard
362
+
363
+ `whiteneuron.monitoring` adds a Grafana-style dashboard at **System → Server monitoring**
364
+ (superusers, or staff with the `view_metricsample` permission):
365
+
366
+ - **Overview**: uptime, CPU, memory, disk, load, throughput, 5xx error rate and p95 latency,
367
+ with sparklines and green / orange / red thresholds.
368
+ - **System**: CPU / memory / disk gauges, per-core heatmap, CPU, load, memory, disk I/O,
369
+ network and disk space time series.
370
+ - **Application** (from the request logs `UserActivityMiddleware` already writes): requests
371
+ per minute by outcome, p50 / p95 / p99 latency, status-code breakdown, Apdex score, and the
372
+ slowest endpoints (IDs are grouped, e.g. `/user/:id/change/`).
373
+ - **Process & dependencies**: database and cache round-trip time, app memory and threads.
374
+ - Time range 5m–7d, auto-refresh (off–5m), host selector, shared crosshair across charts,
375
+ shareable URLs (`?range=6h&refresh=30s&host=web-1`), follows the selected admin theme.
376
+
377
+ Add `"whiteneuron.monitoring"` to `INSTALLED_APPS`, run `migrate`, then collect samples on
378
+ each host (the dashboard also stores a sample while it is open, at most once per interval):
379
+
380
+ ```bash
381
+ python manage.py monitoring_collector # long-running, e.g. a systemd service
382
+ python manage.py monitoring_collector --once # single sample (cron)
383
+ ```
384
+
385
+ or schedule the Celery task `whiteneuron.monitoring.tasks.collect_metrics` with celery beat.
386
+
387
+ ```python
388
+ WN_MONITORING = {
389
+ "INTERVAL": 15, # seconds between samples
390
+ "RETENTION_DAYS": 7, # older samples are pruned automatically
391
+ "DISK_PATH": "/", # filesystem shown in the disk panels
392
+ # "HOST": "web-1", # defaults to the machine hostname
393
+ }
394
+ ```
395
+
396
+ ### Admin themes (daisyUI)
397
+
398
+ All 35 daisyUI themes are compiled into `base/css/styles.css` and selectable from the user menu (**Themes**). The selected theme also re-colors Unfold (primary/base palettes), and its light/dark scheme drives Unfold's dark mode. The choice is stored per browser.
399
+
400
+ ```python
401
+ # Optional: limit the themes offered in the picker (Light/Dark/System are always available)
402
+ WN_ADMIN_THEMES = ["corporate", "nord", "dracula", "forest"] # [] hides the picker
403
+ ```
404
+
405
+ To ship a smaller CSS bundle, compile only some themes: `WN_THEMES="nord,dracula" bash scripts/tailwind.sh`.
406
+
337
407
  ## Modules
338
408
 
339
409
  | Module | Description | Key Models |
@@ -426,6 +496,43 @@ bash scripts/build.sh
426
496
 
427
497
  This builds Tailwind CSS assets, runs migrations, and creates the Python package via `uv build`.
428
498
 
499
+ Publishing a **GitHub Release** (tag `v<version>`, equal to `version` in `pyproject.toml`) runs two
500
+ workflows: `python-publish.yml` uploads the package to PyPI, and `docker-base.yml` builds and pushes
501
+ the Docker base images.
502
+
503
+ ### Docker base images
504
+
505
+ `anhneuron/django-whiteneuron-alpine:v<version>` and `anhneuron/django-whiteneuron-debian:v<version>`
506
+ contain Python 3.13 with this package installed. Its dependencies are pinned from `uv.lock`, the
507
+ same set CI tests. The images run as `appuser` (uid 100, gid 101, home `/app`). Projects build
508
+ `FROM` them, for example WN-Sense's web (Alpine) and core (Debian) images.
509
+
510
+ Every build goes through `docker/build-base.sh`:
511
+ - The source is a `git archive` of the chosen ref, never local files.
512
+ - Dependencies come from that ref's `uv.lock` (`uv export`).
513
+ - The Dockerfiles come from the current checkout, so older tags can be built too.
514
+ - Pushing is only allowed for the release tag `v<version>`, which must match `pyproject.toml`.
515
+ A published tag is never rebuilt from other code.
516
+ - Each image fails to build if the installed version differs from its tag.
517
+
518
+ **CI/CD**: `.github/workflows/docker-base.yml` builds and pushes both images when a GitHub
519
+ Release is published.
520
+ - Required repository secrets: `DOCKERHUB_USERNAME` and `DOCKERHUB_TOKEN` (a Docker Hub access
521
+ token with write access).
522
+ - Optional repository variable: `DOCKERHUB_NAMESPACE` (default `anhneuron`).
523
+ - *Actions → Docker base images → Run workflow* builds any ref. Pushing from there also needs a
524
+ release tag.
525
+ - Pull requests that touch `docker/`, `pyproject.toml` or `uv.lock` only build the images.
526
+
527
+ **By hand** (needs git, uv and docker buildx):
528
+
529
+ ```bash
530
+ bash docker/build-base.sh # HEAD, load into local docker
531
+ GIT_REF=v0.3.8.0 bash docker/build-base.sh # a tag / branch / commit
532
+ GIT_REF=v0.4.0.0 bash docker/push-base.sh # push a release, with provenance and SBOM
533
+ VARIANTS=alpine IMAGE_NAMESPACE=myorg WN_PYTHON_VERSION=3.13 bash docker/build-base.sh
534
+ ```
535
+
429
536
  ## Error Pages
430
537
 
431
538
  Templates in `whiteneuron/templates/` are used automatically when `DEBUG=False`:
@@ -10,10 +10,33 @@ A modern Django Admin extension focused on UI/UX, dashboard, feedback, file mana
10
10
  ![django-whiteneuron](https://raw.githubusercontent.com/White-Neuron/django-whiteneuron/main2.0/docs/images/main.png)
11
11
 
12
12
  ## Current Version
13
- v0.3.8.0
13
+ v0.4.0.0
14
14
 
15
15
  ## Changelog
16
16
 
17
+ ### Latest: v0.4.0.0 (2026-10-13)
18
+ **Feature release: daisyUI multi-theme admin, server monitoring dashboard, django-unfold 0.109, security hardening and performance work**
19
+ - **Added**: 35 daisyUI themes selectable from the user menu (**Themes**); each theme also re-colors Unfold and drives its dark mode. `WN_ADMIN_THEMES` limits the picker (`[]` hides it); `WN_THEMES="nord,dracula" bash scripts/tailwind.sh` builds a smaller CSS bundle.
20
+ - **Added**: `whiteneuron.monitoring` — Grafana-style **Server monitoring** dashboard (CPU, memory, disk, load, network, disk I/O, request throughput, p50/p95/p99 latency, error rate, Apdex, slowest endpoints, DB/cache latency) with time ranges, auto-refresh, host selector and shared crosshair. Collect with `manage.py monitoring_collector` or the Celery task `whiteneuron.monitoring.tasks.collect_metrics`; configure with `WN_MONITORING`. New dependency: `psutil`.
21
+ - **Added**: Docker base images `django-whiteneuron-{alpine,debian}:v<version>` built from this repository (`docker/`, moved from WN-Sense); `.github/workflows/docker-base.yml` builds and pushes them on every GitHub Release (secrets `DOCKERHUB_USERNAME` / `DOCKERHUB_TOKEN`).
22
+ - **Changed**: `django-unfold>=0.109.0,<0.111` (the cap is raised after each Unfold release is re-tested against the template overrides); template overrides ported; uses the avatar badge (unread notifications), sidebar sub-navigation (Celery "Schedules"), `SITE_VERSION`, theme-aware dashboard charts.
23
+ - **Security**: escaped notification/grid HTML (stored XSS), whitelisted `?display_fields` (a GET could call `obj.delete()`) and limited the column picker to fields shown on the change form (never `password`; extra exclusions via `ModelAdmin.field_selection_exclude`), staff-only per-user notification WebSocket with origin check, sandboxed uploaded-HTML preview, private exports scoped to the selected rows, `X-Forwarded-For` read from the right (`TRUSTED_PROXY_COUNT`, `IGNORE_X_FORWARDED_FOR`), open-redirect fix in guest login, new-user signal no longer overwrites passwords, `secrets`-based passwords redacted after sending (never passed to the task broker), POST-only feedback resolve, notification IDOR fix.
24
+ - **Security (dependencies)**: locked anyio 4.15.1, urllib3 2.8.0, autobahn 26.7.1, soupsieve 2.10, tablib 3.10.0 (stored XSS in HTML export) and virtualenv 21.14.5 (dev) to patched versions; Tailwind build tooling patched (`npm audit fix`) and the unused `@tailwindcss/typography` removed. `pip-audit` and `npm audit` report no known vulnerabilities.
25
+ - **Performance**: activity logging 1 INSERT per request (was 3–4 queries), dashboard 4 queries (was ~16) + 60s cache, one `bulk_create` + one broadcast per notification, new indexes, atomic rate-limit counters, request-scoped admin state (grid view / page size no longer shared between users), thumbnails built at upload (regenerated if the file is missing), N+1 fixes, 14KB logo instead of 187KB.
26
+ - **Fixed**: dashboard date ranges overlapped by a day, `App.__str__` crash on create, export action signature, `readonly_fields` growing per request, header horizontal overflow on phones, `_(f"…")` strings that could never be translated, Chart.js crash on oklch theme colors, notification WebSocket reconnect loops, monitoring collector stopping when the cache is down, missing site branding (sidebar logo/title) on the monitoring dashboard and admin index, flash messages shown twice on the admin index, changelist toolbar (filter / grid / page-size) hidden for admins without `search_fields`, "Next" enabled on the last page and Previous/Next stuck disabled when Django ignores `?all`, unreadable monitoring colors under several themes, markdown preview styles (md2html_tailwind4 classes were never compiled); Vietnamese translations updated.
27
+ - **Compatibility**: `ModelAdmin.request` still works (now request-scoped, not stored on the shared instance); the *Server monitoring* sidebar link follows the `monitoring.view_metricsample` permission; in the default light/dark modes daisyUI components take their base/primary colors from `UNFOLD["COLORS"]`.
28
+ - **Validation**: 42 package tests pass (`manage.py test whiteneuron`, also under the package's own settings via `whiteneuron.base.testing.package_test_settings`, and from a clean wheel install with django-unfold 0.110.0), `check` clean, `makemigrations` reports no changes, no untranslated Vietnamese strings, Tailwind build and `uv build` succeed; 101 admin URLs swept in a README-style project; changelists, add/change forms, the monitoring dashboard under all 35 themes and the theme picker checked in Chromium (desktop + mobile).
29
+ - **Breaking / behavior changes**:
30
+ - `SECRET_KEY` is required when `DEBUG=False` (build commands such as `collectstatic` are exempt).
31
+ - `WN_ASYNC_TASKS` (Celery for email, export, GPT translation) is opt-in; without it these run inline.
32
+ - Client IP: auto mode uses the right-most public `X-Forwarded-For` hop — set `TRUSTED_PROXY_COUNT`, or `IGNORE_X_FORWARDED_FOR=True` when the app is not behind a proxy.
33
+ - Whole-page cache middleware only with `USE_CACHE_MIDDLEWARE=True`; `EXTENSIONS.modeltranslation` and `compressed_fields` removed (dropped by Unfold); new notifications store plain-text titles and JSON `changed_data`.
34
+ - Project overrides of `unfold/helpers/navigation_user.html` should be compared with Unfold 0.109.
35
+ - **Upgrade Guidance**: `pip install --upgrade django-whiteneuron`, add `"whiteneuron.monitoring"` to `INSTALLED_APPS`, run `migrate` (indexes + monitoring table), `compilemessages`, and start `monitoring_collector` on each host.
36
+ - **Rollback**: revert to v0.3.8.0 after `migrate monitoring zero`, `migrate base 0027` and `migrate notification 0012` (index-only migrations; no data loss).
37
+
38
+ See [CHANGELOG.md](CHANGELOG.md) for the full version history.
39
+
17
40
  ### Latest: v0.3.8.0 (2026-09-25)
18
41
  **Bugfixes: Django 6 format_html crash in Image previews, app mosaic thumbnail URLs, SHOW_FILE_MANAGEMENT sidebar flag**
19
42
  - **Fixed**: `Image.imgThumbnail()` and `Image.imgPreview()` admin methods — replaced f-string interpolation inside `format_html()` with the proper template + args pattern; resolves the rendering crash on Django 6 and ensures interpolated values are HTML-escaped.
@@ -217,15 +240,15 @@ UNFOLD = {
217
240
  "SITE_TITLE": _("White Neuron Admin"),
218
241
  "SITE_SUBHEADER": _("Admin panel"),
219
242
  "SITE_ICON": {
220
- "light": lambda request: static("base/images/logo/WhiteNeuron.png"),
221
- "dark": lambda request: static("base/images/logo/WhiteNeuron.png"),
243
+ "light": lambda request: static("base/images/logo/WhiteNeuron-128.png"),
244
+ "dark": lambda request: static("base/images/logo/WhiteNeuron-128.png"),
222
245
  },
223
246
  "SITE_FAVICONS": [
224
247
  {
225
248
  "rel": "icon",
226
249
  "sizes": "32x32",
227
- "type": "image/svg+xml",
228
- "href": lambda request: static("base/images/logo/WhiteNeuron.png"),
250
+ "type": "image/png",
251
+ "href": lambda request: static("base/images/logo/WhiteNeuron-32.png"),
229
252
  },
230
253
  ],
231
254
  "SHOW_HISTORY": False,
@@ -249,6 +272,52 @@ UNFOLD = {
249
272
  }
250
273
  ```
251
274
 
275
+ ### Server monitoring dashboard
276
+
277
+ `whiteneuron.monitoring` adds a Grafana-style dashboard at **System → Server monitoring**
278
+ (superusers, or staff with the `view_metricsample` permission):
279
+
280
+ - **Overview**: uptime, CPU, memory, disk, load, throughput, 5xx error rate and p95 latency,
281
+ with sparklines and green / orange / red thresholds.
282
+ - **System**: CPU / memory / disk gauges, per-core heatmap, CPU, load, memory, disk I/O,
283
+ network and disk space time series.
284
+ - **Application** (from the request logs `UserActivityMiddleware` already writes): requests
285
+ per minute by outcome, p50 / p95 / p99 latency, status-code breakdown, Apdex score, and the
286
+ slowest endpoints (IDs are grouped, e.g. `/user/:id/change/`).
287
+ - **Process & dependencies**: database and cache round-trip time, app memory and threads.
288
+ - Time range 5m–7d, auto-refresh (off–5m), host selector, shared crosshair across charts,
289
+ shareable URLs (`?range=6h&refresh=30s&host=web-1`), follows the selected admin theme.
290
+
291
+ Add `"whiteneuron.monitoring"` to `INSTALLED_APPS`, run `migrate`, then collect samples on
292
+ each host (the dashboard also stores a sample while it is open, at most once per interval):
293
+
294
+ ```bash
295
+ python manage.py monitoring_collector # long-running, e.g. a systemd service
296
+ python manage.py monitoring_collector --once # single sample (cron)
297
+ ```
298
+
299
+ or schedule the Celery task `whiteneuron.monitoring.tasks.collect_metrics` with celery beat.
300
+
301
+ ```python
302
+ WN_MONITORING = {
303
+ "INTERVAL": 15, # seconds between samples
304
+ "RETENTION_DAYS": 7, # older samples are pruned automatically
305
+ "DISK_PATH": "/", # filesystem shown in the disk panels
306
+ # "HOST": "web-1", # defaults to the machine hostname
307
+ }
308
+ ```
309
+
310
+ ### Admin themes (daisyUI)
311
+
312
+ All 35 daisyUI themes are compiled into `base/css/styles.css` and selectable from the user menu (**Themes**). The selected theme also re-colors Unfold (primary/base palettes), and its light/dark scheme drives Unfold's dark mode. The choice is stored per browser.
313
+
314
+ ```python
315
+ # Optional: limit the themes offered in the picker (Light/Dark/System are always available)
316
+ WN_ADMIN_THEMES = ["corporate", "nord", "dracula", "forest"] # [] hides the picker
317
+ ```
318
+
319
+ To ship a smaller CSS bundle, compile only some themes: `WN_THEMES="nord,dracula" bash scripts/tailwind.sh`.
320
+
252
321
  ## Modules
253
322
 
254
323
  | Module | Description | Key Models |
@@ -341,6 +410,43 @@ bash scripts/build.sh
341
410
 
342
411
  This builds Tailwind CSS assets, runs migrations, and creates the Python package via `uv build`.
343
412
 
413
+ Publishing a **GitHub Release** (tag `v<version>`, equal to `version` in `pyproject.toml`) runs two
414
+ workflows: `python-publish.yml` uploads the package to PyPI, and `docker-base.yml` builds and pushes
415
+ the Docker base images.
416
+
417
+ ### Docker base images
418
+
419
+ `anhneuron/django-whiteneuron-alpine:v<version>` and `anhneuron/django-whiteneuron-debian:v<version>`
420
+ contain Python 3.13 with this package installed. Its dependencies are pinned from `uv.lock`, the
421
+ same set CI tests. The images run as `appuser` (uid 100, gid 101, home `/app`). Projects build
422
+ `FROM` them, for example WN-Sense's web (Alpine) and core (Debian) images.
423
+
424
+ Every build goes through `docker/build-base.sh`:
425
+ - The source is a `git archive` of the chosen ref, never local files.
426
+ - Dependencies come from that ref's `uv.lock` (`uv export`).
427
+ - The Dockerfiles come from the current checkout, so older tags can be built too.
428
+ - Pushing is only allowed for the release tag `v<version>`, which must match `pyproject.toml`.
429
+ A published tag is never rebuilt from other code.
430
+ - Each image fails to build if the installed version differs from its tag.
431
+
432
+ **CI/CD**: `.github/workflows/docker-base.yml` builds and pushes both images when a GitHub
433
+ Release is published.
434
+ - Required repository secrets: `DOCKERHUB_USERNAME` and `DOCKERHUB_TOKEN` (a Docker Hub access
435
+ token with write access).
436
+ - Optional repository variable: `DOCKERHUB_NAMESPACE` (default `anhneuron`).
437
+ - *Actions → Docker base images → Run workflow* builds any ref. Pushing from there also needs a
438
+ release tag.
439
+ - Pull requests that touch `docker/`, `pyproject.toml` or `uv.lock` only build the images.
440
+
441
+ **By hand** (needs git, uv and docker buildx):
442
+
443
+ ```bash
444
+ bash docker/build-base.sh # HEAD, load into local docker
445
+ GIT_REF=v0.3.8.0 bash docker/build-base.sh # a tag / branch / commit
446
+ GIT_REF=v0.4.0.0 bash docker/push-base.sh # push a release, with provenance and SBOM
447
+ VARIANTS=alpine IMAGE_NAMESPACE=myorg WN_PYTHON_VERSION=3.13 bash docker/build-base.sh
448
+ ```
449
+
344
450
  ## Error Pages
345
451
 
346
452
  Templates in `whiteneuron/templates/` are used automatically when `DEBUG=False`:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-whiteneuron
3
- Version: 0.3.8.0
3
+ Version: 0.4.0.0
4
4
  Summary: A modern Django Admin extension with enhanced UI/UX, dashboard, feedback, file management, rate limiting, IP blacklisting, and advanced admin integrations built on django-unfold.
5
5
  Author-email: White Neuron <anhnt@whiteneuron.ai>
6
6
  License: MIT License
@@ -34,7 +34,7 @@ Keywords: django,plugin,admin,dashboard,whiteneuron
34
34
  Classifier: Development Status :: 4 - Beta
35
35
  Classifier: Intended Audience :: Developers
36
36
  Classifier: Framework :: Django
37
- Classifier: Framework :: Django :: 5.2
37
+ Classifier: Framework :: Django :: 6.0
38
38
  Classifier: Programming Language :: Python :: 3
39
39
  Classifier: Programming Language :: Python :: 3.13
40
40
  Classifier: License :: OSI Approved :: MIT License
@@ -72,10 +72,11 @@ Requires-Dist: daphne>=4.2.0
72
72
  Requires-Dist: twisted[tls]>=26.4.0rc2
73
73
  Requires-Dist: django-ckeditor-5>=0.2.18
74
74
  Requires-Dist: django-cors-headers>=4.3.0
75
- Requires-Dist: django-unfold>=0.92.0
75
+ Requires-Dist: django-unfold<0.111,>=0.109.0
76
76
  Requires-Dist: djangoql>=0.18.1
77
77
  Requires-Dist: pyopenssl>=26.4.0
78
78
  Requires-Dist: md2html-tailwind4==1.5.3
79
+ Requires-Dist: psutil>=7.0.0
79
80
  Provides-Extra: dev
80
81
  Requires-Dist: pytest; extra == "dev"
81
82
  Requires-Dist: black; extra == "dev"
@@ -95,10 +96,33 @@ A modern Django Admin extension focused on UI/UX, dashboard, feedback, file mana
95
96
  ![django-whiteneuron](https://raw.githubusercontent.com/White-Neuron/django-whiteneuron/main2.0/docs/images/main.png)
96
97
 
97
98
  ## Current Version
98
- v0.3.8.0
99
+ v0.4.0.0
99
100
 
100
101
  ## Changelog
101
102
 
103
+ ### Latest: v0.4.0.0 (2026-10-13)
104
+ **Feature release: daisyUI multi-theme admin, server monitoring dashboard, django-unfold 0.109, security hardening and performance work**
105
+ - **Added**: 35 daisyUI themes selectable from the user menu (**Themes**); each theme also re-colors Unfold and drives its dark mode. `WN_ADMIN_THEMES` limits the picker (`[]` hides it); `WN_THEMES="nord,dracula" bash scripts/tailwind.sh` builds a smaller CSS bundle.
106
+ - **Added**: `whiteneuron.monitoring` — Grafana-style **Server monitoring** dashboard (CPU, memory, disk, load, network, disk I/O, request throughput, p50/p95/p99 latency, error rate, Apdex, slowest endpoints, DB/cache latency) with time ranges, auto-refresh, host selector and shared crosshair. Collect with `manage.py monitoring_collector` or the Celery task `whiteneuron.monitoring.tasks.collect_metrics`; configure with `WN_MONITORING`. New dependency: `psutil`.
107
+ - **Added**: Docker base images `django-whiteneuron-{alpine,debian}:v<version>` built from this repository (`docker/`, moved from WN-Sense); `.github/workflows/docker-base.yml` builds and pushes them on every GitHub Release (secrets `DOCKERHUB_USERNAME` / `DOCKERHUB_TOKEN`).
108
+ - **Changed**: `django-unfold>=0.109.0,<0.111` (the cap is raised after each Unfold release is re-tested against the template overrides); template overrides ported; uses the avatar badge (unread notifications), sidebar sub-navigation (Celery "Schedules"), `SITE_VERSION`, theme-aware dashboard charts.
109
+ - **Security**: escaped notification/grid HTML (stored XSS), whitelisted `?display_fields` (a GET could call `obj.delete()`) and limited the column picker to fields shown on the change form (never `password`; extra exclusions via `ModelAdmin.field_selection_exclude`), staff-only per-user notification WebSocket with origin check, sandboxed uploaded-HTML preview, private exports scoped to the selected rows, `X-Forwarded-For` read from the right (`TRUSTED_PROXY_COUNT`, `IGNORE_X_FORWARDED_FOR`), open-redirect fix in guest login, new-user signal no longer overwrites passwords, `secrets`-based passwords redacted after sending (never passed to the task broker), POST-only feedback resolve, notification IDOR fix.
110
+ - **Security (dependencies)**: locked anyio 4.15.1, urllib3 2.8.0, autobahn 26.7.1, soupsieve 2.10, tablib 3.10.0 (stored XSS in HTML export) and virtualenv 21.14.5 (dev) to patched versions; Tailwind build tooling patched (`npm audit fix`) and the unused `@tailwindcss/typography` removed. `pip-audit` and `npm audit` report no known vulnerabilities.
111
+ - **Performance**: activity logging 1 INSERT per request (was 3–4 queries), dashboard 4 queries (was ~16) + 60s cache, one `bulk_create` + one broadcast per notification, new indexes, atomic rate-limit counters, request-scoped admin state (grid view / page size no longer shared between users), thumbnails built at upload (regenerated if the file is missing), N+1 fixes, 14KB logo instead of 187KB.
112
+ - **Fixed**: dashboard date ranges overlapped by a day, `App.__str__` crash on create, export action signature, `readonly_fields` growing per request, header horizontal overflow on phones, `_(f"…")` strings that could never be translated, Chart.js crash on oklch theme colors, notification WebSocket reconnect loops, monitoring collector stopping when the cache is down, missing site branding (sidebar logo/title) on the monitoring dashboard and admin index, flash messages shown twice on the admin index, changelist toolbar (filter / grid / page-size) hidden for admins without `search_fields`, "Next" enabled on the last page and Previous/Next stuck disabled when Django ignores `?all`, unreadable monitoring colors under several themes, markdown preview styles (md2html_tailwind4 classes were never compiled); Vietnamese translations updated.
113
+ - **Compatibility**: `ModelAdmin.request` still works (now request-scoped, not stored on the shared instance); the *Server monitoring* sidebar link follows the `monitoring.view_metricsample` permission; in the default light/dark modes daisyUI components take their base/primary colors from `UNFOLD["COLORS"]`.
114
+ - **Validation**: 42 package tests pass (`manage.py test whiteneuron`, also under the package's own settings via `whiteneuron.base.testing.package_test_settings`, and from a clean wheel install with django-unfold 0.110.0), `check` clean, `makemigrations` reports no changes, no untranslated Vietnamese strings, Tailwind build and `uv build` succeed; 101 admin URLs swept in a README-style project; changelists, add/change forms, the monitoring dashboard under all 35 themes and the theme picker checked in Chromium (desktop + mobile).
115
+ - **Breaking / behavior changes**:
116
+ - `SECRET_KEY` is required when `DEBUG=False` (build commands such as `collectstatic` are exempt).
117
+ - `WN_ASYNC_TASKS` (Celery for email, export, GPT translation) is opt-in; without it these run inline.
118
+ - Client IP: auto mode uses the right-most public `X-Forwarded-For` hop — set `TRUSTED_PROXY_COUNT`, or `IGNORE_X_FORWARDED_FOR=True` when the app is not behind a proxy.
119
+ - Whole-page cache middleware only with `USE_CACHE_MIDDLEWARE=True`; `EXTENSIONS.modeltranslation` and `compressed_fields` removed (dropped by Unfold); new notifications store plain-text titles and JSON `changed_data`.
120
+ - Project overrides of `unfold/helpers/navigation_user.html` should be compared with Unfold 0.109.
121
+ - **Upgrade Guidance**: `pip install --upgrade django-whiteneuron`, add `"whiteneuron.monitoring"` to `INSTALLED_APPS`, run `migrate` (indexes + monitoring table), `compilemessages`, and start `monitoring_collector` on each host.
122
+ - **Rollback**: revert to v0.3.8.0 after `migrate monitoring zero`, `migrate base 0027` and `migrate notification 0012` (index-only migrations; no data loss).
123
+
124
+ See [CHANGELOG.md](CHANGELOG.md) for the full version history.
125
+
102
126
  ### Latest: v0.3.8.0 (2026-09-25)
103
127
  **Bugfixes: Django 6 format_html crash in Image previews, app mosaic thumbnail URLs, SHOW_FILE_MANAGEMENT sidebar flag**
104
128
  - **Fixed**: `Image.imgThumbnail()` and `Image.imgPreview()` admin methods — replaced f-string interpolation inside `format_html()` with the proper template + args pattern; resolves the rendering crash on Django 6 and ensures interpolated values are HTML-escaped.
@@ -302,15 +326,15 @@ UNFOLD = {
302
326
  "SITE_TITLE": _("White Neuron Admin"),
303
327
  "SITE_SUBHEADER": _("Admin panel"),
304
328
  "SITE_ICON": {
305
- "light": lambda request: static("base/images/logo/WhiteNeuron.png"),
306
- "dark": lambda request: static("base/images/logo/WhiteNeuron.png"),
329
+ "light": lambda request: static("base/images/logo/WhiteNeuron-128.png"),
330
+ "dark": lambda request: static("base/images/logo/WhiteNeuron-128.png"),
307
331
  },
308
332
  "SITE_FAVICONS": [
309
333
  {
310
334
  "rel": "icon",
311
335
  "sizes": "32x32",
312
- "type": "image/svg+xml",
313
- "href": lambda request: static("base/images/logo/WhiteNeuron.png"),
336
+ "type": "image/png",
337
+ "href": lambda request: static("base/images/logo/WhiteNeuron-32.png"),
314
338
  },
315
339
  ],
316
340
  "SHOW_HISTORY": False,
@@ -334,6 +358,52 @@ UNFOLD = {
334
358
  }
335
359
  ```
336
360
 
361
+ ### Server monitoring dashboard
362
+
363
+ `whiteneuron.monitoring` adds a Grafana-style dashboard at **System → Server monitoring**
364
+ (superusers, or staff with the `view_metricsample` permission):
365
+
366
+ - **Overview**: uptime, CPU, memory, disk, load, throughput, 5xx error rate and p95 latency,
367
+ with sparklines and green / orange / red thresholds.
368
+ - **System**: CPU / memory / disk gauges, per-core heatmap, CPU, load, memory, disk I/O,
369
+ network and disk space time series.
370
+ - **Application** (from the request logs `UserActivityMiddleware` already writes): requests
371
+ per minute by outcome, p50 / p95 / p99 latency, status-code breakdown, Apdex score, and the
372
+ slowest endpoints (IDs are grouped, e.g. `/user/:id/change/`).
373
+ - **Process & dependencies**: database and cache round-trip time, app memory and threads.
374
+ - Time range 5m–7d, auto-refresh (off–5m), host selector, shared crosshair across charts,
375
+ shareable URLs (`?range=6h&refresh=30s&host=web-1`), follows the selected admin theme.
376
+
377
+ Add `"whiteneuron.monitoring"` to `INSTALLED_APPS`, run `migrate`, then collect samples on
378
+ each host (the dashboard also stores a sample while it is open, at most once per interval):
379
+
380
+ ```bash
381
+ python manage.py monitoring_collector # long-running, e.g. a systemd service
382
+ python manage.py monitoring_collector --once # single sample (cron)
383
+ ```
384
+
385
+ or schedule the Celery task `whiteneuron.monitoring.tasks.collect_metrics` with celery beat.
386
+
387
+ ```python
388
+ WN_MONITORING = {
389
+ "INTERVAL": 15, # seconds between samples
390
+ "RETENTION_DAYS": 7, # older samples are pruned automatically
391
+ "DISK_PATH": "/", # filesystem shown in the disk panels
392
+ # "HOST": "web-1", # defaults to the machine hostname
393
+ }
394
+ ```
395
+
396
+ ### Admin themes (daisyUI)
397
+
398
+ All 35 daisyUI themes are compiled into `base/css/styles.css` and selectable from the user menu (**Themes**). The selected theme also re-colors Unfold (primary/base palettes), and its light/dark scheme drives Unfold's dark mode. The choice is stored per browser.
399
+
400
+ ```python
401
+ # Optional: limit the themes offered in the picker (Light/Dark/System are always available)
402
+ WN_ADMIN_THEMES = ["corporate", "nord", "dracula", "forest"] # [] hides the picker
403
+ ```
404
+
405
+ To ship a smaller CSS bundle, compile only some themes: `WN_THEMES="nord,dracula" bash scripts/tailwind.sh`.
406
+
337
407
  ## Modules
338
408
 
339
409
  | Module | Description | Key Models |
@@ -426,6 +496,43 @@ bash scripts/build.sh
426
496
 
427
497
  This builds Tailwind CSS assets, runs migrations, and creates the Python package via `uv build`.
428
498
 
499
+ Publishing a **GitHub Release** (tag `v<version>`, equal to `version` in `pyproject.toml`) runs two
500
+ workflows: `python-publish.yml` uploads the package to PyPI, and `docker-base.yml` builds and pushes
501
+ the Docker base images.
502
+
503
+ ### Docker base images
504
+
505
+ `anhneuron/django-whiteneuron-alpine:v<version>` and `anhneuron/django-whiteneuron-debian:v<version>`
506
+ contain Python 3.13 with this package installed. Its dependencies are pinned from `uv.lock`, the
507
+ same set CI tests. The images run as `appuser` (uid 100, gid 101, home `/app`). Projects build
508
+ `FROM` them, for example WN-Sense's web (Alpine) and core (Debian) images.
509
+
510
+ Every build goes through `docker/build-base.sh`:
511
+ - The source is a `git archive` of the chosen ref, never local files.
512
+ - Dependencies come from that ref's `uv.lock` (`uv export`).
513
+ - The Dockerfiles come from the current checkout, so older tags can be built too.
514
+ - Pushing is only allowed for the release tag `v<version>`, which must match `pyproject.toml`.
515
+ A published tag is never rebuilt from other code.
516
+ - Each image fails to build if the installed version differs from its tag.
517
+
518
+ **CI/CD**: `.github/workflows/docker-base.yml` builds and pushes both images when a GitHub
519
+ Release is published.
520
+ - Required repository secrets: `DOCKERHUB_USERNAME` and `DOCKERHUB_TOKEN` (a Docker Hub access
521
+ token with write access).
522
+ - Optional repository variable: `DOCKERHUB_NAMESPACE` (default `anhneuron`).
523
+ - *Actions → Docker base images → Run workflow* builds any ref. Pushing from there also needs a
524
+ release tag.
525
+ - Pull requests that touch `docker/`, `pyproject.toml` or `uv.lock` only build the images.
526
+
527
+ **By hand** (needs git, uv and docker buildx):
528
+
529
+ ```bash
530
+ bash docker/build-base.sh # HEAD, load into local docker
531
+ GIT_REF=v0.3.8.0 bash docker/build-base.sh # a tag / branch / commit
532
+ GIT_REF=v0.4.0.0 bash docker/push-base.sh # push a release, with provenance and SBOM
533
+ VARIANTS=alpine IMAGE_NAMESPACE=myorg WN_PYTHON_VERSION=3.13 bash docker/build-base.sh
534
+ ```
535
+
429
536
  ## Error Pages
430
537
 
431
538
  Templates in `whiteneuron/templates/` are used automatically when `DEBUG=False`:
@@ -15,16 +15,22 @@ whiteneuron/base/asgi.py
15
15
  whiteneuron/base/ckeditor.py
16
16
  whiteneuron/base/filters.py
17
17
  whiteneuron/base/forms.py
18
+ whiteneuron/base/html_sanitize.py
18
19
  whiteneuron/base/middleware.py
19
20
  whiteneuron/base/modeladmin.py
20
21
  whiteneuron/base/models.py
22
+ whiteneuron/base/queue.py
21
23
  whiteneuron/base/resources.py
22
24
  whiteneuron/base/settings.py
23
25
  whiteneuron/base/sites.py
24
26
  whiteneuron/base/tasks.py
27
+ whiteneuron/base/testing.py
25
28
  whiteneuron/base/tests.py
29
+ whiteneuron/base/tests_regressions.py
30
+ whiteneuron/base/themes.py
26
31
  whiteneuron/base/thread_local.py
27
32
  whiteneuron/base/urls.py
33
+ whiteneuron/base/urls_testing.py
28
34
  whiteneuron/base/utils.py
29
35
  whiteneuron/base/views.py
30
36
  whiteneuron/base/widgets.py
@@ -62,10 +68,12 @@ whiteneuron/base/migrations/0024_alter_visitprofile_user_agent_to_charfield.py
62
68
  whiteneuron/base/migrations/0025_alter_anonymousactivity_options_and_more.py
63
69
  whiteneuron/base/migrations/0026_alter_anonymousactivity_profile_and_more.py
64
70
  whiteneuron/base/migrations/0027_alter_anonymousactivity_method_and_more.py
71
+ whiteneuron/base/migrations/0028_perf_indexes.py
65
72
  whiteneuron/base/migrations/__init__.py
66
73
  whiteneuron/base/templatetags/__init__.py
67
74
  whiteneuron/base/templatetags/unfold_list_custom.py
68
75
  whiteneuron/base/templatetags/wn_filters.py
76
+ whiteneuron/base/templatetags/wn_theme.py
69
77
  whiteneuron/contrib/__init__.py
70
78
  whiteneuron/contrib/wn_import_export/__init__.py
71
79
  whiteneuron/contrib/wn_import_export/admin.py
@@ -117,6 +125,20 @@ whiteneuron/file_management/migrations/0008_excelfile_allowed_groups_excelfile_a
117
125
  whiteneuron/file_management/migrations/__init__.py
118
126
  whiteneuron/locale/vi/LC_MESSAGES/django.mo
119
127
  whiteneuron/locale/vi/LC_MESSAGES/django.po
128
+ whiteneuron/monitoring/__init__.py
129
+ whiteneuron/monitoring/admin.py
130
+ whiteneuron/monitoring/apps.py
131
+ whiteneuron/monitoring/collector.py
132
+ whiteneuron/monitoring/models.py
133
+ whiteneuron/monitoring/permissions.py
134
+ whiteneuron/monitoring/stats.py
135
+ whiteneuron/monitoring/tasks.py
136
+ whiteneuron/monitoring/tests.py
137
+ whiteneuron/monitoring/management/__init__.py
138
+ whiteneuron/monitoring/management/commands/__init__.py
139
+ whiteneuron/monitoring/management/commands/monitoring_collector.py
140
+ whiteneuron/monitoring/migrations/0001_initial.py
141
+ whiteneuron/monitoring/migrations/__init__.py
120
142
  whiteneuron/notification/__init__.py
121
143
  whiteneuron/notification/admin.py
122
144
  whiteneuron/notification/apps.py
@@ -141,6 +163,7 @@ whiteneuron/notification/migrations/0009_notification_action_by_alter_notificati
141
163
  whiteneuron/notification/migrations/0010_alter_notification_user.py
142
164
  whiteneuron/notification/migrations/0011_alter_notification_user.py
143
165
  whiteneuron/notification/migrations/0012_alter_notification_action_and_more.py
166
+ whiteneuron/notification/migrations/0013_perf_indexes.py
144
167
  whiteneuron/notification/migrations/__init__.py
145
168
  whiteneuron/static/base/css/btn-styles.css
146
169
  whiteneuron/static/base/css/ckeditor5.css
@@ -154,11 +177,15 @@ whiteneuron/static/base/images/loading.gif
154
177
  whiteneuron/static/base/images/login-bg.jpg
155
178
  whiteneuron/static/base/images/login_bg.jpg
156
179
  whiteneuron/static/base/images/logo/LOGO.jpg
180
+ whiteneuron/static/base/images/logo/WhiteNeuron-128.png
181
+ whiteneuron/static/base/images/logo/WhiteNeuron-32.png
157
182
  whiteneuron/static/base/images/logo/WhiteNeuron.png
158
183
  whiteneuron/static/base/js/chart.min.js
159
184
  whiteneuron/static/base/js/d3.v7.min.js
160
185
  whiteneuron/static/base/js/loading.js
161
186
  whiteneuron/static/base/js/whiteneuron.js
187
+ whiteneuron/static/monitoring/css/dashboard.css
188
+ whiteneuron/static/monitoring/js/dashboard.js
162
189
  whiteneuron/templates/400.html
163
190
  whiteneuron/templates/403.html
164
191
  whiteneuron/templates/404.html
@@ -183,6 +210,9 @@ whiteneuron/templates/admin/base/image_change_form.html
183
210
  whiteneuron/templates/admin/base/userprofile_change_form.html
184
211
  whiteneuron/templates/admin/feedbacks/change_form_feedback_list.html
185
212
  whiteneuron/templates/admin/feedbacks/feedback_change_form.html
213
+ whiteneuron/templates/admin/monitoring/dashboard.html
214
+ whiteneuron/templates/admin/monitoring/stat.html
215
+ whiteneuron/templates/admin/monitoring/timeseries.html
186
216
  whiteneuron/templates/base/announcement.html
187
217
  whiteneuron/templates/base/forms/mdeditor.html
188
218
  whiteneuron/templates/base/forms/wysiwyg.html
@@ -192,7 +222,7 @@ whiteneuron/templates/unfold/helpers/account_links.html
192
222
  whiteneuron/templates/unfold/helpers/app_list_badge.html
193
223
  whiteneuron/templates/unfold/helpers/field_password.html
194
224
  whiteneuron/templates/unfold/helpers/language_switch.html
195
- whiteneuron/templates/unfold/helpers/navigation_user.html
196
225
  whiteneuron/templates/unfold/helpers/pagination.html
197
226
  whiteneuron/templates/unfold/helpers/theme_switch.html
198
- whiteneuron/templates/unfold/helpers/userlinks.html
227
+ whiteneuron/templates/unfold/helpers/userlinks.html
228
+ whiteneuron/templates/unfold/helpers/wn_page_button.html
@@ -28,10 +28,11 @@ daphne>=4.2.0
28
28
  twisted[tls]>=26.4.0rc2
29
29
  django-ckeditor-5>=0.2.18
30
30
  django-cors-headers>=4.3.0
31
- django-unfold>=0.92.0
31
+ django-unfold<0.111,>=0.109.0
32
32
  djangoql>=0.18.1
33
33
  pyopenssl>=26.4.0
34
34
  md2html-tailwind4==1.5.3
35
+ psutil>=7.0.0
35
36
 
36
37
  [dev]
37
38
  pytest