Changement du refresh handler, soft reset d'ajouter sur beaucoup de formulaire de modification
CI - Security, Lint & Tests / validate (push) Failing after 1m3s
CI - Security, Lint & Tests / validate (push) Failing after 1m3s
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
"""Helpers for mutating routes that should not force a full page reload.
|
||||
|
||||
The site is server-rendered, and every mutating route used to end with
|
||||
``return redirect(url_for(...))``, so each change reloaded the whole page:
|
||||
scroll reset, open dialogs closed, and chaining several edits meant waiting
|
||||
for a full render between each one.
|
||||
|
||||
These helpers let a route answer an AJAX submit (the ``data-ajax`` forms in
|
||||
main.js) with a small JSON payload instead of a redirect, while the plain
|
||||
HTML form path keeps behaving exactly as before. The client then fetches the
|
||||
page again and swaps only the content region, so the page never reloads.
|
||||
|
||||
The counterpart that performs the swap lives in app/static/js/main.js.
|
||||
"""
|
||||
|
||||
from flask import get_flashed_messages, jsonify, redirect, request, session
|
||||
|
||||
from app.models import AppSettings
|
||||
|
||||
#: Key holding a coarse, monotonically increasing stamp for the whole dataset.
|
||||
#: It advances after every committed mutation so a stale client can be told
|
||||
#: (with a 409) that someone else has changed what it is looking at.
|
||||
REVISION_KEY = 'data_revision'
|
||||
|
||||
|
||||
def is_ajax_submit():
|
||||
"""Whether this POST came from the fetch-based form handler in main.js."""
|
||||
return request.headers.get('X-Requested-With') == 'XMLHttpRequest'
|
||||
|
||||
|
||||
def current_revision():
|
||||
"""The current revision stamp, as an int (0 when nothing has been bumped)."""
|
||||
try:
|
||||
return int(AppSettings.get(REVISION_KEY, '0') or '0')
|
||||
except (TypeError, ValueError):
|
||||
return 0
|
||||
|
||||
|
||||
def bump_revision():
|
||||
"""Advance the revision stamp after a committed change.
|
||||
|
||||
Stored through AppSettings so it survives restarts and is shared by every
|
||||
worker, unlike a module-level counter.
|
||||
"""
|
||||
AppSettings.set(REVISION_KEY, str(current_revision() + 1))
|
||||
|
||||
|
||||
def _flashed_success():
|
||||
"""Whether a success flash is pending, without consuming it.
|
||||
|
||||
The HTML path still redirects and must leave the flash for the next page
|
||||
to render; peeking at the session is the only way to know without clearing
|
||||
it. Only a successful commit advances the revision -- a rejected edit must
|
||||
not make other users reload for nothing.
|
||||
"""
|
||||
flashes = session.get('_flashes', [])
|
||||
return any(category == 'success' for category, _message in flashes)
|
||||
|
||||
|
||||
def respond_after_change(redirect_url):
|
||||
"""Answer a committed (or rejected) mutation.
|
||||
|
||||
For a normal HTML form submit this is exactly the ``redirect(...)`` the
|
||||
routes used to return. For an AJAX submit it returns JSON telling the
|
||||
client where to fetch the refreshed fragment and which flash messages to
|
||||
show, so the page can update in place instead of reloading.
|
||||
"""
|
||||
if _flashed_success():
|
||||
bump_revision()
|
||||
|
||||
if is_ajax_submit():
|
||||
messages = [
|
||||
{'category': category, 'text': message}
|
||||
for category, message in get_flashed_messages(with_categories=True)
|
||||
]
|
||||
return jsonify(
|
||||
{
|
||||
'ok': True,
|
||||
'redirect': redirect_url,
|
||||
'messages': messages,
|
||||
'revision': current_revision(),
|
||||
}
|
||||
)
|
||||
return redirect(redirect_url)
|
||||
Reference in New Issue
Block a user