From 52402d7547660564037f410439e5584010af838e Mon Sep 17 00:00:00 2001 From: mandalore Date: Fri, 4 Sep 2026 19:00:26 -0500 Subject: [PATCH] Color each opponent's column by their disposition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Colors read directly from the template's own "Disposition Matrix" section (Template!B32 header, B33:H37) via its actual XLSX cell fill colors (not visible through CSV export, and not guessed) — a clean 1:1 mapping in the row/column headers, same 5 canonical dispositions and spelling as CANONICAL_DISPOSITIONS in main.js: Purge the Foe -> #E06666, Take and Hold -> #93C47D, Priority Assets -> #FFD966, Disruption -> #4A86E8, Reconnaissance -> #76A5AF (the interior of that section is a separate disposition-vs-disposition matchup heatmap, not used here). Whole opponent column (list/faction/name rows) gets colored, per the requested scope. Needs the new tab's sheetId, which duplicateSheet's reply already includes (only .title was being read out of it before) — sent as its own batchUpdate once that's known, since a single batchUpdate can't both create a sheet and reference the id it produces. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01SBzcNkW7JcYipnAX6HfgmK --- sites/scouting/src/matrix.js | 45 ++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/sites/scouting/src/matrix.js b/sites/scouting/src/matrix.js index 0236cec..90c0fb7 100644 --- a/sites/scouting/src/matrix.js +++ b/sites/scouting/src/matrix.js @@ -251,6 +251,24 @@ const a1 = (sheetTitle, col, row) => `'${sheetTitle.replace(/'/g, "''")}'!${colL /* ---- Row/column value builders ---- */ +// The template's own "Disposition Matrix" section (Template!B32, header + +// B33:H37) color-codes each of the 5 canonical ITC dispositions — same +// spelling/order as CANONICAL_DISPOSITIONS in main.js. Read directly from +// the template's actual cell fill colors (XLSX export, since the Sheets +// API's formatting isn't visible via CSV) rather than guessed. +const DISPOSITION_COLORS = { + "Purge the Foe": "E06666", + "Take and Hold": "93C47D", + "Priority Assets": "FFD966", + "Disruption": "4A86E8", + "Reconnaissance": "76A5AF", +}; + +function hexToRgbColor(hex) { + const n = parseInt(hex, 16); + return { red: ((n >> 16) & 255) / 255, green: ((n >> 8) & 255) / 255, blue: (n & 255) / 255 }; +} + // fullName() takes the nested BCP user object ({firstName, lastName}), not // the roster/teamplayer entry itself — same convention main.js's own // playerRowHTML() uses, matched here. @@ -305,7 +323,7 @@ export async function generateMatrix({ event, ourTeam, opposingTeams, careerReco const size = sizes.find(s => s >= Math.max(oppTeam.members.length, ourTeam.members.length)) || sizes[sizes.length - 1]; const template = templates.get(size); - let title; + let title, newSheetId; try { const dup = await batchUpdate(token, copy.id, [{ duplicateSheet: { @@ -313,12 +331,35 @@ export async function generateMatrix({ event, ourTeam, opposingTeams, careerReco newSheetName: oppTeam.name.slice(0, 100), }, }]); - title = dup.replies[0].duplicateSheet.properties.title; + ({ title, sheetId: newSheetId } = dup.replies[0].duplicateSheet.properties); } catch (err) { skipped.push({ team: oppTeam.name, reason: `Couldn't duplicate tab: ${err.message}` }); continue; } + // Color each opponent's whole column (list/faction/name rows) by their + // disposition, matching the template's own Disposition Matrix colors — + // a separate batchUpdate since it needs newSheetId, only known now. + const colorRequests = oppTeam.members.map((member, i) => { + const col = template.opponentCols[i]; + const color = col != null ? DISPOSITION_COLORS[member.subFaction?.name] : null; + if (!color) return null; + return { + repeatCell: { + range: { sheetId: newSheetId, startRowIndex: template.listRow, endRowIndex: template.opponentRow + 1, startColumnIndex: col, endColumnIndex: col + 1 }, + cell: { userEnteredFormat: { backgroundColor: hexToRgbColor(color) } }, + fields: "userEnteredFormat.backgroundColor", + }, + }; + }).filter(Boolean); + if (colorRequests.length) { + try { + await batchUpdate(token, copy.id, colorRequests); + } catch (err) { + skipped.push({ team: oppTeam.name, reason: `Tab created but couldn't apply disposition colors: ${err.message}` }); + } + } + const data = []; ourTeam.members.forEach((member, i) => { const row = template.playerRows[i];