Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d30d7e7ecc | ||
|
|
71c78476a2 | ||
|
|
156a6b744a | ||
|
|
b812f1658e | ||
|
|
8d6d85bd2e | ||
|
|
3507c323e6 | ||
|
|
f81d6a871a |
+34
-3
@@ -18,6 +18,7 @@ Backend:
|
|||||||
- `/` renders the active calculator template.
|
- `/` renders the active calculator template.
|
||||||
- `/help` renders the authenticated Help landing page.
|
- `/help` renders the authenticated Help landing page.
|
||||||
- `/help/user-manual` renders `docs/de/user_manual.md` server-side inside the RollCalc Help layout.
|
- `/help/user-manual` renders `docs/de/user_manual.md` server-side inside the RollCalc Help layout.
|
||||||
|
- `/help/quick-reference` renders `docs/en/quick_reference.md` server-side inside the RollCalc Help layout.
|
||||||
- `/help/recent-changes` renders `docs/de/recent_changes.md` server-side inside the RollCalc Help layout.
|
- `/help/recent-changes` renders `docs/de/recent_changes.md` server-side inside the RollCalc Help layout.
|
||||||
- `/help/user-manual/screenshots/<path:filename>` serves German manual screenshots from `docs/de/screenshots/`.
|
- `/help/user-manual/screenshots/<path:filename>` serves German manual screenshots from `docs/de/screenshots/`.
|
||||||
- `/static/<path:filename>` is intended to serve static files behind Basic Auth.
|
- `/static/<path:filename>` is intended to serve static files behind Basic Auth.
|
||||||
@@ -54,10 +55,27 @@ 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`.
|
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
|
## 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`.
|
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`.
|
||||||
|
|
||||||
|
`docs/en/quick_reference.md` is the English Quick Reference source and is rendered at `/help/quick-reference`. It is derived from the full German User Manual and must remain a concise workflow reference rather than an independently diverging technical source.
|
||||||
|
|
||||||
The documentation structure is prepared for language-specific manuals:
|
The documentation structure is prepared for language-specific manuals:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
@@ -65,9 +83,11 @@ docs/
|
|||||||
de/
|
de/
|
||||||
user_manual.md
|
user_manual.md
|
||||||
screenshots/
|
screenshots/
|
||||||
|
en/
|
||||||
|
quick_reference.md
|
||||||
```
|
```
|
||||||
|
|
||||||
Additional languages can follow the same structure later. The current public route still opens the German manual and no language switcher is implemented.
|
Additional languages can follow the same structure later. The current public route still opens the German manual, the Quick Reference is currently English only, and no language switcher is implemented.
|
||||||
|
|
||||||
Rendering rules:
|
Rendering rules:
|
||||||
|
|
||||||
@@ -86,7 +106,7 @@ Full user-facing release notes are maintained in:
|
|||||||
docs/de/recent_changes.md
|
docs/de/recent_changes.md
|
||||||
```
|
```
|
||||||
|
|
||||||
The calculator header links directly to `/help/user-manual`. The Help landing page lists only existing documents, currently User Manual and Recent Changes.
|
The calculator header links directly to `/help/user-manual`. The Help landing page lists only existing documents, currently User Manual, Quick Reference, and Recent Changes.
|
||||||
|
|
||||||
The startup What's New dialog uses `build_info.version` and is suppressed when the version is empty or `unknown`. The last acknowledged version is stored only in browser `localStorage` under:
|
The startup What's New dialog uses `build_info.version` and is suppressed when the version is empty or `unknown`. The last acknowledged version is stored only in browser `localStorage` under:
|
||||||
|
|
||||||
@@ -100,7 +120,7 @@ The short dialog item list is maintained separately in:
|
|||||||
static/recent_changes.json
|
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
|
## Authentication
|
||||||
|
|
||||||
@@ -221,6 +241,17 @@ Important data rule:
|
|||||||
- Article data is generated from ERP-derived sources.
|
- Article data is generated from ERP-derived sources.
|
||||||
- These values should not be manually changed unless the task is explicitly data maintenance.
|
- These values should not be manually changed unless the task is explicitly data maintenance.
|
||||||
|
|
||||||
|
Article-data architecture decision:
|
||||||
|
|
||||||
|
- Article data should evolve from a simple article catalogue into a shared production knowledge base.
|
||||||
|
- Each article may optionally provide production-related default values.
|
||||||
|
- Initial defaults include `Product Thickness`, `Area Weight`, `Core Diameter`, and `Roll Width`.
|
||||||
|
- Future production-related defaults can be added without changing the overall architecture.
|
||||||
|
- When an article is selected, available defaults are copied into the calculator fields.
|
||||||
|
- Missing optional values must never overwrite existing user input.
|
||||||
|
- All automatically populated values remain editable by the user.
|
||||||
|
- The planned Article-Data-Admin application will become the authoritative editor for these production defaults.
|
||||||
|
|
||||||
Known domain caveat from existing project notes:
|
Known domain caveat from existing project notes:
|
||||||
|
|
||||||
- For articles in the groups Secugrid, Combigrid, Carbofol MF/MF, Carbofol F/F, Carbofol s/F, and Carbofol BF/s, the thickness from `article-data.json` must not be used without domain validation.
|
- For articles in the groups Secugrid, Combigrid, Carbofol MF/MF, Carbofol F/F, Carbofol s/F, and Carbofol BF/s, the thickness from `article-data.json` must not be used without domain validation.
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ Implemented routes:
|
|||||||
| `/` | `GET` | Basic Auth | Renders `templates/roll_calculator.html`. |
|
| `/` | `GET` | Basic Auth | Renders `templates/roll_calculator.html`. |
|
||||||
| `/help` | `GET` | Basic Auth | Renders the Help landing page. |
|
| `/help` | `GET` | Basic Auth | Renders the Help landing page. |
|
||||||
| `/help/user-manual` | `GET` | Basic Auth | Reads `docs/de/user_manual.md`, renders it as HTML, and displays it in the RollCalc Help layout. |
|
| `/help/user-manual` | `GET` | Basic Auth | Reads `docs/de/user_manual.md`, renders it as HTML, and displays it in the RollCalc Help layout. |
|
||||||
|
| `/help/quick-reference` | `GET` | Basic Auth | Reads `docs/en/quick_reference.md`, renders it as HTML, and displays it in the RollCalc Help layout. |
|
||||||
| `/help/recent-changes` | `GET` | Basic Auth | Reads `docs/de/recent_changes.md`, renders it as HTML, and displays it in the RollCalc Help layout. |
|
| `/help/recent-changes` | `GET` | Basic Auth | Reads `docs/de/recent_changes.md`, renders it as HTML, and displays it in the RollCalc Help layout. |
|
||||||
| `/help/user-manual/screenshots/<path:filename>` | `GET` | Basic Auth | Serves German user-manual screenshots from `docs/de/screenshots/` only. |
|
| `/help/user-manual/screenshots/<path:filename>` | `GET` | Basic Auth | Serves German user-manual screenshots from `docs/de/screenshots/` only. |
|
||||||
| `/static/<path:filename>` | `GET` | Basic Auth | Intended protected static-file serving from `static/`. |
|
| `/static/<path:filename>` | `GET` | Basic Auth | Intended protected static-file serving from `static/`. |
|
||||||
@@ -173,8 +174,16 @@ Recent changes are available at:
|
|||||||
/help/recent-changes
|
/help/recent-changes
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The English Quick Reference is available at:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/help/quick-reference
|
||||||
|
```
|
||||||
|
|
||||||
`docs/de/user_manual.md` is the leading source for the German user manual. The app reads this Markdown file on request and renders it server-side with `markdown-it-py`; no generated static HTML copy is maintained. Raw HTML in the Markdown source is disabled during rendering.
|
`docs/de/user_manual.md` is the leading source for the German user manual. The app reads this Markdown file on request and renders it server-side with `markdown-it-py`; no generated static HTML copy is maintained. Raw HTML in the Markdown source is disabled during rendering.
|
||||||
|
|
||||||
|
`docs/en/quick_reference.md` is the Markdown source for the English Quick Reference. It is derived from the full German User Manual and must remain a concise reference for common workflows, not an independently diverging technical source.
|
||||||
|
|
||||||
`docs/de/recent_changes.md` is the leading source for full German release notes. It is rendered through the same authenticated Markdown infrastructure.
|
`docs/de/recent_changes.md` is the leading source for full German release notes. It is rendered through the same authenticated Markdown infrastructure.
|
||||||
|
|
||||||
The documentation directory is prepared for additional languages:
|
The documentation directory is prepared for additional languages:
|
||||||
@@ -184,9 +193,11 @@ docs/
|
|||||||
de/
|
de/
|
||||||
user_manual.md
|
user_manual.md
|
||||||
screenshots/
|
screenshots/
|
||||||
|
en/
|
||||||
|
quick_reference.md
|
||||||
```
|
```
|
||||||
|
|
||||||
The public route `/help/user-manual` currently opens the German manual. No language switcher is implemented yet.
|
The public route `/help/user-manual` currently opens the German manual. The Quick Reference is currently English only. No language switcher is implemented yet.
|
||||||
|
|
||||||
Screenshots referenced from the manual as `screenshots/filename.png` should be placed in:
|
Screenshots referenced from the manual as `screenshots/filename.png` should be placed in:
|
||||||
|
|
||||||
@@ -212,7 +223,38 @@ The short dialog summary is maintained in:
|
|||||||
static/recent_changes.json
|
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
|
## User Manual PDF Export
|
||||||
|
|
||||||
|
|||||||
+58
@@ -15,3 +15,61 @@
|
|||||||
## Version 0.5
|
## Version 0.5
|
||||||
- Schnittstelle bzw. Import-/Deployment-Prozess zwischen externer Artikelverwaltungs-App und RollCalc definieren
|
- Schnittstelle bzw. Import-/Deployment-Prozess zwischen externer Artikelverwaltungs-App und RollCalc definieren
|
||||||
- Rollen-/Berechtigungskonzept für Zugriff auf RollCalc und externe Artikelverwaltung klären
|
- Rollen-/Berechtigungskonzept für Zugriff auf RollCalc und externe Artikelverwaltung klären
|
||||||
|
|
||||||
|
### Article Data and Selection Improvements
|
||||||
|
|
||||||
|
- Article-specific production defaults
|
||||||
|
- Each article in `article-data.json` may optionally provide production-related default values.
|
||||||
|
- Initially planned defaults are `Product Thickness`, `Area Weight`, `Core Diameter`, and `Roll Width`.
|
||||||
|
- When an article is selected, available defaults should be copied into the existing calculator fields.
|
||||||
|
- Missing optional defaults must not clear or overwrite existing user input.
|
||||||
|
- Users must always be able to override suggested values manually.
|
||||||
|
- Stored `Core Diameter` values must match the values already allowed by the existing GUI control.
|
||||||
|
- `Roll Width` must be positive and plausible because it affects both `Roll Weight` and geometric loading in the `Load Optimizer`.
|
||||||
|
- The design should allow additional production-related defaults to be added later without changing the overall architecture. Possible future examples include preferred transport preset, minimum product length, maximum roll diameter, preferred rounding behavior, production restrictions, and handling limits.
|
||||||
|
- Maintenance of these defaults should be handled by the planned local Article-Data-Admin tool.
|
||||||
|
- Out of scope: deriving values from product group, production line, or site; multiple typical widths per article; multiple possible cores per article; locking manual edits; core load-bearing checks; line-dependent width checks; automatic `Roll Width` optimization.
|
||||||
|
|
||||||
|
### Production Line and Site Rules
|
||||||
|
|
||||||
|
- Define the data source and rule model for production-line- and site-dependent diameter limits.
|
||||||
|
- This planning is separate from article-specific production defaults.
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
- Derive the German Quick Reference from the full User Manual.
|
||||||
|
|
||||||
|
## Version 0.6
|
||||||
|
|
||||||
|
### Roll Planning and Limits
|
||||||
|
|
||||||
|
- Plan and validate minimum allowed `Product Length`.
|
||||||
|
- Validate minimum and maximum `Roll Diameter` once a defined source for production-line and site rules exists.
|
||||||
|
|
||||||
|
### Rounding and Production Logic
|
||||||
|
|
||||||
|
- Configurable rounding for suggested `Product Length` at a given diameter.
|
||||||
|
- Allow rounding up or down.
|
||||||
|
- Make the step size configurable, for example 5 m increments.
|
||||||
|
- Rounding must not violate minimum product length or any other technical limit.
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
- Add the English Quick Reference based on the German Quick Reference and the language-aware Help structure.
|
||||||
|
|
||||||
|
## Version 0.7
|
||||||
|
|
||||||
|
### Handling and Safety Checks
|
||||||
|
|
||||||
|
- Plan extended checks for `Roll Weight`.
|
||||||
|
- Forklift load capacity.
|
||||||
|
- Mandrel load capacity.
|
||||||
|
- Core load capacity.
|
||||||
|
- Additional relevant handling limits.
|
||||||
|
- Requires defined limits and data sources for forklift, mandrel, and core.
|
||||||
|
|
||||||
|
### Result Export
|
||||||
|
|
||||||
|
- PDF export for a concrete calculation result.
|
||||||
|
- Keep separate from the User Manual PDF export.
|
||||||
|
- Stabilize only after the result layout and exported metrics are defined.
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ DOCS_DIR = os.path.join(app.root_path, "docs")
|
|||||||
DEFAULT_DOC_LANGUAGE = "de"
|
DEFAULT_DOC_LANGUAGE = "de"
|
||||||
USER_MANUAL_FILENAME = "user_manual.md"
|
USER_MANUAL_FILENAME = "user_manual.md"
|
||||||
RECENT_CHANGES_FILENAME = "recent_changes.md"
|
RECENT_CHANGES_FILENAME = "recent_changes.md"
|
||||||
|
QUICK_REFERENCE_FILENAME = "quick_reference.md"
|
||||||
WHATS_NEW_SUMMARY_FILE = os.path.join(app.root_path, "static", "recent_changes.json")
|
WHATS_NEW_SUMMARY_FILE = os.path.join(app.root_path, "static", "recent_changes.json")
|
||||||
UNKNOWN_BUILD_INFO = {
|
UNKNOWN_BUILD_INFO = {
|
||||||
"version": "unknown",
|
"version": "unknown",
|
||||||
@@ -74,23 +75,32 @@ BUILD_INFO = load_build_info()
|
|||||||
|
|
||||||
|
|
||||||
def load_whats_new_summary():
|
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:
|
try:
|
||||||
with open(WHATS_NEW_SUMMARY_FILE, "r", encoding="utf-8") as f:
|
with open(WHATS_NEW_SUMMARY_FILE, "r", encoding="utf-8") as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[What's New Error] {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):
|
if not isinstance(items, list):
|
||||||
return []
|
items = []
|
||||||
|
|
||||||
return [
|
return {
|
||||||
item.strip()
|
"version": version.strip()
|
||||||
for item in items
|
if isinstance(version, str) and version.strip()
|
||||||
if isinstance(item, str) and item.strip()
|
else "unknown",
|
||||||
][:5]
|
"items": [
|
||||||
|
item.strip()
|
||||||
|
for item in items
|
||||||
|
if isinstance(item, str) and item.strip()
|
||||||
|
][:5]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
WHATS_NEW_SUMMARY = load_whats_new_summary()
|
WHATS_NEW_SUMMARY = load_whats_new_summary()
|
||||||
@@ -100,9 +110,36 @@ def inject_build_info():
|
|||||||
"""Make build metadata and release-note summary available in templates."""
|
"""Make build metadata and release-note summary available in templates."""
|
||||||
return {
|
return {
|
||||||
"build_info": BUILD_INFO,
|
"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
|
# AUTHENTICATION
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
@@ -305,6 +342,11 @@ def render_recent_changes(language=DEFAULT_DOC_LANGUAGE):
|
|||||||
"""Read and render the Markdown recent changes document."""
|
"""Read and render the Markdown recent changes document."""
|
||||||
return render_markdown_document(RECENT_CHANGES_FILENAME, language)
|
return render_markdown_document(RECENT_CHANGES_FILENAME, language)
|
||||||
|
|
||||||
|
|
||||||
|
def render_quick_reference(language="en"):
|
||||||
|
"""Read and render the Markdown quick reference document."""
|
||||||
|
return render_markdown_document(QUICK_REFERENCE_FILENAME, language)
|
||||||
|
|
||||||
@app.route("/", methods=["GET"])
|
@app.route("/", methods=["GET"])
|
||||||
@auth.login_required
|
@auth.login_required
|
||||||
def index():
|
def index():
|
||||||
@@ -330,6 +372,12 @@ def user_manual():
|
|||||||
"user_manual.html",
|
"user_manual.html",
|
||||||
document_title="User Manual",
|
document_title="User Manual",
|
||||||
document_subtitle="RollCalc technical user documentation",
|
document_subtitle="RollCalc technical user documentation",
|
||||||
|
document_actions=[
|
||||||
|
{
|
||||||
|
"href": url_for("quick_reference"),
|
||||||
|
"label": "Open English Quick Reference",
|
||||||
|
}
|
||||||
|
],
|
||||||
error_title="User Manual unavailable",
|
error_title="User Manual unavailable",
|
||||||
manual_html=manual_html,
|
manual_html=manual_html,
|
||||||
toc=toc,
|
toc=toc,
|
||||||
@@ -341,6 +389,12 @@ def user_manual():
|
|||||||
"user_manual.html",
|
"user_manual.html",
|
||||||
document_title="User Manual",
|
document_title="User Manual",
|
||||||
document_subtitle="RollCalc technical user documentation",
|
document_subtitle="RollCalc technical user documentation",
|
||||||
|
document_actions=[
|
||||||
|
{
|
||||||
|
"href": url_for("quick_reference"),
|
||||||
|
"label": "Open English Quick Reference",
|
||||||
|
}
|
||||||
|
],
|
||||||
error_title="User Manual unavailable",
|
error_title="User Manual unavailable",
|
||||||
manual_html=None,
|
manual_html=None,
|
||||||
toc=[],
|
toc=[],
|
||||||
@@ -351,6 +405,40 @@ def user_manual():
|
|||||||
), 500
|
), 500
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/help/quick-reference", methods=["GET"])
|
||||||
|
@auth.login_required
|
||||||
|
def quick_reference():
|
||||||
|
"""Render the English Quick Reference inside the RollCalc Help layout."""
|
||||||
|
log_access(auth.current_user(), "/help/quick-reference", "GET")
|
||||||
|
try:
|
||||||
|
quick_html, toc = render_quick_reference("en")
|
||||||
|
return render_template(
|
||||||
|
"user_manual.html",
|
||||||
|
document_title="Quick Reference",
|
||||||
|
document_subtitle="Concise English reference for common RollCalc workflows",
|
||||||
|
document_actions=[],
|
||||||
|
error_title="Quick Reference unavailable",
|
||||||
|
manual_html=quick_html,
|
||||||
|
toc=toc,
|
||||||
|
render_error=None
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
app.logger.exception("Could not render quick reference")
|
||||||
|
return render_template(
|
||||||
|
"user_manual.html",
|
||||||
|
document_title="Quick Reference",
|
||||||
|
document_subtitle="Concise English reference for common RollCalc workflows",
|
||||||
|
document_actions=[],
|
||||||
|
error_title="Quick Reference unavailable",
|
||||||
|
manual_html=None,
|
||||||
|
toc=[],
|
||||||
|
render_error=(
|
||||||
|
"The quick reference could not be loaded. "
|
||||||
|
"Please contact the RollCalc maintainer if the problem persists."
|
||||||
|
)
|
||||||
|
), 500
|
||||||
|
|
||||||
|
|
||||||
@app.route("/help/recent-changes", methods=["GET"])
|
@app.route("/help/recent-changes", methods=["GET"])
|
||||||
@auth.login_required
|
@auth.login_required
|
||||||
def recent_changes():
|
def recent_changes():
|
||||||
@@ -362,6 +450,7 @@ def recent_changes():
|
|||||||
"user_manual.html",
|
"user_manual.html",
|
||||||
document_title="Recent Changes",
|
document_title="Recent Changes",
|
||||||
document_subtitle="RollCalc release notes",
|
document_subtitle="RollCalc release notes",
|
||||||
|
document_actions=[],
|
||||||
error_title="Recent Changes unavailable",
|
error_title="Recent Changes unavailable",
|
||||||
manual_html=changes_html,
|
manual_html=changes_html,
|
||||||
toc=toc,
|
toc=toc,
|
||||||
@@ -373,6 +462,7 @@ def recent_changes():
|
|||||||
"user_manual.html",
|
"user_manual.html",
|
||||||
document_title="Recent Changes",
|
document_title="Recent Changes",
|
||||||
document_subtitle="RollCalc release notes",
|
document_subtitle="RollCalc release notes",
|
||||||
|
document_actions=[],
|
||||||
error_title="Recent Changes unavailable",
|
error_title="Recent Changes unavailable",
|
||||||
manual_html=None,
|
manual_html=None,
|
||||||
toc=[],
|
toc=[],
|
||||||
|
|||||||
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": "v0.4-dev",
|
"version": "v0.4-beta2",
|
||||||
"branch": "feature/transport-capacity-optimizer",
|
"branch": "develop/v0.4",
|
||||||
"commit": "216f53c",
|
"commit": "156a6b7",
|
||||||
"timestamp": "2026-07-28T13:02:23+02:00"
|
"timestamp": "2026-07-29T09:15:04+02:00"
|
||||||
}
|
}
|
||||||
|
|||||||
+165
-219
@@ -1,267 +1,213 @@
|
|||||||
# 🚀 RollCalc V14 + QoL Update - Deployment Guide
|
# Deployment Guide
|
||||||
|
|
||||||
## 📦 Archive Contents
|
Dieses Dokument beschreibt den empfohlenen Ablauf für das Deployment von RollCalc auf dem Beta- oder Produktivserver.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Deployment Checklist
|
||||||
|
|
||||||
|
Vor Abschluss eines Deployments sollten alle folgenden Punkte erfüllt sein:
|
||||||
|
|
||||||
|
- [ ] Repository aktualisiert
|
||||||
|
- [ ] Python-Abhängigkeiten installiert
|
||||||
|
- [ ] `config/users.json` vorhanden und lesbar
|
||||||
|
- [ ] `build_info.json` geprüft bzw. aktualisiert
|
||||||
|
- [ ] RollCalc-Service erfolgreich neu gestartet
|
||||||
|
- [ ] Smoke-Test erfolgreich durchgeführt
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Voraussetzungen
|
||||||
|
|
||||||
|
Erwartete Serverstruktur:
|
||||||
|
|
||||||
|
- Projektverzeichnis
|
||||||
|
|
||||||
|
```text
|
||||||
|
/var/www/html
|
||||||
```
|
```
|
||||||
rollcalc_v14_complete_final.tar.gz (18 KB)
|
|
||||||
|
|
||||||
rollcalc_files/
|
- Python Virtual Environment
|
||||||
├── app.py ← Flask Backend
|
|
||||||
├── service-worker.js ← Offline Support
|
```text
|
||||||
├── config.json ← Forklift Rules
|
/opt/rollcalc-venv
|
||||||
├── article-data.json ← Product Database (PLACEHOLDER)
|
```
|
||||||
│
|
|
||||||
├── rollcalc_improvements.js ← V14: Article Selection
|
- systemd-Service
|
||||||
├── rollcalc_stddev_ranges.js ← QoL: Stddev Ranges
|
|
||||||
├── rollcalc_stddev_integration.js ← QoL: Integration
|
```text
|
||||||
│
|
rollcalc.service
|
||||||
├── deploy_rollcalc.py ← 🎯 DEPLOYMENT SCRIPT
|
|
||||||
│
|
|
||||||
├── README.md ← Full Documentation
|
|
||||||
├── QUICKREF.md ← Quick Reference
|
|
||||||
├── INTEGRATION_GUIDE.html ← Step-by-Step Setup
|
|
||||||
├── FILE_STRUCTURE.md ← File Reference
|
|
||||||
├── DELIVERY_SUMMARY.md ← V14 Overview
|
|
||||||
├── QOL_UPDATE_SUMMARY.md ← QoL Overview
|
|
||||||
├── STDDEV_RANGES_DOCS.md ← Stddev Documentation
|
|
||||||
└── STDDEV_IMPLEMENTATION_CHECKLIST.md ← Implementation Checklist
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🎯 Quick Deployment (3 Steps)
|
# Deployment
|
||||||
|
|
||||||
### Step 1: Extract Archive
|
## 1. Repository aktualisieren
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
tar -xzf rollcalc_v14_complete_final.tar.gz
|
cd /var/www/html
|
||||||
cd rollcalc_files/
|
|
||||||
|
git fetch origin
|
||||||
|
git switch develop/v0.4
|
||||||
|
git pull --ff-only origin develop/v0.4
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 2: Run Deployment Script
|
---
|
||||||
|
|
||||||
|
## 2. Python-Abhängigkeiten aktualisieren
|
||||||
|
|
||||||
|
Neue Python-Abhängigkeiten werden ausschließlich in der virtuellen Umgebung installiert.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Make executable (first time only)
|
sudo /opt/rollcalc-venv/bin/python \
|
||||||
chmod +x deploy_rollcalc.py
|
-m pip install -r requirements.txt
|
||||||
|
|
||||||
# Run deployment
|
|
||||||
python3 deploy_rollcalc.py /path/to/your/flask/root/
|
|
||||||
|
|
||||||
# Example:
|
|
||||||
python3 deploy_rollcalc.py /home/user/rollcalc/
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 3: Update Configuration
|
---
|
||||||
|
|
||||||
Edit `app.py` (in your Flask root) and update passwords:
|
## 3. Benutzerdatei prüfen
|
||||||
|
|
||||||
```python
|
Die Datei
|
||||||
BETA_USERS = {
|
|
||||||
"beta": "CHANGE_THIS_PASSWORD",
|
|
||||||
"mtazl": "CHANGE_THIS_PASSWORD",
|
|
||||||
"cniehues": "CHANGE_THIS_PASSWORD",
|
|
||||||
# ... etc
|
|
||||||
}
|
|
||||||
|
|
||||||
ADMIN_USERS = {
|
```text
|
||||||
"admin": "CHANGE_THIS_ADMIN_PASSWORD"
|
config/users.json
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Then run:
|
ist **nicht Bestandteil des Git-Repositories**.
|
||||||
|
|
||||||
|
Vor dem ersten Start nach einem Deployment sicherstellen:
|
||||||
|
|
||||||
|
- Datei vorhanden
|
||||||
|
- gültiges JSON
|
||||||
|
- mindestens ein Benutzer vorhanden
|
||||||
|
- für den Service-Benutzer lesbar
|
||||||
|
|
||||||
|
Empfohlene Dateirechte:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /path/to/your/flask/root/
|
sudo chown martin:www-data config/users.json
|
||||||
python app.py
|
sudo chmod 640 config/users.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Open: **http://localhost:5000**
|
Neue Benutzer werden ausschließlich mit folgendem Werkzeug verwaltet:
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📋 What the Deployment Script Does
|
|
||||||
|
|
||||||
The `deploy_rollcalc.py` script automates everything:
|
|
||||||
|
|
||||||
✅ Creates required directories
|
|
||||||
✅ Backs up existing files
|
|
||||||
✅ Deploys all files to correct locations
|
|
||||||
✅ Verifies Python dependencies
|
|
||||||
✅ Checks for default passwords
|
|
||||||
✅ Validates all files after deployment
|
|
||||||
✅ Prints clear next steps
|
|
||||||
|
|
||||||
**No manual copying needed!**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⚠️ Important: article-data.json
|
|
||||||
|
|
||||||
The archive contains a **placeholder** for `article-data.json`.
|
|
||||||
|
|
||||||
**You need to add your product data:**
|
|
||||||
|
|
||||||
### Option A: Import from Existing System
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# If you already have article-data.json:
|
python3 scripts/manage_users.py
|
||||||
cp /path/to/your/article-data.json /path/to/flask/static/
|
|
||||||
```
|
|
||||||
|
|
||||||
### Option B: Use Minimal Data for Testing
|
|
||||||
|
|
||||||
The placeholder is already there - you can test the calculator without product data.
|
|
||||||
|
|
||||||
### Option C: Generate from ERP
|
|
||||||
|
|
||||||
Update the export script in your ERP system to create article-data.json format:
|
|
||||||
|
|
||||||
```json
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"nr": "180005",
|
|
||||||
"name": "Bfix NSP 4000, 5,00 x 50 m",
|
|
||||||
"thickness": 6.228,
|
|
||||||
"thickness_stddev": 0.379,
|
|
||||||
"area_weight": 3899.02,
|
|
||||||
"area_weight_stddev": 133.24,
|
|
||||||
"core_type": 0.0,
|
|
||||||
...
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🛠️ Manual Deployment (If Script Fails)
|
## 4. Build-Informationen prüfen
|
||||||
|
|
||||||
If the Python script doesn't work, deploy manually:
|
Falls erforderlich:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Extract
|
./scripts/update_build_info.sh
|
||||||
tar -xzf rollcalc_v14_complete_final.tar.gz
|
|
||||||
|
|
||||||
# Backend
|
|
||||||
cp rollcalc_files/app.py /path/to/flask/
|
|
||||||
|
|
||||||
# Static files
|
|
||||||
cp rollcalc_files/*.js /path/to/flask/static/
|
|
||||||
cp rollcalc_files/*.json /path/to/flask/static/
|
|
||||||
|
|
||||||
# Documentation
|
|
||||||
mkdir -p /path/to/flask/docs
|
|
||||||
cp rollcalc_files/*.md /path/to/flask/docs/
|
|
||||||
cp rollcalc_files/*.html /path/to/flask/docs/
|
|
||||||
|
|
||||||
# Run
|
|
||||||
cd /path/to/flask/
|
|
||||||
python app.py
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
Anschließend kontrollieren:
|
||||||
|
|
||||||
## ✅ Verification Checklist
|
|
||||||
|
|
||||||
After deployment, verify:
|
|
||||||
|
|
||||||
- [ ] `app.py` in Flask root
|
|
||||||
- [ ] `service-worker.js` in `/static/`
|
|
||||||
- [ ] `rollcalc_improvements.js` in `/static/`
|
|
||||||
- [ ] `rollcalc_stddev_ranges.js` in `/static/`
|
|
||||||
- [ ] `rollcalc_stddev_integration.js` in `/static/`
|
|
||||||
- [ ] `article-data.json` in `/static/` (with real data)
|
|
||||||
- [ ] `config.json` in `/static/`
|
|
||||||
- [ ] `templates/roll_calculator.html` exists (add 2 script tags for StdDev)
|
|
||||||
- [ ] Passwords updated in `app.py`
|
|
||||||
- [ ] Server runs: `python app.py`
|
|
||||||
- [ ] Page loads: `http://localhost:5000`
|
|
||||||
- [ ] Login works (use credentials from `BETA_USERS`)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎨 HTML Integration (StdDev Ranges)
|
|
||||||
|
|
||||||
If you want to use the **Standard Deviation Ranges** feature, add to your `roll_calculator.html` in the `<head>` section:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<!-- Add these two lines: -->
|
|
||||||
<script src="/static/rollcalc-stddev-ranges.js"></script>
|
|
||||||
<script src="/static/rollcalc-stddev-integration.js"></script>
|
|
||||||
|
|
||||||
<!-- Also add this to your Direct Calc form: -->
|
|
||||||
<!-- (Details in STDDEV_IMPLEMENTATION_CHECKLIST.md) -->
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📚 Documentation Files
|
|
||||||
|
|
||||||
| File | Purpose |
|
|
||||||
|------|---------|
|
|
||||||
| `README.md` | Full technical documentation |
|
|
||||||
| `QUICKREF.md` | Quick reference card |
|
|
||||||
| `QOL_UPDATE_SUMMARY.md` | What's new in this update |
|
|
||||||
| `STDDEV_RANGES_DOCS.md` | How StdDev ranges work |
|
|
||||||
| `STDDEV_IMPLEMENTATION_CHECKLIST.md` | How to implement StdDev ranges |
|
|
||||||
| `INTEGRATION_GUIDE.html` | Original V14 setup guide |
|
|
||||||
| `FILE_STRUCTURE.md` | File reference |
|
|
||||||
|
|
||||||
Read these **after deployment** to understand all features.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🆘 Troubleshooting
|
|
||||||
|
|
||||||
### "Deploy script fails: Missing dependencies"
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install flask flask-httpauth
|
cat build_info.json
|
||||||
```
|
```
|
||||||
|
|
||||||
### "Page won't load at localhost:5000"
|
Die Build-Version wird unter anderem für den **What's New**-Dialog verwendet.
|
||||||
|
|
||||||
1. Check Flask is running: `python app.py`
|
|
||||||
2. Check port 5000 is free
|
|
||||||
3. Check firewall allows localhost:5000
|
|
||||||
|
|
||||||
### "Login prompt appears but password doesn't work"
|
|
||||||
|
|
||||||
1. Check `BETA_USERS` in `app.py` - use those credentials
|
|
||||||
2. Username: `mtazl`, Password: `rollcalc` (default)
|
|
||||||
3. Change to your custom passwords
|
|
||||||
|
|
||||||
### "Article dropdown is empty"
|
|
||||||
|
|
||||||
1. Check `article-data.json` exists in `/static/`
|
|
||||||
2. Check it has valid JSON format
|
|
||||||
3. Refresh browser (Ctrl+F5 or Cmd+Shift+R)
|
|
||||||
4. Check browser console (F12) for errors
|
|
||||||
|
|
||||||
### "Service Worker not working"
|
|
||||||
|
|
||||||
1. Clear browser cache (Ctrl+Shift+Delete)
|
|
||||||
2. Hard refresh (Ctrl+Shift+F5)
|
|
||||||
3. Check DevTools → Application → Service Workers
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🚀 You're Ready!
|
## 5. RollCalc neu starten
|
||||||
|
|
||||||
That's it! The deployment script handles 90% of the work.
|
```bash
|
||||||
|
sudo systemctl restart rollcalc.service
|
||||||
**Questions?** Check the documentation files in `/docs/`
|
sudo systemctl status rollcalc.service --no-pager
|
||||||
|
```
|
||||||
**Issues?** Look in browser console (F12) for error messages
|
|
||||||
|
|
||||||
**Success indicators:**
|
|
||||||
- ✅ Page loads at localhost:5000
|
|
||||||
- ✅ Login prompt appears
|
|
||||||
- ✅ Article dropdown has data
|
|
||||||
- ✅ Calculations work
|
|
||||||
- ✅ Offline mode works (DevTools → Network → Offline)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Version:** 14.1
|
## 6. Smoke-Test
|
||||||
**Date:** 2026-07-01
|
|
||||||
**Status:** Production Ready ✅
|
Nach jedem Deployment mindestens folgende Punkte prüfen:
|
||||||
|
|
||||||
|
- Login funktioniert
|
||||||
|
- Roll Calculator öffnet
|
||||||
|
- User Manual erreichbar
|
||||||
|
- Recent Changes erreichbar
|
||||||
|
- What's New erscheint bei neuer Version
|
||||||
|
- Beispielberechnung durchführen
|
||||||
|
- Load Optimizer funktioniert
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Fehlerdiagnose
|
||||||
|
|
||||||
|
## Service-Status
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl status rollcalc.service --no-pager
|
||||||
|
```
|
||||||
|
|
||||||
|
## Journal anzeigen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo journalctl -u rollcalc.service -n 100 --no-pager
|
||||||
|
```
|
||||||
|
|
||||||
|
## Benutzerdatei prüfen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls -l config/users.json
|
||||||
|
|
||||||
|
sudo -u www-data test -r config/users.json && echo "users.json readable"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Benutzerverwaltung
|
||||||
|
|
||||||
|
Die Benutzerverwaltung erfolgt ausschließlich über:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/manage_users.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Die Datei
|
||||||
|
|
||||||
|
```text
|
||||||
|
config/users.json
|
||||||
|
```
|
||||||
|
|
||||||
|
wird **nicht versioniert** und muss auf jedem Zielsystem separat gepflegt werden.
|
||||||
|
|
||||||
|
Die Datei darf niemals in das Git-Repository eingecheckt werden.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Rollback
|
||||||
|
|
||||||
|
Vor jedem Deployment empfiehlt es sich, den aktuellen Commit zu notieren:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git rev-parse HEAD
|
||||||
|
```
|
||||||
|
|
||||||
|
Rollback auf einen früheren Stand:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git switch develop/v0.4
|
||||||
|
git reset --hard <Commit-ID>
|
||||||
|
|
||||||
|
sudo systemctl restart rollcalc.service
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Wartungshinweise
|
||||||
|
|
||||||
|
- Neue Python-Abhängigkeiten immer über die virtuelle Umgebung installieren.
|
||||||
|
- `config/users.json` regelmäßig sichern.
|
||||||
|
cp config/users.json backups/users_$(date +%F).json
|
||||||
|
- `build_info.json` vor einem Release aktualisieren.
|
||||||
|
- Nach Änderungen an der Authentifizierung die Benutzerverwaltung testen.
|
||||||
|
- Nach Änderungen am Help-System User Manual und Recent Changes prüfen.
|
||||||
|
- Nach Änderungen an Berechnungen mindestens einen vollständigen Rechentest durchführen.
|
||||||
@@ -1,6 +1,18 @@
|
|||||||
# Recent Changes
|
# 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.
|
- User Manual integrated into RollCalc.
|
||||||
- Help area added for internal documentation.
|
- Help area added for internal documentation.
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,315 @@
|
|||||||
|
# RollCalc Quick Reference
|
||||||
|
|
||||||
|
## 1. Before You Start
|
||||||
|
|
||||||
|
RollCalc is an engineering support tool for roll geometry, roll weight, and transport capacity assessment. It helps experienced technical users prepare and interpret calculations, but it does not replace production, handling, or shipping approval.
|
||||||
|
|
||||||
|
Before using a result operationally, check that the selected article, article data, manually entered values, and transport assumptions match the actual case. The calculated result is only meaningful if the input data is technically plausible.
|
||||||
|
|
||||||
|
Use this Quick Reference for the most common workflows. For background, detailed interpretation, and troubleshooting, use the full `User Manual`.
|
||||||
|
|
||||||
|
## 2. Which Function Should I Use?
|
||||||
|
|
||||||
|
| Task | Function / Calculation Mode |
|
||||||
|
| --- | --- |
|
||||||
|
| Calculate the diameter of a planned roll | `Direct Calculation` → `Roll Diameter` |
|
||||||
|
| Estimate product length from a measured roll | `Direct Calculation` → `Product Length` |
|
||||||
|
| Determine maximum permitted product length | `Direct Calculation` → `Target Diameter` |
|
||||||
|
| Estimate a new roll from a reference roll | `Extrapolation` |
|
||||||
|
| Assess transport capacity | `Load Optimizer` |
|
||||||
|
| Understand why a transport result is limited | `Capacity Summary` and `Capacity Analysis` |
|
||||||
|
| Visually check the geometric arrangement | `Front View – Cross-Section` |
|
||||||
|
|
||||||
|
## 3. Article Selection and Input Data
|
||||||
|
|
||||||
|
Use `Article Number (optional)` when an article is available in the article data. The current application can prefill available article values such as `Product Thickness`, tolerance data, `Area Weight`, and `Core Diameter` when these values are present in the data source.
|
||||||
|
|
||||||
|
Prefilled values are starting values, not approvals. The values currently visible in the input fields are decisive for the calculation. You can manually change the populated values before calculating.
|
||||||
|
|
||||||
|
Planned article-data extension: future article data may also provide a typical `Roll Width` for automatic prefilling. Do not assume `Roll Width` is currently populated by article selection unless it is visibly filled in the UI.
|
||||||
|
|
||||||
|
Check before calculation:
|
||||||
|
|
||||||
|
- `Product Category` and `Production Site` match the intended context.
|
||||||
|
- `Article Number (optional)` refers to the correct article.
|
||||||
|
- `Product Thickness` is plausible for the product.
|
||||||
|
- `Area Weight` is current and product-specific.
|
||||||
|
- `Core Diameter` matches the actual core.
|
||||||
|
- `Roll Width` is entered when `Calculated Weight` or `Load Optimizer` will be used.
|
||||||
|
|
||||||
|
## 4. Direct Calculation – Roll Diameter
|
||||||
|
|
||||||
|
Use `Direct Calculation` with `Calculation Mode` `Roll Diameter` when a planned `Product Length` is known and the expected outer roll size must be assessed.
|
||||||
|
|
||||||
|
### Required inputs
|
||||||
|
|
||||||
|
- `Core Diameter (d)`
|
||||||
|
- `Product Thickness (t)`
|
||||||
|
- `Product Length (L)`
|
||||||
|
|
||||||
|
### Optional weight inputs
|
||||||
|
|
||||||
|
- `Roll Width`
|
||||||
|
- `Area Weight`
|
||||||
|
|
||||||
|
### Main results
|
||||||
|
|
||||||
|
- `Roll Diameter (D)`
|
||||||
|
- tolerance range when tolerance is entered
|
||||||
|
- `Calculated Weight`, when `Roll Width`, `Area Weight`, and `Product Length` are available
|
||||||
|
- `Forklift Check`, where applicable
|
||||||
|
|
||||||
|
### Check before use
|
||||||
|
|
||||||
|
- Units: mm for diameters and thickness, m for length and width, g/m² for `Area Weight`, kg for weight.
|
||||||
|
- `Product Thickness` is plausible and belongs to the article.
|
||||||
|
- `Core Diameter` matches the actual core type.
|
||||||
|
- `Product Length` is realistic for the planned roll.
|
||||||
|
- `Calculated Weight` is plausible before using the result in `Forklift Check` or `Load Optimizer`.
|
||||||
|
|
||||||
|
## 5. Direct Calculation – Product Length
|
||||||
|
|
||||||
|
Use `Direct Calculation` with `Calculation Mode` `Product Length` when a roll has a measured `Roll Diameter` and the product length on the roll must be estimated.
|
||||||
|
|
||||||
|
### Required inputs
|
||||||
|
|
||||||
|
- `Core Diameter (d)`
|
||||||
|
- `Roll Diameter (D)`
|
||||||
|
- `Product Thickness (t)`
|
||||||
|
|
||||||
|
### Main result
|
||||||
|
|
||||||
|
- `Product Length (L)`
|
||||||
|
|
||||||
|
### Typical use
|
||||||
|
|
||||||
|
- measured roll
|
||||||
|
- stock check
|
||||||
|
- quality check
|
||||||
|
- comparison with a planned or nominal length
|
||||||
|
|
||||||
|
### Important caution
|
||||||
|
|
||||||
|
The accuracy depends directly on the measured `Roll Diameter` and the assumed `Product Thickness`. If either value is inaccurate or does not match the actual product, the calculated `Product Length` will be inaccurate as well.
|
||||||
|
|
||||||
|
## 6. Direct Calculation – Target Diameter
|
||||||
|
|
||||||
|
Use `Direct Calculation` with `Calculation Mode` `Target Diameter` to determine the maximum allowed `Product Length` for one roll under entered diameter and weight limits. This is a limit workflow for a single roll. It is not a transport optimization and does not answer how many rolls fit into a container or vehicle.
|
||||||
|
|
||||||
|
### Relevant inputs
|
||||||
|
|
||||||
|
- `Core Diameter (d)`
|
||||||
|
- `Product Thickness (t)`
|
||||||
|
- `Roll Width`
|
||||||
|
- `Area Weight`
|
||||||
|
- `Max. Roll Diameter`
|
||||||
|
- `Max. Roll Weight`
|
||||||
|
- `Minimum Product Length`
|
||||||
|
|
||||||
|
### Main results
|
||||||
|
|
||||||
|
- `Maximum Allowed Product Length`
|
||||||
|
- `Resulting Roll Diameter`
|
||||||
|
- `Resulting weight`
|
||||||
|
- `Minimum length`
|
||||||
|
- `Difference`
|
||||||
|
- `Limiting factor`
|
||||||
|
- diameter and weight utilization line
|
||||||
|
|
||||||
|
### Interpretation
|
||||||
|
|
||||||
|
| Result situation | Meaning |
|
||||||
|
| --- | --- |
|
||||||
|
| `Limiting factor: Diameter` | `Max. Roll Diameter` is reached before the weight limit. |
|
||||||
|
| `Limiting factor: Weight` | `Max. Roll Weight` is reached before the diameter limit. |
|
||||||
|
| `Limiting factor: Diameter + Weight` | Both limits are reached at the same practical length. |
|
||||||
|
| warning below `Minimum length` | The requested `Minimum Product Length` cannot be achieved under the entered limits. |
|
||||||
|
|
||||||
|
The result describes the maximum allowed single-roll layout under the entered limits. It is not automatically the best roll design.
|
||||||
|
|
||||||
|
## 7. Roll Weight and Forklift Check
|
||||||
|
|
||||||
|
`Roll Weight` depends on `Product Length`, `Roll Width`, and `Area Weight`. Similar `Roll Diameter` values can therefore produce very different roll weights if width, length, or material weight differ.
|
||||||
|
|
||||||
|
`Calculated Weight` is used as the practical roll weight for downstream assessment. It is relevant for handling, `Forklift Check`, `Max. Roll Weight` checks, and the `Load Optimizer`.
|
||||||
|
|
||||||
|
`Forklift Check` is a technical warning or handling indication. It may show messages such as `Forklift Check OK`, `Heavy Roll – Special Equipment Required`, or `Weight Limit Exceeded`. It is not an operational approval, prohibition, or safety release.
|
||||||
|
|
||||||
|
Check first if `Forklift Check` appears unexpected:
|
||||||
|
|
||||||
|
- `Calculated Weight`
|
||||||
|
- `Core Diameter`
|
||||||
|
- `Product Category`
|
||||||
|
- `Roll Width`
|
||||||
|
- `Area Weight`
|
||||||
|
- article data used for the calculation
|
||||||
|
|
||||||
|
## 8. Extrapolation
|
||||||
|
|
||||||
|
Use `Extrapolation` when a `Known Reference Roll` exists and a comparable roll with a changed length must be estimated.
|
||||||
|
|
||||||
|
### Use only when
|
||||||
|
|
||||||
|
- a known reference roll exists,
|
||||||
|
- the same article is used,
|
||||||
|
- `Core Diameter` is unchanged,
|
||||||
|
- material structure and `Product Thickness` are comparable,
|
||||||
|
- mainly `Product Length` changes.
|
||||||
|
|
||||||
|
### Required inputs
|
||||||
|
|
||||||
|
- `Core Diameter (d)`
|
||||||
|
- `Known Roll Diameter (D₀)`
|
||||||
|
- `Known Roll Length (L₀)`
|
||||||
|
- `New Roll Length (L₁)`
|
||||||
|
|
||||||
|
### Main result
|
||||||
|
|
||||||
|
- `Extrapolated Roll Diameter (D₁)`
|
||||||
|
- optional min/max range when `Tolerance (optional)` is entered
|
||||||
|
|
||||||
|
### Do not use when
|
||||||
|
|
||||||
|
- the article changes,
|
||||||
|
- `Product Thickness` changes,
|
||||||
|
- `Core Diameter` changes,
|
||||||
|
- reference data is uncertain,
|
||||||
|
- a full technical roll layout is required.
|
||||||
|
|
||||||
|
The quality of the result depends on the quality and comparability of the reference roll.
|
||||||
|
|
||||||
|
## 9. Load Optimizer
|
||||||
|
|
||||||
|
Use `Load Optimizer – Transport Capacity Calculator` after the roll has already been defined. The `Load Optimizer` evaluates an existing roll in a selected transport space. It does not redesign the roll and does not automatically select the best transport mode.
|
||||||
|
|
||||||
|
### Required roll data
|
||||||
|
|
||||||
|
- `Roll Diameter`
|
||||||
|
- `Roll Width`
|
||||||
|
- `Roll Weight`
|
||||||
|
|
||||||
|
These values are taken from the completed `Direct Calculation` workflow. Roll data must be plausible before the transport calculation is meaningful.
|
||||||
|
|
||||||
|
### Required transport data
|
||||||
|
|
||||||
|
- `Preset Transport Type:`
|
||||||
|
- or `Custom` with `Length (m)`, `Width (m)`, `Height (m)`, and `Max. Load (kg)`
|
||||||
|
- `Loading Clearances`
|
||||||
|
- `Side Wall Clearance (one side)`
|
||||||
|
- `Ceiling Clearance (top only)`
|
||||||
|
|
||||||
|
`Loading Clearances` reduce the effective loading space. They can change the number of rolls that fit geometrically and may change the `Governing Constraint`.
|
||||||
|
|
||||||
|
## 10. Reading the Transport Results
|
||||||
|
|
||||||
|
Read transport results in this order:
|
||||||
|
|
||||||
|
1. Read `Capacity Summary`.
|
||||||
|
2. Check `Total Rolls`.
|
||||||
|
3. Identify the `Governing Constraint`.
|
||||||
|
4. Review `Remaining Capacity`.
|
||||||
|
5. Check `Front View – Cross-Section`.
|
||||||
|
6. Use `Capacity Analysis` to understand the technical limit.
|
||||||
|
|
||||||
|
### Capacity Summary
|
||||||
|
|
||||||
|
`Capacity Summary` shows the actual transport result. It is divided into:
|
||||||
|
|
||||||
|
- `Governing Constraint`
|
||||||
|
- `Transport Result`
|
||||||
|
- `Remaining Capacity`
|
||||||
|
|
||||||
|
`Transport Result` includes `Total Rolls`, `Weight Utilization`, `Volume Utilization`, and the transported product area. Use these values together; a single utilization value does not explain the transport limit by itself.
|
||||||
|
|
||||||
|
Use this area first because it shows the result that can actually be reached under the entered assumptions.
|
||||||
|
|
||||||
|
### Governing Constraint
|
||||||
|
|
||||||
|
| Governing Constraint | Meaning |
|
||||||
|
| --- | --- |
|
||||||
|
| `Geometry` | No additional roll fits into the actual arrangement. Payload or volume may remain unused. |
|
||||||
|
| `Weight` | The permitted payload is reached before geometric capacity is exhausted. |
|
||||||
|
| `Volume` | The calculated transport volume is reached before another constraint becomes decisive. |
|
||||||
|
|
||||||
|
`Governing Constraint` is not a recommendation. It is the technical constraint that determines the final `Total Rolls`.
|
||||||
|
|
||||||
|
### Remaining Capacity
|
||||||
|
|
||||||
|
`Remaining Capacity` shows reserves after the actual loading result:
|
||||||
|
|
||||||
|
- `Remaining Payload`
|
||||||
|
- `Unused Payload`
|
||||||
|
- `Unused Volume`
|
||||||
|
|
||||||
|
Remaining values do not automatically mean that another roll fits. They must be read together with `Governing Constraint` and `Front View – Cross-Section`.
|
||||||
|
|
||||||
|
### Capacity Analysis
|
||||||
|
|
||||||
|
`Capacity Analysis` is a constraint analysis, not a list of alternative loading solutions. Its rows show theoretical capacity limits for:
|
||||||
|
|
||||||
|
- `Weight`
|
||||||
|
- `Volume`
|
||||||
|
- `Geometry`
|
||||||
|
|
||||||
|
The smallest applicable limit determines the actual `Total Rolls`. The governing row is marked with `→ Governing Constraint`.
|
||||||
|
|
||||||
|
The table columns are:
|
||||||
|
|
||||||
|
- `Constraint`
|
||||||
|
- `Max Rolls`
|
||||||
|
- `Total Weight`
|
||||||
|
- `Transported Area [m²]`
|
||||||
|
- `Payload Util. %` — indicates the percentage of the permitted payload that is used.
|
||||||
|
|
||||||
|
### Front View – Cross-Section
|
||||||
|
|
||||||
|
`Front View – Cross-Section` visualizes the actual geometric loading configuration. Use it to check whether the geometric arrangement is plausible, especially when `Geometry` is the `Governing Constraint`.
|
||||||
|
|
||||||
|
### Important interpretation rules
|
||||||
|
|
||||||
|
- `Remaining Payload` does not automatically mean that another roll fits.
|
||||||
|
- `Unused Volume` does not automatically mean that another roll fits.
|
||||||
|
- `Capacity Analysis` does not show alternative loading solutions.
|
||||||
|
- `Weight`, `Volume`, and `Geometry` are theoretical capacity limits.
|
||||||
|
- The smallest applicable limit determines the actual `Total Rolls`.
|
||||||
|
|
||||||
|
## 11. Final Plausibility Check
|
||||||
|
|
||||||
|
Before using a result for production, handling, or transport planning, check:
|
||||||
|
|
||||||
|
- [ ] Correct article selected
|
||||||
|
- [ ] `Product Thickness` checked
|
||||||
|
- [ ] `Area Weight` checked
|
||||||
|
- [ ] `Core Diameter` checked
|
||||||
|
- [ ] `Roll Width` checked
|
||||||
|
- [ ] `Product Length` or `Roll Diameter` checked
|
||||||
|
- [ ] `Roll Weight` plausible
|
||||||
|
- [ ] `Calculated Weight` plausible
|
||||||
|
- [ ] Transport dimensions correct
|
||||||
|
- [ ] `Max. Load (kg)` correct
|
||||||
|
- [ ] `Loading Clearances` realistic
|
||||||
|
- [ ] `Governing Constraint` understandable
|
||||||
|
- [ ] `Remaining Payload` and `Volume Utilization` plausible
|
||||||
|
- [ ] `Front View – Cross-Section` plausible
|
||||||
|
- [ ] Result compared with experience or a reference case
|
||||||
|
|
||||||
|
## 12. Common Problems
|
||||||
|
|
||||||
|
| Observation | Check first |
|
||||||
|
| --- | --- |
|
||||||
|
| `Roll Diameter` is unexpectedly high or low | `Product Thickness`, `Product Length`, `Core Diameter`, units |
|
||||||
|
| `Product Length` is much larger or smaller than expected | measured `Roll Diameter`, `Product Thickness`, `Core Diameter` |
|
||||||
|
| `Roll Weight` appears incorrect | `Product Length`, `Roll Width`, `Area Weight` |
|
||||||
|
| Similar `Roll Diameter` values have very different weights | `Roll Width`, `Area Weight`, `Product Length` |
|
||||||
|
| `Forklift Check` appears unexpected | `Calculated Weight`, `Core Diameter`, `Product Category`, article data |
|
||||||
|
| `Extrapolation` result appears implausible | `Known Roll Diameter (D₀)`, `Known Roll Length (L₀)`, `New Roll Length (L₁)`, comparability of both rolls |
|
||||||
|
| Fewer rolls fit than expected | roll data, `Loading Clearances`, transport dimensions, `Governing Constraint` |
|
||||||
|
| `Remaining Payload` is available but no additional roll fits | `Geometry`, `Front View – Cross-Section` |
|
||||||
|
| `Capacity Analysis` appears contradictory | governing row, `Capacity Summary`, `Remaining Capacity`, `Front View – Cross-Section` |
|
||||||
|
| Similar calculations produce different results | article data, roll geometry, transport data, `Loading Clearances` |
|
||||||
|
|
||||||
|
Recalculate completely after changes to article data, roll geometry, or transport parameters. Old results should not be interpreted after changing values such as `Product Thickness`, `Area Weight`, `Core Diameter`, `Roll Width`, `Max. Load (kg)`, or `Loading Clearances`.
|
||||||
|
|
||||||
|
## 13. Key Rule
|
||||||
|
|
||||||
|
> The calculated result is only as reliable as the entered article data, roll data, and transport assumptions. Always perform a technical plausibility check before operational use.
|
||||||
Executable
+84
@@ -0,0 +1,84 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
SOURCE_MD="$ROOT_DIR/docs/de/user_manual.md"
|
||||||
|
SCREENSHOT_DIR="$ROOT_DIR/docs/de/screenshots"
|
||||||
|
OUTPUT_PDF="$ROOT_DIR/docs/de/user_manual.pdf"
|
||||||
|
|
||||||
|
if ! command -v pandoc >/dev/null 2>&1; then
|
||||||
|
echo "Error: Pandoc is not installed or not available in PATH." >&2
|
||||||
|
echo "Install Pandoc first, then run this script again." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$SOURCE_MD" ]]; then
|
||||||
|
echo "Error: source Markdown not found: $SOURCE_MD" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
PDF_ENGINE=""
|
||||||
|
for candidate in xelatex lualatex tectonic pdflatex wkhtmltopdf weasyprint; do
|
||||||
|
if command -v "$candidate" >/dev/null 2>&1; then
|
||||||
|
PDF_ENGINE="$candidate"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -z "$PDF_ENGINE" ]]; then
|
||||||
|
echo "Error: no Pandoc-compatible PDF engine found." >&2
|
||||||
|
echo "Install xelatex, lualatex, tectonic, wkhtmltopdf, or weasyprint." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TMP_DIR="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$TMP_DIR"' EXIT
|
||||||
|
TMP_MD="$TMP_DIR/user_manual.md"
|
||||||
|
export XDG_CACHE_HOME="$TMP_DIR/cache"
|
||||||
|
mkdir -p "$XDG_CACHE_HOME/fontconfig"
|
||||||
|
|
||||||
|
python3 - "$SOURCE_MD" "$TMP_MD" "$SCREENSHOT_DIR" <<'PY'
|
||||||
|
import pathlib
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
source = pathlib.Path(sys.argv[1])
|
||||||
|
target = pathlib.Path(sys.argv[2])
|
||||||
|
screenshot_dir = pathlib.Path(sys.argv[3])
|
||||||
|
document_dir = screenshot_dir.parent
|
||||||
|
|
||||||
|
markdown = source.read_text(encoding="utf-8")
|
||||||
|
image_pattern = re.compile(r"!\[([^\]]*)\]\((screenshots/[^)]+)\)")
|
||||||
|
|
||||||
|
|
||||||
|
def replace_missing_image(match):
|
||||||
|
alt_text = match.group(1).strip()
|
||||||
|
image_ref = match.group(2)
|
||||||
|
image_path = document_dir / image_ref
|
||||||
|
|
||||||
|
if image_path.exists():
|
||||||
|
return match.group(0)
|
||||||
|
|
||||||
|
label = alt_text or pathlib.PurePosixPath(image_ref).name
|
||||||
|
return f"*Screenshot placeholder: {label}*"
|
||||||
|
|
||||||
|
|
||||||
|
target.write_text(image_pattern.sub(replace_missing_image, markdown), encoding="utf-8")
|
||||||
|
PY
|
||||||
|
|
||||||
|
pandoc "$TMP_MD" \
|
||||||
|
--from markdown+pipe_tables+grid_tables+multiline_tables+implicit_figures \
|
||||||
|
--resource-path="$ROOT_DIR/docs/de" \
|
||||||
|
--pdf-engine="$PDF_ENGINE" \
|
||||||
|
--toc \
|
||||||
|
--toc-depth=2 \
|
||||||
|
--number-sections \
|
||||||
|
--syntax-highlighting=tango \
|
||||||
|
--wrap=preserve \
|
||||||
|
-V papersize:a4 \
|
||||||
|
-V geometry:margin=20mm \
|
||||||
|
-V lang=de-DE \
|
||||||
|
-V colorlinks=true \
|
||||||
|
-o "$OUTPUT_PDF"
|
||||||
|
|
||||||
|
echo "User manual PDF generated successfully: $OUTPUT_PDF"
|
||||||
@@ -3,7 +3,7 @@ set -e
|
|||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
VERSION="${1:-v0.4-dev}"
|
VERSION="${VERSION:-v0.4-beta2}"
|
||||||
|
|
||||||
cd "$PROJECT_ROOT"
|
cd "$PROJECT_ROOT"
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
|
"version": "v0.4-beta2",
|
||||||
"items": [
|
"items": [
|
||||||
"User Manual integrated",
|
"English Quick Reference added to the Help area.",
|
||||||
"Capacity Analysis improved",
|
"Recent Changes now identifies the current deployed version.",
|
||||||
"Governing Constraint clarified",
|
"Browser cache handling improved for updated frontend data."
|
||||||
"Remaining Capacity added"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<nav class="help-nav" aria-label="Help navigation">
|
<nav class="help-nav" aria-label="Help navigation">
|
||||||
<a href="{{ url_for('index') }}">Calculator</a>
|
<a href="{{ url_for('index') }}">Calculator</a>
|
||||||
|
<a href="{{ url_for('user_manual') }}">User Manual</a>
|
||||||
|
<a href="{{ url_for('quick_reference') }}">Quick Reference</a>
|
||||||
|
<a href="{{ url_for('recent_changes') }}">Recent Changes</a>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@@ -57,6 +60,13 @@
|
|||||||
</p>
|
</p>
|
||||||
<a href="{{ url_for('user_manual') }}">Open User Manual</a>
|
<a href="{{ url_for('user_manual') }}">Open User Manual</a>
|
||||||
</article>
|
</article>
|
||||||
|
<article class="help-card">
|
||||||
|
<h2>Quick Reference</h2>
|
||||||
|
<p>
|
||||||
|
Concise English reference for the most common RollCalc workflows and result interpretations.
|
||||||
|
</p>
|
||||||
|
<a href="{{ url_for('quick_reference') }}">Open Quick Reference</a>
|
||||||
|
</article>
|
||||||
<article class="help-card">
|
<article class="help-card">
|
||||||
<h2>Recent Changes</h2>
|
<h2>Recent Changes</h2>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -1023,6 +1023,8 @@
|
|||||||
// =====================================================
|
// =====================================================
|
||||||
window.ARTICLE_DATA = [];
|
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"}}}}};
|
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
|
// LOAD ARTICLE DATA
|
||||||
@@ -1087,7 +1089,7 @@ function populateArticleDropdowns() {
|
|||||||
|
|
||||||
(async function() {
|
(async function() {
|
||||||
try {
|
try {
|
||||||
const resp = await fetch('/static/article-data.json');
|
const resp = await fetch(ROLLCALC_ARTICLE_DATA_URL);
|
||||||
if (resp.ok) {
|
if (resp.ok) {
|
||||||
window.ARTICLE_DATA = await resp.json();
|
window.ARTICLE_DATA = await resp.json();
|
||||||
console.log('✅ Article data loaded:', window.ARTICLE_DATA.length, 'items');
|
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_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';
|
const ROLLCALC_LAST_SEEN_VERSION_KEY = 'rollcalc_last_seen_version';
|
||||||
|
|
||||||
function shouldShowWhatsNew(currentVersion, storedVersion) {
|
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 overlay = document.getElementById('whatsNewOverlay');
|
||||||
const versionValue = document.getElementById('whatsNewVersion');
|
const versionValue = document.getElementById('whatsNewVersion');
|
||||||
const continueBtn = document.getElementById('whatsNewContinueBtn');
|
const continueBtn = document.getElementById('whatsNewContinueBtn');
|
||||||
const openChangesBtn = document.getElementById('whatsNewOpenChangesBtn');
|
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;
|
let storedVersion = null;
|
||||||
try {
|
try {
|
||||||
@@ -1695,8 +1721,11 @@ function maybeShowWhatsNew() {
|
|||||||
|
|
||||||
if (!shouldShowWhatsNew(ROLLCALC_BUILD_VERSION, storedVersion)) return;
|
if (!shouldShowWhatsNew(ROLLCALC_BUILD_VERSION, storedVersion)) return;
|
||||||
|
|
||||||
|
const releaseData = await loadWhatsNewData(ROLLCALC_BUILD_VERSION);
|
||||||
|
if (!releaseData) return;
|
||||||
|
|
||||||
versionValue.textContent = ROLLCALC_BUILD_VERSION;
|
versionValue.textContent = ROLLCALC_BUILD_VERSION;
|
||||||
renderWhatsNewItems(items);
|
renderWhatsNewItems(releaseData.items);
|
||||||
overlay.classList.remove('is-hidden');
|
overlay.classList.remove('is-hidden');
|
||||||
|
|
||||||
continueBtn.addEventListener('click', () => {
|
continueBtn.addEventListener('click', () => {
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
.help-nav a { color: #fff; border: 1px solid rgba(255,255,255,0.58); border-radius: 5px; padding: 7px 13px; text-decoration: none; font-size: 13px; font-weight: 700; background: rgba(255,255,255,0.08); }
|
.help-nav a { color: #fff; border: 1px solid rgba(255,255,255,0.58); border-radius: 5px; padding: 7px 13px; text-decoration: none; font-size: 13px; font-weight: 700; background: rgba(255,255,255,0.08); }
|
||||||
.help-nav a:hover { background: rgba(255,255,255,0.18); }
|
.help-nav a:hover { background: rgba(255,255,255,0.18); }
|
||||||
.manual-shell { max-width: 1180px; margin: 28px auto; padding: 0 16px 60px; }
|
.manual-shell { max-width: 1180px; margin: 28px auto; padding: 0 16px 60px; }
|
||||||
|
.document-actions { display: flex; gap: 10px; flex-wrap: wrap; margin: 0 0 18px; }
|
||||||
|
.document-actions a { display: inline-block; color: #1F5438; border: 1px solid #cddbd4; border-radius: 6px; background: #fff; padding: 8px 12px; text-decoration: none; font-size: 13px; font-weight: 700; box-shadow: 0 1px 6px rgba(0,0,0,0.04); }
|
||||||
|
.document-actions a:hover { background: #eef4f1; }
|
||||||
.manual-layout { display: grid; grid-template-columns: 260px minmax(0, 1fr); gap: 24px; align-items: start; }
|
.manual-layout { display: grid; grid-template-columns: 260px minmax(0, 1fr); gap: 24px; align-items: start; }
|
||||||
.manual-toc { position: sticky; top: 18px; background: #fff; border: 1px solid #dfe7e2; border-radius: 8px; padding: 16px; box-shadow: 0 2px 12px rgba(0,0,0,0.05); max-height: calc(100vh - 36px); overflow: auto; }
|
.manual-toc { position: sticky; top: 18px; background: #fff; border: 1px solid #dfe7e2; border-radius: 8px; padding: 16px; box-shadow: 0 2px 12px rgba(0,0,0,0.05); max-height: calc(100vh - 36px); overflow: auto; }
|
||||||
.manual-toc h2 { color: #1F5438; font-size: 14px; margin-bottom: 12px; text-transform: uppercase; letter-spacing: 0; }
|
.manual-toc h2 { color: #1F5438; font-size: 14px; margin-bottom: 12px; text-transform: uppercase; letter-spacing: 0; }
|
||||||
@@ -68,11 +71,21 @@
|
|||||||
<nav class="help-nav" aria-label="Help navigation">
|
<nav class="help-nav" aria-label="Help navigation">
|
||||||
<a href="{{ url_for('index') }}">Calculator</a>
|
<a href="{{ url_for('index') }}">Calculator</a>
|
||||||
<a href="{{ url_for('help_index') }}">Help</a>
|
<a href="{{ url_for('help_index') }}">Help</a>
|
||||||
|
<a href="{{ url_for('user_manual') }}">User Manual</a>
|
||||||
|
<a href="{{ url_for('quick_reference') }}">Quick Reference</a>
|
||||||
|
<a href="{{ url_for('recent_changes') }}">Recent Changes</a>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main class="manual-shell">
|
<main class="manual-shell">
|
||||||
|
{% if document_actions %}
|
||||||
|
<nav class="document-actions" aria-label="Related documents">
|
||||||
|
{% for action in document_actions %}
|
||||||
|
<a href="{{ action.href }}">{{ action.label }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</nav>
|
||||||
|
{% endif %}
|
||||||
{% if render_error %}
|
{% if render_error %}
|
||||||
<section class="manual-error" role="alert">
|
<section class="manual-error" role="alert">
|
||||||
<strong>{{ error_title }}</strong>
|
<strong>{{ error_title }}</strong>
|
||||||
|
|||||||
Reference in New Issue
Block a user