WuttaWeb 0.19.2__tar.gz → 0.20.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.
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/CHANGELOG.md +20 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/PKG-INFO +2 -2
- wuttaweb-0.20.0/docs/api/wuttaweb.views.reports.rst +6 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/index.rst +1 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/pyproject.toml +2 -2
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/forms/base.py +26 -1
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/forms/schema.py +31 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/configure.mako +3 -3
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/forms/vue_template.mako +11 -3
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/grids/vue_template.mako +3 -0
- wuttaweb-0.20.0/src/wuttaweb/templates/reports/view.mako +61 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/wutta-components.mako +145 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/views/master.py +42 -12
- wuttaweb-0.20.0/src/wuttaweb/views/reports.py +266 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/forms/test_schema.py +19 -0
- wuttaweb-0.20.0/tests/views/test_reports.py +231 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/.gitignore +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/COPYING.txt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/README.md +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/Makefile +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/_static/.keepme +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.app.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.auth.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.cli.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.cli.webapp.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.conf.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.db.continuum.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.db.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.db.sess.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.emails.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.forms.base.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.forms.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.forms.schema.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.forms.widgets.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.grids.base.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.grids.filters.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.grids.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.handler.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.helpers.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.menus.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.progress.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.static.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.subscribers.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.util.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.views.auth.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.views.base.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.views.batch.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.views.common.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.views.email.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.views.essential.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.views.master.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.views.people.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.views.progress.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.views.roles.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.views.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.views.settings.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.views.upgrades.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/api/wuttaweb.views.users.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/conf.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/glossary.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/make.bat +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/narr/cli/builtin.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/narr/cli/index.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/narr/templates/base.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/narr/templates/index.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/narr/templates/lookup.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/docs/narr/templates/overview.rst +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/__init__.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/_version.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/app.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/auth.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/cli/__init__.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/cli/webapp.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/conf.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/db/__init__.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/db/continuum.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/db/sess.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/email-templates/feedback.html.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/email-templates/feedback.txt.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/emails.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/forms/__init__.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/forms/widgets.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/grids/__init__.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/grids/base.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/grids/filters.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/handler.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/helpers.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/menus.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/progress.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/static/__init__.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/static/img/favicon.ico +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/static/img/logo.png +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/static/img/testing.png +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/subscribers.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/appinfo/configure.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/appinfo/index.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/auth/change_password.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/auth/login.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/base.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/base_meta.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/batch/view.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/deform/checkbox.pt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/deform/checkbox_choice.pt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/deform/checked_password.pt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/deform/dateinput.pt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/deform/datetimeinput.pt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/deform/moneyinput.pt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/deform/password.pt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/deform/permissions.pt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/deform/readonly/checkbox.pt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/deform/readonly/email_recips.pt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/deform/readonly/filedownload.pt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/deform/readonly/notes.pt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/deform/readonly/objectref.pt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/deform/readonly/permissions.pt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/deform/readonly/rolerefs.pt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/deform/select.pt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/deform/textarea.pt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/deform/textinput.pt +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/email/settings/view.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/forbidden.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/form.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/grids/table_element.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/home.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/master/configure.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/master/create.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/master/delete.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/master/edit.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/master/form.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/master/index.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/master/view.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/notfound.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/page.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/people/view_profile.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/progress.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/setup.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/upgrade.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/upgrades/configure.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/templates/upgrades/view.mako +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/testing.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/util.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/views/__init__.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/views/auth.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/views/base.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/views/batch.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/views/common.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/views/email.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/views/essential.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/views/people.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/views/progress.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/views/roles.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/views/settings.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/views/upgrades.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/src/wuttaweb/views/users.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tasks.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/__init__.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/cli/__init__.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/cli/test_webapp.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/db/__init__.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/db/test_continuum.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/forms/test_base.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/forms/test_widgets.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/grids/__init__.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/grids/test_base.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/grids/test_filters.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/libcache/bb_fontawesome_svg_core.js +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/libcache/bb_free_solid_svg_icons.js +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/libcache/bb_oruga.js +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/libcache/bb_oruga_bulma.css +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/libcache/bb_oruga_bulma.js +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/libcache/bb_vue.js +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/libcache/bb_vue_fontawesome.js +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/libcache/buefy.css +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/libcache/buefy.js +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/libcache/fontawesome.js +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/libcache/vue.js +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/libcache/vue_resource.js +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/test_app.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/test_auth.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/test_emails.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/test_handler.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/test_helpers.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/test_menus.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/test_progress.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/test_static.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/test_subscribers.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/test_util.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/util.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/views/__init__.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/views/test___init__.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/views/test_auth.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/views/test_base.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/views/test_batch.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/views/test_common.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/views/test_email.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/views/test_essential.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/views/test_master.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/views/test_people.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/views/test_progress.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/views/test_roles.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/views/test_settings.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/views/test_upgrades.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tests/views/test_users.py +0 -0
- {wuttaweb-0.19.2 → wuttaweb-0.20.0}/tox.ini +0 -0
|
@@ -5,6 +5,26 @@ 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.0 (2025-01-11)
|
|
9
|
+
|
|
10
|
+
### Feat
|
|
11
|
+
|
|
12
|
+
- add basic views for Reports
|
|
13
|
+
|
|
14
|
+
### Fix
|
|
15
|
+
|
|
16
|
+
- add `action_method` and `reset_url` params for Form class
|
|
17
|
+
- add placeholder when grid has no filters
|
|
18
|
+
- add `get_page_templates()` method for master view
|
|
19
|
+
|
|
20
|
+
## v0.19.3 (2025-01-09)
|
|
21
|
+
|
|
22
|
+
### Fix
|
|
23
|
+
|
|
24
|
+
- use `request.url` instead of `current_route_url()`
|
|
25
|
+
- add basic `<wutta-autocomplete>` component
|
|
26
|
+
- add `WuttaDictEnum` form schema type
|
|
27
|
+
|
|
8
28
|
## v0.19.2 (2025-01-07)
|
|
9
29
|
|
|
10
30
|
### Fix
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: WuttaWeb
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.20.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.
|
|
42
|
+
Requires-Dist: wuttjamaican[db]>=0.20.0
|
|
43
43
|
Requires-Dist: zope-sqlalchemy>=1.5
|
|
44
44
|
Provides-Extra: continuum
|
|
45
45
|
Requires-Dist: wutta-continuum; extra == 'continuum'
|
|
@@ -60,6 +60,7 @@ the narrative docs are pretty scant. That will eventually change.
|
|
|
60
60
|
api/wuttaweb.views.master
|
|
61
61
|
api/wuttaweb.views.people
|
|
62
62
|
api/wuttaweb.views.progress
|
|
63
|
+
api/wuttaweb.views.reports
|
|
63
64
|
api/wuttaweb.views.roles
|
|
64
65
|
api/wuttaweb.views.settings
|
|
65
66
|
api/wuttaweb.views.upgrades
|
|
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "WuttaWeb"
|
|
9
|
-
version = "0.
|
|
9
|
+
version = "0.20.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.
|
|
47
|
+
"WuttJamaican[db]>=0.20.0",
|
|
48
48
|
"zope.sqlalchemy>=1.5",
|
|
49
49
|
]
|
|
50
50
|
|
|
@@ -161,10 +161,23 @@ class Form:
|
|
|
161
161
|
|
|
162
162
|
See also :meth:`set_required()` and :meth:`is_required()`.
|
|
163
163
|
|
|
164
|
+
.. attribute:: action_method
|
|
165
|
+
|
|
166
|
+
HTTP method to use when submitting form; ``'post'`` is default.
|
|
167
|
+
|
|
164
168
|
.. attribute:: action_url
|
|
165
169
|
|
|
166
170
|
String URL to which the form should be submitted, if applicable.
|
|
167
171
|
|
|
172
|
+
.. attribute:: reset_url
|
|
173
|
+
|
|
174
|
+
String URL to which the reset button should "always" redirect,
|
|
175
|
+
if applicable.
|
|
176
|
+
|
|
177
|
+
This is null by default, in which case it will use standard
|
|
178
|
+
browser behavior for the form reset button (if shown). See
|
|
179
|
+
also :attr:`show_button_reset`.
|
|
180
|
+
|
|
168
181
|
.. attribute:: cancel_url
|
|
169
182
|
|
|
170
183
|
String URL to which the Cancel button should "always" redirect,
|
|
@@ -227,6 +240,9 @@ class Form:
|
|
|
227
240
|
Flag indicating whether a Reset button should be shown.
|
|
228
241
|
Default is ``False``.
|
|
229
242
|
|
|
243
|
+
Unless there is a :attr:`reset_url`, the reset button will use
|
|
244
|
+
standard behavior per the browser.
|
|
245
|
+
|
|
230
246
|
.. attribute:: show_button_cancel
|
|
231
247
|
|
|
232
248
|
Flag indicating whether a Cancel button should be shown.
|
|
@@ -266,7 +282,9 @@ class Form:
|
|
|
266
282
|
readonly_fields=[],
|
|
267
283
|
required_fields={},
|
|
268
284
|
labels={},
|
|
285
|
+
action_method='post',
|
|
269
286
|
action_url=None,
|
|
287
|
+
reset_url=None,
|
|
270
288
|
cancel_url=None,
|
|
271
289
|
cancel_url_fallback=None,
|
|
272
290
|
vue_tagname='wutta-form',
|
|
@@ -290,9 +308,11 @@ class Form:
|
|
|
290
308
|
self.readonly_fields = set(readonly_fields or [])
|
|
291
309
|
self.required_fields = required_fields or {}
|
|
292
310
|
self.labels = labels or {}
|
|
311
|
+
self.action_method = action_method
|
|
293
312
|
self.action_url = action_url
|
|
294
313
|
self.cancel_url = cancel_url
|
|
295
314
|
self.cancel_url_fallback = cancel_url_fallback
|
|
315
|
+
self.reset_url = reset_url
|
|
296
316
|
self.vue_tagname = vue_tagname
|
|
297
317
|
self.align_buttons_right = align_buttons_right
|
|
298
318
|
self.auto_disable_submit = auto_disable_submit
|
|
@@ -940,10 +960,15 @@ class Form:
|
|
|
940
960
|
"""
|
|
941
961
|
context['form'] = self
|
|
942
962
|
context['dform'] = self.get_deform()
|
|
943
|
-
context.setdefault('form_attrs', {})
|
|
944
963
|
context.setdefault('request', self.request)
|
|
945
964
|
context['model_data'] = self.get_vue_model_data()
|
|
946
965
|
|
|
966
|
+
# set form method, enctype
|
|
967
|
+
context.setdefault('form_attrs', {})
|
|
968
|
+
context['form_attrs'].setdefault('method', self.action_method)
|
|
969
|
+
if self.action_method == 'post':
|
|
970
|
+
context['form_attrs'].setdefault('enctype', 'multipart/form-data')
|
|
971
|
+
|
|
947
972
|
# auto disable button on submit
|
|
948
973
|
if self.auto_disable_submit:
|
|
949
974
|
context['form_attrs']['@submit'] = 'formSubmitting = true'
|
|
@@ -155,6 +155,37 @@ class WuttaEnum(colander.Enum):
|
|
|
155
155
|
return widgets.SelectWidget(**kwargs)
|
|
156
156
|
|
|
157
157
|
|
|
158
|
+
class WuttaDictEnum(colander.String):
|
|
159
|
+
"""
|
|
160
|
+
Schema type for "pseudo-enum" fields which reference a dict for
|
|
161
|
+
known values instead of a true enum class.
|
|
162
|
+
|
|
163
|
+
This is primarily for use with "status" fields such as
|
|
164
|
+
:attr:`~wuttjamaican:wuttjamaican.db.model.batch.BatchRowMixin.status_code`.
|
|
165
|
+
|
|
166
|
+
This is a subclass of :class:`colander.String`, but adds a default
|
|
167
|
+
widget (``SelectWidget``) with enum choices.
|
|
168
|
+
|
|
169
|
+
:param request: Current :term:`request` object.
|
|
170
|
+
|
|
171
|
+
:param enum_dct: Dict with possible enum values and labels.
|
|
172
|
+
"""
|
|
173
|
+
|
|
174
|
+
def __init__(self, request, enum_dct, *args, **kwargs):
|
|
175
|
+
super().__init__(*args, **kwargs)
|
|
176
|
+
self.request = request
|
|
177
|
+
self.config = self.request.wutta_config
|
|
178
|
+
self.app = self.config.get_app()
|
|
179
|
+
self.enum_dct = enum_dct
|
|
180
|
+
|
|
181
|
+
def widget_maker(self, **kwargs):
|
|
182
|
+
""" """
|
|
183
|
+
if 'values' not in kwargs:
|
|
184
|
+
kwargs['values'] = [(k, v) for k, v in self.enum_dct.items()]
|
|
185
|
+
|
|
186
|
+
return widgets.SelectWidget(**kwargs)
|
|
187
|
+
|
|
188
|
+
|
|
158
189
|
class WuttaMoney(colander.Money):
|
|
159
190
|
"""
|
|
160
191
|
Custom schema type for "money" fields.
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
<br />
|
|
19
19
|
${self.buttons_content()}
|
|
20
20
|
|
|
21
|
-
${h.form(request.
|
|
21
|
+
${h.form(request.url, enctype='multipart/form-data', ref='saveSettingsForm', **{'@submit': 'saveSettingsFormSubmit'})}
|
|
22
22
|
${h.csrf_token(request)}
|
|
23
23
|
<div class="wutta-form-wrapper">
|
|
24
24
|
${self.form_content()}
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
<b-button @click="purgeSettingsShowDialog = false">
|
|
54
54
|
Cancel
|
|
55
55
|
</b-button>
|
|
56
|
-
${h.form(request.
|
|
56
|
+
${h.form(request.url, **{'@submit': 'purgingSettings = true'})}
|
|
57
57
|
${h.csrf_token(request)}
|
|
58
58
|
${h.hidden('remove_settings', 'true')}
|
|
59
59
|
<b-button type="is-danger"
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
icon-left="save">
|
|
108
108
|
{{ savingSettings ? "Working, please wait..." : "Save All Settings" }}
|
|
109
109
|
</b-button>
|
|
110
|
-
<b-button tag="a" href="${request.
|
|
110
|
+
<b-button tag="a" href="${request.url}"
|
|
111
111
|
icon-pack="fas"
|
|
112
112
|
icon-left="undo"
|
|
113
113
|
@click="undoChanges = true"
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
## -*- coding: utf-8; -*-
|
|
2
2
|
|
|
3
3
|
<script type="text/x-template" id="${form.vue_tagname}-template">
|
|
4
|
-
${h.form(form.action_url,
|
|
5
|
-
|
|
4
|
+
${h.form(form.action_url, **form_attrs)}
|
|
5
|
+
% if form.action_method == 'post':
|
|
6
|
+
${h.csrf_token(request)}
|
|
7
|
+
% endif
|
|
6
8
|
|
|
7
9
|
% if form.has_global_errors():
|
|
8
10
|
% for msg in form.get_global_errors():
|
|
@@ -33,7 +35,13 @@
|
|
|
33
35
|
% endif
|
|
34
36
|
|
|
35
37
|
% if form.show_button_reset:
|
|
36
|
-
<b-button
|
|
38
|
+
<b-button
|
|
39
|
+
% if form.reset_url:
|
|
40
|
+
tag="a" href="${form.reset_url}"
|
|
41
|
+
% else:
|
|
42
|
+
native-type="reset"
|
|
43
|
+
% endif
|
|
44
|
+
>
|
|
37
45
|
Reset
|
|
38
46
|
</b-button>
|
|
39
47
|
% endif
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
## -*- coding: utf-8; mode: html; -*-
|
|
2
|
+
<%inherit file="/master/view.mako" />
|
|
3
|
+
|
|
4
|
+
<%def name="page_layout()">
|
|
5
|
+
${parent.page_layout()}
|
|
6
|
+
% if report_data is not Undefined:
|
|
7
|
+
<br />
|
|
8
|
+
<a name="report-output"></a>
|
|
9
|
+
<div style="display: flex; justify-content: space-between;">
|
|
10
|
+
<div class="report-header">
|
|
11
|
+
${self.report_output_header()}
|
|
12
|
+
</div>
|
|
13
|
+
<div class="report-tools">
|
|
14
|
+
${self.report_tools()}
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
${self.report_output_body()}
|
|
18
|
+
% endif
|
|
19
|
+
</%def>
|
|
20
|
+
|
|
21
|
+
<%def name="report_output_header()">
|
|
22
|
+
<h4 class="is-size-4"><a href="#report-output">{{ reportData.output_title }}</a></h4>
|
|
23
|
+
</%def>
|
|
24
|
+
|
|
25
|
+
<%def name="report_tools()"></%def>
|
|
26
|
+
|
|
27
|
+
<%def name="report_output_body()">
|
|
28
|
+
${self.report_output_table()}
|
|
29
|
+
</%def>
|
|
30
|
+
|
|
31
|
+
<%def name="report_output_table()">
|
|
32
|
+
<b-table :data="reportData.data"
|
|
33
|
+
narrowed
|
|
34
|
+
hoverable>
|
|
35
|
+
% for column in report_columns:
|
|
36
|
+
<b-table-column field="${column['name']}"
|
|
37
|
+
label="${column['label']}"
|
|
38
|
+
% if column.get('numeric'):
|
|
39
|
+
numeric
|
|
40
|
+
% endif
|
|
41
|
+
v-slot="props">
|
|
42
|
+
<span v-html="props.row.${column['name']}"></span>
|
|
43
|
+
</b-table-column>
|
|
44
|
+
% endfor
|
|
45
|
+
</b-table>
|
|
46
|
+
</%def>
|
|
47
|
+
|
|
48
|
+
<%def name="modify_vue_vars()">
|
|
49
|
+
${parent.modify_vue_vars()}
|
|
50
|
+
% if report_data is not Undefined:
|
|
51
|
+
<script>
|
|
52
|
+
|
|
53
|
+
ThisPageData.reportData = ${json.dumps(report_data)|n}
|
|
54
|
+
|
|
55
|
+
WholePageData.mountedHooks.push(function() {
|
|
56
|
+
location.href = '#report-output'
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
</script>
|
|
60
|
+
% endif
|
|
61
|
+
</%def>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
<%def name="make_wutta_components()">
|
|
3
3
|
${self.make_wutta_request_mixin()}
|
|
4
|
+
${self.make_wutta_autocomplete_component()}
|
|
4
5
|
${self.make_wutta_button_component()}
|
|
5
6
|
${self.make_wutta_datepicker_component()}
|
|
6
7
|
${self.make_wutta_timepicker_component()}
|
|
@@ -86,6 +87,150 @@
|
|
|
86
87
|
</script>
|
|
87
88
|
</%def>
|
|
88
89
|
|
|
90
|
+
<%def name="make_wutta_autocomplete_component()">
|
|
91
|
+
<script type="text/x-template" id="wutta-autocomplete-template">
|
|
92
|
+
<div>
|
|
93
|
+
<b-autocomplete ref="autocomplete"
|
|
94
|
+
v-show="!value"
|
|
95
|
+
v-model="entry"
|
|
96
|
+
:data="data"
|
|
97
|
+
@typing="getAsyncData"
|
|
98
|
+
@select="selectionMade"
|
|
99
|
+
keep-first>
|
|
100
|
+
<template slot-scope="props">
|
|
101
|
+
{{ props.option.label }}
|
|
102
|
+
</template>
|
|
103
|
+
</b-autocomplete>
|
|
104
|
+
<b-button v-if="value"
|
|
105
|
+
@click="clearValue(true, true)">
|
|
106
|
+
{{ recordLabel }} (click to change)
|
|
107
|
+
</b-button>
|
|
108
|
+
</div>
|
|
109
|
+
</script>
|
|
110
|
+
<script>
|
|
111
|
+
const WuttaAutocomplete = {
|
|
112
|
+
template: '#wutta-autocomplete-template',
|
|
113
|
+
|
|
114
|
+
props: {
|
|
115
|
+
|
|
116
|
+
// callers do not specify this directly but rather by way
|
|
117
|
+
// of the `v-model` directive. the component will emit
|
|
118
|
+
// `input` events when this value changes
|
|
119
|
+
value: String,
|
|
120
|
+
|
|
121
|
+
// caller must specify initial display string, if the
|
|
122
|
+
// (v-model) value is not empty when component loads
|
|
123
|
+
display: String,
|
|
124
|
+
|
|
125
|
+
// the url from which search results are obtained. the
|
|
126
|
+
// endpoint should expect a GET with single `term` param
|
|
127
|
+
// in query string, and return list of objects, each with
|
|
128
|
+
// (at least) `value` and `label` properties.
|
|
129
|
+
serviceUrl: String,
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
data() {
|
|
133
|
+
return {
|
|
134
|
+
|
|
135
|
+
// user search input
|
|
136
|
+
entry: null,
|
|
137
|
+
|
|
138
|
+
// display label for button, when value is set
|
|
139
|
+
recordLabel: this.display,
|
|
140
|
+
|
|
141
|
+
// this contains the latest search results; it will
|
|
142
|
+
// change over time as user types. when an option is
|
|
143
|
+
// selected, it will be an element from this list.
|
|
144
|
+
data: [],
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
watch: {
|
|
149
|
+
|
|
150
|
+
value(val) {
|
|
151
|
+
// reset ourself when model value is cleared
|
|
152
|
+
if (!val) {
|
|
153
|
+
this.clearValue()
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
methods: {
|
|
159
|
+
|
|
160
|
+
focus() {
|
|
161
|
+
this.$refs.autocomplete.focus()
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
// convenience for parent component to fetch current label
|
|
165
|
+
getLabel() {
|
|
166
|
+
return this.recordLabel
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
// fetch new search results from server. this is invoked
|
|
170
|
+
// when user types new input
|
|
171
|
+
getAsyncData(entry) {
|
|
172
|
+
|
|
173
|
+
// nb. skip search until we have at least 3 chars of input
|
|
174
|
+
if (entry.length < 3) {
|
|
175
|
+
this.data = []
|
|
176
|
+
return
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// search results become autocomplete options
|
|
180
|
+
this.$http.get(this.serviceUrl + '?term=' + encodeURIComponent(entry))
|
|
181
|
+
.then(({ data }) => {
|
|
182
|
+
this.data = data
|
|
183
|
+
})
|
|
184
|
+
.catch((error) => {
|
|
185
|
+
this.data = []
|
|
186
|
+
throw error
|
|
187
|
+
})
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
// handle selection change. this is invoked when user
|
|
191
|
+
// chooses an autocomplete option
|
|
192
|
+
selectionMade(option) {
|
|
193
|
+
|
|
194
|
+
// reset user input
|
|
195
|
+
this.entry = null
|
|
196
|
+
|
|
197
|
+
// nb. this method can be triggered when a selection
|
|
198
|
+
// is made *or cleared* - if the latter then we do not
|
|
199
|
+
// want to emit event for the empty value; that part
|
|
200
|
+
// is handled in clearValue()
|
|
201
|
+
if (option) {
|
|
202
|
+
this.recordLabel = option.label
|
|
203
|
+
this.$emit('input', option.value)
|
|
204
|
+
} else {
|
|
205
|
+
this.recordLabel = null
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
// clear the component value
|
|
210
|
+
clearValue(emit, focus) {
|
|
211
|
+
|
|
212
|
+
// clear autocomplete selection
|
|
213
|
+
this.$refs.autocomplete.setSelected(null)
|
|
214
|
+
|
|
215
|
+
// maybe emit event for new value
|
|
216
|
+
if (emit) {
|
|
217
|
+
this.$emit('input', null)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// maybe set focus to autocomplete
|
|
221
|
+
if (focus) {
|
|
222
|
+
this.$nextTick(function() {
|
|
223
|
+
this.focus()
|
|
224
|
+
})
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
}
|
|
230
|
+
Vue.component('wutta-autocomplete', WuttaAutocomplete)
|
|
231
|
+
</script>
|
|
232
|
+
</%def>
|
|
233
|
+
|
|
89
234
|
<%def name="make_wutta_button_component()">
|
|
90
235
|
<script type="text/x-template" id="wutta-button-template">
|
|
91
236
|
<b-button :type="type"
|
|
@@ -1178,7 +1178,7 @@ class MasterView(View):
|
|
|
1178
1178
|
self.request.session.flash("Settings have been saved.")
|
|
1179
1179
|
|
|
1180
1180
|
# reload configure page
|
|
1181
|
-
return self.redirect(self.request.
|
|
1181
|
+
return self.redirect(self.request.url)
|
|
1182
1182
|
|
|
1183
1183
|
# render configure page
|
|
1184
1184
|
context = self.configure_get_context()
|
|
@@ -1777,14 +1777,14 @@ class MasterView(View):
|
|
|
1777
1777
|
context = self.get_template_context(context)
|
|
1778
1778
|
|
|
1779
1779
|
# first try the template path most specific to this view
|
|
1780
|
-
|
|
1781
|
-
mako_path =
|
|
1780
|
+
page_templates = self.get_page_templates(template)
|
|
1781
|
+
mako_path = page_templates[0]
|
|
1782
1782
|
try:
|
|
1783
1783
|
return render_to_response(mako_path, context, request=self.request)
|
|
1784
1784
|
except IOError:
|
|
1785
1785
|
|
|
1786
1786
|
# failing that, try one or more fallback templates
|
|
1787
|
-
for fallback in
|
|
1787
|
+
for fallback in page_templates[1:]:
|
|
1788
1788
|
try:
|
|
1789
1789
|
return render_to_response(fallback, context, request=self.request)
|
|
1790
1790
|
except IOError:
|
|
@@ -1815,21 +1815,51 @@ class MasterView(View):
|
|
|
1815
1815
|
"""
|
|
1816
1816
|
return context
|
|
1817
1817
|
|
|
1818
|
+
def get_page_templates(self, template):
|
|
1819
|
+
"""
|
|
1820
|
+
Returns a list of all templates which can be attempted, to
|
|
1821
|
+
render the current page. This is called by
|
|
1822
|
+
:meth:`render_to_response()`.
|
|
1823
|
+
|
|
1824
|
+
The list should be in order of preference, e.g. the first
|
|
1825
|
+
entry will be the most "specific" template, with subsequent
|
|
1826
|
+
entries becoming more generic.
|
|
1827
|
+
|
|
1828
|
+
In practice this method defines the first entry but calls
|
|
1829
|
+
:meth:`get_fallback_templates()` for the rest.
|
|
1830
|
+
|
|
1831
|
+
:param template: Base name for a template (without prefix), e.g.
|
|
1832
|
+
``'view'``.
|
|
1833
|
+
|
|
1834
|
+
:returns: List of template paths to be tried, based on the
|
|
1835
|
+
specified template. For instance if ``template`` is
|
|
1836
|
+
``'view'`` this will (by default) return::
|
|
1837
|
+
|
|
1838
|
+
[
|
|
1839
|
+
'/widgets/view.mako',
|
|
1840
|
+
'/master/view.mako',
|
|
1841
|
+
]
|
|
1842
|
+
|
|
1843
|
+
"""
|
|
1844
|
+
template_prefix = self.get_template_prefix()
|
|
1845
|
+
page_templates = [f'{template_prefix}/{template}.mako']
|
|
1846
|
+
page_templates.extend(self.get_fallback_templates(template))
|
|
1847
|
+
return page_templates
|
|
1848
|
+
|
|
1818
1849
|
def get_fallback_templates(self, template):
|
|
1819
1850
|
"""
|
|
1820
1851
|
Returns a list of "fallback" template paths which may be
|
|
1821
|
-
attempted for rendering
|
|
1822
|
-
:meth:`
|
|
1823
|
-
file was not found.
|
|
1852
|
+
attempted for rendering the current page. See also
|
|
1853
|
+
:meth:`get_page_templates()`.
|
|
1824
1854
|
|
|
1825
1855
|
:param template: Base name for a template (without prefix), e.g.
|
|
1826
|
-
``'
|
|
1856
|
+
``'view'``.
|
|
1827
1857
|
|
|
1828
|
-
:returns: List of
|
|
1829
|
-
|
|
1830
|
-
``'
|
|
1858
|
+
:returns: List of template paths to be tried, based on the
|
|
1859
|
+
specified template. For instance if ``template`` is
|
|
1860
|
+
``'view'`` this will (by default) return::
|
|
1831
1861
|
|
|
1832
|
-
['/master/
|
|
1862
|
+
['/master/view.mako']
|
|
1833
1863
|
"""
|
|
1834
1864
|
return [f'/master/{template}.mako']
|
|
1835
1865
|
|