From 06b0cf4418d07ef1dd77365b53b49d00fddd422a Mon Sep 17 00:00:00 2001 From: mandalore Date: Fri, 4 Sep 2026 18:09:48 -0500 Subject: [PATCH] Add Generate Matrix: auto-build the team scouting matchup matrix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Duplicates the team's Google Sheets matchup-matrix template once per opposing team at a loaded event, pre-filled with names, factions, career win% (all already computed by this page), and cleaned army lists. New "Which team is yours?" selector + Generate Matrix button, team-events only. - Auth: Google Identity Services token client (drive.file + spreadsheets scopes) — the viewer signs in with their own Google account via a real OAuth popup, no backend, no client secret. - Template layout is located at runtime by searching each tab for its own placeholder text ("Player N - Faction", "Opponent N") rather than hardcoded A1 ranges, so it survives the template changing later. Distinguishes the real input area from the template's own "mobile matrix" mirror and reference sections (which repeat the same placeholder text) by checking for literal typed values vs formulas — CSV export can't tell these apart, only the real Sheets API response can, which is how this was actually verified before writing this. Auto-picks between the template's 5-man/8-man tab variants by team size. - List cleaning via a vendored copy of desjani's 40k-compactor (src/vendor/40k-compactor/, see NOTICE.md) — it isn't actually published to npm despite documenting `npm install 40k-compactor` (verified: 404 against the registry under every plausible name), so it can't be a normal dependency; vendored instead, MIT per direct confirmation from the maintainer. Verified against 40k-compactor's own sample list fixtures with real Node before committing. - Generating a matrix needs the same BCP auth token already used for faction/disposition backfill (list text is a subscriber-gated endpoint) — reuses the existing token UI/storage as-is; missing lists are reported, not a hard failure. - nginx CSP updated (script/connect/frame-src) for Google's identity script and the Drive/Sheets REST APIs. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01SBzcNkW7JcYipnAX6HfgmK --- sites/scouting/index.html | 20 + .../scouting/scouting.gateway-gamers.net.conf | 5 +- sites/scouting/src/main.js | 58 + sites/scouting/src/matrix.js | 353 ++ .../src/vendor/40k-compactor/NOTICE.md | 21 + .../src/vendor/40k-compactor/index.js | 13 + .../40k-compactor/modules/abbreviations.js | 318 ++ .../40k-compactor/modules/faction_colors.js | 51 + .../vendor/40k-compactor/modules/parsers.js | 12 + .../modules/parsers/gwapp_v11.js | 468 +++ .../modules/parsers/nr_gw_parser.js | 255 ++ .../modules/parsers/nr_tournament_parser.js | 290 ++ .../modules/parsers/v11_detector.js | 111 + .../modules/parsers/v11_parser.js | 160 + .../modules/parsers/war_organ_parser.js | 395 +++ .../vendor/40k-compactor/modules/renderers.js | 784 ++++ .../src/vendor/40k-compactor/modules/utils.js | 524 +++ .../40k-compactor/skippable_wargear.json | 3137 +++++++++++++++++ 18 files changed, 6974 insertions(+), 1 deletion(-) create mode 100644 sites/scouting/src/matrix.js create mode 100644 sites/scouting/src/vendor/40k-compactor/NOTICE.md create mode 100644 sites/scouting/src/vendor/40k-compactor/index.js create mode 100644 sites/scouting/src/vendor/40k-compactor/modules/abbreviations.js create mode 100644 sites/scouting/src/vendor/40k-compactor/modules/faction_colors.js create mode 100644 sites/scouting/src/vendor/40k-compactor/modules/parsers.js create mode 100644 sites/scouting/src/vendor/40k-compactor/modules/parsers/gwapp_v11.js create mode 100644 sites/scouting/src/vendor/40k-compactor/modules/parsers/nr_gw_parser.js create mode 100644 sites/scouting/src/vendor/40k-compactor/modules/parsers/nr_tournament_parser.js create mode 100644 sites/scouting/src/vendor/40k-compactor/modules/parsers/v11_detector.js create mode 100644 sites/scouting/src/vendor/40k-compactor/modules/parsers/v11_parser.js create mode 100644 sites/scouting/src/vendor/40k-compactor/modules/parsers/war_organ_parser.js create mode 100644 sites/scouting/src/vendor/40k-compactor/modules/renderers.js create mode 100644 sites/scouting/src/vendor/40k-compactor/modules/utils.js create mode 100644 sites/scouting/src/vendor/40k-compactor/skippable_wargear.json diff --git a/sites/scouting/index.html b/sites/scouting/index.html index 506dc47..ca733a3 100644 --- a/sites/scouting/index.html +++ b/sites/scouting/index.html @@ -5,6 +5,8 @@ Gateway Gamers — Scouting + + @@ -133,6 +135,24 @@ + + + diff --git a/sites/scouting/scouting.gateway-gamers.net.conf b/sites/scouting/scouting.gateway-gamers.net.conf index 2508679..9fae010 100644 --- a/sites/scouting/scouting.gateway-gamers.net.conf +++ b/sites/scouting/scouting.gateway-gamers.net.conf @@ -33,7 +33,10 @@ server { # blocks without it (script-src stays locked down — this only affects # CSS, and nothing here renders untrusted external content into a # style attribute). - add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' https://newprod-api.bestcoastpairings.com; img-src 'self' data:;" always; + # script-src/connect-src/frame-src additions are for "Generate Matrix": + # Google Identity Services (accounts.google.com) for the sign-in popup, + # and the Drive/Sheets REST APIs the browser calls directly afterward. + add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://accounts.google.com; style-src 'self' 'unsafe-inline'; connect-src 'self' https://newprod-api.bestcoastpairings.com https://www.googleapis.com https://sheets.googleapis.com https://accounts.google.com https://oauth2.googleapis.com; frame-src https://accounts.google.com; img-src 'self' data:;" always; location /images/ { alias /var/www/domains/gateway-gamers.net/shared/images/; diff --git a/sites/scouting/src/main.js b/sites/scouting/src/main.js index 2c861bd..d9d6740 100644 --- a/sites/scouting/src/main.js +++ b/sites/scouting/src/main.js @@ -1,3 +1,5 @@ +import { generateMatrix, configureMatrixHelpers } from "./matrix.js"; + /* ---- Shared: header / footer ---- */ function loadHTML(file, elementId, callback) { fetch(file) @@ -611,6 +613,22 @@ function renderTeamList(teams, itcRanks, itcLoading, careerRecords, careerLoadin `

No teams match${q ? ` "${esc(filterText)}"` : ""}.

`; } +// Rebuilding the