fix(capture): hold-to-record works by keyboard, confirms only after saving; drop FLAW-16
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m43s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m43s
The + button lost its click handler for pointer events, so keyboard, VoiceOver and switch control could no longer open the capture sheet; a click without pointer (detail 0) now taps. "Im Quick Dump gespeichert" appears after the save succeeded, and the cancel state uses an existing border color. FLAW-16 (setup open until the first account, demo accounts) is removed from the list: intended behaviour, not a flaw. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ac2d9e1412
commit
373987292f
3 files changed
+16
-9
No files matched your search
@@ -25,7 +25,6 @@ Schweregrade: **Hoch** (Datenabfluss oder Rechteumgehung möglich), **Mittel** (
|
||||
| FLAW-13 | Datenbank | ~~Keine Schema-Versionierung; Migrationsfehler werden verschluckt; `migrations/001_init.sql` ist toter Code~~ | **Behoben** |
|
||||
| FLAW-14 | Backend | ~~Fehler von Schreiboperationen werden häufig ignoriert (`_, _ =`)~~ | **Behoben** |
|
||||
| FLAW-15 | Realtime | ~~`WriteTimeout` von 30 s beendet SSE-Streams~~ | **Behoben** |
|
||||
| FLAW-16 | Setup | `/auth/setup` ist bis zum ersten Konto offen; Demo-Modus legt `admin/admin` an | Mittel |
|
||||
| FLAW-17 | Workspace | ~~Bearbeiter-Freigaben für Notizen nicht wählbar~~ | **Behoben** |
|
||||
| FLAW-18 | Suche | ~~Nur eigene Gedanken und Dokumente, `LIKE` ohne Escaping, keine FTS~~ | **Behoben** |
|
||||
| FLAW-19 | Qualität | ~~Frontend-Tests nur für den Outliner, `lint` ist ein Platzhalter~~ | **Behoben** |
|
||||
@@ -146,11 +145,6 @@ Schweregrade: **Hoch** (Datenabfluss oder Rechteumgehung möglich), **Mittel** (
|
||||
- **Problem:** Go beendet nach diesem Zeitraum das Schreiben der Antwort. Für den SSE-Fallback (`ServeSSE`) bedeutet das voraussichtlich einen Verbindungsabbruch alle 30 s. WebSockets sind durch Hijacking nicht betroffen. Der Client verbindet sich neu, daher fällt es kaum auf.
|
||||
- **Maßnahme:** Im SSE-Handler `http.ResponseController.SetWriteDeadline(time.Time{})` setzen oder `WriteTimeout` für diese Route aufheben.
|
||||
|
||||
### FLAW-16: Ersteinrichtung und Demo-Modus
|
||||
- **Fundstellen:** `handleFirstBootSetup`, `Store.EnsureDemoAccounts`, `config.Load` (`MINDA_DEMO`, `MINDSIFT_DEMO`, `DEMO_MODE`).
|
||||
- **Probleme:** Solange kein Konto existiert, kann jeder `POST /auth/setup` aufrufen und wird Administrator. Mit gesetztem Demo-Flag entstehen Konten `admin/admin` und `user/user`; versehentlich auf einer öffentlichen Instanz aktiv wäre das eine Komplettübernahme.
|
||||
- **Maßnahme:** Setup per einmaligem Token aus dem Server-Log absichern; Demo-Modus nur zusammen mit expliziter Warnung/Bestätigung.
|
||||
|
||||
### FLAW-17: Schreibgeschützte Dokumentfreigaben
|
||||
- **Status: Behoben.** Zwangsmigration entfernt, Backend prüft Bearbeiter-Rechte (`DocRole`, `/docs/{id}/sync`), der Editor speichert über die Sync-Engine, und der Freigabe-Dialog bietet „Bearbeiten“ an. Browser-Test: `e2e/share.e2e.mjs`.
|
||||
- **Fundstellen:** Migration in `Store.migrate` (`UPDATE doc_shares SET permission = 'read' …`, ebenso `doc_team_shares`, `workspace_folder_shares`), `PatchDocumentBlocks`/`UpdateDocument` (nur Eigentümer).
|
||||
|
||||
@@ -91,10 +91,10 @@ export const HoldToRecordFab: React.FC<HoldToRecordFabProps> = ({ onTap, onTrans
|
||||
return;
|
||||
}
|
||||
|
||||
triggerHaptic(25);
|
||||
showToast('Im Quick Dump gespeichert');
|
||||
try {
|
||||
await onTranscript(text);
|
||||
triggerHaptic(25);
|
||||
showToast('Im Quick Dump gespeichert');
|
||||
} catch {
|
||||
showToast('Fehler beim Speichern');
|
||||
}
|
||||
@@ -300,7 +300,7 @@ export const HoldToRecordFab: React.FC<HoldToRecordFabProps> = ({ onTap, onTrans
|
||||
<div
|
||||
className={
|
||||
isCancelZone
|
||||
? 'fixed left-1/2 -translate-x-1/2 bottom-[calc(5.5rem+env(safe-area-inset-bottom))] z-50 w-max max-w-[calc(100vw-1.5rem)] px-4 py-2.5 rounded-card bg-panel-elevated border border-status-err-border text-status-err shadow-panel pointer-events-none text-center'
|
||||
? 'fixed left-1/2 -translate-x-1/2 bottom-[calc(5.5rem+env(safe-area-inset-bottom))] z-50 w-max max-w-[calc(100vw-1.5rem)] px-4 py-2.5 rounded-card bg-panel-elevated border border-status-err text-status-err shadow-panel pointer-events-none text-center'
|
||||
: 'fixed left-1/2 -translate-x-1/2 bottom-[calc(5.5rem+env(safe-area-inset-bottom))] z-50 w-max max-w-[calc(100vw-1.5rem)] px-4 py-2.5 rounded-card bg-panel-elevated border border-border text-main shadow-panel pointer-events-none text-center'
|
||||
}
|
||||
>
|
||||
@@ -340,6 +340,10 @@ export const HoldToRecordFab: React.FC<HoldToRecordFabProps> = ({ onTap, onTrans
|
||||
onPointerUp={handlePointerUp}
|
||||
onPointerCancel={handlePointerCancel}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
// Keyboard, screen readers and switch control produce a click without pointer events (detail 0)
|
||||
onClick={(e) => {
|
||||
if (e.detail === 0) onTap();
|
||||
}}
|
||||
className={
|
||||
isRecording
|
||||
? 'w-14 h-14 -mt-6 rounded-full bg-status-err text-on-accent shadow-lg flex items-center justify-center transition-transform border-4 border-panel cursor-pointer touch-none select-none animate-pulse'
|
||||
|
||||
@@ -255,3 +255,12 @@ describe('HoldToRecordFab', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('HoldToRecordFab keyboard access', () => {
|
||||
it('opens the capture sheet when activated without a pointer (keyboard, screen reader)', () => {
|
||||
const onTap = vi.fn();
|
||||
const { getByRole } = render(<HoldToRecordFab onTap={onTap} onTranscript={vi.fn()} />);
|
||||
fireEvent.click(getByRole('button'), { detail: 0 });
|
||||
expect(onTap).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user