Make the toolbar badge count the unique postings captured and waiting for review #5

Open
opened 2026-09-30 15:19:44 +00:00 by tiagoagueda · 1 comment
Owner

The toolbar badge is set in one place, showUnsentCount() in src/lib/local.js: the number of captures in this browser that have not reached Postulo (kept, waiting or refused; UNSENT in src/lib/store.js), in blue #2563eb, on every tab. A capture Postulo has is sent, uncounted, and never learns whether it has been reviewed. The request: “the number of unique job listings captured and need review”. In Postulo a listing is what a capture becomes once reviewed, so this reads it as postings captured and not yet reviewed.

Where the number comes from

GET /api/v1/captures (captures scope) lists exactly the captures waiting for review, newest first, as {items, count}, 100 a page by default, no maximum (src/postulo/api/api.py and paging.py in the core). A decided capture leaves the list, and updated_since cannot report a removal, so the list is read whole each time.

What “unique” should mean

The same posting captured twice is two waiting captures, on purpose (postulo/postulo#178: told rather than refused), and count counts both. Proposed reading: one per posting address, by the core's same_url() (src/postulo/core/addresses.py): scheme, a leading “www.” and trailing slashes dropped, lower-cased, query kept. No row carries that key; the extension applies it to each url.

src/lib/parse.js has a private port, sameUrl, whose keys differ from the core's for an upper-case “WWW.”, default ports, ;parameters, .. segments, spaces, non-ASCII characters and a user name before the host. Proposed: one exported function, tested against the core's cases in tests/test_known.py and those differences, each matched or written down as known. A copy drifts; the tests are what notice.

What the extension should do

  • Count distinct postings among the captures waiting in Postulo and those here not yet sent. A local sent record is not counted: Postulo's list holds it. Not set up, only this browser's unsent captures count, as today.
  • Read the list on the existing five-minute alarm (src/background.js), at startup, after a delivery that sent something (so the number does not dip), when the address or token changes (dropping the old copy), and when the popup opens unless the copy is under a minute old: twelve an hour from the alarm, of the 600 each token gets by default, shared with sending captures. Read pages of 100 until count is reached; after a 429, wait as the refusal says (retryAfter in src/lib/api.js).
  • Ask nothing when the connection state of #4 is testing, not set up or no permission, and feed each read's outcome into it.
  • Keep the last answer in storage.local: when it was read, and per row only id, url, title, company_name, location, created_at and review_url, which #7 shows. Never page.
  • When Postulo cannot be reached or refuses the token, show the last known count with what is here; the grey icon says it may be stale.
  • Fit about four characters: above 99, “99+”. Set the text colour with setBadgeTextColor where it exists (Chrome 110, Firefox 109, by MDN's data). None of this has been tried in a real browser.

Decisions for this repository

  • What counts. Recommended: Postulo's waiting captures and this browser's unsent ones, since a capture waiting while Postulo is down still needs review. Alternative: Postulo's list only, leaving out captures that exist only here, the only kind today's badge counts.
  • What makes two captures one posting. Recommended: the address, as above. Alternatives: also the same title at the same company, which the core asks only of listings, and softly (“a company running two openings with the same title is not a duplicate”, src/postulo/jobs/known.py); or no merging, counting captures as the review screen's queue_left does (src/postulo/jobs/capture_views.py).
  • Colour when stale. Blue (recommended; the icon says so), or grey with the icon.
  • A tooltip in words, “Waiting for review: 3”, beside what #4 writes there. Recommended. test/i18n.test.mjs requires every new key in all 40 _locales at once, with identical placeholders, so each new sentence costs 40 translations in the same commit; messages.json has no plural forms, hence the wording.

Needs from the server

Not filed on postulo/postulo. A normalised address on each row of GET /captures, or a count of distinct postings, would spare the extension its copy of same_url(); the route above works without either.

Documents

  • PRIVACY.md: a row for GET /api/v1/captures, sent in the background with only the token, against “exactly three” (with any row #4 adds); the opening's “only when you press Send”; and what is kept, which gains the addresses, titles, companies and places of captures waiting in Postulo, including ones made elsewhere. The Firefox declaration is postulo/postulo-firefox#3's.
  • README.md: “Without a server”, which says the toolbar number is how many have not reached Postulo; the privacy paragraph's list of what is kept; the Layout row for src/background.js.

Done when

  • Two captures of one posting waiting in Postulo, with and without “www.”, and one of another posting kept here: the badge reads 2.
  • Deciding one of the pair leaves it at 2; deciding both lowers it to 1 within five minutes, or when the popup opens.
  • With Postulo stopped it keeps the last count plus captures made since; with the testing switch on, no request is made; not set up, it counts this browser's unsent captures.
  • The address rule has node --test cases matching the core's, and PRIVACY.md and README.md say all of this.

From the list of extension improvements of 2026-09-30.

The toolbar badge is set in one place, `showUnsentCount()` in `src/lib/local.js`: the number of captures in this browser that have not reached Postulo (kept, waiting or refused; `UNSENT` in `src/lib/store.js`), in blue `#2563eb`, on every tab. A capture Postulo has is `sent`, uncounted, and never learns whether it has been reviewed. The request: “the number of unique job listings captured and need review”. In Postulo a listing is what a capture becomes once reviewed, so this reads it as postings captured and not yet reviewed. ## Where the number comes from `GET /api/v1/captures` (`captures` scope) lists exactly the captures waiting for review, newest first, as `{items, count}`, 100 a page by default, no maximum (`src/postulo/api/api.py` and `paging.py` in the core). A decided capture leaves the list, and `updated_since` cannot report a removal, so the list is read whole each time. ## What “unique” should mean The same posting captured twice is two waiting captures, on purpose (postulo/postulo#178: told rather than refused), and `count` counts both. Proposed reading: one per posting address, by the core's `same_url()` (`src/postulo/core/addresses.py`): scheme, a leading “www.” and trailing slashes dropped, lower-cased, query kept. No row carries that key; the extension applies it to each `url`. `src/lib/parse.js` has a private port, `sameUrl`, whose keys differ from the core's for an upper-case “WWW.”, default ports, `;parameters`, `..` segments, spaces, non-ASCII characters and a user name before the host. Proposed: one exported function, tested against the core's cases in `tests/test_known.py` and those differences, each matched or written down as known. A copy drifts; the tests are what notice. ## What the extension should do - Count distinct postings among the captures waiting in Postulo and those here not yet sent. A local `sent` record is not counted: Postulo's list holds it. Not set up, only this browser's unsent captures count, as today. - Read the list on the existing five-minute alarm (`src/background.js`), at startup, after a delivery that sent something (so the number does not dip), when the address or token changes (dropping the old copy), and when the popup opens unless the copy is under a minute old: twelve an hour from the alarm, of the 600 each token gets by default, shared with sending captures. Read pages of 100 until `count` is reached; after a 429, wait as the refusal says (`retryAfter` in `src/lib/api.js`). - Ask nothing when the connection state of #4 is testing, not set up or no permission, and feed each read's outcome into it. - Keep the last answer in `storage.local`: when it was read, and per row only `id`, `url`, `title`, `company_name`, `location`, `created_at` and `review_url`, which #7 shows. Never `page`. - When Postulo cannot be reached or refuses the token, show the last known count with what is here; the grey icon says it may be stale. - Fit about four characters: above 99, “99+”. Set the text colour with `setBadgeTextColor` where it exists (Chrome 110, Firefox 109, by MDN's data). None of this has been tried in a real browser. ## Decisions for this repository - **What counts.** Recommended: Postulo's waiting captures and this browser's unsent ones, since a capture waiting while Postulo is down still needs review. Alternative: Postulo's list only, leaving out captures that exist only here, the only kind today's badge counts. - **What makes two captures one posting.** Recommended: the address, as above. Alternatives: also the same title at the same company, which the core asks only of listings, and softly (“a company running two openings with the same title is not a duplicate”, `src/postulo/jobs/known.py`); or no merging, counting captures as the review screen's `queue_left` does (`src/postulo/jobs/capture_views.py`). - **Colour when stale.** Blue (recommended; the icon says so), or grey with the icon. - **A tooltip in words**, “Waiting for review: 3”, beside what #4 writes there. Recommended. `test/i18n.test.mjs` requires every new key in all 40 `_locales` at once, with identical placeholders, so each new sentence costs 40 translations in the same commit; `messages.json` has no plural forms, hence the wording. ## Needs from the server Not filed on postulo/postulo. A normalised address on each row of `GET /captures`, or a count of distinct postings, would spare the extension its copy of `same_url()`; the route above works without either. ## Documents - PRIVACY.md: a row for `GET /api/v1/captures`, sent in the background with only the token, against “exactly three” (with any row #4 adds); the opening's “only when you press Send”; and what is kept, which gains the addresses, titles, companies and places of captures waiting in Postulo, including ones made elsewhere. The Firefox declaration is postulo/postulo-firefox#3's. - README.md: “Without a server”, which says the toolbar number is how many have not reached Postulo; the privacy paragraph's list of what is kept; the Layout row for `src/background.js`. ## Done when - Two captures of one posting waiting in Postulo, with and without “www.”, and one of another posting kept here: the badge reads 2. - Deciding one of the pair leaves it at 2; deciding both lowers it to 1 within five minutes, or when the popup opens. - With Postulo stopped it keeps the last count plus captures made since; with the testing switch on, no request is made; not set up, it counts this browser's unsent captures. - The address rule has `node --test` cases matching the core's, and PRIVACY.md and README.md say all of this. From the list of extension improvements of 2026-09-30.
Author
Owner

Landed in part (5f66750, Refs #5): the badge counts Postulo's list plus this browser's unsent captures, once per address, 99+, with a tooltip. Left: the real-browser check (see the manual-check issue) and the server side, filed as postulo/postulo's issue about a normalised address or distinct count on GET /captures, after which src/lib/address.js can go.

Landed in part (`5f66750`, `Refs #5`): the badge counts Postulo's list plus this browser's unsent captures, once per address, `99+`, with a tooltip. Left: the real-browser check (see the manual-check issue) and the server side, filed as postulo/postulo's issue about a normalised address or distinct count on `GET /captures`, after which `src/lib/address.js` can go.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo-chromium#5
No description provided.