WuttaWeb 0.20.5__tar.gz → 0.20.6__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 (205) hide show
  1. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/CHANGELOG.md +12 -0
  2. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/PKG-INFO +1 -1
  3. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/pyproject.toml +1 -1
  4. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/cli/webapp.py +1 -0
  5. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/grids/base.py +16 -0
  6. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/menus.py +3 -1
  7. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/base.mako +10 -6
  8. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/views/common.py +13 -0
  9. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/views/roles.py +35 -4
  10. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/cli/test_webapp.py +4 -2
  11. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/grids/test_base.py +18 -0
  12. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/views/test_roles.py +22 -0
  13. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/.gitignore +0 -0
  14. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/COPYING.txt +0 -0
  15. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/README.md +0 -0
  16. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/Makefile +0 -0
  17. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/_static/.keepme +0 -0
  18. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.app.rst +0 -0
  19. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.auth.rst +0 -0
  20. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.cli.rst +0 -0
  21. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.cli.webapp.rst +0 -0
  22. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.conf.rst +0 -0
  23. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.db.continuum.rst +0 -0
  24. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.db.rst +0 -0
  25. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.db.sess.rst +0 -0
  26. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.emails.rst +0 -0
  27. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.forms.base.rst +0 -0
  28. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.forms.rst +0 -0
  29. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.forms.schema.rst +0 -0
  30. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.forms.widgets.rst +0 -0
  31. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.grids.base.rst +0 -0
  32. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.grids.filters.rst +0 -0
  33. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.grids.rst +0 -0
  34. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.handler.rst +0 -0
  35. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.helpers.rst +0 -0
  36. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.menus.rst +0 -0
  37. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.progress.rst +0 -0
  38. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.rst +0 -0
  39. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.static.rst +0 -0
  40. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.subscribers.rst +0 -0
  41. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.util.rst +0 -0
  42. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.views.auth.rst +0 -0
  43. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.views.base.rst +0 -0
  44. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.views.batch.rst +0 -0
  45. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.views.common.rst +0 -0
  46. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.views.email.rst +0 -0
  47. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.views.essential.rst +0 -0
  48. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.views.master.rst +0 -0
  49. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.views.people.rst +0 -0
  50. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.views.progress.rst +0 -0
  51. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.views.reports.rst +0 -0
  52. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.views.roles.rst +0 -0
  53. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.views.rst +0 -0
  54. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.views.settings.rst +0 -0
  55. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.views.upgrades.rst +0 -0
  56. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/api/wuttaweb.views.users.rst +0 -0
  57. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/conf.py +0 -0
  58. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/glossary.rst +0 -0
  59. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/index.rst +0 -0
  60. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/make.bat +0 -0
  61. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/narr/cli/builtin.rst +0 -0
  62. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/narr/cli/index.rst +0 -0
  63. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/narr/templates/base.rst +0 -0
  64. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/narr/templates/index.rst +0 -0
  65. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/narr/templates/lookup.rst +0 -0
  66. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/docs/narr/templates/overview.rst +0 -0
  67. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/__init__.py +0 -0
  68. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/_version.py +0 -0
  69. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/app.py +0 -0
  70. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/auth.py +0 -0
  71. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/cli/__init__.py +0 -0
  72. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/conf.py +0 -0
  73. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/db/__init__.py +0 -0
  74. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/db/continuum.py +0 -0
  75. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/db/sess.py +0 -0
  76. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/email-templates/feedback.html.mako +0 -0
  77. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/email-templates/feedback.txt.mako +0 -0
  78. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/emails.py +0 -0
  79. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/forms/__init__.py +0 -0
  80. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/forms/base.py +0 -0
  81. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/forms/schema.py +0 -0
  82. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/forms/widgets.py +0 -0
  83. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/grids/__init__.py +0 -0
  84. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/grids/filters.py +0 -0
  85. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/handler.py +0 -0
  86. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/helpers.py +0 -0
  87. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/progress.py +0 -0
  88. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/static/__init__.py +0 -0
  89. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/static/img/favicon.ico +0 -0
  90. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/static/img/logo.png +0 -0
  91. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/static/img/testing.png +0 -0
  92. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/subscribers.py +0 -0
  93. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/appinfo/configure.mako +0 -0
  94. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/appinfo/index.mako +0 -0
  95. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/auth/change_password.mako +0 -0
  96. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/auth/login.mako +0 -0
  97. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/base_meta.mako +0 -0
  98. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/batch/view.mako +0 -0
  99. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/configure.mako +0 -0
  100. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/deform/checkbox.pt +0 -0
  101. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/deform/checkbox_choice.pt +0 -0
  102. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/deform/checked_password.pt +0 -0
  103. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/deform/dateinput.pt +0 -0
  104. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/deform/datetimeinput.pt +0 -0
  105. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/deform/moneyinput.pt +0 -0
  106. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/deform/password.pt +0 -0
  107. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/deform/permissions.pt +0 -0
  108. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/deform/readonly/checkbox.pt +0 -0
  109. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/deform/readonly/email_recips.pt +0 -0
  110. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/deform/readonly/filedownload.pt +0 -0
  111. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/deform/readonly/notes.pt +0 -0
  112. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/deform/readonly/objectref.pt +0 -0
  113. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/deform/readonly/permissions.pt +0 -0
  114. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/deform/readonly/rolerefs.pt +0 -0
  115. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/deform/select.pt +0 -0
  116. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/deform/textarea.pt +0 -0
  117. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/deform/textinput.pt +0 -0
  118. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/email/settings/view.mako +0 -0
  119. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/forbidden.mako +0 -0
  120. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/form.mako +0 -0
  121. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/forms/vue_template.mako +0 -0
  122. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/grids/table_element.mako +0 -0
  123. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/grids/vue_template.mako +0 -0
  124. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/home.mako +0 -0
  125. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/master/configure.mako +0 -0
  126. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/master/create.mako +0 -0
  127. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/master/delete.mako +0 -0
  128. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/master/edit.mako +0 -0
  129. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/master/form.mako +0 -0
  130. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/master/index.mako +0 -0
  131. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/master/view.mako +0 -0
  132. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/notfound.mako +0 -0
  133. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/page.mako +0 -0
  134. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/people/view_profile.mako +0 -0
  135. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/progress.mako +0 -0
  136. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/reports/view.mako +0 -0
  137. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/setup.mako +0 -0
  138. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/upgrade.mako +0 -0
  139. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/upgrades/configure.mako +0 -0
  140. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/upgrades/view.mako +0 -0
  141. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/templates/wutta-components.mako +0 -0
  142. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/testing.py +0 -0
  143. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/util.py +0 -0
  144. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/views/__init__.py +0 -0
  145. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/views/auth.py +0 -0
  146. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/views/base.py +0 -0
  147. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/views/batch.py +0 -0
  148. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/views/email.py +0 -0
  149. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/views/essential.py +0 -0
  150. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/views/master.py +0 -0
  151. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/views/people.py +0 -0
  152. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/views/progress.py +0 -0
  153. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/views/reports.py +0 -0
  154. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/views/settings.py +0 -0
  155. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/views/upgrades.py +0 -0
  156. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/src/wuttaweb/views/users.py +0 -0
  157. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tasks.py +0 -0
  158. {wuttaweb-0.20.5/tests/views → wuttaweb-0.20.6/tests}/__init__.py +0 -0
  159. {wuttaweb-0.20.5/tests/grids → wuttaweb-0.20.6/tests/cli}/__init__.py +0 -0
  160. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/db/__init__.py +0 -0
  161. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/db/test_continuum.py +0 -0
  162. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/forms/test_base.py +0 -0
  163. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/forms/test_schema.py +0 -0
  164. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/forms/test_widgets.py +0 -0
  165. {wuttaweb-0.20.5/tests/cli → wuttaweb-0.20.6/tests/grids}/__init__.py +0 -0
  166. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/grids/test_filters.py +0 -0
  167. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/libcache/bb_fontawesome_svg_core.js +0 -0
  168. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/libcache/bb_free_solid_svg_icons.js +0 -0
  169. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/libcache/bb_oruga.js +0 -0
  170. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/libcache/bb_oruga_bulma.css +0 -0
  171. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/libcache/bb_oruga_bulma.js +0 -0
  172. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/libcache/bb_vue.js +0 -0
  173. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/libcache/bb_vue_fontawesome.js +0 -0
  174. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/libcache/buefy.css +0 -0
  175. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/libcache/buefy.js +0 -0
  176. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/libcache/fontawesome.js +0 -0
  177. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/libcache/vue.js +0 -0
  178. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/libcache/vue_resource.js +0 -0
  179. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/test_app.py +0 -0
  180. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/test_auth.py +0 -0
  181. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/test_emails.py +0 -0
  182. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/test_handler.py +0 -0
  183. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/test_helpers.py +0 -0
  184. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/test_menus.py +0 -0
  185. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/test_progress.py +0 -0
  186. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/test_static.py +0 -0
  187. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/test_subscribers.py +0 -0
  188. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/test_util.py +0 -0
  189. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/util.py +0 -0
  190. {wuttaweb-0.20.5/tests → wuttaweb-0.20.6/tests/views}/__init__.py +0 -0
  191. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/views/test___init__.py +0 -0
  192. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/views/test_auth.py +0 -0
  193. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/views/test_base.py +0 -0
  194. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/views/test_batch.py +0 -0
  195. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/views/test_common.py +0 -0
  196. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/views/test_email.py +0 -0
  197. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/views/test_essential.py +0 -0
  198. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/views/test_master.py +0 -0
  199. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/views/test_people.py +0 -0
  200. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/views/test_progress.py +0 -0
  201. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/views/test_reports.py +0 -0
  202. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/views/test_settings.py +0 -0
  203. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/views/test_upgrades.py +0 -0
  204. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tests/views/test_users.py +0 -0
  205. {wuttaweb-0.20.5 → wuttaweb-0.20.6}/tox.ini +0 -0
@@ -5,6 +5,18 @@ 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.20.6 (2025-01-26)
9
+
10
+ ### Fix
11
+
12
+ - add `setup_enhance_admin_user()` method for initial setup
13
+ - add `render_percent()` method for Grid
14
+ - allow override for Admin menu title
15
+ - add `index_title_controls()` def block for base template
16
+ - add `make_users_grid()` method for RoleView
17
+ - fallback to empty string for uvicorn `root_path`
18
+ - add `root_path` config setting for running webapp via uvicorn
19
+
8
20
  ## v0.20.5 (2025-01-23)
9
21
 
10
22
  ### Fix
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: WuttaWeb
3
- Version: 0.20.5
3
+ Version: 0.20.6
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
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "WuttaWeb"
9
- version = "0.20.5"
9
+ version = "0.20.6"
10
10
  description = "Web App for Wutta Framework"
11
11
  readme = "README.md"
12
12
  authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}]
@@ -74,6 +74,7 @@ def webapp(
74
74
  'reload_dirs': config.get_list(f'{config.appname}.web.app.reload_dirs'),
75
75
  'factory': config.get_bool(f'{config.appname}.web.app.factory', default=False),
76
76
  'interface': config.get(f'{config.appname}.web.app.interface', default='auto'),
77
+ 'root_path': config.get(f'{config.appname}.web.app.root_path', default=''),
77
78
  }
78
79
 
79
80
  # also must inject our config files to env, since there is no
@@ -612,6 +612,7 @@ class Grid:
612
612
  * ``'date'`` -> :meth:`render_date()`
613
613
  * ``'datetime'`` -> :meth:`render_datetime()`
614
614
  * ``'quantity'`` -> :meth:`render_quantity()`
615
+ * ``'percent'`` -> :meth:`render_percent()`
615
616
 
616
617
  Renderer overrides are tracked via :attr:`renderers`.
617
618
  """
@@ -622,6 +623,7 @@ class Grid:
622
623
  'date': self.render_date,
623
624
  'datetime': self.render_datetime,
624
625
  'quantity': self.render_quantity,
626
+ 'percent': self.render_percent,
625
627
  }
626
628
 
627
629
  if renderer in builtins:
@@ -1884,6 +1886,20 @@ class Grid:
1884
1886
  dt = getattr(obj, key)
1885
1887
  return self.app.render_datetime(dt)
1886
1888
 
1889
+ def render_percent(self, obj, key, value, **kwargs):
1890
+ """
1891
+ Column renderer for percentage values.
1892
+
1893
+ This calls
1894
+ :meth:`~wuttjamaican:wuttjamaican.app.AppHandler.render_percent()`
1895
+ for the return value.
1896
+
1897
+ This is not used automatically but you can use it explicitly::
1898
+
1899
+ grid.set_renderer('foo', 'percent')
1900
+ """
1901
+ return self.app.render_percent(value, **kwargs)
1902
+
1887
1903
  def render_quantity(self, obj, key, value):
1888
1904
  """
1889
1905
  Column renderer for quantity values.
@@ -143,6 +143,8 @@ class MenuHandler(GenericHandler):
143
143
  which will ultimately be one element of the final list of
144
144
  dicts as described in :class:`MenuHandler`.
145
145
 
146
+ :param title: Override the menu title; default is "Admin".
147
+
146
148
  :param include_people: You can pass this flag to indicate the
147
149
  admin menu should contain an entry for the "People" view.
148
150
  """
@@ -198,7 +200,7 @@ class MenuHandler(GenericHandler):
198
200
  ])
199
201
 
200
202
  return {
201
- 'title': "Admin",
203
+ 'title': kwargs.get('title', "Admin"),
202
204
  'type': 'menu',
203
205
  'items': items,
204
206
  }
@@ -248,12 +248,7 @@
248
248
  % else:
249
249
  <h1 class="title">${index_title}</h1>
250
250
  % endif
251
- % if master and master.creatable and not master.creating and master.has_perm('create'):
252
- <wutta-button once type="is-primary"
253
- tag="a" href="${url(f'{route_prefix}.create')}"
254
- icon-left="plus"
255
- label="Create New" />
256
- % endif
251
+ ${self.index_title_controls()}
257
252
  % endif
258
253
  </div>
259
254
  </div>
@@ -349,6 +344,15 @@
349
344
  </footer>
350
345
  </%def>
351
346
 
347
+ <%def name="index_title_controls()">
348
+ % if master and master.creatable and not master.creating and master.has_perm('create'):
349
+ <wutta-button once type="is-primary"
350
+ tag="a" href="${url(f'{route_prefix}.create')}"
351
+ icon-left="plus"
352
+ label="Create New" />
353
+ % endif
354
+ </%def>
355
+
352
356
  <%def name="render_vue_template_whole_page()">
353
357
  <script type="text/x-template" id="whole-page-template">
354
358
 
@@ -245,6 +245,8 @@ class CommonView(View):
245
245
  session.add(person)
246
246
  user.person = person
247
247
 
248
+ self.setup_enhance_admin_user(user)
249
+
248
250
  # send user to /login
249
251
  self.request.session.flash("Account created! Please login below.")
250
252
  return self.redirect(self.request.route_url('login'))
@@ -254,6 +256,17 @@ class CommonView(View):
254
256
  'form': form,
255
257
  }
256
258
 
259
+ def setup_enhance_admin_user(self, user):
260
+ """
261
+ Further "enhance" the initial admin user when it is first created.
262
+
263
+ This does nothing by default; subclass can override if needed.
264
+
265
+ :param user: New admin
266
+ :class:`~wuttjamaican:wuttjamaican.db.model.auth.User`
267
+ which was just created as part of initial setup.
268
+ """
269
+
257
270
  @classmethod
258
271
  def defaults(cls, config):
259
272
  cls._defaults(config)
@@ -28,7 +28,7 @@ from wuttjamaican.db.model import Role, Permission
28
28
  from wuttaweb.views import MasterView
29
29
  from wuttaweb.db import Session
30
30
  from wuttaweb.forms import widgets
31
- from wuttaweb.forms.schema import UserRefs, Permissions, RoleRef
31
+ from wuttaweb.forms.schema import Permissions, RoleRef
32
32
 
33
33
 
34
34
  class RoleView(MasterView):
@@ -123,9 +123,7 @@ class RoleView(MasterView):
123
123
  # users
124
124
  if not (self.creating or self.editing):
125
125
  f.append('users')
126
- f.set_readonly('users')
127
- f.set_node('users', UserRefs(self.request))
128
- f.set_default('users', [u.uuid for u in role.users])
126
+ f.set_grid('users', self.make_users_grid(role))
129
127
 
130
128
  # permissions
131
129
  f.append('permissions')
@@ -134,6 +132,39 @@ class RoleView(MasterView):
134
132
  if not self.creating:
135
133
  f.set_default('permissions', list(role.permissions))
136
134
 
135
+ def make_users_grid(self, role):
136
+ """
137
+ Make and return the grid for the Users field.
138
+
139
+ This grid is shown for the Users field when viewing a Role.
140
+
141
+ :returns: Fully configured :class:`~wuttaweb.grids.base.Grid`
142
+ instance.
143
+ """
144
+ model = self.app.model
145
+ route_prefix = self.get_route_prefix()
146
+
147
+ grid = self.make_grid(key=f'{route_prefix}.view.users',
148
+ model_class=model.User,
149
+ data=role.users,
150
+ columns=[
151
+ 'username',
152
+ 'person',
153
+ 'active',
154
+ ])
155
+
156
+ if self.request.has_perm('users.view'):
157
+ url = lambda user, i: self.request.route_url('users.view', uuid=user.uuid)
158
+ grid.add_action('view', icon='eye', url=url)
159
+ grid.set_link('person')
160
+ grid.set_link('username')
161
+
162
+ if self.request.has_perm('users.edit'):
163
+ url = lambda user, i: self.request.route_url('users.edit', uuid=user.uuid)
164
+ grid.add_action('edit', url=url)
165
+
166
+ return grid
167
+
137
168
  def unique_name(self, node, value):
138
169
  """ """
139
170
  model = self.app.model
@@ -88,7 +88,8 @@ app.spec = wuttaweb.app:make_wsgi_app
88
88
  reload=False,
89
89
  reload_dirs=None,
90
90
  factory=False,
91
- interface='auto')
91
+ interface='auto',
92
+ root_path='')
92
93
 
93
94
  # with reload
94
95
  uvicorn.run.reset_mock()
@@ -101,4 +102,5 @@ app.spec = wuttaweb.app:make_wsgi_app
101
102
  reload=True,
102
103
  reload_dirs=None,
103
104
  factory=False,
104
- interface='auto')
105
+ interface='auto',
106
+ root_path='')
@@ -1409,6 +1409,24 @@ class TestGrid(WebTestCase):
1409
1409
  value = decimal.Decimal('-42.42')
1410
1410
  self.assertEqual(grid.render_currency(obj, 'foo', value), '($42.42)')
1411
1411
 
1412
+ def test_render_percent(self):
1413
+ grid = self.make_grid(columns=['foo', 'bar'])
1414
+ obj = MagicMock()
1415
+
1416
+ # null
1417
+ self.assertEqual(grid.render_percent(obj, 'foo', None), "")
1418
+
1419
+ # typical
1420
+ self.assertEqual(grid.render_percent(obj, 'foo', 12.3419), '12.34 %')
1421
+
1422
+ # more decimal places
1423
+ self.assertEqual(grid.render_percent(obj, 'foo', 12.3419, decimals=3), '12.342 %')
1424
+ self.assertEqual(grid.render_percent(obj, 'foo', 12.3419, decimals=4), '12.3419 %')
1425
+
1426
+ # negative
1427
+ self.assertEqual(grid.render_percent(obj, 'foo', -12.3419), '(12.34 %)')
1428
+ self.assertEqual(grid.render_percent(obj, 'foo', -12.3419, decimals=3), '(12.342 %)')
1429
+
1412
1430
  def test_render_quantity(self):
1413
1431
  grid = self.make_grid(columns=['foo', 'bar'])
1414
1432
  obj = MagicMock()
@@ -7,6 +7,7 @@ from sqlalchemy import orm
7
7
  import colander
8
8
 
9
9
  from wuttaweb.views import roles as mod
10
+ from wuttaweb.grids import Grid
10
11
  from wuttaweb.forms.schema import RoleRef
11
12
  from wuttaweb.testing import WebTestCase
12
13
 
@@ -93,6 +94,27 @@ class TestRoleView(WebTestCase):
93
94
  view.configure_form(form)
94
95
  self.assertIsNotNone(form.validators['name'])
95
96
 
97
+ def test_make_users_grid(self):
98
+ model = self.app.model
99
+ view = self.make_view()
100
+ role = model.Role(name="Manager")
101
+
102
+ # basic
103
+ grid = view.make_users_grid(role)
104
+ self.assertIsInstance(grid, Grid)
105
+ self.assertFalse(grid.linked_columns)
106
+ self.assertFalse(grid.actions)
107
+
108
+ # view + edit actions
109
+ with patch.object(self.request, 'is_root', new=True):
110
+ grid = view.make_users_grid(role)
111
+ self.assertIsInstance(grid, Grid)
112
+ self.assertIn('person', grid.linked_columns)
113
+ self.assertIn('username', grid.linked_columns)
114
+ self.assertEqual(len(grid.actions), 2)
115
+ self.assertEqual(grid.actions[0].key, 'view')
116
+ self.assertEqual(grid.actions[1].key, 'edit')
117
+
96
118
  def test_unique_name(self):
97
119
  model = self.app.model
98
120
  view = self.make_view()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes