Skip to content

feat(web): every function in the new UI — team/player follows, seasons, data types, exports, restore; classic views removed [FX-14b] - #161

Merged
tunjayoff merged 6 commits into
mainfrom
feat/fx-14b
Oct 6, 2026
Merged

tunjayoff merged 6 commits into
mainfrom
feat/fx-14b

Conversation

@tunjayoff

@tunjayoff tunjayoff commented Oct 6, 2026 •

Copy link
Copy Markdown
Owner

Item: FX-14b (frontend; after FX-13 #152, FX-14a #154, FX-15 #155, FX-19 #156). It wires the API features that now exist into the new web UI and removes the classic views. Frontend only (frontend/**), plus two minimal Python test updates (below). Do not merge: the owner reviews it.

Behaviour change. Team, player and single-match follows can be added (by name or number) and are downloaded; seasons can be chosen before a league's first download; the data types are checklists (per follow, globally and per sport); exports offer normalized data as CSV, JSONL, Parquet and SQLite; a backup can be restored from the UI; one league's data can be deleted; the classic interface (/classic) is gone and its addresses lead to the new screens. "Download now" of a league follow now downloads it with its own season choice (follows: [id]) instead of every season (league_id).

Branch feat/fx-14b on origin/main at 602f326. Six commits, each green (frontend lint, vue-tsc -b, vitest):

  1. feat(web): coded job log lines and job kinds in words; the connection from /status; Health in quick search and Help
  2. feat(web): team, player and match follows; seasons before the first download; data types as checklists
  3. feat(web): normalized, Parquet and SQLite exports; a real restore; deleting one league's data
  4. refactor(web): remove the classic views
  5. fix(web): a season list as the job records it (mode: seasons)
  6. fix(web): a dialog opened from a table row wraps its text
    (5 and 6 were found with the offline screenshots.)

What changed, per point of the brief

  1. Team, player and single-match follows. MORE_FOLLOW_KINDS is true.
    • Step 1 searches by name with the kind (POST /tournaments/search {q, sport, kinds: [kind]}, one request per search; tournaments keep /search/unique-tournaments, team and player use /search/all). A hit shows its kind, sport, country, a player's team ("takımı: Arsenal") and "Zaten eklendi"; picking it brings its sport along (FX-19 Not done: "the search hit's sport should be sent"). A single unfollowed hit is still pre-selected.
    • A single match is added by its number; the match page's ⋯ menu has Bu maçı takip et and <Takım> takımını takip et for both teams (the editor opens with kind, number, name and sport filled in, ?kind=&id=&name=&sport=). The 404 page of a match offers the follow too, and Bu maçı çek (fetch with event_ids, G16).
    • A team's or a player's seasons is shown as the FX-19 time window ("Son 12 ay", "Son 2 yıl", "Listelenen kadar geriye"), with a note on what is read; a single match has no seasons step.
    • Şimdi indir and "Ekledikten sonra hemen indirmeye başla" start sync {follows: [id]} for every kind.
    • The follow page: a team gets a Maçlar tab with its stored matches (/events?participant=); a match links to itself; every follow's İşler tab reads GET /jobs?target=<kind>:<id> (FX-13/FX-19) merged with the downloads of every follow, shown as "İndirme · Arsenal".
  2. Seasons before the first download. "Sezonları seç…" of a league without a season list shows Sezon listesini SofaScore'dan al (one click, POST /jobs sync {league_id, only: "seasons"}), follows the job (waitForJob), then shows the season names as checkboxes; a failed list links its job. The same on the edit page and as the Seasons tab's empty state. The Seasons tab shows per-season counts (include=counts): "4 maç · 3 bitti · 3 ayrıntılı", a completion bar and "Fikstür okundu: 5 dk. önce" / "Fikstür henüz okunmadı".
  3. Data types. The editor's data step and the edit page offer " için varsayılanları kullan" (slices: null) or "Bu takip için seç" ({include: [...]}, P27), a grouped checklist from GET /sports/{slug}: Maç verisi (the match itself always), Bahis oranları (header badge "varsayılan olarak kapalı" / "açık"), Sezon / Takım / Oyuncu / Spor verisi ("sezon başına bir kez çekilir"); "bu sporda her zaman bulunmaz" for optional match data; the request cost per match follows the ticks. Choosing starts from the defaults' ticks (selected). A follow that cannot hold a selection (old league list) says why. Settings › Veri: İndirilecek veriler with the global defaults.slices as a checklist (unset = the registry's own ticks, "yerleşik"; a fully ticked group is written by its name, e.g. ["core", "odds_featured"]) and Spora göre değişiklikler, one collapsible checklist per sport writing slices.<sport> {enable, disable}; locked values show where they are set and cannot be ticked; Undo / reset as for other settings; staged and saved with "Değişiklikleri kaydet".
  4. Exports. The dialog offers the match table (CSV), normalized data (Maçlar, Tüm veri türleri, Sonradan değişen skorlar, Bahis oranları, Puan durumu) as CSV, JSONL, Parquet or SQLite, and the original data (JSONL). Parquet is disabled with the reason when /status.capabilities.parquet is false. Filters: sport, added leagues, season and match numbers, status classes (not for score changes), a date range (for score changes "Kaydı şu tarihten itibaren"). The list shows the readable file names (FX-19) and the files ssc export wrote (source: "file", badge "ssc export ile", download, no job link; DataTable rows may now open nothing).
  5. Restore. Step 3 restores here: the user types "GERİ YÜKLE" / "RESTORE", the job runs (restore {name, force, dry_run: false}), a 400 confirmation_required shows details.occupied and asks again ("Değiştir ve geri yükle") before it sends force; progress and the result (index rebuilt, "Geri yüklemeden sonraki denetim: Sorun yok" or the number of problems) come from the job. The server command stays under "Ya da sunucuda çalıştırın". The status is read again afterwards (the job history is the backup's).
  6. Delete one league's data. The remove dialog of a league follow has Kayıtlı maçlarını da sil (then the typed word "SİL"; DELETE /follows/{id}?delete_data=true; the toast links the clear job, which is followed). Veri bakımı has a new card Bir ligin verisini sil (league, optionally one season; clear {scope: all, tournament_id, season_id}). A follow of the old league list shows Buraya taşı (PATCH {origin: "api"}) on its page, its edit page and in its row menu; afterwards every field is editable.
  7. Connection. The state comes from /status.connection (never_tried → "Henüz denenmedi", failed → "Son istek başarısız", a failed last_check with no success since → "Son denetim başarısız"); FX-14a's per-tab memory is gone (a check's answer updates the store at once). Health adds "Son başarısız istek" (reason in words, time) and "Son bağlantı denetimi". Servers without connection still fall back to the bridge times.
  8. Job log lines. Every code of the download path has a text in both locales (sync_season_list, sync_season_list_failed, sync_schedule, sync_schedule_failed, sync_season_outdated, sync_follow_skipped, sync_refreshing, sync_details, sync_details_checking, sync_details_selected, sync_breaker_stopped, sync_extras, sync_follow_listing, sync_follow_listing_failed, sync_follow_details); leagues, seasons and follows by name, request outcomes and the breaker's "what" in words. Unknown codes show the server text. Job kinds by spec: "Sezon listesi", "Eski oranların temizliği" (the prune-history clear {scope: history, older_than}, target "90 gün öncesine ait olanlar", output "Silinen anlık görüntü"), "Lig verisinin silinmesi", "Geri yükleme" (a real restore; the dry run stays "Yedek kontrolü"). Run again keeps follows, the season-list choice and event ids.
  9. /health. Ctrl K "sağlık", "health", "durum", "bağlantı"… offers Sağlık (in either language); Help has a paragraph saying /health in the address bar is the server's JSON check and the page is /system/health, with a link. The server serves the SPA for unknown paths; no server route changed.
  10. Classic views removed (src/views/**, src/classic/**, the /classic routes, the "Klasik arayüz" menu entry), with the modules only they used (src/components/**, src/stores/**, src/api/client.ts, lib/appVersion, format, jobLabel, latest, sport, tabs, toast, upstream), their 18 test files, and the classic texts of locales/en.ts / tr.ts (the sport names stay). /classic/... addresses redirect to their new screens; the 2.x redirects stay. The Python side is untouched (the legacy /api routes stay until P30).

Classic function → new screen

Classic view: function New home
Ligler: list, add (search), remove, assign sport Ligler ve takipler; Lig ya da takım ekle (search, number); row menu Kaldır; edit page Spor
Ligler: enable/disable row menu Kapat/Aç (legacy rows after "Buraya taşı")
İndir: choose leagues and seasons, download follow page Şimdi indir / Bu sezonu indir; editor seasons step
İndir: refresh seasons ("sezonları yenile") "Sezon listesini SofaScore'dan al" (editor, edit page, Seasons tab)
İndir: fetch missing details follow page "Eksik ayrıntıları çek"; Maçlar bulk "Eksik veriyi çek"
Maçlar: list by league/season, missing-details banner Maçlar (filters, has=missing), a follow's Maçlar tab
Maç: one match, "Fetch now" Maç sayfası, "Yeniden çek" (also without a league: event_ids); 404 "Bu maçı çek"
Etkinlik: job cards İşler, İş ayrıntısı, the top-bar job pill, finish toasts
Ayarlar: settings Ayarlar (sections, locks; data types as checklists)
Ayarlar: connection test Sağlık › Bağlantı denetimi
Ayarlar: backup Yedekler › Yedek oluştur
Ayarlar: clear data Veri bakımı › Veriyi sil, and now Bir ligin verisini sil
Ayarlar: stats Genel bakış, Sağlık › Depolama
Ayarlar: sign out ⋯ menu / Ayarlar › Bu tarayıcı › Oturumu kapat
Language ⋯ menu Dil; Ayarlar › Görünüm

The 12 newcomer tasks again (on this branch, offline, same method)

# Task Review (b567409) Now
1 Find/add a league, choose seasons, download Empty OK; with data hard; seasons not possible OK: add league everywhere (FX-14a); season names before the first download
2 See a download run, progress, done; stop OK, no "done" notice OK (season-list jobs named as such, no false "up to date" toast)
3 Browse matches, filter, open one OK with rough edges OK (unchanged here; team links, all statuses since FX-14a)
4 Follow a team/player; follow one match Not possible OK: by name or number, from the match page; downloads (search shape needs live validation, FX-19)
5 Choose data types (all / one league), odds off Not possible OK: per follow, global and per sport checklists; odds off and marked
6 Export CSV/JSON/Parquet/SQLite CSV OK; Parquet/SQLite not possible OK: normalized CSV/JSONL/Parquet/SQLite (Parquet needs pyarrow on the server; disabled with the reason otherwise); readable names
7 Back up and restore Restore not possible in the UI OK: restore as a job with confirmation and result (still no upload, decision 15)
8 Settings: language, rate, proxy, data folder Hard Hard (unchanged here apart from the data checklists)
9 What is running, is something wrong OK, misleading health OK: the server's connection state, last failure and last check
10 Live matches / live watching Hard Hard (by design: ssc watch on the server; Help explains it since FX-14a)
11 Remove a league and its data Delete data not possible OK: "Kayıtlı maçlarını da sil", per league/season in Veri bakımı; old-list leagues movable
12 Help Not possible OK: Help panel (FX-14a) with the Health link

Tests

  • Frontend: 20 files, 247 tests (329 on main; 18 classic test files removed; 45 new tests in 4 new files). npm run lint, vue-tsc -b, npm run build, npm audit --audit-level=high (0 vulnerabilities) and npm run gen:api (no diff) are green. The axe checks run in the new tests (editor steps, checklists, settings data, exports dialog and list, restore dialog, remove dialog, Data cleanup, Health, job output).
  • New: tests/jobWords.test.ts (every code in both languages, no English left in Turkish, names instead of ids, unknown codes as server text, the Job detail log in Turkish, kinds/targets by spec, prune labels, Run again, job outputs, Ctrl K and Help → Health, Health from /status.connection); tests/dataTypes.test.ts (selection resolution, the editor's defaults/choose, edit page, locked follow, Settings › Data global, per sport, locked); tests/followKinds.test.ts (team and player search, single match, season list on a click and its failure, per-season counts, team page, jobs by target, remove with data, typed word, "Buraya taşı", match page follow links and fetch by number, dialog wrapping); tests/exportsRestore.test.ts (normalized SQLite with filters, Parquet with pyarrow and the changes dataset, file list with ssc export files, restore run, confirmation_required → force, refused restore, league/season clear).
  • Existing tests changed, and why:
    • newcomer.test.ts: connectionState takes the status (bridge + connection) and the check is kept by the server (point 7), so its two tests were rewritten for the server-kept state plus a pre-FX-19 fallback; the Health check test now gets the server's state from /status; the palette's SofaScore search body has kinds; the placeholder key is per kind; MORE_FOLLOW_KINDS is true; a team follow's "Download now" works (was "coming soon"); a follow page reads its jobs twice (by target and the downloads of every follow).
    • dataScreens.test.ts: Download now sends follows: ['tournament:17']; the search body has kinds; a hit's radio value is kind:id; the "coming soon" note of the data step is gone; the follow body has slices: null; the sync after saving uses follows; "no hits" is per kind; the "coming soon" kinds test became "every kind can be chosen; a team by its number; 409"; the follow-detail jobs test answers ?target= separately; a missing match offers "Fetch this match" and "Follow this match".
    • operationsScreens.test.ts: normalized exports are enabled (Parquet's reason still shown); the restore's last step runs here (the command stays).
    • shell.test.ts: the ⋯ menu has no "Classic interface"; /classic/... addresses redirect.
    • Removed with the classic views: a11y, activityView, addLeagueDialog, auth, bridge, client, downloadSeasons, errors, jobCard, jobGuards, latest, matchDetail, matchesView, scrape, settingsConnection, settingsRateLimit, sport, version (.test.ts). Their new-UI counterparts are covered by shell, settingsScreen, healthOverview, dataScreens, jobsScreen, jobDetail and the new files.
  • Python (the only Python changes, both pinned a removed file): tests/test_throttle.py::test_settings_page_knows_the_same_default reads SAFE_RATE of screens/settings/settingsMeta.ts (was DEFAULT_RATE_LIMIT of views/SettingsView.vue); tests/test_sports_registry.py::test_frontend_sport_list_matches_the_registry now checks that the UI reads the sport list from the API (app/sports.ts, v1.sports()) and that the hard-coded list is gone. Full suite with STORE_SHADOW_CHECK=1, home-disk TMPDIR and basetemp, foreground, frontend built in the worktree: 9735 passed, 33 skipped, 20 deselected (same as FX-19 on main).
  • No request to any SofaScore host.

Screenshots (offline)

The review's method: ssc serve on 127.0.0.1 from this worktree (shared .venv read-only) with the CLI goldens' fake transport (tests/characterization/cli_env/sitecustomize.py), proxies at a dead local port, a copy of world.json with search hits (Premier League, Trendyol Süper Lig with its season list, Arsenal and Bukayo Saka via /search/all, Arsenal's match list) set up under ~/.cache/fx14b; headless Chromium (the shared venv's playwright, read-only) aborted every request not to 127.0.0.1: 0 aborted requests, console errors only the expected 404s (a match that is not stored, no season list yet). States: A = empty install, B = Premier League (api) and Arsenal (team) followed and downloaded, a legacy leagues.txt row (Süper Lig), a backup, a normalized export and one ssc export-style file; R = a real restore of the backup. Folder ~/.local/share/sofascore-orch/fx14b-shots/: before/ 46 shots (origin/main 602f326), after/ 60 shots (-tr-1440, -en-390).

Before → after, the main ones: A-editor-step1-team (Takım disabled "yakında" → Arsenal found by name), A-editor-step2-choose/-seasons ("henüz indirilmedi" → the button, then three named seasons), A-editor-step3 (one line → defaults/choose with the checklist; after-A-editor-step3-odds-on), A-settings-data (free text core → checklists), A-export-dialog (normalized disabled → datasets and four formats), B-follow-seasons (bare list → counts), B-follow-jobs, B-remove-dialog (+ delete data), B-maintenance (+ league card), B-event-menu (copy only → follow match/teams), B-job-log (English lines → Turkish), B-exports (job ids → readable names, ssc export file), B-restore-last-step (command only → typed word and run; after-R-restore-*), B-classic (classic page → redirected to Ligler ve takipler); new: after-A-editor-step1-player, after-A-palette-health, after-A-event-not-stored, after-B-team-follow, after-B-legacy-edit.

API gaps found (frontend stops at the UI; no Python changed)

  1. A team or player job's name: the Job detail of sync {follows: ["team:42"]} says "Takım research: SofaScore push channel — coverage, lag, cost, direct connection (Talimat 06+07) #42" unless the follows were read in this tab (Ligler ve takipler, the follow's page, Ctrl K); the job record carries no follow name (only progress.league_name while listing). A target_name on Job (or the follow name in the recorded spec) would let every screen name it without an extra request.
  2. The recorded sync spec differs from the body: POST /jobs takes only: "seasons", GET /jobs returns mode: "seasons" (the service SyncSpec); a fetch by event_ids is recorded as mode: "details" with per-tournament selections plus event_ids. The UI reads both forms; a documented, stable job-spec shape would help.
  3. Season-list age: still no route for the tournament's own season-list age (FX-13 Not done); the Seasons tab shows each season's schedule age instead.
  4. /status.connection is per process (FX-19 Not done): requests of ssc commands and ssc watch do not count.
  5. No search across kinds in one request for tournaments: the editor searches one kind at a time (tournaments keep the tournament endpoint, whose answer shape is known); a newcomer who types a team under "Lig" gets a hint to switch the kind.
  6. Restore upload: an archive must already be in the server's backups folder (decision 15, unchanged).
  7. A player follow and live watching: ssc watch skips player follows (FX-19 Not done); the editor's "Canlı izlemeye dahil et" is still offered for players.

Design mismatches

  1. 05-web-ui.md lines 8, 41, 138–145, 261, 299–301, 1272–1276, 1286, 1387: the classic views, /classic and frontend/src/api/client.ts are gone; /classic/... redirects to the new screens.
  2. 6.2/6.4 "Sync now": built as sync {follows: [id]} for every kind (with the follow's season choice), not league_id.
  3. 6.3 step 1: Team/Player are searched by name (kinds), one kind per search; Single match by number or from the match page. Step 2 for team/player: the FX-19 time window words. The data step: the radios came back (FX-14a had removed them) with the grouped checklist; groups are by section (match, odds, season, team, player, sport) rather than one group per group value; required does not lock a box (P27 owner decision), it only marks optional match data.
  4. 6.4: per-season counts (G17) built; Jobs tab by target plus the downloads of every follow; team follows get a Matches tab by participant.
  5. 6.6: "Follow " in the match's ⋯ menu; "Fetch again" without a tournament uses event_ids; the 404 page offers "Fetch this match".
  6. 6.10: the dialog's filter has status classes and a date range; files of ssc export are listed (section 17 of the plan still says they are not).
  7. 6.11 restore: built as designed (Check, Choose, typed confirm) with a localized word ("GERİ YÜKLE" / "RESTORE") instead of restore; 400 confirmation_required asks again before force. Maintenance gains a fourth card (one league's or one season's data).
  8. 6.12/3.3: the connection state and the last check come from /status.connection (FX-19), not from the browser.
  9. 6.16 Data: defaults.slices and slices.<sport> are checklists (G-wise as designed); unset defaults are shown as the registry's ticks ("built-in"), and a fully ticked group is written by its group name.
  10. New: a Health action in quick search and a Health paragraph in Help (/health is the server's JSON); job kind names by spec (season list, odds clean-up, league deletion, restore).
  11. UiDialog: a dialog inside a table row inherited white-space: nowrap and right alignment (since FE-2b); fixed in the overlay.

Changelog entry

Added

  • Web UI (FX-14b):
    • Follow teams, players and single matches: find teams and players by name, follow a match or its teams from the match page; their matches are downloaded.
    • Choose seasons before the first download: the season list of a new league is read on a click and its seasons can be ticked by name; each season shows its counts.
    • Choose the data to download as checklists: per follow ("use the defaults" or "choose"), and in Settings › Data for every sport and per sport. Betting odds are off by default and marked so.
    • Exports of normalized data as CSV, JSONL, Parquet (with pyarrow on the server) or SQLite, with status and date filters; files written by ssc export are listed.
    • Restore a backup from the Backups screen, as a job, with a confirmation and its result.
    • Delete one league's data, when removing it or in Data cleanup (also one season); move a league of the old league list into the app to edit it.
    • Job log lines in Turkish and English; readable names for the season-list and odds clean-up jobs.

Changed

  • Web UI: "Download now" of a league downloads its chosen seasons (was every season). The connection state comes from the server, the same in every browser. Quick search finds Health; Help says /health is the server's own check.

Removed

  • Web UI: the classic interface (/classic); its addresses lead to the new screens. (FX-14b)

Files outside ownership

  • tests/test_throttle.py, tests/test_sports_registry.py (one test each, see Tests).

Not done

  • The phone (390 px) screenshots of the row-menu dialogs (Remove, Restore) were not taken by the script (the card list's menu differs); the 390 px layouts of the screens are in after/.
  • src/style.css still carries the classic stylesheet's shared names; only its comment changed. Pruning it is a separate, visual-diff item.
  • Settings › Data shows every registered sport (21); a long list, collapsed per sport.
  • No live check of the team/player search answers (FX-19's "needs live validation" items stand).

… from /status; Health in quick search and Help [FX-14b]

- The download path's coded log lines (FX-13, FX-19: sync_season_list ... sync_follow_listing,
  sync_extras, sync_follow_details) have texts in both locales; leagues, seasons and follows are shown by
  name, request outcomes and breaker reasons in words. A line with an unknown code shows the server text.
- Job kinds by spec: Season list (sync only: seasons), Clean-up of old odds (clear scope history, the
  prune-history task, "Older than 90 days"), Deletion of league data (clear tournament_id), Restore
  (restore dry_run false). Targets of follows, event ids and league clears; Run again keeps them.
- Job output: one league's deletion, the prune result, a real restore (index rebuilt, check after it).
- The connection state comes from /status.connection (FX-19) instead of the per-tab memory of FX-14a;
  Health shows the last failed request and the server's last connection check.
- Ctrl K "health"/"sağlık" opens Health; Help says where Health is (/health is the server's JSON).
…ownload; data types as checklists [FX-14b]

- MORE_FOLLOW_KINDS is on (FX-19). The editor searches teams and players by name
  (POST /tournaments/search with kinds); a hit shows its kind, sport, country, a player's team and
  "Already added", and brings its sport. A single match is added by number, or from the match page's
  "Follow this match"; the match page also offers "Follow <team>". A team's or player's seasons are a
  time window. Download now and "Start downloading right away" download the follow itself
  (sync follows: [id]), for every kind.
- "Choose seasons" of a league without a season list starts the season-list job (sync only: seasons)
  on a click, follows it, then shows the seasons by name; also on the edit page and the Seasons tab.
- A follow's page: per-season counts (include=counts) with the schedule's age; a team's stored matches
  (participant); jobs by target (GET /jobs?target=kind:id) plus the downloads of every follow.
- Data step and edit page: "Use the defaults for <sport>" (slices null) or "Choose for this follow"
  ({include}), a grouped checklist from GET /sports/{slug} (match data, betting odds off by default and
  marked so, season/team/player/sport data), the request cost per match.
- Settings › Data: defaults.slices and slices.<sport> {enable, disable} as checklists, locks respected.
- A follow of the old league list can be moved here (PATCH origin api); removing a league can delete its
  stored matches too (DELETE ?delete_data=true, typed word, the clear job linked).
- A stored match without a league, or one not stored at all, can be fetched by its number (event_ids).
…leting one league's data [FX-14b]

- New export: normalized data (matches, data types, score changes, betting odds, standings) as CSV,
  JSONL, Parquet or SQLite, next to the match table and the original data. Parquet is disabled with the
  reason when the server has no pyarrow (capabilities.parquet). Filters: sport, added leagues, season
  and match numbers, status classes (not for score changes) and a time range.
- Exports list: the readable file names (FX-19) are shown; files written by `ssc export` (source "file")
  are listed with their download and no job link. DataTable rows may open nothing.
- Restore: step 3 runs the restore as a job (dry_run false) after a typed word; 400
  confirmation_required with details.occupied asks before it sends force; the job is followed and its
  result shown (index rebuilt, the check after the restore). The server command stays as the other way.
- Data cleanup: a card to delete one league's data, or one season's (clear with tournament_id and
  season_id), with the typed word.
Every function of the classic views has a home in the new screens now (the map is in the PR):
src/views/**, src/classic/**, the /classic routes and the "Classic interface" menu entry are removed,
with the modules only they used (src/components, src/stores, src/api/client.ts, lib/appVersion, format,
jobLabel, latest, sport, tabs, toast, upstream), their tests, and the classic texts of locales/en.ts and
tr.ts (the sport names stay). The /classic/... addresses lead to their new screens; the old 2.x
redirects stay.

Python tests that pinned a removed file, updated minimally:
- tests/test_throttle.py::test_settings_page_knows_the_same_default reads SAFE_RATE of
  screens/settings/settingsMeta.ts (was DEFAULT_RATE_LIMIT of views/SettingsView.vue);
- tests/test_sports_registry.py::test_frontend_sport_list_matches_the_registry checks that the UI reads
  the sport list from the registry (app/sports.ts, v1.sports()) instead of the removed hard-coded list.
POST /jobs takes only: "seasons"; the recorded spec that GET /jobs returns is the service's SyncSpec,
mode: "seasons". Both now name the job "Season list", leave it out of the download toast and out of a
follow's last download, and Run again keeps it. Found with the offline screenshots.
The row-actions cell of a table is nowrap and right-aligned, and a dialog of a row (Remove) inherited
both: a longer text ran out of the dialog. The overlay resets them. Found with the offline screenshots.
@tunjayoff
tunjayoff merged commit b6caf2f into main Oct 6, 2026
8 checks passed
@tunjayoff
tunjayoff deleted the feat/fx-14b branch October 6, 2026 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant