mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat: add URL-based image import (single + bulk)
Add a fourth image ingestion path: importing images by URL. Backend: - POST /api/v1/fetch-urls endpoint with SSRF protection, image validation, preview generation, and p-queue concurrency - SSRF utility blocking private IPs, validating redirect hops, with comprehensive IPv4/IPv6 range coverage Frontend: - Always-visible URL input in the dropzone for quick single-image import - Bulk URL import modal with smart URL parsing (lists, markdown, HTML), per-URL progress tracking, retry on failure, and batch add - useUrlImport hook managing the full fetch lifecycle Tests: 48 new tests (23 SSRF unit, 10 URL parser unit, 15 integration)
This commit is contained in:
@@ -283,6 +283,13 @@ export function ToolPage() {
|
||||
[setFiles, reset],
|
||||
);
|
||||
|
||||
const handleUrlImport = useCallback(
|
||||
(file: File) => {
|
||||
addFiles([file]);
|
||||
},
|
||||
[addFiles],
|
||||
);
|
||||
|
||||
const handleUndo = useCallback(() => {
|
||||
undoProcessing();
|
||||
setEraserSliderInitPos(null);
|
||||
@@ -434,7 +441,15 @@ export function ToolPage() {
|
||||
// Custom results panel (find-duplicates, etc.)
|
||||
if (displayMode === "custom-results" && registryEntry?.ResultsPanel) {
|
||||
if (!hasFile)
|
||||
return <Dropzone onFiles={handleFiles} accept="image/*" multiple currentFiles={files} />;
|
||||
return (
|
||||
<Dropzone
|
||||
onFiles={handleFiles}
|
||||
onUrlImport={handleUrlImport}
|
||||
accept="image/*"
|
||||
multiple
|
||||
currentFiles={files}
|
||||
/>
|
||||
);
|
||||
const ResultsPanel = registryEntry.ResultsPanel;
|
||||
return (
|
||||
<Suspense fallback={<div className="text-sm text-muted-foreground">Loading...</div>}>
|
||||
@@ -637,7 +652,15 @@ export function ToolPage() {
|
||||
);
|
||||
}
|
||||
|
||||
return <Dropzone onFiles={handleFiles} accept="image/*" multiple currentFiles={files} />;
|
||||
return (
|
||||
<Dropzone
|
||||
onFiles={handleFiles}
|
||||
onUrlImport={handleUrlImport}
|
||||
accept="image/*"
|
||||
multiple
|
||||
currentFiles={files}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Navigation arrows (shared between mobile/desktop)
|
||||
|
||||
Reference in New Issue
Block a user