WuttaWeb 0.22.0__tar.gz → 0.23.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 (212) hide show
  1. wuttaweb-0.23.0/.hgignore +3 -0
  2. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/CHANGELOG.md +18 -0
  3. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/PKG-INFO +2 -2
  4. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/pyproject.toml +2 -2
  5. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/forms/widgets.py +16 -1
  6. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/grids/base.py +32 -3
  7. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/appinfo/configure.mako +10 -5
  8. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/base.mako +7 -3
  9. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/deform/checked_password.pt +2 -0
  10. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/deform/dateinput.pt +2 -1
  11. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/deform/datetimeinput.pt +2 -0
  12. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/deform/moneyinput.pt +1 -0
  13. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/deform/password.pt +1 -0
  14. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/deform/textarea.pt +1 -0
  15. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/deform/textinput.pt +1 -0
  16. wuttaweb-0.23.0/src/wuttaweb/templates/deform/wutta_checked_password.pt +8 -0
  17. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/grids/table_element.mako +20 -1
  18. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/themes/butterfly/buefy-components.mako +71 -29
  19. wuttaweb-0.23.0/src/wuttaweb/templates/users/view.mako +126 -0
  20. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/wutta-components.mako +49 -0
  21. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/util.py +7 -7
  22. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/views/auth.py +7 -2
  23. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/views/users.py +128 -0
  24. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/grids/test_base.py +44 -0
  25. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/test_util.py +14 -14
  26. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/views/test_users.py +118 -0
  27. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/.gitignore +0 -0
  28. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/COPYING.txt +0 -0
  29. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/README.md +0 -0
  30. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/Makefile +0 -0
  31. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/_static/.keepme +0 -0
  32. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.app.rst +0 -0
  33. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.auth.rst +0 -0
  34. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.cli.rst +0 -0
  35. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.cli.webapp.rst +0 -0
  36. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.conf.rst +0 -0
  37. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.db.continuum.rst +0 -0
  38. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.db.rst +0 -0
  39. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.db.sess.rst +0 -0
  40. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.emails.rst +0 -0
  41. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.forms.base.rst +0 -0
  42. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.forms.rst +0 -0
  43. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.forms.schema.rst +0 -0
  44. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.forms.widgets.rst +0 -0
  45. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.grids.base.rst +0 -0
  46. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.grids.filters.rst +0 -0
  47. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.grids.rst +0 -0
  48. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.handler.rst +0 -0
  49. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.helpers.rst +0 -0
  50. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.menus.rst +0 -0
  51. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.progress.rst +0 -0
  52. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.rst +0 -0
  53. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.static.rst +0 -0
  54. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.subscribers.rst +0 -0
  55. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.util.rst +0 -0
  56. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.views.auth.rst +0 -0
  57. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.views.base.rst +0 -0
  58. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.views.batch.rst +0 -0
  59. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.views.common.rst +0 -0
  60. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.views.email.rst +0 -0
  61. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.views.essential.rst +0 -0
  62. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.views.master.rst +0 -0
  63. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.views.people.rst +0 -0
  64. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.views.progress.rst +0 -0
  65. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.views.reports.rst +0 -0
  66. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.views.roles.rst +0 -0
  67. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.views.rst +0 -0
  68. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.views.settings.rst +0 -0
  69. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.views.upgrades.rst +0 -0
  70. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/api/wuttaweb.views.users.rst +0 -0
  71. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/conf.py +0 -0
  72. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/glossary.rst +0 -0
  73. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/index.rst +0 -0
  74. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/make.bat +0 -0
  75. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/narr/cli/builtin.rst +0 -0
  76. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/narr/cli/index.rst +0 -0
  77. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/narr/templates/base.rst +0 -0
  78. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/narr/templates/index.rst +0 -0
  79. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/narr/templates/lookup.rst +0 -0
  80. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/docs/narr/templates/overview.rst +0 -0
  81. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/__init__.py +0 -0
  82. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/_version.py +0 -0
  83. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/app.py +0 -0
  84. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/auth.py +0 -0
  85. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/cli/__init__.py +0 -0
  86. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/cli/webapp.py +0 -0
  87. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/conf.py +0 -0
  88. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/db/__init__.py +0 -0
  89. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/db/continuum.py +0 -0
  90. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/db/sess.py +0 -0
  91. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/email-templates/feedback.html.mako +0 -0
  92. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/email-templates/feedback.txt.mako +0 -0
  93. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/emails.py +0 -0
  94. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/forms/__init__.py +0 -0
  95. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/forms/base.py +0 -0
  96. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/forms/schema.py +0 -0
  97. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/grids/__init__.py +0 -0
  98. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/grids/filters.py +0 -0
  99. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/handler.py +0 -0
  100. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/helpers.py +0 -0
  101. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/menus.py +0 -0
  102. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/progress.py +0 -0
  103. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/static/__init__.py +0 -0
  104. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/static/img/favicon.ico +0 -0
  105. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/static/img/logo.png +0 -0
  106. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/static/img/testing.png +0 -0
  107. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/subscribers.py +0 -0
  108. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/appinfo/index.mako +0 -0
  109. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/auth/change_password.mako +0 -0
  110. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/auth/login.mako +0 -0
  111. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/base_meta.mako +0 -0
  112. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/batch/view.mako +0 -0
  113. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/configure.mako +0 -0
  114. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/deform/checkbox.pt +0 -0
  115. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/deform/checkbox_choice.pt +0 -0
  116. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/deform/permissions.pt +0 -0
  117. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/deform/readonly/checkbox.pt +0 -0
  118. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/deform/readonly/email_recips.pt +0 -0
  119. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/deform/readonly/filedownload.pt +0 -0
  120. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/deform/readonly/notes.pt +0 -0
  121. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/deform/readonly/objectref.pt +0 -0
  122. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/deform/readonly/permissions.pt +0 -0
  123. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/deform/readonly/rolerefs.pt +0 -0
  124. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/deform/select.pt +0 -0
  125. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/email/settings/view.mako +0 -0
  126. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/forbidden.mako +0 -0
  127. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/form.mako +0 -0
  128. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/forms/vue_template.mako +0 -0
  129. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/grids/vue_template.mako +0 -0
  130. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/home.mako +0 -0
  131. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/master/configure.mako +0 -0
  132. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/master/create.mako +0 -0
  133. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/master/delete.mako +0 -0
  134. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/master/edit.mako +0 -0
  135. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/master/form.mako +0 -0
  136. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/master/index.mako +0 -0
  137. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/master/view.mako +0 -0
  138. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/notfound.mako +0 -0
  139. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/page.mako +0 -0
  140. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/people/view_profile.mako +0 -0
  141. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/progress.mako +0 -0
  142. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/reports/view.mako +0 -0
  143. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/setup.mako +0 -0
  144. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/themes/butterfly/base.mako +0 -0
  145. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/themes/butterfly/buefy-plugin.mako +0 -0
  146. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/themes/butterfly/http-plugin.mako +0 -0
  147. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/upgrade.mako +0 -0
  148. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/upgrades/configure.mako +0 -0
  149. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/templates/upgrades/view.mako +0 -0
  150. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/testing.py +0 -0
  151. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/views/__init__.py +0 -0
  152. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/views/base.py +0 -0
  153. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/views/batch.py +0 -0
  154. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/views/common.py +0 -0
  155. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/views/email.py +0 -0
  156. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/views/essential.py +0 -0
  157. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/views/master.py +0 -0
  158. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/views/people.py +0 -0
  159. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/views/progress.py +0 -0
  160. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/views/reports.py +0 -0
  161. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/views/roles.py +0 -0
  162. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/views/settings.py +0 -0
  163. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/src/wuttaweb/views/upgrades.py +0 -0
  164. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tasks.py +0 -0
  165. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/__init__.py +0 -0
  166. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/cli/__init__.py +0 -0
  167. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/cli/test_webapp.py +0 -0
  168. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/db/__init__.py +0 -0
  169. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/db/test_continuum.py +0 -0
  170. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/forms/test_base.py +0 -0
  171. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/forms/test_schema.py +0 -0
  172. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/forms/test_widgets.py +0 -0
  173. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/grids/__init__.py +0 -0
  174. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/grids/test_filters.py +0 -0
  175. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/libcache/bb_fontawesome_svg_core.js +0 -0
  176. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/libcache/bb_free_solid_svg_icons.js +0 -0
  177. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/libcache/bb_oruga.js +0 -0
  178. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/libcache/bb_oruga_bulma.css +0 -0
  179. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/libcache/bb_oruga_bulma.js +0 -0
  180. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/libcache/bb_vue.js +0 -0
  181. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/libcache/bb_vue_fontawesome.js +0 -0
  182. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/libcache/buefy.css +0 -0
  183. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/libcache/buefy.js +0 -0
  184. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/libcache/fontawesome.js +0 -0
  185. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/libcache/vue.js +0 -0
  186. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/libcache/vue_resource.js +0 -0
  187. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/test_app.py +0 -0
  188. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/test_auth.py +0 -0
  189. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/test_emails.py +0 -0
  190. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/test_handler.py +0 -0
  191. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/test_helpers.py +0 -0
  192. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/test_menus.py +0 -0
  193. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/test_progress.py +0 -0
  194. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/test_static.py +0 -0
  195. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/test_subscribers.py +0 -0
  196. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/util.py +0 -0
  197. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/views/__init__.py +0 -0
  198. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/views/test___init__.py +0 -0
  199. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/views/test_auth.py +0 -0
  200. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/views/test_base.py +0 -0
  201. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/views/test_batch.py +0 -0
  202. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/views/test_common.py +0 -0
  203. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/views/test_email.py +0 -0
  204. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/views/test_essential.py +0 -0
  205. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/views/test_master.py +0 -0
  206. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/views/test_people.py +0 -0
  207. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/views/test_progress.py +0 -0
  208. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/views/test_reports.py +0 -0
  209. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/views/test_roles.py +0 -0
  210. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/views/test_settings.py +0 -0
  211. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tests/views/test_upgrades.py +0 -0
  212. {wuttaweb-0.22.0 → wuttaweb-0.23.0}/tox.ini +0 -0
@@ -0,0 +1,3 @@
1
+ syntax:glob
2
+ *.pyc
3
+ *~
@@ -5,6 +5,24 @@ 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.23.0 (2025-08-09)
9
+
10
+ ### Feat
11
+
12
+ - add tools to manage user API tokens
13
+
14
+ ### Fix
15
+
16
+ - add default sorter, tools for basic table-element grid
17
+ - add custom password+confirmation widget for Vue3 + Oruga
18
+ - fix butterfly wrapper for b-notification component
19
+ - add butterfly wrapper for b-timepicker component
20
+ - style tweaks for butterfly/oruga; mostly expand fields
21
+ - fix b-datepicker component wrapper per oruga 0.9.0
22
+ - fix b-button component wrapper per oruga 0.9.0
23
+ - update butterfly component for b-autocomplete, per oruga 0.11.4
24
+ - update default versions for Vue3 + Oruga + FontAwesome
25
+
8
26
  ## v0.22.0 (2025-06-29)
9
27
 
10
28
  ### Feat
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: WuttaWeb
3
- Version: 0.22.0
3
+ Version: 0.23.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.6
42
+ Requires-Dist: wuttjamaican[db]>=0.22.0
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.22.0"
9
+ version = "0.23.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.6",
47
+ "WuttJamaican[db]>=0.22.0",
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
  #
@@ -153,6 +153,21 @@ class WuttaCheckboxChoiceWidget(CheckboxChoiceWidget):
153
153
  self.app = self.config.get_app()
154
154
 
155
155
 
156
+ class WuttaCheckedPasswordWidget(PasswordWidget):
157
+ """
158
+ Custom widget for password+confirmation field.
159
+
160
+ This widget is used only for Vue 3 + Oruga, but is *not* used for
161
+ Vue 2 + Buefy.
162
+
163
+ This is a subclass of :class:`deform:deform.widget.PasswordWidget`
164
+ and uses these Deform templates:
165
+
166
+ * ``wutta_checked_password``
167
+ """
168
+ template = 'wutta_checked_password'
169
+
170
+
156
171
  class WuttaDateWidget(DateInputWidget):
157
172
  """
158
173
  Custom widget for :class:`python:datetime.date` fields.
@@ -2041,9 +2041,9 @@ class Grid:
2041
2041
  """
2042
2042
  Render a simple Vue table element for the grid.
2043
2043
 
2044
- This is what you want for a "simple" grid which does require a
2045
- unique Vue component, but can instead use the standard table
2046
- component.
2044
+ This is what you want for a "simple" grid which does not
2045
+ require a unique Vue component, but can instead use the
2046
+ standard table component.
2047
2047
 
2048
2048
  This returns something like:
2049
2049
 
@@ -2227,6 +2227,35 @@ class Grid:
2227
2227
  'order': sorter['dir']})
2228
2228
  return sorters
2229
2229
 
2230
+ def get_vue_first_sorter(self):
2231
+ """
2232
+ Returns the first active sorter, if applicable.
2233
+
2234
+ This method is used to declare the initial sort for a simple
2235
+ table component, i.e. for use with the ``table-element.mako``
2236
+ template. It generally is assumed that frontend sorting is in
2237
+ use, as opposed to backend sorting, although it should work
2238
+ for either scenario.
2239
+
2240
+ This checks :attr:`active_sorters` and if set, will use the
2241
+ first sorter from that. Note that ``active_sorters`` will
2242
+ *not* be set unless :meth:`load_settings()` has been called.
2243
+
2244
+ Otherwise this will use the first sorter from
2245
+ :attr:`sort_defaults` which is defined in constructor.
2246
+
2247
+ :returns: The first sorter in format ``[sortkey, sortdir]``,
2248
+ or ``None``.
2249
+ """
2250
+ if hasattr(self, 'active_sorters'):
2251
+ if self.active_sorters:
2252
+ sorter = self.active_sorters[0]
2253
+ return [sorter['key'], sorter['dir']]
2254
+
2255
+ elif self.sort_defaults:
2256
+ sorter = self.sort_defaults[0]
2257
+ return [sorter.sortkey, sorter.sortdir]
2258
+
2230
2259
  def get_vue_filters(self):
2231
2260
  """
2232
2261
  Returns a list of Vue-compatible filter definitions.
@@ -112,31 +112,36 @@
112
112
  <b-field label="Default Sender">
113
113
  <b-input name="${app.appname}.email.default.sender"
114
114
  v-model="simpleSettings['${app.appname}.email.default.sender']"
115
- @input="settingsNeedSaved = true" />
115
+ @input="settingsNeedSaved = true"
116
+ expanded />
116
117
  </b-field>
117
118
 
118
119
  <b-field label="Default Recipient(s)">
119
120
  <b-input name="${app.appname}.email.default.to"
120
121
  v-model="simpleSettings['${app.appname}.email.default.to']"
121
- @input="settingsNeedSaved = true" />
122
+ @input="settingsNeedSaved = true"
123
+ expanded />
122
124
  </b-field>
123
125
 
124
126
  <b-field label="Default Subject (optional)">
125
127
  <b-input name="${app.appname}.email.default.subject"
126
128
  v-model="simpleSettings['${app.appname}.email.default.subject']"
127
- @input="settingsNeedSaved = true" />
129
+ @input="settingsNeedSaved = true"
130
+ expanded />
128
131
  </b-field>
129
132
 
130
133
  <b-field label="Feedback Recipient(s) (optional)">
131
134
  <b-input name="${app.appname}.email.feedback.to"
132
135
  v-model="simpleSettings['${app.appname}.email.feedback.to']"
133
- @input="settingsNeedSaved = true" />
136
+ @input="settingsNeedSaved = true"
137
+ expanded />
134
138
  </b-field>
135
139
 
136
140
  <b-field label="Feedback Subject (optional)">
137
141
  <b-input name="${app.appname}.email.feedback.subject"
138
142
  v-model="simpleSettings['${app.appname}.email.feedback.subject']"
139
- @input="settingsNeedSaved = true" />
143
+ @input="settingsNeedSaved = true"
144
+ expanded />
140
145
  </b-field>
141
146
 
142
147
  </div>
@@ -498,23 +498,26 @@
498
498
  % if request.user:
499
499
  disabled
500
500
  % endif
501
- />
501
+ expanded />
502
502
  </b-field>
503
503
 
504
504
  <b-field label="Referring URL">
505
505
  <b-input v-model="referrer"
506
- disabled="true" />
506
+ disabled="true"
507
+ expanded />
507
508
  </b-field>
508
509
 
509
510
  <b-field label="Message"
510
511
  :type="message && message.trim() ? null : 'is-danger'">
511
512
  <b-input type="textarea"
512
513
  v-model="message"
513
- ref="textarea" />
514
+ ref="textarea"
515
+ expanded />
514
516
  </b-field>
515
517
  </section>
516
518
 
517
519
  <footer class="modal-card-foot">
520
+ <div style="display: flex; gap: 0.5rem;">
518
521
  <b-button @click="showDialog = false">
519
522
  Cancel
520
523
  </b-button>
@@ -525,6 +528,7 @@
525
528
  :disabled="submitDisabled">
526
529
  {{ sendingFeedback ? "Working, please wait..." : "Send Message" }}
527
530
  </b-button>
531
+ </div>
528
532
  </footer>
529
533
  </div>
530
534
  </${b}-modal>
@@ -5,10 +5,12 @@
5
5
  <b-input name="${name}"
6
6
  value="${field.widget.redisplay and cstruct or ''}"
7
7
  type="password"
8
+ expanded
8
9
  placeholder="Password" />
9
10
  <b-input name="${name}-confirm"
10
11
  value="${field.widget.redisplay and confirm or ''}"
11
12
  type="password"
13
+ expanded
12
14
  placeholder="Confirm Password" />
13
15
  ${field.end_mapping()}
14
16
  </div>
@@ -1,6 +1,7 @@
1
1
  <div>
2
2
  ${field.start_mapping()}
3
3
  <wutta-datepicker name="date"
4
- value="${cstruct}" />
4
+ value="${cstruct}"
5
+ expanded />
5
6
  ${field.end_mapping()}
6
7
  </div>
@@ -2,9 +2,11 @@
2
2
  ${field.start_mapping()}
3
3
  <wutta-datepicker name="date"
4
4
  style="flex-grow: 1;"
5
+ expanded
5
6
  value="${date}" />
6
7
  <wutta-timepicker name="time"
7
8
  style="flex-grow: 1;"
9
+ expanded
8
10
  value="${time}" />
9
11
  ${field.end_mapping()}
10
12
  </div>
@@ -3,5 +3,6 @@
3
3
  vmodel vmodel|'modelData.'+oid;">
4
4
  <b-input name="${name}"
5
5
  v-model="${vmodel}"
6
+ expanded
6
7
  tal:attributes="attributes|field.widget.attributes|{};" />
7
8
  </tal:omit>
@@ -5,5 +5,6 @@
5
5
  <b-input name="${name}"
6
6
  v-model="${vmodel}"
7
7
  type="password"
8
+ expanded
8
9
  tal:attributes="attributes|field.widget.attributes|{};" />
9
10
  </div>
@@ -7,5 +7,6 @@
7
7
  <b-input name="${name}"
8
8
  v-model="${vmodel}"
9
9
  type="textarea"
10
+ expanded
10
11
  tal:attributes="attributes|field.widget.attributes|{};" />
11
12
  </div>
@@ -4,5 +4,6 @@
4
4
  vmodel vmodel|'modelData.'+oid;">
5
5
  <b-input name="${name}"
6
6
  v-model="${vmodel}"
7
+ expanded
7
8
  tal:attributes="attributes|field.widget.attributes|{};" />
8
9
  </div>
@@ -0,0 +1,8 @@
1
+ <div tal:omit-tag
2
+ tal:define="name name|field.name;
3
+ oid oid|field.oid;
4
+ vmodel vmodel|'modelData.'+oid;">
5
+ <wutta-checked-password name="${name}"
6
+ v-model="${vmodel}"
7
+ tal:attributes="attributes|field.widget.attributes|{};" />
8
+ </div>
@@ -1,5 +1,22 @@
1
1
  ## -*- coding: utf-8; -*-
2
- <${b}-table :data="gridContext['${grid.key}'].data">
2
+ <div>
3
+
4
+ % if grid.tools:
5
+ <div class="table-tools-wrapper">
6
+ % for html in grid.tools.values():
7
+ ${html}
8
+ % endfor
9
+ </div>
10
+ % endif
11
+
12
+ <${b}-table :data="gridContext['${grid.key}'].data"
13
+
14
+ ## sorting
15
+ % if grid.sortable:
16
+ :default-sort="${grid.get_vue_first_sorter() or 'null'}"
17
+ % endif
18
+
19
+ icon-pack="fas">
3
20
 
4
21
  % for column in grid.get_vue_columns():
5
22
  % if not column['hidden']:
@@ -52,3 +69,5 @@
52
69
  </template>
53
70
 
54
71
  </${b}-table>
72
+
73
+ </div>
@@ -5,6 +5,7 @@
5
5
  ${self.make_b_checkbox_component()}
6
6
  ${self.make_b_collapse_component()}
7
7
  ${self.make_b_datepicker_component()}
8
+ ${self.make_b_timepicker_component()}
8
9
  ${self.make_b_dropdown_component()}
9
10
  ${self.make_b_dropdown_item_component()}
10
11
  ${self.make_b_field_component()}
@@ -25,16 +26,10 @@
25
26
 
26
27
  <%def name="make_b_autocomplete_component()">
27
28
  <script type="text/x-template" id="b-autocomplete-template">
28
- <o-autocomplete v-model="orugaValue"
29
- :data="data"
30
- :field="field"
31
- :open-on-focus="openOnFocus"
32
- :keep-first="keepFirst"
33
- :clearable="clearable"
34
- :clear-on-select="clearOnSelect"
35
- :formatter="customFormatter"
36
- :placeholder="placeholder"
37
- @update:model-value="orugaValueUpdated"
29
+ <o-autocomplete v-model:input="orugaValue"
30
+ :options="options"
31
+ clear-icon="circle-xmark"
32
+ @update:input="orugaValueUpdated"
38
33
  ref="autocomplete">
39
34
  </o-autocomplete>
40
35
  </script>
@@ -45,12 +40,7 @@
45
40
  modelValue: String,
46
41
  data: Array,
47
42
  field: String,
48
- openOnFocus: Boolean,
49
- keepFirst: Boolean,
50
- clearable: Boolean,
51
- clearOnSelect: Boolean,
52
43
  customFormatter: null,
53
- placeholder: String,
54
44
  },
55
45
  data() {
56
46
  return {
@@ -64,13 +54,33 @@
64
54
  }
65
55
  },
66
56
  },
57
+ computed: {
58
+ options() {
59
+ const options = []
60
+ const field = this.field || 'label'
61
+ for (let opt of this.data) {
62
+ const newOpt = {
63
+ label: opt[field],
64
+ value: opt,
65
+ }
66
+ if (this.customFormatter) {
67
+ newOpt.label = this.customFormatter(opt)
68
+ }
69
+ options.push(newOpt)
70
+ }
71
+ return options
72
+ },
73
+ },
67
74
  methods: {
68
75
  focus() {
69
76
  const input = this.$refs.autocomplete.$el.querySelector('input')
70
77
  input.focus()
71
78
  },
72
79
  orugaValueUpdated(value) {
73
- this.$emit('update:modelValue', value)
80
+ if (this.field) {
81
+ value = value[this.field]
82
+ }
83
+ this.$emit('update:modelValue', value || '')
74
84
  },
75
85
  },
76
86
  }
@@ -82,7 +92,7 @@
82
92
  <script type="text/x-template" id="b-button-template">
83
93
  <o-button :variant="variant"
84
94
  :size="orugaSize"
85
- :native-type="nativeType"
95
+ :type="nativeType"
86
96
  :tag="tag"
87
97
  :href="href"
88
98
  :icon-left="iconLeft">
@@ -181,8 +191,8 @@
181
191
  @update:model-value="orugaValueUpdated"
182
192
  :value="value"
183
193
  :placeholder="placeholder"
184
- :date-formatter="dateFormatter"
185
- :date-parser="dateParser"
194
+ :formatter="dateFormatter"
195
+ :parser="dateParser"
186
196
  :disabled="disabled"
187
197
  :editable="editable"
188
198
  :icon="icon"
@@ -228,6 +238,45 @@
228
238
  <% request.register_component('b-datepicker', 'BDatepicker') %>
229
239
  </%def>
230
240
 
241
+ <%def name="make_b_timepicker_component()">
242
+ <script type="text/x-template" id="b-timepicker-template">
243
+ <o-timepicker v-model="orugaValue"
244
+ @update:model-value="orugaValueUpdated"
245
+ :formatter="timeFormatter"
246
+ :parser="timeParser" />
247
+ </script>
248
+ <script>
249
+ const BTimepicker = {
250
+ template: '#b-timepicker-template',
251
+ props: {
252
+ modelValue: null,
253
+ timeFormatter: null,
254
+ timeParser: null,
255
+ },
256
+ data() {
257
+ return {
258
+ orugaValue: this.modelValue,
259
+ }
260
+ },
261
+ watch: {
262
+ modelValue(to, from) {
263
+ if (this.orugaValue != to) {
264
+ this.orugaValue = to
265
+ }
266
+ },
267
+ },
268
+ methods: {
269
+ orugaValueUpdate(value) {
270
+ if (this.modelValue != value) {
271
+ this.$emit('update:modelValue', value)
272
+ }
273
+ },
274
+ },
275
+ }
276
+ </script>
277
+ <% request.register_component('b-timepicker', 'BTimepicker') %>
278
+ </%def>
279
+
231
280
  <%def name="make_b_dropdown_component()">
232
281
  <script type="text/x-template" id="b-dropdown-template">
233
282
  <o-dropdown :position="buefyPosition"
@@ -364,15 +413,7 @@
364
413
  },
365
414
  methods: {
366
415
  focus() {
367
- if (this.type == 'textarea') {
368
- // TODO: this does not always work right?
369
- this.$refs.input.$el.querySelector('textarea').focus()
370
- } else {
371
- // TODO: pretty sure we can rely on the <o-input> focus()
372
- // here, but not sure why we weren't already doing that?
373
- //this.$refs.input.$el.querySelector('input').focus()
374
- this.$refs.input.focus()
375
- }
416
+ this.$refs.input.focus()
376
417
  },
377
418
  },
378
419
  }
@@ -445,7 +486,8 @@
445
486
  <%def name="make_b_notification_component()">
446
487
  <script type="text/x-template" id="b-notification-template">
447
488
  <o-notification :variant="variant"
448
- :closable="closable">
489
+ ## nb. prop name changed for oruga
490
+ :closeable="closable">
449
491
  <slot />
450
492
  </o-notification>
451
493
  </script>
@@ -0,0 +1,126 @@
1
+ ## -*- coding: utf-8; -*-
2
+ <%inherit file="/master/view.mako" />
3
+
4
+ <%def name="page_content()">
5
+ ${parent.page_content()}
6
+
7
+ % if master.has_perm('manage_api_tokens'):
8
+ <b-modal :active.sync="newTokenShowDialog"
9
+ has-modal-card>
10
+ <div class="modal-card">
11
+ <header class="modal-card-head">
12
+ <p class="modal-card-title">
13
+ New API Token
14
+ </p>
15
+ </header>
16
+ <section class="modal-card-body">
17
+
18
+ <div v-if="!newTokenSaved">
19
+ <b-field label="Description"
20
+ :type="{'is-danger': !newTokenDescription}">
21
+ <b-input v-model.trim="newTokenDescription"
22
+ expanded
23
+ ref="newTokenDescription">
24
+ </b-input>
25
+ </b-field>
26
+ </div>
27
+
28
+ <div v-if="newTokenSaved">
29
+ <p class="block">
30
+ Your new API token is shown below.
31
+ </p>
32
+ <p class="block">
33
+ IMPORTANT:&nbsp; You must record this token elsewhere
34
+ for later reference.&nbsp; You will NOT be able to
35
+ recover the value if you lose it.
36
+ </p>
37
+ <b-field horizontal label="API Token">
38
+ {{ newTokenRaw }}
39
+ </b-field>
40
+ <b-field horizontal label="Description">
41
+ {{ newTokenDescription }}
42
+ </b-field>
43
+ </div>
44
+
45
+ </section>
46
+ <footer class="modal-card-foot">
47
+ <b-button @click="newTokenShowDialog = false">
48
+ {{ newTokenSaved ? "Close" : "Cancel" }}
49
+ </b-button>
50
+ <b-button v-if="!newTokenSaved"
51
+ type="is-primary"
52
+ icon-pack="fas"
53
+ icon-left="save"
54
+ @click="newTokenSave()"
55
+ :disabled="!newTokenDescription || newTokenSaving">
56
+ {{ newTokenSaving ? "Working, please wait..." : "Save" }}
57
+ </b-button>
58
+ </footer>
59
+ </div>
60
+ </b-modal>
61
+ % endif
62
+ </%def>
63
+
64
+ <%def name="render_form_tag()">
65
+ % if master.has_perm('manage_api_tokens'):
66
+ ${form.render_vue_tag(**{'@new-token': 'newTokenInit', '@delete-token': 'deleteTokenInit'})}
67
+ % else:
68
+ ${form.render_vue_tag()}
69
+ % endif
70
+ </%def>
71
+
72
+ <%def name="modify_vue_vars()">
73
+ ${parent.modify_vue_vars()}
74
+ <script>
75
+ % if master.has_perm('manage_api_tokens'):
76
+
77
+ ThisPageData.newTokenShowDialog = false
78
+ ThisPageData.newTokenDescription = null
79
+ ThisPageData.newTokenRaw = null
80
+ ThisPageData.newTokenSaved = false
81
+ ThisPageData.newTokenSaving = false
82
+
83
+ ThisPage.methods.newTokenInit = function() {
84
+ this.newTokenDescription = null
85
+ this.newTokenRaw = null
86
+ this.newTokenSaved = false
87
+ this.newTokenShowDialog = true
88
+ this.$nextTick(() => {
89
+ this.$refs.newTokenDescription.focus()
90
+ })
91
+ }
92
+
93
+ ThisPage.methods.newTokenSave = function() {
94
+ this.newTokenSaving = true
95
+
96
+ const url = '${master.get_action_url('add_api_token', instance)}'
97
+ const params = {
98
+ description: this.newTokenDescription,
99
+ }
100
+
101
+ this.wuttaPOST(url, params, response => {
102
+ this.newTokenSaving = false
103
+ this.newTokenRaw = response.data.token_string
104
+ ${form.vue_component}Data.gridContext['users.view.api_tokens'].data.push(response.data)
105
+ this.newTokenSaved = true
106
+ }, response => {
107
+ this.newTokenSaving = false
108
+ })
109
+ }
110
+
111
+ ThisPage.methods.deleteTokenInit = function(token) {
112
+ if (!confirm("Really delete this API token?")) {
113
+ return
114
+ }
115
+
116
+ const url = '${master.get_action_url('delete_api_token', instance)}'
117
+ const params = {uuid: token.uuid}
118
+ this.wuttaPOST(url, params, response => {
119
+ const i = ${form.vue_component}Data.gridContext['users.view.api_tokens'].data.indexOf(token)
120
+ ${form.vue_component}Data.gridContext['users.view.api_tokens'].data.splice(i, 1)
121
+ })
122
+ }
123
+
124
+ % endif
125
+ </script>
126
+ </%def>