WuttaWeb 0.4.0__tar.gz → 0.5.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 (108) hide show
  1. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/CHANGELOG.md +12 -0
  2. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/PKG-INFO +3 -2
  3. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/pyproject.toml +3 -2
  4. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/app.py +11 -2
  5. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/forms/base.py +1 -0
  6. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/helpers.py +10 -2
  7. wuttaweb-0.5.0/src/wuttaweb/templates/appinfo/configure.mako +177 -0
  8. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/templates/base.mako +21 -8
  9. wuttaweb-0.5.0/src/wuttaweb/templates/configure.mako +181 -0
  10. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/templates/forms/vue_template.mako +1 -0
  11. wuttaweb-0.5.0/src/wuttaweb/templates/master/configure.mako +9 -0
  12. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/util.py +122 -22
  13. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/views/master.py +363 -4
  14. wuttaweb-0.5.0/src/wuttaweb/views/settings.py +138 -0
  15. wuttaweb-0.5.0/tests/libcache/bb_free_solid_svg_icons.js +0 -0
  16. wuttaweb-0.5.0/tests/libcache/bb_oruga.js +0 -0
  17. wuttaweb-0.5.0/tests/libcache/bb_oruga_bulma.css +0 -0
  18. wuttaweb-0.5.0/tests/libcache/bb_oruga_bulma.js +0 -0
  19. wuttaweb-0.5.0/tests/libcache/bb_vue.js +0 -0
  20. wuttaweb-0.5.0/tests/libcache/bb_vue_fontawesome.js +0 -0
  21. wuttaweb-0.5.0/tests/libcache/buefy.css +0 -0
  22. wuttaweb-0.5.0/tests/libcache/buefy.js +0 -0
  23. wuttaweb-0.5.0/tests/libcache/fontawesome.js +0 -0
  24. wuttaweb-0.5.0/tests/libcache/vue.js +0 -0
  25. wuttaweb-0.5.0/tests/libcache/vue_resource.js +0 -0
  26. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tests/test_app.py +11 -0
  27. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tests/test_util.py +155 -2
  28. wuttaweb-0.5.0/tests/views/__init__.py +0 -0
  29. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tests/views/test_master.py +113 -25
  30. wuttaweb-0.5.0/tests/views/test_settings.py +23 -0
  31. wuttaweb-0.4.0/src/wuttaweb/views/settings.py +0 -47
  32. wuttaweb-0.4.0/tests/views/test_settings.py +0 -13
  33. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/.gitignore +0 -0
  34. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/COPYING.txt +0 -0
  35. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/README.md +0 -0
  36. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/Makefile +0 -0
  37. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/_static/.keepme +0 -0
  38. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/index.rst +0 -0
  39. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/app.rst +0 -0
  40. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/auth.rst +0 -0
  41. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/db.rst +0 -0
  42. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/forms.base.rst +0 -0
  43. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/forms.rst +0 -0
  44. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/handler.rst +0 -0
  45. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/helpers.rst +0 -0
  46. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/index.rst +0 -0
  47. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/menus.rst +0 -0
  48. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/static.rst +0 -0
  49. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/subscribers.rst +0 -0
  50. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/util.rst +0 -0
  51. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/views.auth.rst +0 -0
  52. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/views.base.rst +0 -0
  53. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/views.common.rst +0 -0
  54. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/views.essential.rst +0 -0
  55. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/views.master.rst +0 -0
  56. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/views.rst +0 -0
  57. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/api/wuttaweb/views.settings.rst +0 -0
  58. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/conf.py +0 -0
  59. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/glossary.rst +0 -0
  60. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/index.rst +0 -0
  61. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/make.bat +0 -0
  62. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/docs/narr/index.rst +0 -0
  63. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/__init__.py +0 -0
  64. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/_version.py +0 -0
  65. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/auth.py +0 -0
  66. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/db.py +0 -0
  67. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/forms/__init__.py +0 -0
  68. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/handler.py +0 -0
  69. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/menus.py +0 -0
  70. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/static/__init__.py +0 -0
  71. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/static/img/favicon.ico +0 -0
  72. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/static/img/logo.png +0 -0
  73. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/static/img/testing.png +0 -0
  74. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/subscribers.py +0 -0
  75. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/templates/appinfo/index.mako +0 -0
  76. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/templates/auth/change_password.mako +0 -0
  77. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/templates/auth/login.mako +0 -0
  78. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/templates/base_meta.mako +0 -0
  79. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/templates/deform/checked_password.pt +0 -0
  80. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/templates/deform/password.pt +0 -0
  81. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/templates/deform/textinput.pt +0 -0
  82. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/templates/form.mako +0 -0
  83. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/templates/home.mako +0 -0
  84. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/templates/master/index.mako +0 -0
  85. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/templates/page.mako +0 -0
  86. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/views/__init__.py +0 -0
  87. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/views/auth.py +0 -0
  88. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/views/base.py +0 -0
  89. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/views/common.py +0 -0
  90. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/src/wuttaweb/views/essential.py +0 -0
  91. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tasks.py +0 -0
  92. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tests/__init__.py +0 -0
  93. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tests/forms/__init__.py +0 -0
  94. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tests/forms/test_base.py +0 -0
  95. /wuttaweb-0.4.0/tests/views/__init__.py → /wuttaweb-0.5.0/tests/libcache/bb_fontawesome_svg_core.js +0 -0
  96. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tests/test_auth.py +0 -0
  97. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tests/test_handler.py +0 -0
  98. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tests/test_helpers.py +0 -0
  99. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tests/test_menus.py +0 -0
  100. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tests/test_static.py +0 -0
  101. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tests/test_subscribers.py +0 -0
  102. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tests/utils.py +0 -0
  103. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tests/views/test___init__.py +0 -0
  104. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tests/views/test_auth.py +0 -0
  105. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tests/views/test_base.py +0 -0
  106. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tests/views/test_common.py +0 -0
  107. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/tests/views/utils.py +0 -0
  108. {wuttaweb-0.4.0 → wuttaweb-0.5.0}/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.5.0 (2024-08-06)
9
+
10
+ ### Feat
11
+
12
+ - add basic support for fanstatic / libcache
13
+ - expose Web Libraries in app info config page
14
+ - add basic configure view for appinfo
15
+
16
+ ### Fix
17
+
18
+ - bump min version for wuttjamaican
19
+
8
20
  ## v0.4.0 (2024-08-05)
9
21
 
10
22
  ### Feat
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: WuttaWeb
3
- Version: 0.4.0
3
+ Version: 0.5.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
@@ -26,12 +26,13 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
26
  Requires-Python: >=3.8
27
27
  Requires-Dist: pyramid-beaker
28
28
  Requires-Dist: pyramid-deform
29
+ Requires-Dist: pyramid-fanstatic
29
30
  Requires-Dist: pyramid-mako
30
31
  Requires-Dist: pyramid-tm
31
32
  Requires-Dist: pyramid>=2
32
33
  Requires-Dist: waitress
33
34
  Requires-Dist: webhelpers2
34
- Requires-Dist: wuttjamaican[db]>=0.8.3
35
+ Requires-Dist: wuttjamaican[db]>=0.10.0
35
36
  Requires-Dist: zope-sqlalchemy>=1.5
36
37
  Provides-Extra: docs
37
38
  Requires-Dist: furo; extra == 'docs'
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "WuttaWeb"
9
- version = "0.4.0"
9
+ version = "0.5.0"
10
10
  description = "Web App for Wutta Framework"
11
11
  readme = "README.md"
12
12
  authors = [{name = "Lance Edgar", email = "lance@edbob.org"}]
@@ -33,11 +33,12 @@ dependencies = [
33
33
  "pyramid>=2",
34
34
  "pyramid_beaker",
35
35
  "pyramid_deform",
36
+ "pyramid_fanstatic",
36
37
  "pyramid_mako",
37
38
  "pyramid_tm",
38
39
  "waitress",
39
40
  "WebHelpers2",
40
- "WuttJamaican[db]>=0.8.3",
41
+ "WuttJamaican[db]>=0.10.0",
41
42
  "zope.sqlalchemy>=1.5",
42
43
  ]
43
44
 
@@ -110,7 +110,12 @@ def make_pyramid_config(settings):
110
110
 
111
111
  The config is initialized with certain features deemed useful for
112
112
  all apps.
113
+
114
+ :returns: Instance of
115
+ :class:`pyramid:pyramid.config.Configurator`.
113
116
  """
117
+ settings.setdefault('fanstatic.versioning', 'true')
118
+ settings.setdefault('mako.directories', ['wuttaweb:templates'])
114
119
  settings.setdefault('pyramid_deform.template_search_path',
115
120
  'wuttaweb:templates/deform')
116
121
 
@@ -119,8 +124,14 @@ def make_pyramid_config(settings):
119
124
  # configure user authorization / authentication
120
125
  pyramid_config.set_security_policy(WuttaSecurityPolicy())
121
126
 
127
+ # require CSRF token for POST
128
+ pyramid_config.set_default_csrf_options(require_csrf=True,
129
+ token='_csrf',
130
+ header='X-CSRF-TOKEN')
131
+
122
132
  pyramid_config.include('pyramid_beaker')
123
133
  pyramid_config.include('pyramid_deform')
134
+ pyramid_config.include('pyramid_fanstatic')
124
135
  pyramid_config.include('pyramid_mako')
125
136
  pyramid_config.include('pyramid_tm')
126
137
 
@@ -143,8 +154,6 @@ def main(global_config, **settings):
143
154
  will need to define their own ``main()`` function, and use that
144
155
  instead.
145
156
  """
146
- settings.setdefault('mako.directories', ['wuttaweb:templates'])
147
-
148
157
  wutta_config = make_wutta_config(settings)
149
158
  pyramid_config = make_pyramid_config(settings)
150
159
 
@@ -323,6 +323,7 @@ class Form:
323
323
  """
324
324
  context['form'] = self
325
325
  context.setdefault('form_attrs', {})
326
+ context.setdefault('request', self.request)
326
327
 
327
328
  # auto disable button on submit
328
329
  if self.auto_disable_submit:
@@ -38,12 +38,20 @@ instance:
38
38
 
39
39
  This module contains the following references:
40
40
 
41
- * :func:`~wuttaweb.util.get_liburl()`
42
41
  * all names from :mod:`webhelpers2:webhelpers2.html`
43
42
  * all names from :mod:`webhelpers2:webhelpers2.html.tags`
43
+ * :func:`~wuttaweb.util.get_liburl()`
44
+ * :func:`~wuttaweb.util.get_csrf_token()`
45
+ * :func:`~wuttaweb.util.render_csrf_token()` (as :func:`csrf_token()`)
46
+
47
+ .. function:: csrf_token
48
+
49
+ This is a shorthand reference to
50
+ :func:`wuttaweb.util.render_csrf_token()`.
51
+
44
52
  """
45
53
 
46
54
  from webhelpers2.html import *
47
55
  from webhelpers2.html.tags import *
48
56
 
49
- from wuttaweb.util import get_liburl
57
+ from wuttaweb.util import get_liburl, get_csrf_token, render_csrf_token as csrf_token
@@ -0,0 +1,177 @@
1
+ ## -*- coding: utf-8; -*-
2
+ <%inherit file="/configure.mako" />
3
+
4
+ <%def name="form_content()">
5
+
6
+ <h3 class="block is-size-3">Basics</h3>
7
+ <div class="block" style="padding-left: 2rem; width: 50%;">
8
+
9
+ <b-field label="App Title">
10
+ <b-input name="${app.appname}.app_title"
11
+ v-model="simpleSettings['${app.appname}.app_title']"
12
+ @input="settingsNeedSaved = true">
13
+ </b-input>
14
+ </b-field>
15
+
16
+ <b-field>
17
+ <b-checkbox name="${app.appname}.production"
18
+ v-model="simpleSettings['${app.appname}.production']"
19
+ native-value="true"
20
+ @input="settingsNeedSaved = true">
21
+ Production Mode
22
+ </b-checkbox>
23
+ </b-field>
24
+
25
+ </div>
26
+
27
+ <h3 class="block is-size-3">Web Libraries</h3>
28
+ <div class="block" style="padding-left: 2rem;">
29
+
30
+ <${b}-table :data="weblibs">
31
+
32
+ <${b}-table-column field="title"
33
+ label="Name"
34
+ v-slot="props">
35
+ {{ props.row.title }}
36
+ </${b}-table-column>
37
+
38
+ <${b}-table-column field="configured_version"
39
+ label="Version"
40
+ v-slot="props">
41
+ {{ props.row.configured_version || props.row.default_version }}
42
+ </${b}-table-column>
43
+
44
+ <${b}-table-column field="configured_url"
45
+ label="URL Override"
46
+ v-slot="props">
47
+ {{ props.row.configured_url }}
48
+ </${b}-table-column>
49
+
50
+ <${b}-table-column field="live_url"
51
+ label="Effective (Live) URL"
52
+ v-slot="props">
53
+ <span v-if="props.row.modified"
54
+ class="has-text-warning">
55
+ save settings and refresh page to see new URL
56
+ </span>
57
+ <span v-if="!props.row.modified">
58
+ {{ props.row.live_url }}
59
+ </span>
60
+ </${b}-table-column>
61
+
62
+ <${b}-table-column field="actions"
63
+ label="Actions"
64
+ v-slot="props">
65
+ <a href="#"
66
+ @click.prevent="editWebLibraryInit(props.row)">
67
+ % if request.use_oruga:
68
+ <o-icon icon="edit" />
69
+ % else:
70
+ <i class="fas fa-edit"></i>
71
+ % endif
72
+ Edit
73
+ </a>
74
+ </${b}-table-column>
75
+
76
+ </${b}-table>
77
+
78
+ % for weblib in weblibs or []:
79
+ ${h.hidden('wuttaweb.libver.{}'.format(weblib['key']), **{':value': "simpleSettings['wuttaweb.libver.{}']".format(weblib['key'])})}
80
+ ${h.hidden('wuttaweb.liburl.{}'.format(weblib['key']), **{':value': "simpleSettings['wuttaweb.liburl.{}']".format(weblib['key'])})}
81
+ % endfor
82
+
83
+ <${b}-modal has-modal-card
84
+ % if request.use_oruga:
85
+ v-model:active="editWebLibraryShowDialog"
86
+ % else:
87
+ :active.sync="editWebLibraryShowDialog"
88
+ % endif
89
+ >
90
+ <div class="modal-card">
91
+
92
+ <header class="modal-card-head">
93
+ <p class="modal-card-title">Web Library: {{ editWebLibraryRecord.title }}</p>
94
+ </header>
95
+
96
+ <section class="modal-card-body">
97
+
98
+ <b-field grouped>
99
+
100
+ <b-field label="Default Version">
101
+ <b-input v-model="editWebLibraryRecord.default_version"
102
+ disabled>
103
+ </b-input>
104
+ </b-field>
105
+
106
+ <b-field label="Override Version">
107
+ <b-input v-model="editWebLibraryVersion">
108
+ </b-input>
109
+ </b-field>
110
+
111
+ </b-field>
112
+
113
+ <b-field label="Override URL">
114
+ <b-input v-model="editWebLibraryURL"
115
+ expanded />
116
+ </b-field>
117
+
118
+ <b-field label="Effective URL (as of last page load)">
119
+ <b-input v-model="editWebLibraryRecord.live_url"
120
+ disabled
121
+ expanded />
122
+ </b-field>
123
+
124
+ </section>
125
+
126
+ <footer class="modal-card-foot">
127
+ <b-button type="is-primary"
128
+ @click="editWebLibrarySave()"
129
+ icon-pack="fas"
130
+ icon-left="save">
131
+ Save
132
+ </b-button>
133
+ <b-button @click="editWebLibraryShowDialog = false">
134
+ Cancel
135
+ </b-button>
136
+ </footer>
137
+ </div>
138
+ </${b}-modal>
139
+
140
+ </div>
141
+ </%def>
142
+
143
+ <%def name="modify_this_page_vars()">
144
+ ${parent.modify_this_page_vars()}
145
+ <script>
146
+
147
+ ThisPageData.weblibs = ${json.dumps(weblibs or [])|n}
148
+
149
+ ThisPageData.editWebLibraryShowDialog = false
150
+ ThisPageData.editWebLibraryRecord = {}
151
+ ThisPageData.editWebLibraryVersion = null
152
+ ThisPageData.editWebLibraryURL = null
153
+
154
+ ThisPage.methods.editWebLibraryInit = function(row) {
155
+ this.editWebLibraryRecord = row
156
+ this.editWebLibraryVersion = row.configured_version
157
+ this.editWebLibraryURL = row.configured_url
158
+ this.editWebLibraryShowDialog = true
159
+ }
160
+
161
+ ThisPage.methods.editWebLibrarySave = function() {
162
+ this.editWebLibraryRecord.configured_version = this.editWebLibraryVersion
163
+ this.editWebLibraryRecord.configured_url = this.editWebLibraryURL
164
+ this.editWebLibraryRecord.modified = true
165
+
166
+ this.simpleSettings[`wuttaweb.libver.${'$'}{this.editWebLibraryRecord.key}`] = this.editWebLibraryVersion
167
+ this.simpleSettings[`wuttaweb.liburl.${'$'}{this.editWebLibraryRecord.key}`] = this.editWebLibraryURL
168
+
169
+ this.settingsNeedSaved = true
170
+ this.editWebLibraryShowDialog = false
171
+ }
172
+
173
+ </script>
174
+ </%def>
175
+
176
+
177
+ ${parent.body()}
@@ -209,16 +209,14 @@
209
209
  </div>
210
210
  </nav>
211
211
 
212
- <nav class="level" style="margin: 0.5rem auto;">
212
+ <nav class="level" style="margin: 0.5rem 0.5rem 0.5rem auto;">
213
213
  <div class="level-left">
214
214
 
215
215
  ## Current Context
216
216
  <div id="current-context" class="level-item">
217
217
  % if index_title:
218
218
  % if index_url:
219
- <span class="header-text">
220
- ${h.link_to(index_title, index_url)}
221
- </span>
219
+ <h1 class="title">${h.link_to(index_title, index_url)}</h1>
222
220
  % else:
223
221
  <h1 class="title">${index_title}</h1>
224
222
  % endif
@@ -226,6 +224,23 @@
226
224
  </div>
227
225
 
228
226
  </div><!-- level-left -->
227
+
228
+ <div class="level-right">
229
+
230
+ ## TODO
231
+ % if master and master.configurable and not master.configuring:
232
+ <div class="level-item">
233
+ <b-button type="is-primary"
234
+ tag="a"
235
+ href="${url(f'{route_prefix}.configure')}"
236
+ icon-pack="fas"
237
+ icon-left="cog">
238
+ Configure
239
+ </b-button>
240
+ </div>
241
+ % endif
242
+
243
+ </div> <!-- level-right -->
229
244
  </nav><!-- level -->
230
245
  </header>
231
246
 
@@ -318,8 +333,7 @@
318
333
  <div class="navbar-dropdown">
319
334
  % if request.is_root:
320
335
  ${h.form(url('stop_root'), ref='stopBeingRootForm')}
321
- ## TODO
322
- ## ${h.csrf_token(request)}
336
+ ${h.csrf_token(request)}
323
337
  <input type="hidden" name="referrer" value="${request.current_route_url()}" />
324
338
  <a @click="stopBeingRoot()"
325
339
  class="navbar-item has-background-danger has-text-white">
@@ -328,8 +342,7 @@
328
342
  ${h.end_form()}
329
343
  % elif request.is_admin:
330
344
  ${h.form(url('become_root'), ref='startBeingRootForm')}
331
- ## TODO
332
- ## ${h.csrf_token(request)}
345
+ ${h.csrf_token(request)}
333
346
  <input type="hidden" name="referrer" value="${request.current_route_url()}" />
334
347
  <a @click="startBeingRoot()"
335
348
  class="navbar-item has-background-danger has-text-white">
@@ -0,0 +1,181 @@
1
+ ## -*- coding: utf-8; -*-
2
+ <%inherit file="/page.mako" />
3
+
4
+ <%def name="title()">Configure ${config_title}</%def>
5
+
6
+ <%def name="page_content()">
7
+ <br />
8
+ ${self.buttons_content()}
9
+
10
+ ${h.form(request.current_route_url(), enctype='multipart/form-data', ref='saveSettingsForm', **{'@submit': 'saveSettingsFormSubmit'})}
11
+ ${h.csrf_token(request)}
12
+ ${self.form_content()}
13
+ ${h.end_form()}
14
+
15
+ <b-modal has-modal-card
16
+ :active.sync="purgeSettingsShowDialog">
17
+ <div class="modal-card">
18
+
19
+ <header class="modal-card-head">
20
+ <p class="modal-card-title">Remove All Settings</p>
21
+ </header>
22
+
23
+ <section class="modal-card-body">
24
+ <p class="block">
25
+ Really remove all settings for ${config_title} from the DB?
26
+ </p>
27
+ <p class="block">
28
+ Note that when you <span class="is-italic">save</span>
29
+ settings, any existing settings are first removed and then
30
+ new ones are saved.
31
+ </p>
32
+ <p class="block">
33
+ But here you can remove existing without saving new
34
+ ones.&nbsp; It is basically "factory reset" for
35
+ ${config_title}.
36
+ </p>
37
+ </section>
38
+
39
+ <footer class="modal-card-foot">
40
+ <b-button @click="purgeSettingsShowDialog = false">
41
+ Cancel
42
+ </b-button>
43
+ ${h.form(request.current_route_url())}
44
+ ${h.csrf_token(request)}
45
+ ${h.hidden('remove_settings', 'true')}
46
+ <b-button type="is-danger"
47
+ native-type="submit"
48
+ :disabled="purgingSettings"
49
+ icon-pack="fas"
50
+ icon-left="trash"
51
+ @click="purgingSettings = true">
52
+ {{ purgingSettings ? "Working, please wait..." : "Remove All Settings for ${config_title}" }}
53
+ </b-button>
54
+ ${h.end_form()}
55
+ </footer>
56
+ </div>
57
+ </b-modal>
58
+
59
+ </%def>
60
+
61
+ <%def name="buttons_content()">
62
+ <div class="level">
63
+ <div class="level-left">
64
+
65
+ <div class="level-item">
66
+ ${self.intro_message()}
67
+ </div>
68
+
69
+ <div class="level-item">
70
+ ${self.save_undo_buttons()}
71
+ </div>
72
+ </div>
73
+
74
+ <div class="level-right">
75
+ <div class="level-item">
76
+ ${self.purge_button()}
77
+ </div>
78
+ </div>
79
+ </div>
80
+ </%def>
81
+
82
+ <%def name="intro_message()">
83
+ <p class="block">
84
+ This page lets you modify the settings for ${config_title}.
85
+ </p>
86
+ </%def>
87
+
88
+ <%def name="save_undo_buttons()">
89
+ <div class="buttons"
90
+ v-if="settingsNeedSaved">
91
+ <b-button type="is-primary"
92
+ @click="saveSettings"
93
+ :disabled="savingSettings"
94
+ icon-pack="fas"
95
+ icon-left="save">
96
+ {{ savingSettings ? "Working, please wait..." : "Save All Settings" }}
97
+ </b-button>
98
+ <b-button tag="a" href="${request.current_route_url()}"
99
+ icon-pack="fas"
100
+ icon-left="undo"
101
+ @click="undoChanges = true"
102
+ :disabled="undoChanges">
103
+ {{ undoChanges ? "Working, please wait..." : "Undo All Changes" }}
104
+ </b-button>
105
+ </div>
106
+ </%def>
107
+
108
+ <%def name="purge_button()">
109
+ <b-button type="is-danger"
110
+ @click="purgeSettingsShowDialog = true"
111
+ icon-pack="fas"
112
+ icon-left="trash">
113
+ Remove All Settings
114
+ </b-button>
115
+ </%def>
116
+
117
+ <%def name="form_content()">
118
+ <b-notification type="is-warning"
119
+ :closable="false">
120
+ <h4 class="block is-size-4">
121
+ TODO: you must define the
122
+ <span class="is-family-monospace">&lt;%def name="form_content()"&gt;</span>
123
+ template block
124
+ </h4>
125
+ <p class="block">
126
+ or if you need more control, define the
127
+ <span class="is-family-monospace">&lt;%def name="page_content()"&gt;</span>
128
+ template block
129
+ </p>
130
+ <p class="block">
131
+ for a real-world example see template at
132
+ <span class="is-family-monospace">wuttaweb:templates/appinfo/configure.mako</span>
133
+ </p>
134
+ </b-notification>
135
+ </%def>
136
+
137
+ <%def name="modify_this_page_vars()">
138
+ ${parent.modify_this_page_vars()}
139
+ <script>
140
+
141
+ % if simple_settings is not Undefined:
142
+ ThisPageData.simpleSettings = ${json.dumps(simple_settings)|n}
143
+ % endif
144
+
145
+ ThisPageData.purgeSettingsShowDialog = false
146
+ ThisPageData.purgingSettings = false
147
+
148
+ ThisPageData.settingsNeedSaved = false
149
+ ThisPageData.undoChanges = false
150
+ ThisPageData.savingSettings = false
151
+
152
+ ThisPage.methods.saveSettings = function() {
153
+ this.savingSettings = true
154
+ this.$refs.saveSettingsForm.submit()
155
+ }
156
+
157
+ // nb. this is here to avoid auto-submitting form when user
158
+ // presses ENTER while some random input field has focus
159
+ ThisPage.methods.saveSettingsFormSubmit = function(event) {
160
+ if (!this.savingSettings) {
161
+ event.preventDefault()
162
+ }
163
+ }
164
+
165
+ // cf. https://stackoverflow.com/a/56551646
166
+ ThisPage.methods.beforeWindowUnload = function(e) {
167
+ if (this.settingsNeedSaved && !this.savingSettings && !this.undoChanges) {
168
+ e.preventDefault()
169
+ e.returnValue = ''
170
+ }
171
+ }
172
+
173
+ ThisPage.created = function() {
174
+ window.addEventListener('beforeunload', this.beforeWindowUnload)
175
+ }
176
+
177
+ </script>
178
+ </%def>
179
+
180
+
181
+ ${parent.body()}
@@ -2,6 +2,7 @@
2
2
 
3
3
  <script type="text/x-template" id="${form.vue_tagname}-template">
4
4
  ${h.form(form.action_url, method='post', enctype='multipart/form-data', **form_attrs)}
5
+ ${h.csrf_token(request)}
5
6
 
6
7
  <section>
7
8
  % for fieldname in form:
@@ -0,0 +1,9 @@
1
+ ## -*- coding: utf-8; -*-
2
+ <%inherit file="/configure.mako" />
3
+
4
+ ## NB. /master/configure.mako is only a placeholder.
5
+ ## there is no reason to *inherit* from this template;
6
+ ## you can always just inherit from /configure.mako
7
+
8
+
9
+ ${parent.body()}