1
Fork 0
mirror of https://github.com/thegeneralist01/archivr synced 2026-07-21 18:55:36 +02:00

feat: non-blocking batch capture dialog, toasts on failure, fix /runs errors

CaptureDialog:
- Replace single textarea with multi-row inputs; + button adds rows
- Submit fires all pending rows in parallel, dialog stays open/usable
- Polling intervals live on a persistent ref (not cleared on close) so
  toasts fire even after the dialog is dismissed
- archiveId stored per item at submit time; page-refresh reconnect uses
  it.archiveId instead of the possibly-null prop
- Completed rows flash green then self-remove; failed rows show inline
  error + retry button
- Cancel becomes Close while jobs are in flight

ToastStack (new component):
- Fixed bottom-right overlay with spring-in animation
- Error toast: truncated locator, View error / Hide toggle expanding
  full error_text in a monospace pre block
- Auto-dismisses after 7 s; timer pauses while detail is expanded

RunsView:
- Failed rows are clickable and expand a full-width detail row showing
  error_summary in a scrollable monospace block

capture.rs (archivr-core):
- Staging dir is now "{millis}-{uuid}" — parallel captures in the same
  millisecond can no longer collide on temp paths
- create_archive_run moved before URL Content-Type probe so every
  attempt appears in /runs regardless of outcome
- Probe failures now call create_archive_run_item with source_metadata
  fallback then fail_run, recording error_text on the item and
  error_summary on the run with correct failed_count

styles.css:
- Capture dialog: header row, multi-row layout, status dots, spinner,
  add-row dashed button, per-row error text
- Toast stack: fixed overlay, error card with coloured left border,
  monospace detail expansion
- Run error rows: clickable hover tint, expand hint chevron, detail pre
This commit is contained in:
TheGeneralist 2026-07-05 13:56:00 +02:00
parent d83faab8e6
commit fb1115a409
Signed by: thegeneralist01
SSH key fingerprint: SHA256:pp9qddbCNmVNoSjevdvQvM5z0DHN7LTa8qBMbcMq/R4
11 changed files with 698 additions and 223 deletions

View file

@ -13,6 +13,7 @@ import CollectionsView from './components/CollectionsView'
import SettingsView from './components/SettingsView'
import ContextRail from './components/ContextRail'
import { displayPath } from './utils'
import ToastStack from './components/ToastStack'
export const AuthContext = createContext(null);
@ -82,6 +83,9 @@ export default function App() {
return saved === 'true'
})
const [toasts, setToasts] = useState([])
const toastIdRef = useRef(0)
const humanizeTags = currentUser?.humanize_slugs ?? false;
// Persist captureDialogOpen to sessionStorage
@ -234,6 +238,15 @@ export default function App() {
])
}, [archiveId, searchQuery, tagFilter, loadEntries])
const handleToast = useCallback((errorText, locator) => {
const id = ++toastIdRef.current
setToasts(prev => [...prev, { id, errorText, locator }])
}, [])
const handleDismissToast = useCallback((id) => {
setToasts(prev => prev.filter(t => t.id !== id))
}, [])
if (authState === 'loading') return <div className="auth-loading">Loading\u2026</div>;
if (authState === 'setup') return <SetupPage onComplete={() => setAuthState('login')} />;
if (authState === 'login') return <LoginPage onLogin={user => { setCurrentUser(user); setAuthState('authenticated'); }} />;
@ -332,7 +345,9 @@ export default function App() {
archiveId={archiveId}
onClose={handleCaptureClose}
onCaptured={handleCaptured}
onToast={handleToast}
/>
<ToastStack toasts={toasts} onDismiss={handleDismissToast} />
</>
</AuthContext.Provider>
)