Some checks failed
Forgejo Android APK / Root app tests (push) Successful in 46s
Forgejo Docker Build / Root app tests (push) Successful in 59s
Forgejo Android APK / Build signed APK (push) Successful in 2m7s
Forgejo Docker Build / Build Docker image (push) Successful in 10s
Forgejo Docker Build / Deploy to the host (push) Failing after 0s
Asking someone to find Settings → Security → Create new app password is a poor first run, and it is the step people give up on. Nextcloud has its own answer: Login Flow v2. The person enters their server address, signs in on Nextcloud the way they normally do — SSO, 2FA, a password manager — and Nextcloud generates an app password for this app. We never see their real password. Pasting an app password still works, behind "Use an app password instead". It is the fallback, not the front door. The security of this is all in what is trusted. The remote server chooses both the login URL and the poll endpoint, so both are SSRF-checked and both must be on the host the person actually typed — an endpoint pointing elsewhere would make this a request-forgery gadget aimed at whatever it named. The server Nextcloud reports at the end is re-checked before it is stored. The poll token is a credential, so polling happens server-side and the browser holds only an opaque handle bound to its own account. Flows live in memory with a 20 minute life, matching Nextcloud's own expiry: a login lasts minutes, and a restart mid-flow is a retry rather than a loss. Starting a second flow replaces the first, which is what clicking again means. The tab is opened from the click itself, before the request — opening it after an await is what a popup blocker stops. Removed with Learning Hub: the WebDAV browse path. Its field, its route and its column are gone, since nothing browses Nextcloud any more. nextcloud_folder is a different column and still in use. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
227 lines
16 KiB
HTML
227 lines
16 KiB
HTML
<div class="module-header">
|
|
<h2><i class="fas fa-cog"></i> Settings</h2>
|
|
<p>Account security, integrations, and personal templates</p>
|
|
</div>
|
|
|
|
<div class="settings-page">
|
|
|
|
<!-- Voice Preferences (STT & TTS) -->
|
|
<div class="settings-section card" id="voice-preferences-section">
|
|
<h3><i class="fas fa-microphone-lines"></i> Voice Preferences</h3>
|
|
<p style="font-size:13px;color:var(--g600);">Customize your speech-to-text model and text-to-speech voice. These settings apply to all your recording and read-aloud features.</p>
|
|
|
|
<div style="margin-bottom:16px;">
|
|
<label style="display:block;font-size:13px;font-weight:600;color:var(--g700);margin-bottom:6px;">Speech-to-Text Model (Transcription)</label>
|
|
<p style="font-size:12px;color:var(--g500);margin:4px 0 8px;">Choose the AI model for transcribing your audio recordings. More accurate models may be slower.</p>
|
|
<select id="stt-model-select" style="font-size:13px;padding:6px 10px;border:1px solid var(--g300);border-radius:6px;width:100%;max-width:400px;">
|
|
<option value="">Server default</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div data-feature="read_aloud" style="margin-bottom:16px;">
|
|
<label style="display:block;font-size:13px;font-weight:600;color:var(--g700);margin-bottom:6px;">Text-to-Speech Voice (Read Aloud)</label>
|
|
<p style="font-size:12px;color:var(--g500);margin:4px 0 8px;">Choose the voice for the "Read Aloud" feature. Preview available after selection.</p>
|
|
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
|
|
<select id="tts-voice-select" style="font-size:13px;padding:6px 10px;border:1px solid var(--g300);border-radius:6px;flex:1;max-width:400px;">
|
|
<option value="">Server default</option>
|
|
</select>
|
|
<button id="btn-preview-voice" class="btn-sm btn-ghost"><i class="fas fa-play"></i> Preview</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="margin-top:12px;">
|
|
<button id="btn-save-voice-prefs" class="btn-sm btn-primary"><i class="fas fa-save"></i> Save Voice Preferences</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Web Speech Recognition (Real-time Streaming) -->
|
|
<div class="settings-section card" id="web-speech-section" style="border-left:3px solid var(--orange);">
|
|
<h3><i class="fas fa-wave-square"></i> Real-Time Streaming Transcription</h3>
|
|
<div style="background:var(--orange-light);padding:12px;border-radius:6px;margin-bottom:12px;">
|
|
<p style="font-size:13px;color:var(--orange-dark);margin:0;"><i class="fas fa-exclamation-triangle"></i> <strong>Privacy Warning:</strong> Uses your browser's built-in speech recognition, which <strong>may send audio to cloud servers</strong> (Chrome/Edge send to Google). Only enable if you accept this trade-off for real-time transcription.</p>
|
|
</div>
|
|
<p style="font-size:13px;color:var(--g600);">See words appear as you speak (streaming). Overrides browser and server transcription when enabled. <strong>Not HIPAA-compliant</strong> in most browsers.</p>
|
|
|
|
<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:12px;">
|
|
<label style="font-size:13px;font-weight:600;">Enable real-time streaming:</label>
|
|
<label style="display:flex;align-items:center;gap:6px;cursor:pointer;">
|
|
<input type="checkbox" id="web-speech-enabled" style="accent-color:var(--orange);width:16px;height:16px;">
|
|
<span style="font-size:13px;" id="web-speech-status">Off</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div id="web-speech-privacy-info" style="font-size:12px;color:var(--g500);padding:10px;background:var(--g50);border-radius:6px;margin-top:8px;">
|
|
<p style="margin:0 0 4px;font-weight:600;">Current Browser:</p>
|
|
<p style="margin:0;" id="web-speech-browser-info">Detecting...</p>
|
|
</div>
|
|
|
|
<p style="font-size:11px;color:var(--g400);margin:8px 0 0;"><i class="fas fa-info-circle"></i> <strong>Trade-off:</strong> Immediate transcription vs. privacy. For maximum privacy, use server transcription with a HIPAA-eligible provider.</p>
|
|
</div>
|
|
|
|
<!-- Change Password — hidden by default; unhidden only for users with a real password -->
|
|
<div class="settings-section card" id="change-password-section" style="display:none;">
|
|
<h3><i class="fas fa-key"></i> Change Password</h3>
|
|
<div class="form-group" style="max-width:340px;">
|
|
<label>Current Password</label>
|
|
<input type="password" id="pw-current" placeholder="Enter current password">
|
|
</div>
|
|
<div class="form-group" style="max-width:340px;">
|
|
<label>New Password (8+ characters)</label>
|
|
<input type="password" id="pw-new" minlength="8" placeholder="Enter new password">
|
|
</div>
|
|
<div class="form-group" style="max-width:340px;">
|
|
<label>Confirm New Password</label>
|
|
<input type="password" id="pw-confirm" minlength="8" placeholder="Confirm new password">
|
|
</div>
|
|
<button id="btn-change-password" class="btn-sm btn-primary"><i class="fas fa-check"></i> Change Password</button>
|
|
<span id="pw-change-status" style="font-size:13px;margin-left:8px;"></span>
|
|
</div>
|
|
|
|
<!-- 2FA — hidden by default; unhidden only for users with a real password (SSO users use their IdP's MFA) -->
|
|
<div class="settings-section card" id="2fa-section" style="display:none;">
|
|
<h3><i class="fas fa-shield-halved"></i> Two-Factor Authentication</h3>
|
|
<p id="2fa-status">Status: Loading...</p>
|
|
<button id="btn-setup-2fa" class="btn-sm btn-primary">Enable 2FA</button>
|
|
<button id="btn-disable-2fa" class="btn-sm btn-ghost hidden" style="color:var(--red);">Disable 2FA</button>
|
|
<div id="2fa-backup-info"></div>
|
|
<div id="2fa-disable-confirm" class="hidden" style="margin-top:10px;padding:12px;background:var(--g50);border-radius:8px;border:1px solid var(--g200);max-width:340px;">
|
|
<div class="form-group" style="margin-bottom:8px;">
|
|
<label>Enter your password to confirm:</label>
|
|
<input type="password" id="2fa-disable-password" placeholder="Password">
|
|
</div>
|
|
<div style="display:flex;gap:6px;">
|
|
<button id="btn-disable-2fa-confirm" class="btn-sm btn-primary" style="background:var(--red);border-color:var(--red);">Confirm Disable</button>
|
|
<button id="btn-disable-2fa-cancel" class="btn-sm btn-ghost">Cancel</button>
|
|
</div>
|
|
</div>
|
|
<div id="2fa-setup" class="hidden">
|
|
<p>Scan this QR code with your authenticator app:</p>
|
|
<img id="2fa-qr" src="" alt="QR Code">
|
|
<p>Or enter manually: <code id="2fa-secret"></code></p>
|
|
<div class="form-group">
|
|
<label>Enter the 6-digit code to verify:</label>
|
|
<input type="text" id="2fa-verify-code" maxlength="6" placeholder="123456">
|
|
<button id="btn-verify-2fa" class="btn-sm btn-success">Verify & Enable</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Active Sessions — hidden for SSO-only users (revoke can't stick against an active IdP session) -->
|
|
<div class="settings-section card" id="sessions-section" style="display:none;">
|
|
<h3><i class="fas fa-desktop"></i> Active Sessions</h3>
|
|
<p style="font-size:13px;color:var(--g600);">Devices where you are currently logged in. Revoke any session to immediately log that device out.</p>
|
|
<div style="margin-bottom:10px;">
|
|
<button id="btn-revoke-all-sessions" class="btn-sm btn-ghost" style="color:var(--red);font-size:12px;"><i class="fas fa-ban"></i> Revoke All Other Sessions</button>
|
|
</div>
|
|
<div id="sessions-list" style="display:flex;flex-direction:column;gap:6px;">
|
|
<p style="color:var(--g400);font-size:13px;">Loading sessions...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Nextcloud -->
|
|
<div class="settings-section card" data-feature="nextcloud">
|
|
<h3><i class="fas fa-cloud"></i> Nextcloud Integration</h3>
|
|
<p>Save generated notes and teaching material to your own Nextcloud.</p>
|
|
<div id="nc-status">Not connected</div>
|
|
|
|
<div class="form-group">
|
|
<label for="nc-url">Nextcloud address</label>
|
|
<input type="text" id="nc-url" placeholder="https://cloud.example.com">
|
|
</div>
|
|
|
|
<!-- The ordinary way in: sign in on Nextcloud itself, however you
|
|
normally do, and it hands back a password made for this app. -->
|
|
<button id="btn-nc-login-flow" class="btn-sm btn-primary">
|
|
<i class="fas fa-arrow-up-right-from-square"></i> Sign in with Nextcloud
|
|
</button>
|
|
<p id="nc-login-flow-status" role="status" style="margin:6px 0 0;font-size:12px;color:var(--g600);"></p>
|
|
|
|
<details id="nc-manual" style="margin-top:12px;">
|
|
<summary style="cursor:pointer;font-size:13px;color:var(--g600);">Use an app password instead</summary>
|
|
<div class="form-group" style="margin-top:10px;">
|
|
<label for="nc-user">Username</label>
|
|
<input type="text" id="nc-user" placeholder="your-username">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="nc-pass">App password</label>
|
|
<input type="password" id="nc-pass" placeholder="Generate in Nextcloud → Settings → Security">
|
|
<small>Nextcloud → Settings → Security → Create new app password</small>
|
|
</div>
|
|
<button id="btn-nc-connect" class="btn-sm btn-primary">Connect</button>
|
|
</details>
|
|
|
|
<button id="btn-nc-disconnect" class="btn-sm btn-ghost hidden" style="margin-top:10px;">Disconnect</button>
|
|
</div>
|
|
|
|
<!-- My Templates / Memories -->
|
|
<div class="settings-section card" data-feature="memories">
|
|
<h3><i class="fas fa-book-medical"></i> My Templates</h3>
|
|
<p style="font-size:13px;color:var(--g600);">Save reusable templates for physical exam, ROS, encounter format, etc. Only template categories are sent to AI when generating notes — anything saved as <strong>Custom</strong> is never sent. Templates go out with Encounter HPI, Dictation HPI, SOAP, Sick Visit, Well Visit, ED Encounter and Hospital Course, and shape how a note is laid out and worded. The AI is told never to copy clinical content out of a template, so a template cannot supply findings you did not dictate: say them instead, for example “normal cardiac exam”, and they are documented.</p>
|
|
<div style="margin-bottom:10px;display:flex;gap:8px;flex-wrap:wrap;align-items:center;">
|
|
<select id="mem-category" style="font-size:13px;padding:5px 8px;border:1px solid var(--g300);border-radius:6px;">
|
|
<option value="physical_exam">Physical Exam Template</option>
|
|
<option value="ros">Review of Systems Template</option>
|
|
<option value="encounter_format">Encounter Note Format</option>
|
|
<option value="family_history">Family History Format</option>
|
|
<option value="assessment_plan">Assessment & Plan Format</option>
|
|
<option value="template_soap">SOAP Note Template</option>
|
|
<option value="template_hpi">HPI Template</option>
|
|
<option value="template_wellvisit">Well Visit Template</option>
|
|
<option value="template_sickvisit">Sick Visit Template</option>
|
|
<option value="template_ed">ED Template</option>
|
|
</select>
|
|
<input type="text" id="mem-name" style="font-size:13px;padding:5px 8px;border:1px solid var(--g300);border-radius:6px;flex:1;min-width:150px;" placeholder="Template name (e.g. Normal PE)">
|
|
<a href="/template-guide.md" download="ped-ai-template-guide.md" class="btn-sm btn-ghost" style="text-decoration:none;"><i class="fas fa-download"></i> Template Guide</a>
|
|
</div>
|
|
<textarea id="mem-content" rows="5" style="width:100%;font-size:12px;padding:8px;border:1px solid var(--g300);border-radius:6px;resize:vertical;box-sizing:border-box;" placeholder="Paste your template here. Example: HEENT: Normocephalic, atraumatic. Eyes: PERRL. Ears: TMs clear. Throat: clear..."></textarea>
|
|
<div style="margin-top:8px;display:flex;gap:8px;">
|
|
<button id="btn-mem-save" class="btn-sm btn-primary"><i class="fas fa-plus"></i> Add Template</button>
|
|
</div>
|
|
<div id="mem-list" style="margin-top:12px;display:flex;flex-direction:column;gap:6px;">
|
|
<p style="color:var(--g400);font-size:13px;">Loading templates...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Documents (S3) -->
|
|
<div class="settings-section card" id="documents-section">
|
|
<h3><i class="fas fa-file-arrow-up"></i> Documents</h3>
|
|
<p style="font-size:13px;color:var(--g600);">Upload and manage documents via S3 storage (PDF, images, Word docs, text files). Max 10 MB per file.</p>
|
|
<div id="doc-upload-area" style="margin-bottom:12px;">
|
|
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
|
|
<input type="file" id="doc-file-input" accept=".pdf,.jpg,.jpeg,.png,.gif,.doc,.docx,.txt,.csv" style="font-size:13px;">
|
|
<input type="text" id="doc-description" placeholder="Description (optional)" style="font-size:13px;padding:5px 8px;border:1px solid var(--g300);border-radius:6px;flex:1;min-width:150px;">
|
|
<button id="btn-doc-upload" class="btn-sm btn-primary"><i class="fas fa-upload"></i> Upload</button>
|
|
</div>
|
|
</div>
|
|
<div id="documents-list" style="display:flex;flex-direction:column;gap:6px;">
|
|
<p style="color:var(--g400);font-size:13px;">Loading...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Audio Backups -->
|
|
<div class="settings-section card">
|
|
<h3><i class="fas fa-microphone-lines"></i> Audio Backups</h3>
|
|
<p style="font-size:13px;color:var(--g600);">Recordings are automatically backed up locally and kept for 24 hours. Retry transcription if it failed.</p>
|
|
<div id="audio-backups-list" style="display:flex;flex-direction:column;gap:6px;">
|
|
<p style="color:var(--g400);font-size:13px;">Loading...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Saved Encounters -->
|
|
<div class="settings-section card">
|
|
<h3><i class="fas fa-floppy-disk"></i> Saved Encounters</h3>
|
|
<p style="font-size:13px;color:var(--g600);">Encounters are automatically deleted after 7 days per site policy.</p>
|
|
<div id="saved-enc-list" style="display:flex;flex-direction:column;gap:6px;">
|
|
<p style="color:var(--g400);font-size:13px;">Loading...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Compliance -->
|
|
<div class="settings-section card">
|
|
<h3><i class="fas fa-shield-halved"></i> Compliance & Usage</h3>
|
|
<div class="hipaa-info">
|
|
<p><strong>Important:</strong> Check with your institution's guidelines and policies before use. This tool is not intended for production clinical use without proper organizational authorization and provider BAAs in place. Use with caution.</p>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|