diff --git a/archivebox/personas/forms.py b/archivebox/personas/forms.py index 5520a004..c742a4ce 100644 --- a/archivebox/personas/forms.py +++ b/archivebox/personas/forms.py @@ -30,7 +30,7 @@ class PersonaAdminForm(PluginConfigFormMixin, forms.ModelForm): label="Permissions", choices=PERMISSIONS_CHOICES, required=True, - help_text="Default visibility for crawls and snapshots that use this persona.", + help_text="Default visibility for crawls and snapshots created using this persona.", ) import_mode = forms.ChoiceField( required=False, diff --git a/archivebox/services/runner.py b/archivebox/services/runner.py index d8b014dc..5ff2dd5f 100644 --- a/archivebox/services/runner.py +++ b/archivebox/services/runner.py @@ -1210,14 +1210,14 @@ def queued_plugins_for_snapshot(snapshot_id: str) -> list[str] | None: ] if obsolete_result_ids: # Hook names are the scheduler identity for ArchiveResults. If an old - # queued row names a hook that the current plugin model cannot run, mark - # only that row final so the Snapshot scheduler can drain normally instead - # of re-running the whole plugin forever. + # queued row names a hook that the current plugin model cannot run, hard + # fail only that row so the scheduler drains without hiding stale/broken + # plugin state as an intentional skip. ArchiveResult.objects.filter( id__in=obsolete_result_ids, status=ArchiveResult.StatusChoices.QUEUED, ).update( - status=ArchiveResult.StatusChoices.SKIPPED, + status=ArchiveResult.StatusChoices.FAILED, output_str="Hook no longer exists in the current plugin set.", modified_at=timezone.now(), ) diff --git a/archivebox/templates/admin/personas/persona/change_form.html b/archivebox/templates/admin/personas/persona/change_form.html index 52aef94b..8fd76e25 100644 --- a/archivebox/templates/admin/personas/persona/change_form.html +++ b/archivebox/templates/admin/personas/persona/change_form.html @@ -16,10 +16,6 @@ radial-gradient(circle at top right, rgba(67, 97, 238, 0.10), transparent 32%), linear-gradient(135deg, #fff7ed 0%, #ffffff 45%, #ecfeff 100%); box-shadow: 0 10px 30px rgba(15, 23, 42, 0.06); - display: grid; - gap: 18px; - grid-template-columns: minmax(0, 1.8fr) minmax(280px, 1fr); - align-items: start; } .persona-import-hero h2 { @@ -32,37 +28,14 @@ .persona-import-hero p { margin: 0; color: #475569; - max-width: 70ch; + max-width: 92ch; font-size: 14px; } - .persona-import-hero__meta { - display: grid; - gap: 10px; - grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); - } - - .persona-import-hero__stat { - padding: 14px 16px; - border-radius: 14px; - background: rgba(255, 255, 255, 0.86); - border: 1px solid rgba(203, 213, 225, 0.85); - } - - .persona-import-hero__stat span { - display: block; - font-size: 11px; - text-transform: uppercase; - letter-spacing: 0.08em; - font-weight: 700; - color: #64748b; - margin-bottom: 8px; - } - - .persona-import-hero__stat strong, - .persona-import-hero__stat code { - font-size: 18px; + .persona-import-copy { + cursor: pointer; color: #0f172a; + border-bottom: 1px dashed #64748b; } .field-import_mode ul, @@ -194,12 +167,6 @@ color: #991b1b; } - @media (max-width: 960px) { - .persona-import-hero { - grid-template-columns: 1fr; - } - } - body.model-persona.change-form #content-main form fieldset.persona-card-primary { flex: 1 1 520px !important; max-width: calc(66.66% - 10px) !important; @@ -260,6 +227,7 @@ document.addEventListener('DOMContentLoaded', function () { const discoveredRow = document.querySelector('.form-row.field-import_discovered_profile'); const sourceRow = document.querySelector('.form-row.field-import_source'); const profileRow = document.querySelector('.form-row.field-import_profile_name'); + const copyInspect = document.querySelector('[data-copy-text]'); const updateVisibility = () => { const selected = modeInputs.find((input) => input.checked)?.value || 'none'; @@ -270,6 +238,12 @@ document.addEventListener('DOMContentLoaded', function () { modeInputs.forEach((input) => input.addEventListener('change', updateVisibility)); updateVisibility(); + + if (copyInspect) { + copyInspect.addEventListener('click', function () { + navigator.clipboard?.writeText(this.dataset.copyText || this.textContent.trim()); + }); + } }); {% endblock %} @@ -277,25 +251,13 @@ document.addEventListener('DOMContentLoaded', function () { {% block form_top %}
-

Bootstrap a persona from a real browser session

+

Create a new Persona (Authentication + Configuration Profile)

- Pick a local Chromium profile, paste an absolute profile path, or attach to a live CDP endpoint. - The form saves the Persona normally, then imports profile files, cookies, and optional tab storage into - the Persona's own directories. + Import cookies and settings from any Chrome-based browser by pasting in the local path of a User Data Directory to import from, + or by pasting in your CDP url from + chrome://inspect#remote-debugging.

-
-
- Detected profiles - {{ detected_profile_count }} -
-
- Persona artifacts - chrome_profile - cookies.txt - auth.json -
-
{{ block.super }} {% endblock %} diff --git a/archivebox/tests/test_cli_run.py b/archivebox/tests/test_cli_run.py index 441de554..5f69fd06 100644 --- a/archivebox/tests/test_cli_run.py +++ b/archivebox/tests/test_cli_run.py @@ -1220,7 +1220,7 @@ class TestRecoverOrchestratorState: assert result.status == ArchiveResult.StatusChoices.SUCCEEDED assert snapshot.retry_at is None - def test_run_due_snapshot_skips_obsolete_queued_hook_name(self): + def test_run_due_snapshot_fails_obsolete_queued_hook_name(self): from django.utils import timezone from archivebox.base_models.models import get_or_create_system_user_pk @@ -1251,7 +1251,7 @@ class TestRecoverOrchestratorState: result.refresh_from_db() snapshot.refresh_from_db() - assert result.status == ArchiveResult.StatusChoices.SKIPPED + assert result.status == ArchiveResult.StatusChoices.FAILED assert snapshot.retry_at is None def test_recover_orchestrator_state_ignores_sealed_downloaded_snapshot_without_results(self): diff --git a/etc/package.json b/etc/package.json index 64d63b4c..2baad15e 100644 --- a/etc/package.json +++ b/etc/package.json @@ -1,6 +1,6 @@ { "name": "archivebox", - "version": "0.9.33rc41", + "version": "0.9.33rc42", "repository": "github:ArchiveBox/ArchiveBox", "license": "MIT", "dependencies": { diff --git a/pyproject.toml b/pyproject.toml index 94f2cf1a..243d24c9 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "archivebox" -version = "0.9.33rc41" +version = "0.9.33rc42" requires-python = ">=3.13" description = "Self-hosted internet archiving solution." authors = [{name = "Nick Sweeting", email = "pyproject.toml@archivebox.io"}] @@ -79,9 +79,9 @@ dependencies = [ ### Extractor dependencies (optional binaries detected at runtime via shutil.which) ### Binary/Package Management "abxbus==2.5.8", # EventBus API - "abxpkg>=1.11.67", # for: detecting, versioning, and installing binaries via apt/brew/pip/npm - "abx-plugins>=1.11.73", # shared ArchiveBox plugin package with Chrome/Puppeteer dependency wiring - "abx-dl>=1.11.73", # shared ArchiveBox downloader package with blocking install preflight + "abxpkg>=1.11.68", # for: detecting, versioning, and installing binaries via apt/brew/pip/npm + "abx-plugins>=1.11.74", # shared ArchiveBox plugin package with Chrome/Puppeteer dependency wiring + "abx-dl>=1.11.74", # shared ArchiveBox downloader package with blocking install preflight ### UUID7 backport for Python <3.14 "uuid7>=0.1.0; python_version < '3.14'", # provides the uuid_extensions module on Python 3.13 ]