fix: file display, persistence, PDF support and save error handling

- Add file proxy route in maker blueprint (X-API-Key auth for browser requests)
- Persist file_path/annotations_json to DB via RecipeCreate/RecipeUpdate schemas
- Fix canvas sizing using grandparent container instead of Fabric.js wrapper div
- Defer canvas init with requestAnimationFrame for x-show timing
- Add PDF.js support in annotation-editor and annotation-viewer
- Fix annotations_json double-serialization (parse string to object before send)
- Handle FastAPI 422 validation error arrays in api_client and JS error display
- Update template URLs to use /maker/api/files/ proxy path

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Adriano
2026-02-07 22:04:45 +01:00
parent d262ef68af
commit b075115cef
8 changed files with 315 additions and 65 deletions
+11 -4
View File
@@ -580,7 +580,11 @@
{% block extra_js %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.1/fabric.min.js"></script>
<script src="{{ url_for('static', filename='js/annotation-editor.js') }}"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
<script>
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
</script>
<script src="{{ url_for('static', filename='js/annotation-editor.js') }}?v=5"></script>
<script>
function recipeEditor() {
return {
@@ -649,9 +653,11 @@ function recipeEditor() {
payload.change_notes = this.changeNotes.trim();
}
// Include annotations if available
// Include annotations if available (may be a JSON string or an object)
if (this.annotationsJson) {
payload.annotations_json = this.annotationsJson;
payload.annotations_json = (typeof this.annotationsJson === 'string')
? JSON.parse(this.annotationsJson)
: this.annotationsJson;
}
// Include file path if uploaded
@@ -677,7 +683,8 @@ function recipeEditor() {
const data = await resp.json();
if (data.error) {
this.errorMessage = data.detail || data.error || '{{ _("Errore nel salvataggio") }}';
var detail = data.detail || data.error || '{{ _("Errore nel salvataggio") }}';
this.errorMessage = (typeof detail === 'string') ? detail : JSON.stringify(detail);
this.saving = false;
return;
}
+7 -3
View File
@@ -207,7 +207,7 @@
<div class="annotation-container"
x-data="annotationViewer()"
x-init="
imageUrl = '/api/files/{{ task.file_path }}';
imageUrl = '/maker/api/files/{{ task.file_path }}';
annotations = {{ task.annotations_json|default('null')|tojson }};
$nextTick(() => init());
">
@@ -225,7 +225,7 @@
<p class="text-sm font-medium text-[var(--text-primary)]">{{ _('Documento PDF allegato') }}</p>
<p class="text-xs text-[var(--text-muted)]">{{ task.file_path }}</p>
</div>
<a href="/api/files/{{ task.file_path }}"
<a href="/maker/api/files/{{ task.file_path }}"
target="_blank"
class="btn btn-secondary text-xs gap-1.5">
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
@@ -424,7 +424,11 @@
{% endblock %}
{% block extra_js %}
<script src="{{ url_for('static', filename='js/annotation-viewer.js') }}"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
<script>
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
</script>
<script src="{{ url_for('static', filename='js/annotation-viewer.js') }}?v=2"></script>
<script>
/**
* Recipe Preview - Minimal Alpine.js component