WuttaWeb 0.21.5__tar.gz → 0.22.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 (210) hide show
  1. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/CHANGELOG.md +11 -0
  2. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/PKG-INFO +2 -2
  3. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/pyproject.toml +2 -2
  4. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/app.py +35 -1
  5. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/subscribers.py +88 -1
  6. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/appinfo/configure.mako +7 -0
  7. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/base.mako +37 -5
  8. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/forms/vue_template.mako +2 -0
  9. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/grids/vue_template.mako +2 -0
  10. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/page.mako +1 -1
  11. wuttaweb-0.22.0/src/wuttaweb/templates/themes/butterfly/base.mako +78 -0
  12. wuttaweb-0.22.0/src/wuttaweb/templates/themes/butterfly/buefy-components.mako +760 -0
  13. wuttaweb-0.22.0/src/wuttaweb/templates/themes/butterfly/buefy-plugin.mako +32 -0
  14. wuttaweb-0.22.0/src/wuttaweb/templates/themes/butterfly/http-plugin.mako +100 -0
  15. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/wutta-components.mako +17 -7
  16. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/util.py +158 -1
  17. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/views/common.py +23 -1
  18. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/views/settings.py +3 -1
  19. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/forms/test_base.py +5 -1
  20. wuttaweb-0.22.0/tests/test_app.py +195 -0
  21. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/test_subscribers.py +48 -2
  22. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/test_util.py +90 -1
  23. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/views/test_common.py +30 -0
  24. wuttaweb-0.21.5/tests/test_app.py +0 -131
  25. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/.gitignore +0 -0
  26. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/COPYING.txt +0 -0
  27. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/README.md +0 -0
  28. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/Makefile +0 -0
  29. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/_static/.keepme +0 -0
  30. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.app.rst +0 -0
  31. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.auth.rst +0 -0
  32. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.cli.rst +0 -0
  33. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.cli.webapp.rst +0 -0
  34. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.conf.rst +0 -0
  35. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.db.continuum.rst +0 -0
  36. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.db.rst +0 -0
  37. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.db.sess.rst +0 -0
  38. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.emails.rst +0 -0
  39. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.forms.base.rst +0 -0
  40. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.forms.rst +0 -0
  41. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.forms.schema.rst +0 -0
  42. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.forms.widgets.rst +0 -0
  43. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.grids.base.rst +0 -0
  44. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.grids.filters.rst +0 -0
  45. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.grids.rst +0 -0
  46. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.handler.rst +0 -0
  47. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.helpers.rst +0 -0
  48. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.menus.rst +0 -0
  49. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.progress.rst +0 -0
  50. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.rst +0 -0
  51. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.static.rst +0 -0
  52. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.subscribers.rst +0 -0
  53. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.util.rst +0 -0
  54. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.views.auth.rst +0 -0
  55. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.views.base.rst +0 -0
  56. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.views.batch.rst +0 -0
  57. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.views.common.rst +0 -0
  58. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.views.email.rst +0 -0
  59. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.views.essential.rst +0 -0
  60. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.views.master.rst +0 -0
  61. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.views.people.rst +0 -0
  62. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.views.progress.rst +0 -0
  63. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.views.reports.rst +0 -0
  64. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.views.roles.rst +0 -0
  65. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.views.rst +0 -0
  66. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.views.settings.rst +0 -0
  67. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.views.upgrades.rst +0 -0
  68. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/api/wuttaweb.views.users.rst +0 -0
  69. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/conf.py +0 -0
  70. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/glossary.rst +0 -0
  71. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/index.rst +0 -0
  72. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/make.bat +0 -0
  73. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/narr/cli/builtin.rst +0 -0
  74. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/narr/cli/index.rst +0 -0
  75. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/narr/templates/base.rst +0 -0
  76. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/narr/templates/index.rst +0 -0
  77. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/narr/templates/lookup.rst +0 -0
  78. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/docs/narr/templates/overview.rst +0 -0
  79. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/__init__.py +0 -0
  80. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/_version.py +0 -0
  81. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/auth.py +0 -0
  82. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/cli/__init__.py +0 -0
  83. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/cli/webapp.py +0 -0
  84. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/conf.py +0 -0
  85. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/db/__init__.py +0 -0
  86. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/db/continuum.py +0 -0
  87. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/db/sess.py +0 -0
  88. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/email-templates/feedback.html.mako +0 -0
  89. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/email-templates/feedback.txt.mako +0 -0
  90. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/emails.py +0 -0
  91. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/forms/__init__.py +0 -0
  92. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/forms/base.py +0 -0
  93. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/forms/schema.py +0 -0
  94. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/forms/widgets.py +0 -0
  95. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/grids/__init__.py +0 -0
  96. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/grids/base.py +0 -0
  97. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/grids/filters.py +0 -0
  98. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/handler.py +0 -0
  99. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/helpers.py +0 -0
  100. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/menus.py +0 -0
  101. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/progress.py +0 -0
  102. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/static/__init__.py +0 -0
  103. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/static/img/favicon.ico +0 -0
  104. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/static/img/logo.png +0 -0
  105. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/static/img/testing.png +0 -0
  106. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/appinfo/index.mako +0 -0
  107. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/auth/change_password.mako +0 -0
  108. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/auth/login.mako +0 -0
  109. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/base_meta.mako +0 -0
  110. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/batch/view.mako +0 -0
  111. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/configure.mako +0 -0
  112. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/deform/checkbox.pt +0 -0
  113. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/deform/checkbox_choice.pt +0 -0
  114. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/deform/checked_password.pt +0 -0
  115. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/deform/dateinput.pt +0 -0
  116. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/deform/datetimeinput.pt +0 -0
  117. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/deform/moneyinput.pt +0 -0
  118. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/deform/password.pt +0 -0
  119. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/deform/permissions.pt +0 -0
  120. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/deform/readonly/checkbox.pt +0 -0
  121. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/deform/readonly/email_recips.pt +0 -0
  122. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/deform/readonly/filedownload.pt +0 -0
  123. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/deform/readonly/notes.pt +0 -0
  124. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/deform/readonly/objectref.pt +0 -0
  125. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/deform/readonly/permissions.pt +0 -0
  126. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/deform/readonly/rolerefs.pt +0 -0
  127. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/deform/select.pt +0 -0
  128. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/deform/textarea.pt +0 -0
  129. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/deform/textinput.pt +0 -0
  130. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/email/settings/view.mako +0 -0
  131. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/forbidden.mako +0 -0
  132. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/form.mako +0 -0
  133. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/grids/table_element.mako +0 -0
  134. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/home.mako +0 -0
  135. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/master/configure.mako +0 -0
  136. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/master/create.mako +0 -0
  137. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/master/delete.mako +0 -0
  138. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/master/edit.mako +0 -0
  139. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/master/form.mako +0 -0
  140. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/master/index.mako +0 -0
  141. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/master/view.mako +0 -0
  142. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/notfound.mako +0 -0
  143. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/people/view_profile.mako +0 -0
  144. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/progress.mako +0 -0
  145. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/reports/view.mako +0 -0
  146. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/setup.mako +0 -0
  147. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/upgrade.mako +0 -0
  148. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/upgrades/configure.mako +0 -0
  149. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/templates/upgrades/view.mako +0 -0
  150. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/testing.py +0 -0
  151. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/views/__init__.py +0 -0
  152. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/views/auth.py +0 -0
  153. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/views/base.py +0 -0
  154. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/views/batch.py +0 -0
  155. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/views/email.py +0 -0
  156. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/views/essential.py +0 -0
  157. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/views/master.py +0 -0
  158. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/views/people.py +0 -0
  159. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/views/progress.py +0 -0
  160. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/views/reports.py +0 -0
  161. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/views/roles.py +0 -0
  162. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/views/upgrades.py +0 -0
  163. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/src/wuttaweb/views/users.py +0 -0
  164. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tasks.py +0 -0
  165. {wuttaweb-0.21.5/tests/views → wuttaweb-0.22.0/tests}/__init__.py +0 -0
  166. {wuttaweb-0.21.5/tests/grids → wuttaweb-0.22.0/tests/cli}/__init__.py +0 -0
  167. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/cli/test_webapp.py +0 -0
  168. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/db/__init__.py +0 -0
  169. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/db/test_continuum.py +0 -0
  170. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/forms/test_schema.py +0 -0
  171. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/forms/test_widgets.py +0 -0
  172. {wuttaweb-0.21.5/tests/cli → wuttaweb-0.22.0/tests/grids}/__init__.py +0 -0
  173. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/grids/test_base.py +0 -0
  174. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/grids/test_filters.py +0 -0
  175. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/libcache/bb_fontawesome_svg_core.js +0 -0
  176. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/libcache/bb_free_solid_svg_icons.js +0 -0
  177. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/libcache/bb_oruga.js +0 -0
  178. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/libcache/bb_oruga_bulma.css +0 -0
  179. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/libcache/bb_oruga_bulma.js +0 -0
  180. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/libcache/bb_vue.js +0 -0
  181. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/libcache/bb_vue_fontawesome.js +0 -0
  182. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/libcache/buefy.css +0 -0
  183. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/libcache/buefy.js +0 -0
  184. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/libcache/fontawesome.js +0 -0
  185. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/libcache/vue.js +0 -0
  186. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/libcache/vue_resource.js +0 -0
  187. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/test_auth.py +0 -0
  188. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/test_emails.py +0 -0
  189. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/test_handler.py +0 -0
  190. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/test_helpers.py +0 -0
  191. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/test_menus.py +0 -0
  192. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/test_progress.py +0 -0
  193. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/test_static.py +0 -0
  194. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/util.py +0 -0
  195. {wuttaweb-0.21.5/tests → wuttaweb-0.22.0/tests/views}/__init__.py +0 -0
  196. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/views/test___init__.py +0 -0
  197. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/views/test_auth.py +0 -0
  198. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/views/test_base.py +0 -0
  199. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/views/test_batch.py +0 -0
  200. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/views/test_email.py +0 -0
  201. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/views/test_essential.py +0 -0
  202. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/views/test_master.py +0 -0
  203. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/views/test_people.py +0 -0
  204. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/views/test_progress.py +0 -0
  205. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/views/test_reports.py +0 -0
  206. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/views/test_roles.py +0 -0
  207. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/views/test_settings.py +0 -0
  208. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/views/test_upgrades.py +0 -0
  209. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tests/views/test_users.py +0 -0
  210. {wuttaweb-0.21.5 → wuttaweb-0.22.0}/tox.ini +0 -0
@@ -5,6 +5,17 @@ All notable changes to wuttaweb will be documented in this file.
5
5
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
6
6
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## v0.22.0 (2025-06-29)
9
+
10
+ ### Feat
11
+
12
+ - add basic theme system
13
+
14
+ ### Fix
15
+
16
+ - improve styles for testing watermark background image
17
+ - fix timezone offset bug for datepicker
18
+
8
19
  ## v0.21.5 (2025-02-21)
9
20
 
10
21
  ### Fix
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: WuttaWeb
3
- Version: 0.21.5
3
+ Version: 0.22.0
4
4
  Summary: Web App for Wutta Framework
5
5
  Project-URL: Homepage, https://wuttaproject.org/
6
6
  Project-URL: Repository, https://forgejo.wuttaproject.org/wutta/wuttaweb
@@ -39,7 +39,7 @@ Requires-Dist: pyramid-tm
39
39
  Requires-Dist: pyramid>=2
40
40
  Requires-Dist: waitress
41
41
  Requires-Dist: webhelpers2
42
- Requires-Dist: wuttjamaican[db]>=0.20.4
42
+ Requires-Dist: wuttjamaican[db]>=0.20.6
43
43
  Requires-Dist: zope-sqlalchemy>=1.5
44
44
  Provides-Extra: continuum
45
45
  Requires-Dist: wutta-continuum; extra == 'continuum'
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "WuttaWeb"
9
- version = "0.21.5"
9
+ version = "0.22.0"
10
10
  description = "Web App for Wutta Framework"
11
11
  readme = "README.md"
12
12
  authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}]
@@ -44,7 +44,7 @@ dependencies = [
44
44
  "pyramid_tm",
45
45
  "waitress",
46
46
  "WebHelpers2",
47
- "WuttJamaican[db]>=0.20.4",
47
+ "WuttJamaican[db]>=0.20.6",
48
48
  "zope.sqlalchemy>=1.5",
49
49
  ]
50
50
 
@@ -2,7 +2,7 @@
2
2
  ################################################################################
3
3
  #
4
4
  # wuttaweb -- Web App for Wutta Framework
5
- # Copyright © 2024 Lance Edgar
5
+ # Copyright © 2024-2025 Lance Edgar
6
6
  #
7
7
  # This file is part of Wutta Framework.
8
8
  #
@@ -35,6 +35,7 @@ from pyramid.config import Configurator
35
35
 
36
36
  import wuttaweb.db
37
37
  from wuttaweb.auth import WuttaSecurityPolicy
38
+ from wuttaweb.util import get_effective_theme, get_theme_template_path
38
39
 
39
40
 
40
41
  log = logging.getLogger(__name__)
@@ -132,6 +133,9 @@ def make_pyramid_config(settings):
132
133
  settings.setdefault('pyramid_deform.template_search_path',
133
134
  'wuttaweb:templates/deform')
134
135
 
136
+ # update settings per current theme
137
+ establish_theme(settings)
138
+
135
139
  pyramid_config = Configurator(settings=settings)
136
140
 
137
141
  # configure user authorization / authentication
@@ -248,3 +252,33 @@ def make_asgi_app(main_app=None, config=None):
248
252
  """
249
253
  wsgi_app = make_wsgi_app(main_app, config=config)
250
254
  return WsgiToAsgi(wsgi_app)
255
+
256
+
257
+ def establish_theme(settings):
258
+ """
259
+ Establishes initial theme on app startup. This mostly involves
260
+ updating the given ``settings`` dict.
261
+
262
+ This function is called automatically from within
263
+ :func:`make_pyramid_config()`.
264
+
265
+ It will first call :func:`~wuttaweb.util.get_effective_theme()` to
266
+ read the current theme from the :term:`settings table`, and store
267
+ this within ``settings['wuttaweb.theme']``.
268
+
269
+ It then calls :func:`~wuttaweb.util.get_theme_template_path()` and
270
+ will update ``settings['mako.directories']`` such that the theme's
271
+ template path is listed first.
272
+ """
273
+ config = settings['wutta_config']
274
+
275
+ theme = get_effective_theme(config)
276
+ settings['wuttaweb.theme'] = theme
277
+
278
+ directories = settings['mako.directories']
279
+ if isinstance(directories, str):
280
+ directories = config.parse_list(directories)
281
+
282
+ path = get_theme_template_path(config)
283
+ directories.insert(0, path)
284
+ settings['mako.directories'] = directories
@@ -2,7 +2,7 @@
2
2
  ################################################################################
3
3
  #
4
4
  # wuttaweb -- Web App for Wutta Framework
5
- # Copyright © 2024 Lance Edgar
5
+ # Copyright © 2024-2025 Lance Edgar
6
6
  #
7
7
  # This file is part of Wutta Framework.
8
8
  #
@@ -38,11 +38,13 @@ hooks contained here, depending on the circumstance.
38
38
  import functools
39
39
  import json
40
40
  import logging
41
+ from collections import OrderedDict
41
42
 
42
43
  from pyramid import threadlocal
43
44
 
44
45
  from wuttaweb import helpers
45
46
  from wuttaweb.db import Session
47
+ from wuttaweb.util import get_available_themes
46
48
 
47
49
 
48
50
  log = logging.getLogger(__name__)
@@ -79,6 +81,43 @@ def new_request(event):
79
81
  Flag indicating whether the frontend should be displayed using
80
82
  Vue 3 + Oruga (if ``True``), or else Vue 2 + Buefy (if
81
83
  ``False``). This flag is ``False`` by default.
84
+
85
+ .. function:: request.register_component(tagname, classname)
86
+
87
+ Request method which registers a Vue component for use within
88
+ the app templates.
89
+
90
+ :param tagname: Component tag name as string.
91
+
92
+ :param classname: Component class name as string.
93
+
94
+ This is meant to be analogous to the ``Vue.component()`` call
95
+ which is part of Vue 2. It is good practice to always call
96
+ both at the same time/place:
97
+
98
+ .. code-block:: mako
99
+
100
+ ## define component template
101
+ <script type="text/x-template" id="my-example-template">
102
+ <div>my example</div>
103
+ </script>
104
+
105
+ <script>
106
+
107
+ ## define component logic
108
+ const MyExample = {
109
+ template: 'my-example-template'
110
+ }
111
+
112
+ ## register the component both ways here..
113
+
114
+ ## this is for Vue 2 - note the lack of quotes for classname
115
+ Vue.component('my-example', MyExample)
116
+
117
+ ## this is for Vue 3 - note the classname must be quoted
118
+ <% request.register_component('my-example', 'MyExample') %>
119
+
120
+ </script>
82
121
  """
83
122
  request = event.request
84
123
  config = request.registry.settings['wutta_config']
@@ -104,10 +143,34 @@ def new_request(event):
104
143
  if spec:
105
144
  func = app.load_object(spec)
106
145
  return func(request)
146
+
147
+ theme = request.registry.settings.get('wuttaweb.theme')
148
+ if theme == 'butterfly':
149
+ return True
107
150
  return False
108
151
 
109
152
  request.set_property(use_oruga, reify=True)
110
153
 
154
+ def register_component(tagname, classname):
155
+ """
156
+ Register a Vue 3 component, so the base template knows to
157
+ declare it for use within the app (page).
158
+ """
159
+ if not hasattr(request, '_wuttaweb_registered_components'):
160
+ request._wuttaweb_registered_components = OrderedDict()
161
+
162
+ if tagname in request._wuttaweb_registered_components:
163
+ log.warning("component with tagname '%s' already registered "
164
+ "with class '%s' but we are replacing that "
165
+ "with class '%s'",
166
+ tagname,
167
+ request._wuttaweb_registered_components[tagname],
168
+ classname)
169
+
170
+ request._wuttaweb_registered_components[tagname] = classname
171
+
172
+ request.register_component = register_component
173
+
111
174
 
112
175
  def default_user_getter(request, db_session=None):
113
176
  """
@@ -290,6 +353,23 @@ def before_render(event):
290
353
 
291
354
  Reference to the request method,
292
355
  :meth:`~pyramid:pyramid.request.Request.route_url()`.
356
+
357
+ .. data:: 'theme'
358
+
359
+ String name of the current theme. This will be ``'default'``
360
+ unless a custom theme is in effect.
361
+
362
+ .. data:: 'expose_theme_picker'
363
+
364
+ Boolean indicating whether the theme picker should *ever* be
365
+ exposed. For a user to see it, this flag must be true *and*
366
+ the user must have permission to change theme.
367
+
368
+ .. data:: 'available_themes'
369
+
370
+ List of theme names from which user may choose, if they are
371
+ allowed to change theme. Only set/relevant if
372
+ ``expose_theme_picker`` is true (see above).
293
373
  """
294
374
  request = event.get('request') or threadlocal.get_current_request()
295
375
  config = request.wutta_config
@@ -311,6 +391,13 @@ def before_render(event):
311
391
  menus = web.get_menu_handler()
312
392
  context['menus'] = menus.do_make_menus(request)
313
393
 
394
+ # theme
395
+ context['theme'] = request.registry.settings.get('wuttaweb.theme', 'default')
396
+ context['expose_theme_picker'] = config.get_bool('wuttaweb.themes.expose_picker',
397
+ default=False)
398
+ if context['expose_theme_picker']:
399
+ context['available_themes'] = get_available_themes(config)
400
+
314
401
 
315
402
  def includeme(config):
316
403
  config.add_subscriber(new_request, 'pyramid.events.NewRequest')
@@ -39,6 +39,13 @@
39
39
  @input="settingsNeedSaved = true">
40
40
  Production Mode
41
41
  </b-checkbox>
42
+ <span style="width: 1rem;" />
43
+ <b-checkbox name="wuttaweb.themes.expose_picker"
44
+ v-model="simpleSettings['wuttaweb.themes.expose_picker']"
45
+ native-value="true"
46
+ @input="settingsNeedSaved = true">
47
+ Expose Theme Picker
48
+ </b-checkbox>
42
49
  </b-field>
43
50
 
44
51
  <b-field label="Menu Handler">
@@ -130,7 +130,7 @@
130
130
  }
131
131
 
132
132
  % if not request.wutta_config.production():
133
- html, .navbar, .footer {
133
+ html, body, .navbar, .footer {
134
134
  background-image: url(${request.static_url('wuttaweb:static/img/testing.png')});
135
135
  }
136
136
  % endif
@@ -440,7 +440,27 @@
440
440
  </div>
441
441
  </%def>
442
442
 
443
- <%def name="render_theme_picker()"></%def>
443
+ <%def name="render_theme_picker()">
444
+ % if expose_theme_picker and request.has_perm('common.change_theme'):
445
+ <div class="level-item">
446
+ ${h.form(url('change_theme'), method='POST', ref='themePickerForm')}
447
+ ${h.csrf_token(request)}
448
+ <input type="hidden" name="referrer" :value="referrer" />
449
+ <div style="display: flex; align-items: center; gap: 0.5rem;">
450
+ <span>Theme:</span>
451
+ <${b}-select name="theme"
452
+ v-model="globalTheme"
453
+ @input="changeTheme()">
454
+ % for name in available_themes:
455
+ <option value="${name}">${name}</option>
456
+ % endfor
457
+ </${b}-select>
458
+ </div>
459
+ ${h.end_form()}
460
+ </div>
461
+ % endif
462
+
463
+ </%def>
444
464
 
445
465
  <%def name="render_feedback_button()">
446
466
  % if request.has_perm('common.feedback'):
@@ -459,8 +479,8 @@
459
479
  Feedback
460
480
  </b-button>
461
481
 
462
- <b-modal has-modal-card
463
- :active.sync="showDialog">
482
+ <${b}-modal has-modal-card
483
+ :active.sync="showDialog">
464
484
  <div class="modal-card">
465
485
 
466
486
  <header class="modal-card-head">
@@ -507,7 +527,7 @@
507
527
  </b-button>
508
528
  </footer>
509
529
  </div>
510
- </b-modal>
530
+ </${b}-modal>
511
531
 
512
532
  </div>
513
533
  </script>
@@ -631,6 +651,12 @@
631
651
  },
632
652
 
633
653
  % endif
654
+
655
+ % if expose_theme_picker and request.has_perm('common.change_theme'):
656
+ changeTheme() {
657
+ this.$refs.themePickerForm.submit()
658
+ },
659
+ % endif
634
660
  },
635
661
  }
636
662
 
@@ -638,6 +664,10 @@
638
664
  contentTitleHTML: ${json.dumps(capture(self.content_title))|n},
639
665
  referrer: location.href,
640
666
  mountedHooks: [],
667
+
668
+ % if expose_theme_picker and request.has_perm('common.change_theme'):
669
+ globalTheme: ${json.dumps(theme or None)|n},
670
+ % endif
641
671
  }
642
672
 
643
673
  ## declare nested menu visibility toggle flags
@@ -774,11 +804,13 @@
774
804
  <script>
775
805
  WholePage.data = function() { return WholePageData }
776
806
  Vue.component('whole-page', WholePage)
807
+ <% request.register_component('whole-page', 'WholePage') %>
777
808
  </script>
778
809
  % if request.has_perm('common.feedback'):
779
810
  <script>
780
811
  WuttaFeedbackForm.data = function() { return WuttaFeedbackFormData }
781
812
  Vue.component('wutta-feedback-form', WuttaFeedbackForm)
813
+ <% request.register_component('wutta-feedback-form', 'WuttaFeedbackForm') %>
782
814
  </script>
783
815
  % endif
784
816
  </%def>
@@ -95,3 +95,5 @@
95
95
  }
96
96
 
97
97
  </script>
98
+
99
+ <% request.register_component(form.vue_tagname, form.vue_component) %>
@@ -739,3 +739,5 @@
739
739
  }
740
740
 
741
741
  </script>
742
+
743
+ <% request.register_component(grid.vue_tagname, grid.vue_component) %>
@@ -50,6 +50,6 @@
50
50
  <script>
51
51
  ThisPage.data = function() { return ThisPageData }
52
52
  Vue.component('this-page', ThisPage)
53
- ## <% request.register_component('this-page', 'ThisPage') %>
53
+ <% request.register_component('this-page', 'ThisPage') %>
54
54
  </script>
55
55
  </%def>
@@ -0,0 +1,78 @@
1
+ ## -*- coding: utf-8; -*-
2
+ <%inherit file="wuttaweb:templates/base.mako" />
3
+ <%namespace file="/http-plugin.mako" import="make_http_plugin" />
4
+ <%namespace file="/buefy-plugin.mako" import="make_buefy_plugin" />
5
+ <%namespace file="/buefy-components.mako" import="make_buefy_components" />
6
+
7
+ <%def name="core_javascript()">
8
+ <script type="importmap">
9
+ {
10
+ "imports": {
11
+ "vue": "${h.get_liburl(request, 'bb_vue')}",
12
+ "@oruga-ui/oruga-next": "${h.get_liburl(request, 'bb_oruga')}",
13
+ "@oruga-ui/theme-bulma": "${h.get_liburl(request, 'bb_oruga_bulma')}",
14
+ "@fortawesome/fontawesome-svg-core": "${h.get_liburl(request, 'bb_fontawesome_svg_core')}",
15
+ "@fortawesome/free-solid-svg-icons": "${h.get_liburl(request, 'bb_free_solid_svg_icons')}",
16
+ "@fortawesome/vue-fontawesome": "${h.get_liburl(request, 'bb_vue_fontawesome')}"
17
+ }
18
+ }
19
+ </script>
20
+ <script>
21
+ ## nb. empty stub to avoid errors for older buefy templates
22
+ const Vue = {
23
+ component(tagname, classname) {},
24
+ }
25
+ </script>
26
+ </%def>
27
+
28
+ <%def name="core_styles()">
29
+ ${h.stylesheet_link(h.get_liburl(request, 'bb_oruga_bulma_css'))}
30
+ </%def>
31
+
32
+ <%def name="render_vue_templates()">
33
+ ${parent.render_vue_templates()}
34
+ ${make_buefy_components()}
35
+ </%def>
36
+
37
+ <%def name="extra_styles()">
38
+ ${parent.extra_styles()}
39
+ <style>
40
+ html, body, .navbar, .footer {
41
+ background-color: LightYellow;
42
+ }
43
+ </style>
44
+ </%def>
45
+
46
+ <%def name="make_vue_app()">
47
+ ${make_http_plugin()}
48
+ ${make_buefy_plugin()}
49
+ <script type="module">
50
+ import { createApp } from 'vue'
51
+ import { Oruga } from '@oruga-ui/oruga-next'
52
+ import { bulmaConfig } from '@oruga-ui/theme-bulma'
53
+ import { library } from "@fortawesome/fontawesome-svg-core"
54
+ import { fas } from "@fortawesome/free-solid-svg-icons"
55
+ import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"
56
+ library.add(fas)
57
+
58
+ const app = createApp()
59
+ app.component('vue-fontawesome', FontAwesomeIcon)
60
+
61
+ % if hasattr(request, '_wuttaweb_registered_components'):
62
+ % for tagname, classname in request._wuttaweb_registered_components.items():
63
+ app.component('${tagname}', ${classname})
64
+ % endfor
65
+ % endif
66
+
67
+ app.use(Oruga, {
68
+ ...bulmaConfig,
69
+ iconComponent: 'vue-fontawesome',
70
+ iconPack: 'fas',
71
+ })
72
+
73
+ app.use(HttpPlugin)
74
+ app.use(BuefyPlugin)
75
+
76
+ app.mount('#app')
77
+ </script>
78
+ </%def>