Updates go through the collection cell: collid- and version_id-exact
The last unverified flow failed on its guess — the collection row has no link named "own"; the edit affordances are icon anchors with no text. The site offers something far better, now verified: the row's VERSION CELL carries its own collid in an onclick, and the inline editor it opens is a radio list whose values ARE version ids. So an update addresses the copy by collid and the edition by version id — no name matching, no pagination, no dialog, and structurally incapable of creating a duplicate entry (it sets one field on one collid). Clicking the radio fires CE_SaveData itself; there is no Save button, and the save has landed when the cell stops reading "Editing". A version id the editor doesn't offer aborts with the entry untouched. The class docstring's UNVERIFIED list is now empty but for the second-copy add, which --verify already reports as a copy-count shortfall. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jXZFSTZQKzAC8fqpWSz9g
This commit is contained in:
co-authored by
Claude Fable 5
parent
74ecd5059b
commit
0af9ae86c5
+38
-23
@@ -290,10 +290,11 @@ class Uploader(Protocol):
|
||||
class PlaywrightUploader:
|
||||
"""Drives the real site. Selector documentation: docs/bgg-upload-flow.md.
|
||||
|
||||
Verified selectors (2026-08-01): the login form (#inputUsername /
|
||||
#inputPassword / "Sign In") and the Add-to-Collection dialog structure.
|
||||
UNVERIFIED: version-picker pagination, post-save behavior, and the whole
|
||||
collection-row edit flow for updates — expect first-real-run adjustments.
|
||||
All flows verified against the live site 2026-08-06 (adds, the version
|
||||
picker with pagination, and the collection-row version edit). The
|
||||
remaining unknown is the second-copy add: BGG may edit the existing
|
||||
entry instead of creating one, which run_upload reports as a copy-count
|
||||
shortfall during --verify.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -583,33 +584,47 @@ class PlaywrightUploader:
|
||||
def update_entry(self, job: UploadJob) -> tuple[str, str]:
|
||||
"""Set the version on an EXISTING entry — strictly additive.
|
||||
|
||||
UNVERIFIED FLOW: the collection table can't target a collid directly,
|
||||
so this filters by game and opens the row's status link. With several
|
||||
copies of one game the wrong row could open — acceptable only while
|
||||
every 2018 entry is version-less; revisit after the first real run.
|
||||
Verified 2026-08-06. The collection table's version cell carries its
|
||||
own collid in an onclick and opens an inline editor whose radios
|
||||
carry VERSION IDS as their values, so both the copy and the edition
|
||||
are addressed exactly — no name matching, no dialog, no pagination.
|
||||
Clicking a radio fires CE_SaveData itself; there is no Save button.
|
||||
"""
|
||||
self._ensure_logged_in()
|
||||
page = self._page
|
||||
self._goto(
|
||||
f"{BGG}/collection/user/{self._username}?objectid={job.bgg_id}&own=1"
|
||||
)
|
||||
row = (
|
||||
page.get_by_role("row")
|
||||
.filter(has_text=re.compile(re.escape(job.name), re.I))
|
||||
.first
|
||||
)
|
||||
opener = row.get_by_role("link", name=re.compile("own", re.I)).first
|
||||
dialog = self._open_dialog(opener)
|
||||
picked, why = self._select_version(dialog, job.version_name)
|
||||
if not picked:
|
||||
# Never guess a version: close without touching the entry.
|
||||
dialog.get_by_role("button", name="Cancel").first.click()
|
||||
cell = page.locator(f'td.collection_version[onclick*="{job.collid}"]')
|
||||
if cell.count() == 0:
|
||||
raise RuntimeError(
|
||||
f"version {job.version_name!r}: {why} — entry left untouched"
|
||||
f"collid {job.collid} has no version cell on the collection "
|
||||
"page — the entry may have been removed; re-run diff"
|
||||
)
|
||||
dialog.get_by_role("button", name="Save").click()
|
||||
dialog.wait_for(state="hidden", timeout=15_000)
|
||||
return "updated", "row-edit flow is unverified; confirm with --verify"
|
||||
cell.first.click()
|
||||
radio = page.locator(
|
||||
f'form[id^="form_version"] input[type="radio"][value="{job.version_id}"]'
|
||||
)
|
||||
try:
|
||||
radio.first.wait_for(timeout=15_000)
|
||||
except self._timeout_error as err:
|
||||
# the editor lists every version of the game: an absent id means
|
||||
# the wrong game's editor opened, or BGG retired that version
|
||||
page.keyboard.press("Escape")
|
||||
raise RuntimeError(
|
||||
f"version {job.version_id} not offered for collid "
|
||||
f"{job.collid} — entry left untouched"
|
||||
) from err
|
||||
radio.first.click() # fires CE_SaveData: no separate Save button
|
||||
for _ in range(40):
|
||||
settled = " ".join((cell.first.text_content() or "").split())
|
||||
if settled and "editing" not in settled.casefold():
|
||||
return "updated", ""
|
||||
page.wait_for_timeout(500)
|
||||
raise RuntimeError(
|
||||
"the version cell never left its editing state — the save may "
|
||||
"not have landed; re-run with --verify"
|
||||
)
|
||||
|
||||
|
||||
def _process(
|
||||
|
||||
Reference in New Issue
Block a user