diff --git a/src/engineering_platform/assets/dashboard_locales.mjs b/src/engineering_platform/assets/dashboard_locales.mjs index 7f390261..18239a70 100644 --- a/src/engineering_platform/assets/dashboard_locales.mjs +++ b/src/engineering_platform/assets/dashboard_locales.mjs @@ -4015,6 +4015,11 @@ Object.assign(DASHBOARD_MESSAGES.nl, {"copy.path_success":"Pad gekopieerd naar k Object.assign(DASHBOARD_MESSAGES.de, {"copy.path_success":"Pfad in die Zwischenablage kopiert"}); Object.assign(DASHBOARD_MESSAGES.fr, {"copy.path_success":"Chemin copié dans le presse-papiers"}); Object.assign(DASHBOARD_MESSAGES.es, {"copy.path_success":"Ruta copiada al portapapeles"}); +Object.assign(DASHBOARD_MESSAGES.en, {"configuration.file_inbox":"File Inbox","configuration.file_inbox_location":"File Inbox location","configuration.relocate_file_inbox":"Relocate File Inbox","configuration.file_inbox_relocation_help":"Relocate the File Inbox only when it is empty.","configuration.current_folder":"Current folder","configuration.new_folder":"New folder"}); +Object.assign(DASHBOARD_MESSAGES.nl, {"configuration.file_inbox":"File Inbox","configuration.file_inbox_location":"File Inbox-locatie","configuration.relocate_file_inbox":"Verplaats File Inbox","configuration.file_inbox_relocation_help":"Verplaats de File Inbox alleen wanneer deze leeg is.","configuration.current_folder":"Huidige map","configuration.new_folder":"Nieuwe map"}); +Object.assign(DASHBOARD_MESSAGES.de, {"configuration.file_inbox":"File Inbox","configuration.file_inbox_location":"File-Inbox-Speicherort","configuration.relocate_file_inbox":"File Inbox verschieben","configuration.file_inbox_relocation_help":"Verschieben Sie die File Inbox nur, wenn sie leer ist.","configuration.current_folder":"Aktueller Ordner","configuration.new_folder":"Neuer Ordner"}); +Object.assign(DASHBOARD_MESSAGES.fr, {"configuration.file_inbox":"File Inbox","configuration.file_inbox_location":"Emplacement de File Inbox","configuration.relocate_file_inbox":"Déplacer File Inbox","configuration.file_inbox_relocation_help":"Déplacez File Inbox uniquement lorsqu’elle est vide.","configuration.current_folder":"Dossier actuel","configuration.new_folder":"Nouveau dossier"}); +Object.assign(DASHBOARD_MESSAGES.es, {"configuration.file_inbox":"File Inbox","configuration.file_inbox_location":"Ubicación de File Inbox","configuration.relocate_file_inbox":"Reubicar File Inbox","configuration.file_inbox_relocation_help":"Reubique File Inbox solo cuando esté vacía.","configuration.current_folder":"Carpeta actual","configuration.new_folder":"Nueva carpeta"}); Object.assign(DASHBOARD_MESSAGES.en, {"configuration.relocate_database":"Relocate database","configuration.relocate_database_help":"Choose a writable local folder. The server stops safely first and then restarts.","configuration.choose_folder":"Choose folder","configuration.relocate":"Relocate","configuration.relocation_restarting":"Relocation is scheduled; the server is restarting.","configuration.relocation_failed":"Relocation could not be scheduled."}); Object.assign(DASHBOARD_MESSAGES.nl, {"configuration.relocate_database":"Verplaats database","configuration.relocate_database_help":"Kies een beschrijfbare lokale map. De server stopt eerst veilig en start daarna opnieuw.","configuration.choose_folder":"Kies map","configuration.relocate":"Verplaatsen","configuration.relocation_restarting":"Verplaatsing staat klaar; de server start opnieuw.","configuration.relocation_failed":"De verplaatsing kon niet worden ingepland."}); Object.assign(DASHBOARD_MESSAGES.de, {"configuration.relocate_database":"Datenbank verschieben","configuration.relocate_database_help":"Wählen Sie einen beschreibbaren lokalen Ordner. Der Server wird sicher beendet und dann neu gestartet.","configuration.choose_folder":"Ordner auswählen","configuration.relocate":"Verschieben","configuration.relocation_restarting":"Verschiebung ist geplant; der Server startet neu.","configuration.relocation_failed":"Die Verschiebung konnte nicht geplant werden."}); diff --git a/src/engineering_platform/server.py b/src/engineering_platform/server.py index 5182b1fa..aed0a488 100644 --- a/src/engineering_platform/server.py +++ b/src/engineering_platform/server.py @@ -2149,6 +2149,16 @@ def _central_database_script() -> str: return '''const maintenance=document.getElementById('centralDatabaseMaintenanceInterval'),maintenanceStatus=document.getElementById('centralDatabaseMaintenanceStatus'),translate=window.__engineeringPlatformDashboardTranslate;if(maintenance)maintenance.addEventListener('change',async()=>{const previous=maintenance.dataset.savedValue||maintenance.value,requested=Number(maintenance.value);maintenance.disabled=true;maintenance.setAttribute('aria-busy','true');if(maintenanceStatus)maintenanceStatus.textContent='';try{const response=await fetch('/api/central-database/configuration',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({interval_seconds:requested})});const result=response.ok?await response.json():null;if(!result||Number(result.interval_seconds)!==requested)throw Error();maintenance.dataset.savedValue=String(requested);if(maintenanceStatus)maintenanceStatus.textContent=translate('configuration.ep_database_maintenance_saved')}catch{maintenance.value=previous;if(maintenanceStatus)maintenanceStatus.textContent=translate('configuration.ep_database_maintenance_failed')}finally{maintenance.disabled=false;maintenance.removeAttribute('aria-busy')}});const modal=document.getElementById('centralDatabaseRelocateModal'),open=document.getElementById('centralDatabaseRelocate'),input=document.getElementById('centralDatabaseRelocateDirectory'),destination=document.getElementById('centralDatabaseRelocateDestination'),destinationValue=document.getElementById('centralDatabaseRelocateDestinationValue'),save=document.getElementById('centralDatabaseRelocateSave'),status=document.getElementById('centralDatabaseRelocateStatus');open?.addEventListener('click',()=>modal.showModal());modal?.querySelector('[data-close-relocation]')?.addEventListener('click',()=>modal.close());document.getElementById('centralDatabaseRelocateBrowse')?.addEventListener('click',async()=>{const r=await fetch('/api/central-database/relocate/browse',{method:'POST'}),p=await r.json();if(p.value){input.value=p.value;destinationValue.textContent=p.value;destination.hidden=false;save.disabled=false;}});save?.addEventListener('click',async()=>{const r=await fetch('/api/central-database/relocate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({directory:input.value})}),p=await r.json();status.textContent=r.ok?translate('configuration.relocation_restarting'):p.error||translate('configuration.relocation_failed');if(r.ok)setTimeout(()=>location.reload(),2500);});''' +def _file_inbox_section(data_root: Path) -> str: + """Render File Inbox relocation with the same installation-owned affordance.""" + location = escape(str((data_root / FILE_INBOX_DIRECTORY).resolve())) + return f'''

File Inbox

Verplaats de File Inbox alleen wanneer deze leeg is.

File Inbox-locatie
{location}

Verplaats File Inbox

Verplaats de File Inbox alleen wanneer deze leeg is.

Huidige map
{location}

''' + + +def _file_inbox_relocation_script() -> str: + return '''const inboxModal=document.getElementById('fileInboxRelocateModal'),inboxOpen=document.getElementById('fileInboxRelocate'),inboxInput=document.getElementById('fileInboxRelocateDirectory'),inboxDestination=document.getElementById('fileInboxRelocateDestination'),inboxDestinationValue=document.getElementById('fileInboxRelocateDestinationValue'),inboxSave=document.getElementById('fileInboxRelocateSave'),inboxStatus=document.getElementById('fileInboxRelocateStatus');inboxOpen?.addEventListener('click',()=>inboxModal.showModal());inboxModal?.querySelector('[data-close-relocation]')?.addEventListener('click',()=>inboxModal.close());document.getElementById('fileInboxRelocateBrowse')?.addEventListener('click',async()=>{const r=await fetch('/api/configuration/file-inbox/relocate/browse',{method:'POST'}),p=await r.json();if(p.value){inboxInput.value=p.value;inboxDestinationValue.textContent=p.value;inboxDestination.hidden=false;inboxSave.disabled=false;}});inboxSave?.addEventListener('click',async()=>{const r=await fetch('/api/configuration/file-inbox/relocate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({directory:inboxInput.value})}),p=await r.json();inboxStatus.textContent=r.ok?window.__engineeringPlatformDashboardTranslate('configuration.relocation_restarting'):p.error||window.__engineeringPlatformDashboardTranslate('configuration.relocation_failed');if(r.ok)setTimeout(()=>location.reload(),2500);});''' + + def _retire_legacy_inbox_configuration(document: bytes, data_root: Path) -> bytes: """Add the canonical File Inbox projection to the installed Console. @@ -2210,7 +2220,7 @@ def _console_project_boundary(project_id: str, options: str) -> str: }); })(); '''.replace("$PROJECT", json.dumps(project_id)).replace("$OPTIONS", json.dumps(options)).replace( - "$CENTRAL_DATABASE_SCRIPT", _central_database_script(), + "$CENTRAL_DATABASE_SCRIPT", _central_database_script() + _file_inbox_relocation_script(), ) @@ -2225,7 +2235,7 @@ def _no_project_console_document(projects: list[dict[str, str]], data_root: Path ) options = _console_project_options(None, projects) selector = f'''''' - boundary = ''''''.replace("$CENTRAL_DATABASE_SCRIPT", _central_database_script()) + boundary = ''''''.replace("$CENTRAL_DATABASE_SCRIPT", _central_database_script() + _file_inbox_relocation_script()) empty_state = '''''' scoped_style = '''