From 5ba86c1f51f2292167b17c37605faec5d8015de5 Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Thu, 30 Mar 2023 15:26:02 -0500 Subject: [PATCH 01/34] Added checking for result name inconsistancies --- scripts/transfer.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/scripts/transfer.js b/scripts/transfer.js index 7e2d9cbf..b6c67037 100644 --- a/scripts/transfer.js +++ b/scripts/transfer.js @@ -760,6 +760,8 @@ class ZipHandler let text = await content.text() let write = true let existing = localStorage.getItem(n) + + // prompt if file should be overriden if (existing !== null) { if (existing !== text && !n.startsWith('avatar-')) @@ -771,6 +773,29 @@ class ZipHandler write = false } } + + // ignore and alert if a result file name doesn't match its metadata + if (n.startsWith(`${PIT_MODE}-`) || n.startsWith(`${MATCH_MODE}-`) || n.startsWith(`${NOTE_MODE}-`)) + { + let name_team = parseInt(n.split('-')[2]) + let meta_team = JSON.parse(text).meta_team + if (name_team !== meta_team) + { + alert(`Team number mismatch on ${n}`) + write = false + } + } + if (n.startsWith(`${MATCH_MODE}-`) || n.startsWith(`${NOTE_MODE}-`)) + { + let name_match = n.split('-')[1] + let meta_match = JSON.parse(text).meta_match_key + if (name_match !== meta_match) + { + alert(`Match key mismatch on ${n}`) + write = false + } + } + if (write) { console.log(`Importing ${n}`) From c87b0c1a629455053c1f9c1b624ca9ac36865177 Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Thu, 30 Mar 2023 16:09:38 -0500 Subject: [PATCH 02/34] Added an option to renumber a pit result --- scripts/pits.js | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/scripts/pits.js b/scripts/pits.js index 577f2807..24ba4c4a 100644 --- a/scripts/pits.js +++ b/scripts/pits.js @@ -102,7 +102,13 @@ function open_option(team_num) { let edit = new Button('edit_result', 'Edit Results') edit.link = `start_scouting('${team_num}', true)` - result_buttons.innerHTML += edit.toString + edit.add_class('slim') + + let renumber = new Button('renumber', 'Renumber Result') + renumber.link = `renumber_pit('${team_num}')` + renumber.add_class('slim') + + result_buttons.innerHTML += edit.toString + renumber.toString } // update capture button for new team @@ -185,7 +191,6 @@ function capture(team_num) */ function cache_image(server, team_num, base64) { - console.log(base64) fetch(base64) .then(response => response.blob()) .then(blob => { @@ -218,6 +223,31 @@ function start_scouting(team_num, edit) return build_url('index', {'page': 'scout', [TYPE_COOKIE]: PIT_MODE, 'team': team_num, 'alliance': 'white', [EVENT_COOKIE]: event_id, [POSITION_COOKIE]: 0, [USER_COOKIE]: user_id, 'edit': edit, 'generate': generate }) } +/** + * function: renumber_pit + * parameters: existing team number + * returns: none + * description: Prompts to renumber a pit result. + */ +function renumber_pit(team_num) +{ + let input = prompt('New team number') + if (input !== null) + { + let new_num = parseInt(input) + let pit = localStorage.getItem(`${PIT_MODE}-${event_id}-${team_num}`) + if (pit !== null) + { + let jpit = JSON.parse(pit) + jpit.meta_team = new_num + localStorage.setItem(`${PIT_MODE}-${event_id}-${new_num}`, JSON.stringify(jpit)) + localStorage.removeItem(`${PIT_MODE}-${event_id}-${team_num}`) + + location.reload() + } + } +} + /** * function: export_results * parameters: none From 63c9ea2c255c2746442daece08fd3ab7be50249e Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Thu, 30 Mar 2023 16:40:02 -0500 Subject: [PATCH 03/34] Hide server warnings when capturing image --- scripts/pits.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pits.js b/scripts/pits.js index 24ba4c4a..a282603a 100644 --- a/scripts/pits.js +++ b/scripts/pits.js @@ -144,7 +144,7 @@ function capture(team_num) // upload image let addr = parse_server_addr(document.location.href) - if (check_server(addr)) + if (check_server(addr, notify=false)) { canvas.toBlob(function (blob) { From 467cc6e1b90dd2cdcfc1451227104c71de6acc53 Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Thu, 30 Mar 2023 17:04:09 -0500 Subject: [PATCH 04/34] Always cache pictures, clean up directories in export --- scripts/pits.js | 7 ++----- scripts/transfer.js | 7 ++++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/scripts/pits.js b/scripts/pits.js index a282603a..1453cd79 100644 --- a/scripts/pits.js +++ b/scripts/pits.js @@ -162,13 +162,9 @@ function capture(team_num) } else if (result.name === 'Invalid password') { - cache_image(addr, team_num, data) alert('Invalid password!') } - else - { - cache_image(addr, team_num, data) - } + cache_image(addr, team_num, data) }) .catch(e => { cache_image(addr, team_num, data) @@ -260,5 +256,6 @@ function export_results() handler.pit = true handler.pictures = true handler.user = user_id + handler.server = parse_server_addr(document.location.href) handler.export_zip() } \ No newline at end of file diff --git a/scripts/transfer.js b/scripts/transfer.js index b6c67037..f9879d06 100644 --- a/scripts/transfer.js +++ b/scripts/transfer.js @@ -881,15 +881,16 @@ class ZipHandler { file = key.url } - + // check for pictures and don't put in directory if belonging to server (like server does) if ((file.endsWith('.jpg') || file.endsWith('.png')) && !file.startsWith(`${this.server}/assets/`)) { + // put locally captured pictures in a cache directory if (file.startsWith(`${this.server}/uploads/`)) { - file = file.replace(`${this.server}/uploads/`, '') + file = file.replace(`${this.server}/uploads/`, 'cache/') } - zip.file(file, response.blob()) + zip.file(file.replace('://', '/').replace(':', '.'), response.blob()) num_uploads++ } } From e72381613ed68c7445a4b3b936d32b455b485214 Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Sun, 2 Apr 2023 09:55:24 -0500 Subject: [PATCH 05/34] Added max score calculator extra page --- scripts/home.js | 5 +- scripts/links.js | 3 +- scripts/misc/max-score.js | 128 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 scripts/misc/max-score.js diff --git a/scripts/home.js b/scripts/home.js index 5911e97d..8374d484 100644 --- a/scripts/home.js +++ b/scripts/home.js @@ -38,7 +38,9 @@ const CONFIGS = { 'Reset': ['reset_cache', 'reset_storage', 'reset_config'] }, 'extras': { - 'Generic': ['misc/test', 'misc/match-counter', 'misc/district-counter', 'misc/international-counter', 'misc/score-counter', 'misc/event-planner', 'misc/team-profile', 'misc/revival-counter'], + 'Debug': ['misc/test'], + 'Team': ['misc/event-planner', 'misc/team-profile'], + 'Events': ['misc/match-counter', 'misc/district-counter', 'misc/international-counter', 'misc/score-counter', 'misc/revival-counter', 'misc/max-score'], 'Game Specific': ['misc/2022-score-estimator', 'misc/2023-score-estimator'] } } @@ -92,6 +94,7 @@ const BUTTONS = { 'misc/district-counter': { name: 'District Counter', limits: ['admin'], configs: [] }, 'misc/event-planner': { name: 'Event Planner', limits: ['admin'], configs: [] }, 'misc/international-counter': { name: 'International Counter', limits: ['admin'], configs: [] }, + 'misc/max-score': { name: 'Max Score', limits: ['admin'], configs: [] }, 'misc/score-counter': { name: 'Score Counter', limits: ['admin'], configs: [] }, 'misc/team-profile': { name: 'Team Profile', limits: ['admin'], configs: [] }, 'misc/revival-counter': { name: 'Revival Counter', limits: ['admin'], configs: [] }, diff --git a/scripts/links.js b/scripts/links.js index c266be23..173ea00f 100644 --- a/scripts/links.js +++ b/scripts/links.js @@ -38,7 +38,8 @@ var BLANK_PAGES = { 'misc/test': [], 'misc/district-counter': ['year'], 'misc/international-counter': ['year'], - 'misc/event-planner': ['year'] + 'misc/event-planner': ['year'], + 'misc/max-score': ['year'] } var SELECTION_PAGES = { diff --git a/scripts/misc/max-score.js b/scripts/misc/max-score.js new file mode 100644 index 00000000..c72c4f9e --- /dev/null +++ b/scripts/misc/max-score.js @@ -0,0 +1,128 @@ +/** + * file: max-score.js + * description: Displays a table summarizing the max combined score without fouls at each event. + * author: Liam Fruzyna + * date: 2023-04-02 + */ + +/** + * function: init_page + * parameters: none + * returns: none + * description: Runs onload to fill out the page. + */ +function init_page() +{ + let summary = '
Loading data....
' + let table = '
EventMatchRed AllianceRed ScoreBlue AllianceBlue ScoreCombined Score
' + let card = new Card('card', summary + table) + document.body.innerHTML += new PageFrame('', '', [card]).toString + + process_year(cfg.year) +} + +/** + * function: process_year + * parameters: year to add to table + * returns: none + * description: Counts the highest scores for the given year. + */ +function process_year(year) +{ + if (!TBA_KEY) + { + let file = cfg.keys + if (file != null) + { + if (cfg.keys.hasOwnProperty('tba')) + { + TBA_KEY = cfg.keys.tba + } + } + if (!TBA_KEY) + { + alert('No API key found for TBA!') + return + } + } + + fetch(`https://www.thebluealliance.com/api/v3/events/${year}${build_query({[TBA_AUTH_KEY]: TBA_KEY})}`) + .then(response => { + if (response.status === 401) { + alert('Invalid API Key Suspected') + } + return response.json() + }) + .then(events => { + let maxes = [] + let count = 0 + for (let event of events) + { + fetch(`https://www.thebluealliance.com/api/v3/event/${event.key}/matches${build_query({[TBA_AUTH_KEY]: TBA_KEY})}`) + .then(response => { + if (response.status === 401) { + alert('Invalid API Key Suspected') + } + return response.json() + }) + .then(matches => { + // find the highest score at the event + let max_event = 0 + let max_match + for (let match of matches) + { + if (match.score_breakdown !== null) + { + let score = match.alliances.red.score + match.alliances.blue.score + score -= match.score_breakdown.red.foulPoints + match.score_breakdown.blue.foulPoints + if (score > max_event) + { + max_event = score + max_match = match + } + } + } + + // add the match to the list + if (typeof max_match !== 'undefined') + { + maxes.push(max_match) + } + + // wait for every event to be counted + if (++count === events.length) + { + let overall_max = 0 + let max_event = '' + let table = '' + for (let match of maxes) + { + // find the match's event + let ev = events.filter(e => e.key == match.event_key)[0] + + // search for the highest overall score + let score = match.alliances.red.score - match.score_breakdown.red.foulPoints + match.alliances.blue.score - match.score_breakdown.blue.foulPoints + if (score > overall_max) + { + overall_max = score + max_event = ev.name + } + + // add a row to the table + table += `${ev.name}${match.key.replace(`${match.event_key}_`, '')}${match.alliances.red.team_keys.join('
').replaceAll('frc', '')}${match.alliances.red.score - match.score_breakdown.red.foulPoints}${match.alliances.blue.team_keys.join('
').replaceAll('frc', '')}${match.alliances.red.score - match.score_breakdown.red.foulPoints}${score}` + } + + // populate summary and table + document.getElementById('table').innerHTML += table + document.getElementById('summary').innerHTML = `The max score for ${year} is ${overall_max} at ${max_event}.` + } + }) + .catch(err => { + console.log(`Error fetching ${event.event_key} matches, ${err}`) + }) + } + }) + .catch(err => { + console.log(`Error fetching ${year} events, ${err}`) + }) +} From 2b71b729235a34c065958bbe24113283adf11e9d Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Sun, 2 Apr 2023 10:15:20 -0500 Subject: [PATCH 06/34] Max score page sorting and other cleanup --- scripts/misc/max-score.js | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/scripts/misc/max-score.js b/scripts/misc/max-score.js index c72c4f9e..e5162689 100644 --- a/scripts/misc/max-score.js +++ b/scripts/misc/max-score.js @@ -67,17 +67,15 @@ function process_year(year) }) .then(matches => { // find the highest score at the event - let max_event = 0 let max_match for (let match of matches) { if (match.score_breakdown !== null) { - let score = match.alliances.red.score + match.alliances.blue.score - score -= match.score_breakdown.red.foulPoints + match.score_breakdown.blue.foulPoints - if (score > max_event) + match.score = match.alliances.red.score + match.alliances.blue.score + match.score -= match.score_breakdown.red.foulPoints + match.score_breakdown.blue.foulPoints + if (typeof max_match === 'undefined' || match.score > max_match.score) { - max_event = score max_match = match } } @@ -92,29 +90,27 @@ function process_year(year) // wait for every event to be counted if (++count === events.length) { - let overall_max = 0 - let max_event = '' + // sort maxes and find highest + maxes.sort((a, b) => b.score - a.score) + let highest = maxes[0] + let highest_ev = events.filter(e => e.key == highest.event_key)[0] + + // create an HTML table of scores let table = '' for (let match of maxes) { - // find the match's event let ev = events.filter(e => e.key == match.event_key)[0] - - // search for the highest overall score - let score = match.alliances.red.score - match.score_breakdown.red.foulPoints + match.alliances.blue.score - match.score_breakdown.blue.foulPoints - if (score > overall_max) - { - overall_max = score - max_event = ev.name - } - - // add a row to the table - table += `${ev.name}${match.key.replace(`${match.event_key}_`, '')}${match.alliances.red.team_keys.join('
').replaceAll('frc', '')}${match.alliances.red.score - match.score_breakdown.red.foulPoints}${match.alliances.blue.team_keys.join('
').replaceAll('frc', '')}${match.alliances.red.score - match.score_breakdown.red.foulPoints}${score}` + let match_key = match.key.replace(`${match.event_key}_`, '') + let red_teams = match.alliances.red.team_keys.join('
').replaceAll('frc', '') + let red_share = match.alliances.red.score - match.score_breakdown.red.foulPoints + let blue_teams = match.alliances.blue.team_keys.join('
').replaceAll('frc', '') + let blue_share = match.alliances.blue.score - match.score_breakdown.blue.foulPoints + table += `${ev.name}${match_key}${red_teams}${red_share}${blue_teams}${blue_share}${match.score}` } // populate summary and table document.getElementById('table').innerHTML += table - document.getElementById('summary').innerHTML = `The max score for ${year} is ${overall_max} at ${max_event}.` + document.getElementById('summary').innerHTML = `The max score for ${year} is ${highest.score} at ${highest_ev.name}.` } }) .catch(err => { From 0cd0340b08443561aadc7d91974b11e2038a6937 Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Sun, 2 Apr 2023 10:32:33 -0500 Subject: [PATCH 07/34] Decreased header size significantly --- styles/style.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/styles/style.css b/styles/style.css index 3a21f65b..fa81dd4f 100644 --- a/styles/style.css +++ b/styles/style.css @@ -54,6 +54,12 @@ body { -webkit-user-select: none; } +#header h1, #header h2 +{ + margin: 0; + display: inline-block +} + @keyframes rainbow { 0%{background-position:0% 82%} 50%{background-position:100% 19%} From c9f6ff89d892ca7257765fd415cdd667dbec4147 Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Sun, 2 Apr 2023 11:10:05 -0500 Subject: [PATCH 08/34] Added config version metadata to result and warn for mismatches on import --- scripts/note.js | 1 + scripts/scout.js | 1 + scripts/transfer.js | 31 +++++++++++++++++++------------ 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/scripts/note.js b/scripts/note.js index ec2c2a80..998a62ac 100644 --- a/scripts/note.js +++ b/scripts/note.js @@ -145,6 +145,7 @@ function get_results_from_page() results['meta_note_scouter_id'] = parseInt(user_id) results['meta_note_scout_time'] = Math.round(start / 1000) results['meta_note_scouting_duration'] = (Date.now() - start) / 1000 + results['meta_config_version'] = cfg.version // scouting metadata results['meta_scout_mode'] = NOTE_MODE diff --git a/scripts/scout.js b/scripts/scout.js index 5dc57f3d..b825036d 100644 --- a/scripts/scout.js +++ b/scripts/scout.js @@ -409,6 +409,7 @@ function get_results_from_page() results['meta_scouter_id'] = parseInt(user_id) results['meta_scout_time'] = Math.round(start / 1000) results['meta_scouting_duration'] = (Date.now() - start) / 1000 + results['meta_config_version'] = cfg.version if (scout_mode === MATCH_MODE) { results['meta_unsure'] = document.getElementById('unsure').checked diff --git a/scripts/transfer.js b/scripts/transfer.js index f9879d06..983de91e 100644 --- a/scripts/transfer.js +++ b/scripts/transfer.js @@ -775,24 +775,31 @@ class ZipHandler } // ignore and alert if a result file name doesn't match its metadata - if (n.startsWith(`${PIT_MODE}-`) || n.startsWith(`${MATCH_MODE}-`) || n.startsWith(`${NOTE_MODE}-`)) + if (write && (n.startsWith(`${PIT_MODE}-`) || n.startsWith(`${MATCH_MODE}-`) || n.startsWith(`${NOTE_MODE}-`))) { - let name_team = parseInt(n.split('-')[2]) - let meta_team = JSON.parse(text).meta_team - if (name_team !== meta_team) + let parts = n.split('-') + let name_team = parseInt(parts[2]) + let result = JSON.parse(text) + if (name_team !== result.meta_team) { alert(`Team number mismatch on ${n}`) write = false } - } - if (n.startsWith(`${MATCH_MODE}-`) || n.startsWith(`${NOTE_MODE}-`)) - { - let name_match = n.split('-')[1] - let meta_match = JSON.parse(text).meta_match_key - if (name_match !== meta_match) + + if (!n.startsWith(`${PIT_MODE}-`)) { - alert(`Match key mismatch on ${n}`) - write = false + let meta_match = JSON.parse(text).meta_match_key + if (parts[1] !== meta_match) + { + alert(`Match key mismatch on ${n}`) + write = false + } + } + + // warn if reported config version does not match + if (write && result.hasOwnProperty('meta_config_version') && result.meta_config_version !== cfg.version) + { + alert(`Config version mismatch on ${n}`) } } From dd8d4d5a7c5f7f90a02f13d0df15b001b9bfe5df Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Mon, 3 Apr 2023 17:42:45 -0500 Subject: [PATCH 09/34] Added standard deviation to pivot --- scripts/pivot.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pivot.js b/scripts/pivot.js index 11313364..43664f71 100644 --- a/scripts/pivot.js +++ b/scripts/pivot.js @@ -13,7 +13,7 @@ let selected_keys = [] let last_sort = '' let last_reverse = false -const STATS = ['Mean', 'Median', 'Mode', 'Min', 'Max', 'Total'] +const STATS = ['Mean', 'Median', 'Mode', 'Min', 'Max', 'Total', 'StdDev'] /** * function: init_page From 0e48afef8ba92489c87671d6840757219a31c1f2 Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Mon, 3 Apr 2023 18:20:34 -0500 Subject: [PATCH 10/34] Fixed selection filtering to filter by option id --- scripts/pivot.js | 4 ++++ scripts/plot.js | 8 ++++++-- scripts/selection.js | 24 +++++++++++++----------- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/scripts/pivot.js b/scripts/pivot.js index 43664f71..dead9210 100644 --- a/scripts/pivot.js +++ b/scripts/pivot.js @@ -89,6 +89,10 @@ function filter_teams() { filter_by(dal.picklists[list], false) } + else + { + select_all(false) + } build_table() } diff --git a/scripts/plot.js b/scripts/plot.js index 7c2c4c5c..93c9e1fc 100644 --- a/scripts/plot.js +++ b/scripts/plot.js @@ -57,9 +57,13 @@ function init_canvas() function filter_teams() { let list = document.getElementById('picklist_filter').value - if (Object.keys(lists).includes(list)) + if (Object.keys(dal.picklists).includes(list)) { - filter_by(lists[list], false) + filter_by(dal.picklists[list], false) + } + else + { + deselect_all(false) } init_canvas() diff --git a/scripts/selection.js b/scripts/selection.js index 487bfbd5..2d6540c8 100644 --- a/scripts/selection.js +++ b/scripts/selection.js @@ -117,24 +117,26 @@ function toggle_select(primary_list=true) */ function filter_by(filter, primary_list=true) { - let id = 'option_list' + let start = 'option_' if (!primary_list) { - id = 'secondary_option_list' + start = 'soption_' } - let options = document.getElementById(id).children - for (let i = 0; i < options.length; ++i) + deselect_all(primary_list) + for (let f of filter) { - if (filter.includes(options[i].innerText)) + let op = start + f + let element = document.getElementById(op) + if (element !== null) { - if (!options[i].classList.contains('selected')) + if (!element.classList.contains('selected')) { - options[i].classList.add('selected') + element.classList.add('selected') + } + else + { + element.classList.remove('selected') } - } - else - { - options[i].classList.remove('selected') } } } From ccec5458c2a26a45bb0c76c8dfaa47f024ef3279 Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Mon, 3 Apr 2023 18:49:01 -0500 Subject: [PATCH 11/34] Fixed note bugs on users --- scripts/users.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/users.js b/scripts/users.js index 515be40e..2e656c3d 100644 --- a/scripts/users.js +++ b/scripts/users.js @@ -131,13 +131,13 @@ function open_option(user_id) let actual = dal.get_match_value(match.meta_match_key, 'started_time') if (typeof actual === 'number') { - delays.push(actual - match.meta_scout_time) + delays.push(actual - match.meta_note_scout_time) } else { delays.push(0) } - time_table += `${dal.get_match_value(match.meta_match_key, 'short_match_name')}${match.meta_alliance}${match.meta_position}${delays[delays.length - 1]}s${match.meta_scouting_duration.toFixed()}s` + time_table += `${dal.get_match_value(match.meta_match_key, 'short_match_name')}${match.meta_alliance}${match.meta_note_position}${delays[delays.length - 1]}s${match.meta_note_scouting_duration.toFixed()}s` } time_table += `Averages${mean(delays).toFixed()}s${mean(durations).toFixed()}s` From 457edaa6134f4ce0a1acc5576ec39961d6cbd1bf Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Mon, 3 Apr 2023 18:49:48 -0500 Subject: [PATCH 12/34] Fixed import bug with string in results teams --- scripts/transfer.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/transfer.js b/scripts/transfer.js index 983de91e..f0971f2a 100644 --- a/scripts/transfer.js +++ b/scripts/transfer.js @@ -780,7 +780,8 @@ class ZipHandler let parts = n.split('-') let name_team = parseInt(parts[2]) let result = JSON.parse(text) - if (name_team !== result.meta_team) + let result_team = parseInt(result.meta_team) + if (name_team !== result_team) { alert(`Team number mismatch on ${n}`) write = false From d72f17861d9ab2c80f5e1fe869782696b2f5f856 Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Mon, 3 Apr 2023 19:08:59 -0500 Subject: [PATCH 13/34] Store last sort for pivot --- scripts/pivot.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/scripts/pivot.js b/scripts/pivot.js index dead9210..009ddcd0 100644 --- a/scripts/pivot.js +++ b/scripts/pivot.js @@ -8,6 +8,8 @@ const SESSION_KEYS_KEY = 'pivot-selected-keys' const SESSION_TYPES_KEY = 'pivot-selected-types' +const SESSION_SORT_KEY = 'pivot-sort-key' +const SESSION_REVERSE_KEY = 'pivot-reverse-key' let selected_keys = [] let last_sort = '' @@ -44,6 +46,8 @@ function init_page() // select keys from sessionStorage let stored_keys = sessionStorage.getItem(SESSION_KEYS_KEY) let stored_types = sessionStorage.getItem(SESSION_TYPES_KEY) + last_sort = sessionStorage.getItem(SESSION_SORT_KEY) + last_reverse = sessionStorage.getItem(SESSION_REVERSE_KEY) == 'true' if (stored_keys !== null) { selected_keys = JSON.parse(stored_keys) @@ -56,7 +60,7 @@ function init_page() selected_keys.splice(i, 1) } } - build_table() + build_table(last_sort, last_reverse) if (stored_types !== null) { @@ -73,7 +77,7 @@ function init_page() } } - build_table() + build_table(last_sort, last_reverse) } /** @@ -94,7 +98,7 @@ function filter_teams() select_all(false) } - build_table() + build_table(last_sort, last_reverse) } /** @@ -145,7 +149,7 @@ function open_option(key) // save selection to sessionStorage sessionStorage.setItem(SESSION_KEYS_KEY, JSON.stringify(get_selected_keys())) - build_table() + build_table(last_sort, last_reverse) } /** @@ -167,7 +171,7 @@ function alt_option(key) // save selection to sessionStorage sessionStorage.setItem(SESSION_KEYS_KEY, JSON.stringify(get_selected_keys())) - build_table() + build_table(last_sort, last_reverse) } } @@ -191,7 +195,7 @@ function open_secondary_option(key) } select_none() - build_table() + build_table(last_sort, last_reverse) } /** @@ -241,6 +245,9 @@ function get_sorted_teams(sort_by='', reverse=false) last_sort = sort_by last_reverse = reverse + sessionStorage.setItem(SESSION_SORT_KEY, last_sort) + sessionStorage.setItem(SESSION_REVERSE_KEY, last_reverse) + return filter_teams } @@ -760,5 +767,5 @@ function drop_handler(e) // save selection to sessionStorage sessionStorage.setItem(SESSION_KEYS_KEY, JSON.stringify(get_selected_keys())) - build_table() + build_table(last_sort, last_reverse) } From 0c6d3de18e16077945659e32ceef277d984d02bd Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Mon, 3 Apr 2023 19:36:45 -0500 Subject: [PATCH 14/34] Added export results button to analyst --- scripts/home.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/scripts/home.js b/scripts/home.js index 8374d484..29933582 100644 --- a/scripts/home.js +++ b/scripts/home.js @@ -25,7 +25,7 @@ const CONFIGS = { 'analysis': { 'Teams': ['ranker', 'sides', 'multipicklists'], 'Keys': ['pivot', 'distro', 'plot', 'scatter'], - 'Results': ['import_results', 'results', 'cycles'], + 'Results': ['import_results', 'results', 'cycles', 'export_results'], 'Overviews': ['teams', 'match-overview', 'users', 'progress', 'events'] }, 'admin': { @@ -58,6 +58,7 @@ const BUTTONS = { 'event-generator': { name: 'Event Generator', limits: ['admin'], configs: [] }, 'events': { name: 'Other Events', limits: ['teams', 'admin'], configs: [] }, 'export': { name: 'Server Exporter', limits: ['admin'], configs: [] }, + 'export_results': { name: 'Export All Results', limits: ['admin'], configs: [] }, 'match-overview': { name: 'Match Summaries', limits: ['event', 'admin'], configs: ['settings'] }, 'matches': { name: 'Scout', limits: ['event'], configs: [MATCH_MODE, 'settings'] }, 'multipicklists': { name: 'Pick Lists', limits: ['teams', 'admin'], configs: ['settings'] }, @@ -389,6 +390,23 @@ function import_results() handler.import_zip_from_file() } +/** + * function: export_results + * parameters: none + * returns: none + * description: Starts the zip export process for results. + */ +function export_results() +{ + let handler = new ZipHandler() + handler.match = true + handler.note = true + handler.pit = true + handler.pictures = true + handler.user = get_cookie(USER_COOKIE, USER_DEFAULT) + handler.export_zip() +} + /** * function: export_config * parameters: none From d31d035ece45877b399d2434ef9e6f41183a89b8 Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Mon, 3 Apr 2023 19:57:56 -0500 Subject: [PATCH 15/34] Added export all button to progress --- scripts/matches.js | 2 +- scripts/progress.js | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/scripts/matches.js b/scripts/matches.js index 97dac8f5..c708206b 100644 --- a/scripts/matches.js +++ b/scripts/matches.js @@ -169,7 +169,7 @@ function can_edit(match_num, team_num) } /** - * function: expport_results + * function: export_results * parameters: none * returns: none * description: Starts the zip export process for this page type's results. diff --git a/scripts/progress.js b/scripts/progress.js index 778093e7..f685662b 100644 --- a/scripts/progress.js +++ b/scripts/progress.js @@ -5,6 +5,8 @@ * date: 2022-01-31 */ +include('transfer') + /** * function: init_page * parameters: none @@ -113,6 +115,8 @@ function init_page() page.add_column(pit) let pit_card = new Card('pits', pit_table) pit.add_input(pit_card) + let export_all = new Button('export', 'Export All Results', 'export_results()') + pit.add_input(export_all) let match = new ColumnFrame('match_page', 'Match Progress') page.add_column(match) @@ -120,4 +124,21 @@ function init_page() match.add_input(match_card) document.body.innerHTML += page.toString +} + +/** + * function: export_results + * parameters: none + * returns: none + * description: Starts the zip export process for results. + */ +function export_results() +{ + let handler = new ZipHandler() + handler.match = true + handler.note = true + handler.pit = true + handler.pictures = true + handler.user = get_cookie(USER_COOKIE, USER_DEFAULT) + handler.export_zip() } \ No newline at end of file From 224c190604c600cef319d1a2d8265223dbdf02a0 Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Fri, 7 Apr 2023 09:16:57 -0500 Subject: [PATCH 16/34] Allow columns to wrap to a new column, plus hack for champs config --- scripts/inputs.js | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/scripts/inputs.js b/scripts/inputs.js index d94a674d..22224155 100644 --- a/scripts/inputs.js +++ b/scripts/inputs.js @@ -86,6 +86,7 @@ class ColumnFrame extends Element { super(id, label) this.inputs = inputs + this.max = 0 } add_input(input) @@ -100,10 +101,29 @@ class ColumnFrame extends Element get toString() { - return `
- ${this.header} - ${this.inputs.map(i => typeof i === 'string' ? i : i.toString).join('')} -
` + if (this.max > 0 && this.inputs.length > this.max) + { + let cols = [] + for (let i = 0; i < Math.ceil(this.inputs.length / this.max); i++) + { + let col = `
${this.header}` + for (let j = i * this.max; j < (i + 1) * this.max && j < this.inputs.length; j++) + { + let input = this.inputs[j] + col += typeof input === 'string' ? input : input.toString + } + col += '
' + cols.push(col) + } + return cols.join('') + } + else + { + return `
+ ${this.header} + ${this.inputs.map(i => typeof i === 'string' ? i : i.toString).join('')} +
` + } } } @@ -1068,6 +1088,10 @@ function build_column_from_config(column, scout_mode, select_ids, edit=false, ma col_name = col_name.replace('TEAM', team).replace('ALLIANCE', alliance_color) } let col_frame = new ColumnFrame(column.id, col_name) + if (column.id === 'match_auto_auto') + { + col_frame.max = 3 + } // iterate through input in the column for (let input of column.inputs) From 8d91843032180ad46473304d16a2aa99cb44c59c Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Fri, 7 Apr 2023 09:21:36 -0500 Subject: [PATCH 17/34] Pull TBA data into results --- scripts/data.js | 56 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/scripts/data.js b/scripts/data.js index d9095e2b..69b69f66 100644 --- a/scripts/data.js +++ b/scripts/data.js @@ -636,6 +636,8 @@ class DAL for (let file of match_files) { let match = JSON.parse(localStorage.getItem(file)) + let team = match.meta_team.toString() + // add match key to pre-WR2 results if (!match.hasOwnProperty('meta_match_key') && match.hasOwnProperty('meta_match') && match.hasOwnProperty('meta_event_id')) { @@ -649,6 +651,7 @@ class DAL { match.meta_set_number = 1 } + // add notes if available let note_file = file.replace(MATCH_MODE, NOTE_MODE) if (files.includes(note_file)) @@ -661,9 +664,54 @@ class DAL { match.meta_both_scouted = false } - let team = match.meta_team.toString() + + // only add team if it is in the team list if (teams.includes(team)) { + // add TBA data to results + // TODO: do this the "right" way be adding it as a separate section and supporting that + if (this.matches.hasOwnProperty(match.meta_match_key)) + { + let match_info = this.matches[match.meta_match_key] + if (match_info.hasOwnProperty('red_score') && match_info.red_score >= 0 && + match_info.hasOwnProperty('blue_score') && match_info.blue_score >= 0) + { + if (match_info.blue_alliance.includes(team)) + { + match.meta_score = match_info.blue_score + match.meta_opp_score = match_info.red_score + if (match_info.score_breakdown !== null) + { + for (let key in match_info.score_breakdown.blue) + { + match[`meta_${key.toLowerCase()}`] = match_info.score_breakdown.blue[key] + } + for (let key in match_info.score_breakdown.red) + { + match[`meta_opp_${key.toLowerCase()}`] = match_info.score_breakdown.red[key] + } + } + } + else if (match_info.red_alliance.includes(team)) + { + match.meta_score = match_info.red_score + match.meta_opp_score = match_info.blue_score + if (match_info.score_breakdown !== null) + { + for (let key in match_info.score_breakdown.red) + { + match[`meta_${key.toLowerCase()}`] = match_info.score_breakdown.red[key] + } + for (let key in match_info.score_breakdown.blue) + { + match[`meta_opp_${key.toLowerCase()}`] = match_info.score_breakdown.blue[key] + } + } + } + } + } + + // add smart stats, then add to results this.teams[team].results.push(this.add_smart_stats(match, stats)) } } @@ -1847,7 +1895,7 @@ class DAL values.push(this.get_value(team, id, stat)) } values = values.filter(v => v !== '') - + switch (this.meta[id].type) { case 'checkbox': @@ -1864,7 +1912,7 @@ class DAL { counts[i] = values.filter(val => val == i).length } - + // compute stats let min_op = '' let max_op = '' @@ -1890,7 +1938,7 @@ class DAL min_op = min_op == 'true' max_op = max_op == 'true' } - + // build data structure global_stats[`${id}.mean`] = mode_op global_stats[`${id}.median`] = median_op From e0c9844a4be2f873feb8122854bd03912007f21b Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Fri, 7 Apr 2023 09:36:21 -0500 Subject: [PATCH 18/34] Fixed pivot starting with no last sort --- scripts/pivot.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/pivot.js b/scripts/pivot.js index 009ddcd0..07550ed9 100644 --- a/scripts/pivot.js +++ b/scripts/pivot.js @@ -48,6 +48,12 @@ function init_page() let stored_types = sessionStorage.getItem(SESSION_TYPES_KEY) last_sort = sessionStorage.getItem(SESSION_SORT_KEY) last_reverse = sessionStorage.getItem(SESSION_REVERSE_KEY) == 'true' + + if (last_sort === null) + { + last_sort = '' + } + if (stored_keys !== null) { selected_keys = JSON.parse(stored_keys) From f8f26fb1522240c5084a014e8b12eda1a1c3687e Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Fri, 7 Apr 2023 09:52:26 -0500 Subject: [PATCH 19/34] Use current time for generating matches to sort properly --- scripts/event-generator.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/event-generator.js b/scripts/event-generator.js index 43ed7298..993cf096 100644 --- a/scripts/event-generator.js +++ b/scripts/event-generator.js @@ -318,8 +318,9 @@ function add_match() red_teams.push(`frc${document.getElementById(`red_${pos}`).value}`) blue_teams.push(`frc${document.getElementById(`blue_${pos}`).value}`) } + let time = Date.now() / 1000 matches.push({ - actual_time: 0, + actual_time: time, alliances: { blue: { dq_team_keys: [], @@ -336,9 +337,9 @@ function add_match() event_key: event_id, key: `${event_id}_qm${match_number}`, match_number: match_number, - predicted_time: 1294765871, + predicted_time: time, set_number: 1, - time: 1294765871 + time: time }) localStorage.setItem(file_name, JSON.stringify(matches)) From dc8efeefe394edfcb42ea6fbc5680868b788267f Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Fri, 7 Apr 2023 10:02:49 -0500 Subject: [PATCH 20/34] Fixed sorting by non-mean in pivot --- scripts/pivot.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/pivot.js b/scripts/pivot.js index 07550ed9..a8712c28 100644 --- a/scripts/pivot.js +++ b/scripts/pivot.js @@ -237,10 +237,11 @@ function get_sorted_teams(sort_by='', reverse=false) let filter_teams = get_secondary_selected_keys() // sort teams based on parameters + // TODO: sort by the non-first duplicate column let type = 'mean' - if (document.getElementById(`select_${sort_by}`)) + if (document.getElementById(`select_${sort_by}_0`)) { - type = document.getElementById(`select_${sort_by}`).value.toLowerCase() + type = document.getElementById(`select_${sort_by}_0`).value.toLowerCase() } filter_teams.sort((a,b) => dal.get_value(b, sort_by, type) - dal.get_value(a, sort_by, type)) if (reverse) From 83dc258486db1017aa2cffe56f846544232495fd Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Fri, 7 Apr 2023 10:05:20 -0500 Subject: [PATCH 21/34] Added labels to pivot top rows --- scripts/pivot.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/pivot.js b/scripts/pivot.js index a8712c28..35696dc2 100644 --- a/scripts/pivot.js +++ b/scripts/pivot.js @@ -276,9 +276,9 @@ function build_table(sort_by='', reverse=false) // build table headers let table = `` - let types = '' - let filters = '' - let totals = '' + let types = '' + let filters = '' + let totals = '' for (let i in selected) { let key = selected[i] From dc28baed17b6cbbf723736bbfdac6ccab6e16eec Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Fri, 7 Apr 2023 11:43:53 -0500 Subject: [PATCH 22/34] Added support for ties --- scripts/data.js | 42 ++++++++++++++++++++++++------------------ scripts/teams.js | 11 ++++++++++- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/scripts/data.js b/scripts/data.js index 69b69f66..b3fdcf50 100644 --- a/scripts/data.js +++ b/scripts/data.js @@ -902,27 +902,11 @@ class DAL match_name = `${match.comp_level.toUpperCase()} ${match.set_number}-${match.match_number}` short_match_name = `${match.comp_level.toUpperCase()}${match.set_number}${match.match_number}` } + let display_time = '' - let score_str = '' - let complete = false if (match.actual_time > 0) { display_time = `${unix_to_match_time(match.actual_time)}` - if (match.winning_alliance !== '' && match.alliances.red.score !== '' && match.alliances.blue.score !== '') - { - complete = true - let winner = match.winning_alliance - let red_score = match.alliances.red.score - let blue_score = match.alliances.blue.score - if (winner === 'red') - { - score_str = `${red_score} - ${blue_score}` - } - else - { - score_str = `${blue_score} - ${red_score}` - } - } } else if (match.predicted_time > 0) { @@ -932,6 +916,28 @@ class DAL { display_time = `${unix_to_match_time(match.time)} (Scheduled)` } + + let score_str = '' + let complete = false + let winner = match.winning_alliance + if (match.alliances.red.score !== '' && match.alliances.blue.score !== '') + { + complete = true + if (winner === '') + { + winner = 'tie' + } + let red_score = match.alliances.red.score + let blue_score = match.alliances.blue.score + if (winner === 'red') + { + score_str = `${red_score} - ${blue_score}` + } + else + { + score_str = `${blue_score} - ${red_score}` + } + } this.matches[match.key] = { match_name: match_name, short_match_name: short_match_name, @@ -950,7 +956,7 @@ class DAL score_str: score_str, videos: match.videos, score_breakdown: match.score_breakdown, - winner: match.winning_alliance + winner: winner } if (this.matches[match.key].red_alliance.length > this.max_alliance_size) { diff --git a/scripts/teams.js b/scripts/teams.js index 3a51156f..72f0a39a 100644 --- a/scripts/teams.js +++ b/scripts/teams.js @@ -126,7 +126,16 @@ function open_option(team_num) if (dal.get_match_value(match_key, 'complete')) { let winner = dal.get_match_value(match_key, 'winner') - let result = `${winner === alliance ? 'W' : 'L'}
${dal.get_match_value(match_key, 'score_str')}` + let win = 'L' + if (winner === alliance) + { + win = 'W' + } + else if (winner === 'tie') + { + win = 'T' + } + let result = `${win}
${dal.get_match_value(match_key, 'score_str')}` time += `
${result}` } From 600910db2ff7e0ab8cd7b01ff71fd83ea6f5f66c Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Fri, 7 Apr 2023 19:39:39 -0500 Subject: [PATCH 23/34] Updated pivot column management to support all features for duplicate columns --- scripts/pivot.js | 198 +++++++++++++++++++++++++++++++---------------- 1 file changed, 130 insertions(+), 68 deletions(-) diff --git a/scripts/pivot.js b/scripts/pivot.js index 35696dc2..67bf45bf 100644 --- a/scripts/pivot.js +++ b/scripts/pivot.js @@ -8,11 +8,11 @@ const SESSION_KEYS_KEY = 'pivot-selected-keys' const SESSION_TYPES_KEY = 'pivot-selected-types' -const SESSION_SORT_KEY = 'pivot-sort-key' +const SESSION_SORT_KEY = 'pivot-sort-idx' const SESSION_REVERSE_KEY = 'pivot-reverse-key' let selected_keys = [] -let last_sort = '' +let last_sort = 0 let last_reverse = false const STATS = ['Mean', 'Median', 'Mode', 'Min', 'Max', 'Total', 'StdDev'] @@ -51,7 +51,11 @@ function init_page() if (last_sort === null) { - last_sort = '' + last_sort = 0 + } + else + { + last_sort = parseInt(last_sort) } if (stored_keys !== null) @@ -232,30 +236,62 @@ function get_secondary_selected_keys() * returns: array of selected and sorted teams * description: Builds an array of the currently selected teams then sorts. */ -function get_sorted_teams(sort_by='', reverse=false) +function get_sorted_teams(sort_by=0, type='mean', reverse=false) { let filter_teams = get_secondary_selected_keys() - // sort teams based on parameters - // TODO: sort by the non-first duplicate column - let type = 'mean' - if (document.getElementById(`select_${sort_by}_0`)) + let key = selected_keys[sort_by] + if (typeof key === 'undefined') { - type = document.getElementById(`select_${sort_by}_0`).value.toLowerCase() + key = '' } - filter_teams.sort((a,b) => dal.get_value(b, sort_by, type) - dal.get_value(a, sort_by, type)) + filter_teams.sort((a,b) => dal.get_value(b, key, type) - dal.get_value(a, key, type)) if (reverse) { filter_teams.reverse() } - last_sort = sort_by - last_reverse = reverse + return filter_teams +} - sessionStorage.setItem(SESSION_SORT_KEY, last_sort) - sessionStorage.setItem(SESSION_REVERSE_KEY, last_reverse) +/** + * function: get_previous_pos + * parameters: current position, position that was moved, position it was moved to + * returns: position before move + * description: Determines where the position was previously. + */ +function get_previous_pos(idx, moved_idx, placed_idx) +{ + let prev_idx = idx + if (idx === placed_idx) + { + prev_idx = moved_idx + } + else if (idx > placed_idx && idx <= moved_idx) + { + prev_idx-- + } + else if (idx >= moved_idx && idx < placed_idx) + { + prev_idx++ + } + return prev_idx +} - return filter_teams +/** + * function: get_selected_type + * parameters: sort position + * returns: selected type + * description: Returns the stat select on a column. + */ +function get_selected_type(idx=0) +{ + let type = 'mean' + if (document.getElementById(`select_${idx}`)) + { + type = document.getElementById(`select_${idx}`).value.toLowerCase() + } + return type } /** @@ -264,48 +300,64 @@ function get_sorted_teams(sort_by='', reverse=false) * returns: none * description: Completes the center info pane with the selected options. */ -function build_table(sort_by='', reverse=false) +function build_table(sort_by=0, reverse=false, moved_idx=-1, placed_idx=-1) { // get selected keys on either side let selected = get_selected_keys() - let filter_teams = get_sorted_teams(sort_by, reverse) + + // sort teams based on parameters + let pos = get_previous_pos(sort_by, moved_idx, placed_idx) + let filter_teams = get_sorted_teams(sort_by, get_selected_type(pos), reverse) + let selected_types = {} + // update stored sort + last_sort = sort_by + last_reverse = reverse + sessionStorage.setItem(SESSION_SORT_KEY, last_sort) + sessionStorage.setItem(SESSION_REVERSE_KEY, last_reverse) + // compute totals let global_stats = dal.compute_global_stats(selected, filter_teams) // build table headers let table = `
Sort By
Filter By
Total
` - let types = '' - let filters = '' + let types = '' + let filters = `` let totals = '' for (let i in selected) { let key = selected[i] // add key names - table += `` + table += `` + + // determine column to pull existing stat and filter values from + let from_idx = get_previous_pos(parseInt(i), moved_idx, placed_idx) // determine previously selected stat let type = 'Mean' - if (document.getElementById(`select_${key}_${i}`)) + if (document.getElementById(`select_${from_idx}`)) { - type = document.getElementById(`select_${key}_${i}`).value - selected_types[`select_${key}_${i}`] = type + type = document.getElementById(`select_${from_idx}`).value + selected_types[`select_${i}`] = type } // determine previously selected filter let filter = '' - if (document.getElementById(`filter_${key}_${i}`)) + if (document.getElementById(`filter_${from_idx}`)) { - filter = document.getElementById(`filter_${key}_${i}`).value + filter = document.getElementById(`filter_${from_idx}`).value } // determine previously less/greater let ltgt_def = '' - if (document.getElementById(`ltgt_${key}_${i}`)) + if (document.getElementById(`ltgt_${from_idx}`)) { - ltgt_def = Select.get_selected_option(`ltgt_${key}_${i}`) + ltgt_def = Select.get_selected_option(`ltgt_${from_idx}`) } // find unique values and make array of teams that don't match filter @@ -366,7 +418,7 @@ function build_table(sort_by='', reverse=false) let filter_str = '' if (type !== 'Total' || (t !== 'select' || t === 'dropdown')) { - let filter_dd = new Dropdown(`filter_${key}_${i}`, '', unique, filter) + let filter_dd = new Dropdown(`filter_${i}`, '', unique, filter) filter_dd.on_change = `build_table('${sort_by}', ${reverse})` filter_dd.add_class('slim') filter_dd.add_class('thin') @@ -382,7 +434,7 @@ function build_table(sort_by='', reverse=false) { stats = stats.concat(dal.meta[key].options) } - let dropdown = new Dropdown(`select_${key}_${i}`, '', stats, type) + let dropdown = new Dropdown(`select_${i}`, '', stats, type) dropdown.on_change = `build_table('${sort_by}', ${reverse})` dropdown.add_class('slim') dropdown.add_class('thin') @@ -392,7 +444,7 @@ function build_table(sort_by='', reverse=false) // build a select for less/greater than if a number if (t === 'number' || t === 'counter' || t === 'slider' || !STATS.includes(type)) { - let ltgt = new Select(`ltgt_${key}_${i}`, '', ['Less', 'Greater'], ['Less', 'Greater'][ltgt_def]) + let ltgt = new Select(`ltgt_${i}`, '', ['Less', 'Greater'], ['Less', 'Greater'][ltgt_def]) ltgt.on_change = `build_table('${sort_by}', ${reverse})` ltgt.add_class('slim') ltgt.add_class('thin') @@ -416,9 +468,9 @@ function build_table(sort_by='', reverse=false) // determine previously selected stat let type = 'mean' - if (document.getElementById(`select_${key}_${i}`)) + if (document.getElementById(`select_${i}`)) { - type = document.getElementById(`select_${key}_${i}`).value.toLowerCase() + type = selected_types[`select_${i}`].toLowerCase() } // compute color @@ -476,7 +528,7 @@ function save_picklist() { // get selected keys on either side let selected = get_selected_keys() - let teams = get_sorted_teams(last_sort, last_reverse) + let teams = get_sorted_teams(last_sort, get_selected_type(last_sort), last_reverse) for (let i in selected) { @@ -484,23 +536,23 @@ function save_picklist() // determine previously selected stat let type = 'Mean' - if (document.getElementById(`select_${key}_${i}`)) + if (document.getElementById(`select_${i}`)) { - type = document.getElementById(`select_${key}_${i}`).value + type = document.getElementById(`select_${i}`).value } // determine previously selected filter let filter = '' - if (document.getElementById(`filter_${key}_${i}`)) + if (document.getElementById(`filter_${i}`)) { - filter = document.getElementById(`filter_${key}_${i}`).value + filter = document.getElementById(`filter_${i}`).value } // determine previously less/greater let ltgt_def = '' - if (document.getElementById(`ltgt_${key}_${i}`)) + if (document.getElementById(`ltgt_${i}`)) { - ltgt_def = Select.get_selected_option(`ltgt_${key}_${i}`) + ltgt_def = Select.get_selected_option(`ltgt_${i}`) } // make array of teams that don't match filter @@ -525,13 +577,13 @@ function save_picklist() } let name = '' - if (last_sort === '') + if (last_sort === 0) { name = 'Team Number' } else { - name = dal.get_name(last_sort) + name = dal.get_name(selected_keys[last_sort]) } if (last_reverse) { @@ -556,7 +608,7 @@ function export_csv() { // get selected keys on either side let selected = get_selected_keys() - let filter_teams = get_sorted_teams(last_sort, last_reverse) + let filter_teams = get_sorted_teams(last_sort, get_selected_type(last_sort), last_reverse) // compute totals let global_stats = dal.compute_global_stats(selected, filter_teams) @@ -569,9 +621,9 @@ function export_csv() // determine previously selected stat let type = 'Mean' - if (document.getElementById(`select_${key}_${i}`)) + if (document.getElementById(`select_${i}`)) { - type = document.getElementById(`select_${key}_${i}`).value + type = document.getElementById(`select_${i}`).value } // add key names and totals @@ -597,9 +649,9 @@ function export_csv() // determine previously selected stat let type = 'mean' - if (document.getElementById(`select_${key}_${i}`)) + if (document.getElementById(`select_${i}`)) { - type = document.getElementById(`select_${key}_${i}`).value.toLowerCase() + type = document.getElementById(`select_${i}`).value.toLowerCase() } // add cell @@ -679,9 +731,9 @@ function import_keys(event) { let key = keys[i].substring(1, keys[i].length - 1) let type = types[i].substring(1, types[i].length - 1) - if (document.getElementById(`select_${key}_${i-1}`)) + if (document.getElementById(`select_${i-1}`)) { - document.getElementById(`select_${key}_${i-1}`).value = type + document.getElementById(`select_${i-1}`).value = type } } } @@ -748,31 +800,41 @@ function drop_handler(e) let dropped_on = e.target.id let dragging = e.dataTransfer.getData("text") - // select true key if a discrete input - if (!selected_keys.includes(dropped_on)) + // determine what was moved + let old_idx = parseInt(dragging.split('_')[1]) + let key = selected_keys.splice(old_idx, 1)[0] + + // determine which column index to move to + if (dropped_on === 'team') { - for (let key of selected_keys) - { - if (dropped_on.startsWith(key)) - { - dropped_on = key - if (dragging.startsWith(key)) - { - return - } - } - } + i = 0 } - - // remove dragged key - selected_keys = selected_keys.filter(s => s != dragging) + else + { + i = parseInt(dropped_on.split('_')[1]) + 1 + } + if (i > old_idx) + { + i -= 1 + } + selected_keys.splice(i, 0, key) - // insert dragged key - let index = dropped_on == 'team' ? 0 : selected_keys.indexOf(dropped_on) + 1 - selected_keys.splice(index, 0, dragging) + // update sorted column index + if (last_sort === old_idx) + { + last_sort = i + } + else if (last_sort > old_idx && last_sort <= i) + { + last_sort -= 1 + } + else if (last_sort < old_idx && last_sort >= i) + { + last_sort += 1 + } // save selection to sessionStorage sessionStorage.setItem(SESSION_KEYS_KEY, JSON.stringify(get_selected_keys())) - build_table(last_sort, last_reverse) + build_table(last_sort, last_reverse, old_idx, i) } From 8dc0e8163ac58481c284301cdad07b891e85b17f Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Sat, 8 Apr 2023 08:14:49 -0500 Subject: [PATCH 24/34] Look for valid score before assuming complete --- scripts/data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/data.js b/scripts/data.js index b3fdcf50..6bbb3cf5 100644 --- a/scripts/data.js +++ b/scripts/data.js @@ -920,7 +920,7 @@ class DAL let score_str = '' let complete = false let winner = match.winning_alliance - if (match.alliances.red.score !== '' && match.alliances.blue.score !== '') + if (match.alliances.red.score !== '' && match.alliances.blue.score !== '' && match.alliances.red.score >= 0 && match.alliances.blue.score >= 0) { complete = true if (winner === '') From 8209878f6e23153d24dc99022a98dc7a906c6ac9 Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Sat, 8 Apr 2023 10:17:17 -0500 Subject: [PATCH 25/34] Allow multiple teams to be added to a photo carousel --- scripts/data.js | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/scripts/data.js b/scripts/data.js index 6bbb3cf5..a472be36 100644 --- a/scripts/data.js +++ b/scripts/data.js @@ -1370,24 +1370,45 @@ class DAL /** * function: get_photo_carousel - * parameters: team number + * parameters: team numbers * returns: a carousel of images * description: Builds a carousel of a team's images. */ - get_photo_carousel(team_num, width='500px') + get_photo_carousel(team_nums, width='500px') { - if (cfg.settings.use_images && this.teams.hasOwnProperty(team_num) && this.teams[team_num].pictures.hasOwnProperty('photos')) + if (cfg.settings.use_images) { - let html = `` + } } return '' } From 219a123492a1295d300435596f603b30a9904d7c Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Sat, 8 Apr 2023 10:17:38 -0500 Subject: [PATCH 26/34] Color alliance name in coach --- scripts/coach.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/coach.js b/scripts/coach.js index 2232487f..be0f5fdb 100644 --- a/scripts/coach.js +++ b/scripts/coach.js @@ -146,6 +146,6 @@ function build_table(alliance, teams) table += '' } table += '
Sort By
Filter By
Stat
Filter
Total${dal.get_name(key, '')}${dal.get_name(key, '')}
' - let header = `

${alliance[0].toUpperCase()}${alliance.substring(1)} Alliance

` + let header = `

${alliance[0].toUpperCase()}${alliance.substring(1)} Alliance

` document.getElementById(`${alliance}_details`).innerHTML = header + images + table } \ No newline at end of file From 77524bb9f7a02b19f8f379c4e91f31a681adde78 Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Sat, 8 Apr 2023 10:18:11 -0500 Subject: [PATCH 27/34] Double elims coach page --- scripts/bracket.js | 233 +++++++++++++++++++++++++++++++++++++++++++++ scripts/home.js | 3 +- scripts/links.js | 1 + scripts/pwa.js | 1 + 4 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 scripts/bracket.js diff --git a/scripts/bracket.js b/scripts/bracket.js new file mode 100644 index 00000000..5f7a1d48 --- /dev/null +++ b/scripts/bracket.js @@ -0,0 +1,233 @@ +/** + * file: bracket.js + * description: Builds a double elim bracket for your team. + * TODO: support manually marking teams as won and generating matches + * author: Liam Fruzyna + * date: 2023-04-07 + */ + +include('transfer') + +/** + * function: init_page + * parameters: contents card, buttons container + * returns: none + * description: Fetch simple event matches from localStorage. Initialize page contents. + */ +function init_page() +{ + // build page + first = populate_teams(false) + + if (dal.event.playoff_type !== 10) + { + contents_card.innerHTML = '

Not a double elim event!

' + } + else if (first) + { + // build template + contents_card.innerHTML = `


vs

` + let card = new Card('table', '') + let edit = new Button('edit_coach', 'Edit Values') + edit.link = `open_page('edit-coach')` + let preload = new Button('preload', 'Update Matches', 'preload_event()') + buttons_container.innerHTML = new ColumnFrame('', '', [card, edit, preload]).toString + + // open default time + if (cfg.settings.hasOwnProperty('team_number')) + { + let team = cfg.settings.team_number.toString() + if (team in dal.teams) + { + first = cfg.settings.team_number.toString() + } + } + open_option(first) + } + else + { + contents_card.innerHTML = '

No Teams Found

Please preload event' + } +} + +/** + * function: open_match + * parameters: Selected team number + * returns: none + * description: Completes right info pane for a given team number. + */ +function open_option(team) +{ + // select option + deselect_all() + document.getElementById(`option_${team}`).classList.add('selected') + + // get the team's matches + let matches = Object.values(dal.matches) + let team_matches = matches.filter(m => (m.red_alliance.includes(team) || m.blue_alliance.includes(team)) && !m.complete) + + // find the templates + let title = document.getElementById('next_match') + let alliance_box = document.getElementById('alliance') + let partner_box = document.getElementById('partners') + let opp_section = document.getElementById('opp_alliance') + let opp_teams = document.getElementById('opponents') + document.getElementById(`table`).innerHTML = '' + + // if no matches find assume team is eliminated + if (team_matches.length === 0) + { + title.innerHTML = 'Team Eliminated' + alliance_box.innerHTML = '' + partner_box.innerHTML = '' + opp_section.innerHTML = '' + opp_teams.innerHTML = '' + } + // if there still is a qualification match scheduled, elims hasn't started + else if (team_matches[0].comp_level === 'qm') + { + title.innerHTML = 'Elims not yet started' + alliance_box.innerHTML = '' + partner_box.innerHTML = '' + opp_section.innerHTML = '' + opp_teams.innerHTML = '' + } + // otherwise populate with the assumed next elim match + else + { + let match = team_matches[0] + title.innerHTML = `Next Match: ${match.match_name}` + + // determine alliance color and teams + let alliance = 'Blue' + let opp_alliance = 'Red' + if (match.red_alliance.includes(team)) + { + alliance = 'Red' + opp_alliance = 'Blue' + } + let partners = match[`${alliance.toLowerCase()}_alliance`] + let opponents = match[`${opp_alliance.toLowerCase()}_alliance`] + + // place alliance color + alliance_box.innerHTML = `${alliance} Alliance` + alliance_box.style.color = alliance + partner_box.innerHTML = partners.join(', ') + + if (opponents.length > 0 && !opponents.includes('0')) + { + // place alliance partners + opp_section.style.color = opp_alliance + opp_section.innerHTML = `${opp_alliance} Alliance` + opp_teams.innerHTML = opponents.join(', ') + build_table(opp_alliance.toLowerCase(), opponents) + } + else + { + // determine match that determines opponents + let match_name = '' + let winner = true + switch (match.short_match_name) + { + case 'M5': + match_name = 'M2' + winner = false + break + case 'M6': + match_name = 'M4' + winner = false + break + case 'M7': + match_name = 'M2' + break + case 'M8': + match_name = 'M4' + break + case 'M9': + match_name = 'M7' + winner = false + break + case 'M10': + match_name = 'M8' + winner = false + break + case 'M11': + match_name = 'M10' + break + case 'M12': + match_name = 'M8' + break + case 'M13': + match_name = 'M12' + winner = false + break + case 'F1': + match_name = 'M13' + break + } + let opp_match = matches.filter(m => m.short_match_name === match_name)[0] + + // populate with opponent match + opp_section.innerHTML = `Determined by ${winner ? 'WINNER' : 'LOSER'} of ${opp_match.match_name}` + opp_teams.innerHTML += `${opp_match.red_alliance.map(t => ``).join('')} + ${opp_match.blue_alliance.map(t => ``).join('')}
${t}
${t}
` + + build_table('red', opp_match.red_alliance) + build_table('blue', opp_match.blue_alliance) + } + } +} + +/** + * function: build_table + * parameters: alliance color, array of team numbers + * returns: none + * description: Populates a card with coach vals of each team in an alliance. + */ +function build_table(alliance, teams) +{ + let images = dal.get_photo_carousel(teams, '400px') + let table = '' + let names = '' + for (let team of teams) + { + table += `` + names += `` + } + table += `${names}` + for (let v of cfg.coach) + { + table += `` + for (let team of teams) + { + table += `` + } + table += '' + } + table += '
${team}${dal.get_value(team, 'meta.name')}
${dal.get_name(v.key, v.function)}${dal.get_value(team, v.key, v.function, true)}
' + let header = `

${alliance[0].toUpperCase()}${alliance.substring(1)} Alliance

` + document.getElementById(`table`).innerHTML += header + images + table +} + +/** + * function: process_files + * parameters: none + * returns: none + * description: Reloads the page on new results. + */ +function process_files() +{ + dal.build_teams() + init_page() +} + +/** + * function: get_event + * parameters: none + * returns: Currently entered event ID. + * description: Returns text in event id box. + */ +function get_event() +{ + return get_cookie(EVENT_COOKIE, cfg.defaults.event_id) +} \ No newline at end of file diff --git a/scripts/home.js b/scripts/home.js index 29933582..8f98684a 100644 --- a/scripts/home.js +++ b/scripts/home.js @@ -20,7 +20,7 @@ const CONFIGS = { 'Notes': ['pits', 'notes'] }, 'drive': { - 'Drive Team': ['import_results', 'coach', 'whiteboard'] + 'Drive Team': ['import_results', 'coach', 'whiteboard', 'bracket'] }, 'analysis': { 'Teams': ['ranker', 'sides', 'multipicklists'], @@ -47,6 +47,7 @@ const CONFIGS = { // requirements for each button const BUTTONS = { + 'bracket': { name: 'Double Elims', limits: ['event', 'admin'], configs: ['settings', 'coach'] }, 'cache': { name: 'Cache Manager', limits: [], configs: [] }, 'clear_events': { name: 'Clear Other Events', limits: ['admin'], configs: [] }, 'coach': { name: 'Coach View', limits: ['event', 'admin', 'results'], configs: ['settings', 'coach'] }, diff --git a/scripts/links.js b/scripts/links.js index 173ea00f..bbfd3368 100644 --- a/scripts/links.js +++ b/scripts/links.js @@ -59,6 +59,7 @@ var SELECTION_PAGES = { plot: ['event', 'user'], scatter: ['event', 'user'], coach: ['event', 'user'], + bracket: ['event', 'user'], results: ['event'], // file cycles: ['event'] // file } diff --git a/scripts/pwa.js b/scripts/pwa.js index 1effcf23..bdbede64 100644 --- a/scripts/pwa.js +++ b/scripts/pwa.js @@ -18,6 +18,7 @@ const CACHE_LIST = [ // scripts '/scripts/about.js', '/scripts/blank.js', + '/scripts/bracket.js', '/scripts/cache.js', '/scripts/coach.js', '/scripts/config-debug.js', From 51c60c55fbff248ac36f3df5dd6a28d4393c72af Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Sat, 8 Apr 2023 10:31:45 -0500 Subject: [PATCH 28/34] Bracket name and fixes --- scripts/bracket.js | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/scripts/bracket.js b/scripts/bracket.js index 5f7a1d48..63172c1e 100644 --- a/scripts/bracket.js +++ b/scripts/bracket.js @@ -26,7 +26,7 @@ function init_page() else if (first) { // build template - contents_card.innerHTML = `


vs

` + contents_card.innerHTML = `


vs

` let card = new Card('table', '') let edit = new Button('edit_coach', 'Edit Values') edit.link = `open_page('edit-coach')` @@ -68,6 +68,7 @@ function open_option(team) // find the templates let title = document.getElementById('next_match') + let bracket = document.getElementById('bracket') let alliance_box = document.getElementById('alliance') let partner_box = document.getElementById('partners') let opp_section = document.getElementById('opp_alliance') @@ -78,6 +79,7 @@ function open_option(team) if (team_matches.length === 0) { title.innerHTML = 'Team Eliminated' + bracket.innerHTML = '' alliance_box.innerHTML = '' partner_box.innerHTML = '' opp_section.innerHTML = '' @@ -87,6 +89,7 @@ function open_option(team) else if (team_matches[0].comp_level === 'qm') { title.innerHTML = 'Elims not yet started' + bracket.innerHTML = '' alliance_box.innerHTML = '' partner_box.innerHTML = '' opp_section.innerHTML = '' @@ -114,6 +117,21 @@ function open_option(team) alliance_box.style.color = alliance partner_box.innerHTML = partners.join(', ') + // determine bracket + let num = parseInt(match.short_match_name.substring(1)) + if (match.short_match_name.startsWith('F')) + { + bracket.innerHTML = 'Finals' + } + else if (num < 5 || num === 7 || num === 8 || num === 12) + { + bracket.innerHTML = 'Upper Bracket' + } + else + { + bracket.innerHTML = 'Lower Bracket' + } + if (opponents.length > 0 && !opponents.includes('0')) { // place alliance partners @@ -169,8 +187,10 @@ function open_option(team) // populate with opponent match opp_section.innerHTML = `Determined by ${winner ? 'WINNER' : 'LOSER'} of ${opp_match.match_name}` - opp_teams.innerHTML += `${opp_match.red_alliance.map(t => ``).join('')} - ${opp_match.blue_alliance.map(t => ``).join('')}
${t}
${t}
` + opp_section.style.color = 'black' + opp_teams.innerHTML = ` + ${opp_match.red_alliance.map(t => ``).join('')} + ${opp_match.blue_alliance.map(t => ``).join('')}
${t}
${t}
` build_table('red', opp_match.red_alliance) build_table('blue', opp_match.blue_alliance) From 4de974d11169eeab28e6d5da3f325054de7bc77f Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Sat, 8 Apr 2023 22:49:05 -0500 Subject: [PATCH 29/34] Checkbox and standard deviation fixes --- scripts/data.js | 26 ++++++++------------------ scripts/pivot.js | 2 +- scripts/scout.js | 2 +- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/scripts/data.js b/scripts/data.js index a472be36..90e53c95 100644 --- a/scripts/data.js +++ b/scripts/data.js @@ -83,7 +83,7 @@ class DAL } if (type === 'checkbox') { - ops = [false, true] + ops = ['No', 'Yes'] } if (typeof ops === 'undefined') { @@ -113,7 +113,7 @@ class DAL name: `${name} ${ops[i]}`, type: 'checkbox', negative: neg[i], - options: [], + options: ['No', 'Yes'], options_index: [], cycle: cycle } @@ -1664,7 +1664,8 @@ class DAL return '' } // map to option if available - else if (map && typeof val === 'number' && this.meta[id].options && val < this.meta[id].options.length && (this.meta[id].type === 'dropdown' || this.meta[id].type === 'select')) + else if (map && typeof val === 'number' && this.meta[id].options && val < this.meta[id].options.length && + (this.meta[id].type === 'dropdown' || this.meta[id].type === 'select') && stat !== 'stddev') { // don't map when an option was sent as the step let options = this.meta[id].options.map(op => op.toLowerCase()) @@ -1708,7 +1709,8 @@ class DAL return '' } // map to option if available - else if (map && typeof val === 'number' && this.meta[id].options && val < this.meta[id].options.length && (this.meta[id].type === 'dropdown' || this.meta[id].type === 'select')) + else if (map && typeof val === 'number' && this.meta[id].options && val < this.meta[id].options.length && + (this.meta[id].type === 'dropdown' || this.meta[id].type === 'select') && stat !== 'stddev') { // don't map when an option was sent as the step let options = this.meta[id].options.map(op => op.toLowerCase()) @@ -1834,12 +1836,6 @@ class DAL max_op = parseInt(op) } } - // convert checkbox values to booleans - if (meta.type === 'checkbox') - { - min_op = min_op == 'true' - max_op = max_op == 'true' - } // build data structure this.teams[team].stats[`${key}.mean`] = mode_op @@ -1850,7 +1846,7 @@ class DAL this.teams[team].stats[`${key}.low`] = 0 this.teams[team].stats[`${key}.high`] = options.length this.teams[team].stats[`${key}.total`] = total_op - this.teams[team].stats[`${key}.stddev`] = '---' + this.teams[team].stats[`${key}.stddev`] = std_dev(values) if (this.meta[`results.${key}`].type === 'select' || this.meta[`results.${key}`].type === 'dropdown') { let total = Object.values(counts).reduce((a, b) => a + b) @@ -1959,12 +1955,6 @@ class DAL max_op = parseInt(op) } } - // convert checkbox values to booleans - if (this.meta[id].type === 'checkbox') - { - min_op = min_op == 'true' - max_op = max_op == 'true' - } // build data structure global_stats[`${id}.mean`] = mode_op @@ -1975,7 +1965,7 @@ class DAL global_stats[`${id}.low`] = 0 global_stats[`${id}.high`] = options.length global_stats[`${id}.total`] = total_op - global_stats[`${id}.stddev`] = '---' + global_stats[`${id}.stddev`] = std_dev(values) if (this.meta[id.replace('stats.', 'results.')].type === 'select' || this.meta[id.replace('stats.', 'results.')].type === 'dropdown') { let total = Object.values(counts).reduce((a, b) => a + b) diff --git a/scripts/pivot.js b/scripts/pivot.js index 67bf45bf..70403c74 100644 --- a/scripts/pivot.js +++ b/scripts/pivot.js @@ -499,7 +499,7 @@ function build_table(sort_by=0, reverse=false, moved_idx=-1, placed_idx=-1) colors = [256, 0, 0, (mean - val) / (mean - min) / 2] } - if (dal.meta[key].negative === true) + if (dal.meta[key].negative === true || type === 'stddev') { colors = [colors[1], colors[0], colors[2], colors[3]] } diff --git a/scripts/scout.js b/scripts/scout.js index b825036d..3e0b889f 100644 --- a/scripts/scout.js +++ b/scripts/scout.js @@ -591,7 +591,7 @@ function generate_results() document.getElementById(id).selectedIndex = random_int(0, options.length - 1) break case 'number': - case 'silder': + case 'slider': let min = 0 let max = 10 if (options.length == 2) From 06b019bc2354edff782efc872c9be8b5df5e156e Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Sat, 8 Apr 2023 22:49:41 -0500 Subject: [PATCH 30/34] Changed default pivot filter selection to stats --- scripts/pivot.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/pivot.js b/scripts/pivot.js index 70403c74..8b24dc2e 100644 --- a/scripts/pivot.js +++ b/scripts/pivot.js @@ -34,7 +34,7 @@ function init_page() // add pick list filter add_dropdown_filter('picklist_filter', ['None'].concat(Object.keys(dal.picklists)), 'filter_teams()', false) - add_dropdown_filter('stat_filter', ['All', 'Stats', 'Pit', 'Rank', 'Meta'], 'filter_stats()', true) + add_dropdown_filter('stat_filter', ['All', 'Stats', 'Pit', 'Rank', 'Meta'], 'filter_stats()', true, 'Stats') // add select button above secondary list add_button_filter('select_toggle', '(De)Select All', 'toggle_select(false); select_none()', false) @@ -88,6 +88,7 @@ function init_page() } build_table(last_sort, last_reverse) + filter_stats() } /** From 2b90bee6888869d52cedc94b12447279d09d5495 Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Sat, 8 Apr 2023 23:05:17 -0500 Subject: [PATCH 31/34] Updated scouting config --- config/2023-config.json | 198 ++++++++++++++++++---------------------- 1 file changed, 91 insertions(+), 107 deletions(-) diff --git a/config/2023-config.json b/config/2023-config.json index f22678d2..04f4a3de 100644 --- a/config/2023-config.json +++ b/config/2023-config.json @@ -1,5 +1,5 @@ { - "version": "wr-2.2.1", + "version": "wr-230408", "note": [{ "name": "Notes", "id": "note_notes", @@ -8,6 +8,18 @@ "id": "note_notes_team", "cycle": false, "inputs": [{ + "name": "AS Auto Drops", + "id": "note_notes_team_auto_drops", + "type": "counter", + "default": 0, + "negative": true + }, { + "name": "AS Missed Auto Intakes", + "id": "note_notes_team_missed_auto_intakes", + "type": "counter", + "default": 0, + "negative": true + }, { "name": "Rank", "id": "note_notes_team_rank", "type": "slider", @@ -80,23 +92,19 @@ "id": "pit_pit_game_pieces", "cycle": false, "inputs": [{ - "name": "Handle Cones", - "id": "pit_pit_game_pieces_handle_cones", - "type": "checkbox", - "default": false, - "negative": false - }, { - "name": "Handle Tipped Cones", - "id": "pit_pit_game_pieces_handle_tipped_cones", - "type": "checkbox", - "default": false, - "negative": false + "name": "Preferred Cone Pickup", + "id": "pit_pit_game_pieces_preferred_cone_pickup", + "type": "select", + "colors": [""], + "options": ["None", "Double", "Single", "Floor"], + "default": "None" }, { - "name": "Handle Cubes", - "id": "pit_pit_game_pieces_handle_cubes", - "type": "checkbox", - "default": false, - "negative": false + "name": "Preferred Cube Pickup", + "id": "pit_pit_game_pieces_preferred_cube_pickup", + "type": "select", + "colors": [""], + "options": ["None", "Double", "Single", "Floor"], + "default": "None" }, { "name": "Grid Rows - Cone", "id": "pit_pit_game_pieces_grid_rows_cone", @@ -112,28 +120,46 @@ "options": ["Low", "Middle", "High"], "default": "" }] + }, { + "name": "Auto", + "id": "pit_pit_auto", + "cycle": false, + "inputs": [{ + "name": "Starting Positions With Engage", + "id": "pit_pit_auto_starting_positions_with_engage", + "type": "multiselect", + "colors": [""], + "options": ["LoadingZone", "ChargeStation", "BumpSide"], + "default": "" + }, { + "name": "GP Scored From Starting Position With Engage", + "id": "pit_pit_auto_gp_scored_from_starting_position_with_engage", + "type": "multicounter", + "negative": [false, false, false], + "options": ["LoadingZone", "ChargeStation", "BumpSide"], + "default": 0 + }, { + "name": "GP Scored From Starting Position No Engage", + "id": "pit_pit_auto_gp_scored_from_starting_position_no_engage", + "type": "multicounter", + "negative": [false, false, false], + "options": ["LoadingZone", "ChargeStation", "BumpSide"], + "default": 0 + }] }, { "name": "Other", "id": "pit_pit_other", "cycle": false, "inputs": [{ - "name": "Build Quality", - "id": "pit_pit_other_build_quality", - "type": "slider", - "options": [1, 10, 1], - "default": 5, - "negative": false + "name": "Changes From Last Event?", + "id": "pit_pit_other_changes_from_last_event", + "type": "text", + "default": "N/A" }, { "name": "Notes", "id": "pit_pit_other_notes", "type": "text", "default": "N/A" - }, { - "name": "Sleep Mode Disabled?", - "id": "pit_pit_other_sleep_mode_disabled", - "type": "checkbox", - "default": false, - "negative": false }] }] }], @@ -141,48 +167,40 @@ "name": "Auto", "id": "match_auto", "columns": [{ - "name": "Auto Cycling", - "id": "match_auto_auto_cycling", + "name": "Auto", + "id": "match_auto_auto", "cycle": true, "inputs": [{ - "name": "Game Piece", - "id": "match_auto_auto_cycling_game_piece", - "type": "select", - "options": ["Cone", "Cube"], - "colors": ["#FFD700", "#9932CC"], - "default": "Cone" - }, { - "name": "Grid Row", - "id": "match_auto_auto_cycling_grid_row", + "name": "Starting Location", + "id": "match_auto_auto_starting_location", "type": "select", + "disallow_default": true, "colors": [""], - "options": ["Low", "Middle", "High", "Thrown"], - "default": "High" - }] - }, { - "name": "Misc", - "id": "match_auto_misc", - "cycle": false, - "inputs": [{ - "name": "Auto Dropped", - "id": "match_auto_misc_auto_dropped", - "type": "counter", - "default": 0, - "negative": true - }] - }, { - "name": "Position", - "id": "match_auto_position", - "cycle": false, - "inputs": [{ + "options": ["Default", "LoadingZone", "CS", "BumpSide"], + "default": "Default" + }, { "name": "Mobility Bonus", - "id": "match_auto_position_mobility_bonus", + "id": "match_auto_auto_mobility_bonus", "type": "checkbox", "default": false, "negative": false }, { - "name": "Auto Charging Station", - "id": "match_auto_position_auto_charging_station", + "name": "Auto Scores", + "id": "match_auto_auto_auto_scores", + "type": "multicounter", + "negative": [false, false, false, false, false], + "options": ["HighCones", "HighCubes", "MidCones", "MidCubes", "Low"], + "default": 0 + }, { + "name": "Auto Misses", + "id": "match_auto_auto_auto_misses", + "type": "multicounter", + "negative": [true, true], + "options": ["DroppedScores", "MissedIntakes"], + "default": 0 + }, { + "name": "Auto Charge Station", + "id": "match_auto_auto_auto_charge_station", "type": "select", "disallow_default": true, "colors": [""], @@ -194,56 +212,22 @@ "name": "Tele", "id": "match_tele", "columns": [{ - "name": "Cycling", - "id": "match_tele_cycling", - "cycle": true, - "inputs": [{ - "name": "Game Piece", - "id": "match_tele_cycling_game_piece", - "type": "select", - "options": ["Cone", "Cube"], - "colors": ["#FFD700", "#9932CC"], - "default": "Cone" - }, { - "name": "Grid Row", - "id": "match_tele_cycling_grid_row", - "type": "select", - "colors": [""], - "options": ["Low", "Middle", "High", "Thrown"], - "default": "High" - }] - }, { - "name": "Driver", - "id": "match_tele_driver", + "name": "Scoring", + "id": "match_tele_scoring", "cycle": false, "inputs": [{ - "name": "Tele Dropped", - "id": "match_tele_driver_tele_dropped", + "name": "Tele Scoring", + "id": "match_tele_scoring_tele_scoring", + "type": "multicounter", + "negative": [false, false, false, false, false], + "options": ["HighCones", "HighCubes", "MidCones", "MidCubes", "Low"], + "default": 0 + }, { + "name": "Tele Drops", + "id": "match_tele_scoring_tele_drops", "type": "counter", "default": 0, "negative": true - }, { - "name": "Percent of Time on Offense", - "id": "match_tele_driver_percent_offense", - "type": "slider", - "options": [0, 100, 20], - "default": 0, - "negative": false - }, { - "name": "Percent of Time on Defense", - "id": "match_tele_driver_percent_defense", - "type": "slider", - "options": [0, 100, 20], - "default": 0, - "negative": false - }, { - "name": "Driver Skill", - "id": "match_tele_driver_driver_skill", - "type": "slider", - "options": [0, 10, 1], - "default": 0, - "negative": false, - "disallow_default": true }] }, { "name": "Post Match", From ef8c3f725978709cce84eb62303517938f1c3728 Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Sun, 9 Apr 2023 08:44:54 -0500 Subject: [PATCH 32/34] Reload page on import config --- scripts/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/index.js b/scripts/index.js index 41c6a9e2..02a90d40 100644 --- a/scripts/index.js +++ b/scripts/index.js @@ -410,6 +410,9 @@ function check_press(id) */ function import_config() { + // allow page reload to be run on complete + const callback = window.location.reload.bind(window.location) + let handler = new ZipHandler() handler.event = true handler.config = true @@ -418,7 +421,7 @@ function import_config() handler.settings = true handler.pictures = true handler.always_overwrite = true - handler.on_complete = process_files + handler.on_complete = callback handler.server = get_upload_addr() handler.import_zip_from_file() } From b85219b8db958308d666bb56d069ec5b7e07953b Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Sun, 9 Apr 2023 08:49:43 -0500 Subject: [PATCH 33/34] Import results on progress --- scripts/progress.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/scripts/progress.js b/scripts/progress.js index f685662b..22c26927 100644 --- a/scripts/progress.js +++ b/scripts/progress.js @@ -115,6 +115,10 @@ function init_page() page.add_column(pit) let pit_card = new Card('pits', pit_table) pit.add_input(pit_card) + + let import_all = new Button('import', 'Import All Results', 'import_results()') + pit.add_input(import_all) + let export_all = new Button('export', 'Export All Results', 'export_results()') pit.add_input(export_all) @@ -126,6 +130,25 @@ function init_page() document.body.innerHTML += page.toString } +/** + * function: import_results + * parameters: none + * returns: none + * description: Starts the zip import process for results. + */ +function import_results() +{ + // allow page reload to be run on complete + const callback = window.location.reload.bind(window.location) + + let handler = new ZipHandler() + handler.match = true + handler.note = true + handler.pit = true + handler.on_complete = callback + handler.import_zip_from_file() +} + /** * function: export_results * parameters: none From 6270d85a20ef8ee308ff0c0097e48419ef15f2be Mon Sep 17 00:00:00 2001 From: Liam Fruzyna Date: Mon, 10 Apr 2023 18:04:01 -0500 Subject: [PATCH 34/34] Updated version numbers --- config/2023-config.json | 2 +- scripts/pwa.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/2023-config.json b/config/2023-config.json index 04f4a3de..f2501a8b 100644 --- a/config/2023-config.json +++ b/config/2023-config.json @@ -1,5 +1,5 @@ { - "version": "wr-230408", + "version": "wr-2.3.0", "note": [{ "name": "Notes", "id": "note_notes", diff --git a/scripts/pwa.js b/scripts/pwa.js index bdbede64..fb837c68 100644 --- a/scripts/pwa.js +++ b/scripts/pwa.js @@ -5,7 +5,7 @@ * date: 2022-01-21 */ -const CACHE_NAME = 'wildrank-2.2.1' +const CACHE_NAME = 'wildrank-2.3.0' const CACHE_LIST = [ // html files '/',