feat(import): restore MindSift data and import Obsidian vaults
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m28s

- Two separate paths: POST /import/mindsift (JSON backup or the Markdown
  archive) and POST /import/obsidian (vault ZIP into a folder named after it)
- Everything is planned and validated first; ?preview=1 returns what would
  be created and what is skipped (with reason), nothing is written
- MindSift data round-trips: folders, note structure, task lists with
  subtasks/due dates/priorities/notes, lists with quantity/category/done,
  triage thoughts from the JSON backup
- Markdown to outliner: nested lists, heading sections, callouts, code,
  paragraphs; front matter tags become hashtags; .obsidian/attachments skipped
- Limits against zip bombs and path tricks (100 MB upload, 10 MB per note,
  500 MB unpacked, 20k files, no .. escapes)
- Settings: two import cards with drag & drop, preview, confirm, result;
  touch-sized buttons; mobile download/upload verified

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-29 06:10:21 +01:00
1 parent d8a16c6775
commit 1601a6a2d5
9 files changed
+1314 -1

No files matched your search

@@ -27,6 +27,7 @@ import themeTemplateCss from '../../themes/theme-template.css?raw';
import { UserAvatar, resizeImageToDataUrl } from '../../components/UserAvatar';
import { LegalLinks } from '../../components/LegalLinks';
import { AboutModal } from '../../components/AboutModal';
import { ImportCard } from './ImportCard';
interface UserSettingsViewProps {
currentUser: User;
@@ -1273,6 +1274,42 @@ export const UserSettingsView: React.FC<UserSettingsViewProps> = ({
<span>{exportingVault ? 'Wird erstellt…' : 'Markdown-Archiv herunterladen'}</span>
</button>
</div>
{/* Import: two separate paths, never guessed from the file */}
<div className="pt-4 border-t border-border space-y-3">
<div>
<h3 className="font-bold text-main">Daten importieren</h3>
<p className="text-muted text-[11px]">
Ein Import legt alles neu an und ändert nichts Bestehendes. Vor dem Import siehst du, was angelegt wird.
</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-3">
<ImportCard
source="mindsift"
title="MindSift-Daten"
accept=".json,.zip,application/json,application/zip"
description={
<>
Eigenes Backup zurückspielen: JSON-Backup (<code className="font-mono">.json</code>) oder Markdown-Archiv
(<code className="font-mono">.zip</code>). Notizen kommen in ihre Ordner, Aufgabenlisten mit Unteraufgaben,
Fälligkeiten und Prioritäten sowie Listen werden wiederhergestellt.
</>
}
/>
<ImportCard
source="obsidian"
title="Obsidian-Vault"
accept=".zip,application/zip"
description={
<>
Vault als <code className="font-mono">.zip</code>. Alle Notizen landen in einem eigenen Ordner mit dem Namen
des Vaults, Unterordner bleiben erhalten. Checkboxen bleiben Checkboxen in der Notiz, Frontmatter-Tags werden zu
#Hashtags. Bilder und andere Anhänge werden übersprungen.
</>
}
/>
</div>
</div>
</div>
)}
</div>