fix: improve release visibility and cache handling
This commit is contained in:
+16
-1
@@ -55,6 +55,21 @@ If `build_info.json` is missing, malformed, or does not contain a usable value,
|
||||
|
||||
The data is loaded centrally in `app.py` and made available to every template as `build_info`.
|
||||
|
||||
## Cache and Release Visibility
|
||||
|
||||
RollCalc uses the current build identifier to cache-bust RollCalc-owned static assets referenced by active templates. The preferred identifier is `build_info.commit`; if it is missing or `unknown`, the fallback is `build_info.version`.
|
||||
|
||||
Dynamic HTML responses are sent with `Cache-Control: no-cache` so the calculator and Help pages are revalidated after deployments. Static assets are not globally marked no-cache; versioned URLs are used for active static JSON assets instead.
|
||||
|
||||
For releases, keep these sources aligned:
|
||||
|
||||
- `build_info.json`
|
||||
- the default `VERSION` in `scripts/update_build_info.sh`, unless deployment overrides it
|
||||
- the newest heading in `docs/de/recent_changes.md`
|
||||
- `version` in `static/recent_changes.json`
|
||||
|
||||
The Recent Changes page includes a persistent force-reload fallback note for users whose browser still shows an older interface after deployment.
|
||||
|
||||
## Help and User Manual
|
||||
|
||||
The in-app Help area keeps `docs/de/user_manual.md` as the leading German documentation source. RollCalc reads the Markdown file on each `/help/user-manual` request and renders it server-side with `markdown-it-py`.
|
||||
@@ -105,7 +120,7 @@ The short dialog item list is maintained separately in:
|
||||
static/recent_changes.json
|
||||
```
|
||||
|
||||
This JSON is a compact summary for the dialog, not the complete release history. Keep it aligned with the most relevant current entries from `docs/de/recent_changes.md`.
|
||||
This JSON is a compact summary for the dialog, not the complete release history. It contains a `version` field and an `items` list. The browser displays the dialog only when the JSON version matches `build_info.version`; mismatched or invalid JSON must not block the calculator.
|
||||
|
||||
## Authentication
|
||||
|
||||
|
||||
@@ -223,7 +223,38 @@ The short dialog summary is maintained in:
|
||||
static/recent_changes.json
|
||||
```
|
||||
|
||||
Keep `docs/de/recent_changes.md` as the complete release-note source and `static/recent_changes.json` as the short 3-5 item summary for the startup dialog.
|
||||
The JSON is versioned:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "v0.4-beta2",
|
||||
"items": []
|
||||
}
|
||||
```
|
||||
|
||||
The dialog loads this file in the browser and only displays the items when `static/recent_changes.json.version` matches `build_info.version`. Keep `docs/de/recent_changes.md` as the complete user-facing release-note source and `static/recent_changes.json` as the short 3-5 item summary for the currently deployed version.
|
||||
|
||||
### Browser Cache and Release Visibility
|
||||
|
||||
RollCalc uses the build identifier as a cache-busting query parameter for RollCalc-owned static assets referenced by active templates. The preferred identifier is `build_info.commit`; if it is missing or `unknown`, the app falls back to `build_info.version`.
|
||||
|
||||
Dynamic HTML responses use:
|
||||
|
||||
```text
|
||||
Cache-Control: no-cache
|
||||
```
|
||||
|
||||
This requires browser revalidation for the calculator and Help pages while allowing versioned static assets to be cached normally.
|
||||
|
||||
For each deployment, keep these sources aligned:
|
||||
|
||||
- `build_info.json`
|
||||
- `scripts/update_build_info.sh` default `VERSION`, unless overridden during deployment
|
||||
- newest section in `docs/de/recent_changes.md`
|
||||
- `version` in `static/recent_changes.json`
|
||||
|
||||
If RollCalc does not display the latest interface after an update, perform a force reload:
|
||||
`Ctrl+F5` or `Ctrl+Shift+R` on Windows/Linux, `Cmd+Shift+R` on macOS.
|
||||
|
||||
## User Manual PDF Export
|
||||
|
||||
|
||||
@@ -75,23 +75,32 @@ BUILD_INFO = load_build_info()
|
||||
|
||||
|
||||
def load_whats_new_summary():
|
||||
"""Load compact release notes for the What's New dialog."""
|
||||
"""Load compact release-note metadata for the What's New dialog."""
|
||||
try:
|
||||
with open(WHATS_NEW_SUMMARY_FILE, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
except Exception as e:
|
||||
print(f"[What's New Error] {e}")
|
||||
return []
|
||||
return {"version": "unknown", "items": []}
|
||||
|
||||
items = data.get("items") if isinstance(data, dict) else None
|
||||
if not isinstance(data, dict):
|
||||
return {"version": "unknown", "items": []}
|
||||
|
||||
version = data.get("version")
|
||||
items = data.get("items")
|
||||
if not isinstance(items, list):
|
||||
return []
|
||||
items = []
|
||||
|
||||
return [
|
||||
item.strip()
|
||||
for item in items
|
||||
if isinstance(item, str) and item.strip()
|
||||
][:5]
|
||||
return {
|
||||
"version": version.strip()
|
||||
if isinstance(version, str) and version.strip()
|
||||
else "unknown",
|
||||
"items": [
|
||||
item.strip()
|
||||
for item in items
|
||||
if isinstance(item, str) and item.strip()
|
||||
][:5]
|
||||
}
|
||||
|
||||
|
||||
WHATS_NEW_SUMMARY = load_whats_new_summary()
|
||||
@@ -101,9 +110,36 @@ def inject_build_info():
|
||||
"""Make build metadata and release-note summary available in templates."""
|
||||
return {
|
||||
"build_info": BUILD_INFO,
|
||||
"whats_new_summary": WHATS_NEW_SUMMARY
|
||||
"whats_new_summary": WHATS_NEW_SUMMARY,
|
||||
"static_asset_url": static_asset_url
|
||||
}
|
||||
|
||||
|
||||
def get_static_asset_version(build_info=None):
|
||||
"""Return the preferred cache-busting build identifier."""
|
||||
info = build_info or BUILD_INFO
|
||||
for key in ("commit", "version"):
|
||||
value = info.get(key) if isinstance(info, dict) else None
|
||||
if isinstance(value, str) and value.strip() and value.strip() != "unknown":
|
||||
return value.strip()
|
||||
return None
|
||||
|
||||
|
||||
def static_asset_url(filename):
|
||||
"""Build a URL for RollCalc-owned static assets with a build query."""
|
||||
asset_version = get_static_asset_version()
|
||||
if asset_version:
|
||||
return url_for("serve_static", filename=filename, v=asset_version)
|
||||
return url_for("serve_static", filename=filename)
|
||||
|
||||
|
||||
@app.after_request
|
||||
def add_html_cache_policy(response):
|
||||
"""Require revalidation for dynamic HTML while leaving static caching intact."""
|
||||
if response.mimetype == "text/html":
|
||||
response.headers["Cache-Control"] = "no-cache"
|
||||
return response
|
||||
|
||||
# ============================================================================
|
||||
# AUTHENTICATION
|
||||
# ============================================================================
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
# Recent Changes
|
||||
|
||||
## Version 0.4
|
||||
## v0.4-beta2 — Current Version
|
||||
|
||||
- English Quick Reference added to the integrated Help area for the main calculation and transport-analysis workflows.
|
||||
- Release notes and What’s New now focus on the currently deployed version.
|
||||
- Browser cache handling improved so updated frontend data is loaded more reliably after deployments.
|
||||
|
||||
## After an Update
|
||||
|
||||
If RollCalc does not display the latest interface after an update, perform a force reload:
|
||||
Ctrl+F5 or Ctrl+Shift+R on Windows/Linux,
|
||||
Cmd+Shift+R on macOS.
|
||||
|
||||
## Earlier Changes
|
||||
|
||||
- User Manual integrated into RollCalc.
|
||||
- Help area added for internal documentation.
|
||||
- English Quick Reference added to the integrated Help area for the main calculation and transport-analysis workflows.
|
||||
- Capacity Analysis presentation improved.
|
||||
- Governing Constraint highlighted more clearly.
|
||||
- Remaining Capacity added to the Capacity Summary.
|
||||
|
||||
@@ -3,7 +3,7 @@ set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
VERSION="${VERSION:-v0.4-dev}"
|
||||
VERSION="${VERSION:-v0.4-beta2}"
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
{
|
||||
"version": "v0.4-beta2",
|
||||
"items": [
|
||||
"User Manual integrated",
|
||||
"English Quick Reference added to the Help area",
|
||||
"Capacity Analysis improved",
|
||||
"Governing Constraint clarified",
|
||||
"Remaining Capacity added"
|
||||
"English Quick Reference added to the Help area.",
|
||||
"Recent Changes now identifies the current deployed version.",
|
||||
"Browser cache handling improved for updated frontend data."
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1023,6 +1023,8 @@
|
||||
// =====================================================
|
||||
window.ARTICLE_DATA = [];
|
||||
window.APP_CONFIG = {"forklift_rules":{"applicable_categories":["bentofix"],"rules":[{"weight_threshold_kg":1700,"max_weight_kg":2750,"requirements":{"min_core_outer_diameter_mm":170},"messages":{"en":{"warning_title":"Heavy Roll – Special Equipment Required","core_ok":"Core diameter OK (≥ 170 mm)","core_nok":"Core diameter too small"}}}],"hard_limit":{"max_weight_kg":2750,"messages":{"en":{"block_title":"Weight Limit Exceeded","block_text":"Roll weight exceeds 2750 kg maximum"}}}}};
|
||||
const ROLLCALC_ARTICLE_DATA_URL = {{ static_asset_url('article-data.json')|tojson }};
|
||||
const ROLLCALC_RECENT_CHANGES_JSON_URL = {{ static_asset_url('recent_changes.json')|tojson }};
|
||||
|
||||
// =====================================================
|
||||
// LOAD ARTICLE DATA
|
||||
@@ -1087,7 +1089,7 @@ function populateArticleDropdowns() {
|
||||
|
||||
(async function() {
|
||||
try {
|
||||
const resp = await fetch('/static/article-data.json');
|
||||
const resp = await fetch(ROLLCALC_ARTICLE_DATA_URL);
|
||||
if (resp.ok) {
|
||||
window.ARTICLE_DATA = await resp.json();
|
||||
console.log('✅ Article data loaded:', window.ARTICLE_DATA.length, 'items');
|
||||
@@ -1645,7 +1647,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
|
||||
const ROLLCALC_BUILD_VERSION = {{ build_info.version|tojson }};
|
||||
const ROLLCALC_WHATS_NEW_ITEMS = {{ whats_new_summary|tojson }};
|
||||
const ROLLCALC_LAST_SEEN_VERSION_KEY = 'rollcalc_last_seen_version';
|
||||
|
||||
function shouldShowWhatsNew(currentVersion, storedVersion) {
|
||||
@@ -1675,16 +1676,41 @@ function renderWhatsNewItems(items) {
|
||||
});
|
||||
}
|
||||
|
||||
function maybeShowWhatsNew() {
|
||||
async function loadWhatsNewData(currentVersion) {
|
||||
try {
|
||||
const resp = await fetch(ROLLCALC_RECENT_CHANGES_JSON_URL);
|
||||
if (!resp.ok) {
|
||||
console.warn('Could not load RollCalc release notes summary:', resp.status);
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = await resp.json();
|
||||
if (!data || typeof data.version !== 'string' || !Array.isArray(data.items)) {
|
||||
console.warn('Invalid RollCalc release notes summary format');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (data.version !== currentVersion) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const items = data.items.filter(item =>
|
||||
typeof item === 'string' && item.trim()
|
||||
);
|
||||
return items.length ? { version: data.version, items } : null;
|
||||
} catch (e) {
|
||||
console.warn('Could not load RollCalc release notes summary', e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function maybeShowWhatsNew() {
|
||||
const overlay = document.getElementById('whatsNewOverlay');
|
||||
const versionValue = document.getElementById('whatsNewVersion');
|
||||
const continueBtn = document.getElementById('whatsNewContinueBtn');
|
||||
const openChangesBtn = document.getElementById('whatsNewOpenChangesBtn');
|
||||
const items = Array.isArray(ROLLCALC_WHATS_NEW_ITEMS)
|
||||
? ROLLCALC_WHATS_NEW_ITEMS
|
||||
: [];
|
||||
|
||||
if (!overlay || !versionValue || !continueBtn || !openChangesBtn || items.length === 0) return;
|
||||
if (!overlay || !versionValue || !continueBtn || !openChangesBtn) return;
|
||||
|
||||
let storedVersion = null;
|
||||
try {
|
||||
@@ -1695,8 +1721,11 @@ function maybeShowWhatsNew() {
|
||||
|
||||
if (!shouldShowWhatsNew(ROLLCALC_BUILD_VERSION, storedVersion)) return;
|
||||
|
||||
const releaseData = await loadWhatsNewData(ROLLCALC_BUILD_VERSION);
|
||||
if (!releaseData) return;
|
||||
|
||||
versionValue.textContent = ROLLCALC_BUILD_VERSION;
|
||||
renderWhatsNewItems(items);
|
||||
renderWhatsNewItems(releaseData.items);
|
||||
overlay.classList.remove('is-hidden');
|
||||
|
||||
continueBtn.addEventListener('click', () => {
|
||||
|
||||
Reference in New Issue
Block a user