From 94d3c275f934617179579d72e0da7bbf2094421c Mon Sep 17 00:00:00 2001 From: Nate-Wessel Date: Fri, 12 Jul 2024 16:53:28 +0000 Subject: [PATCH 01/11] rename function --- frontend/src/spatialData.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/frontend/src/spatialData.js b/frontend/src/spatialData.js index 93d1650..2fbe65b 100644 --- a/frontend/src/spatialData.js +++ b/frontend/src/spatialData.js @@ -82,8 +82,9 @@ export class SpatialData { this.#factors.push(new HolidayOption(this,true)) this.#factors.push(new HolidayOption(this,false)) } - get travelTimeQueries(){ - // is the crossproduct of all complete/valid factors + updateQueries(){ + // this should be run any time the inputs change to keep the list fresh + // queries are the crossproduct of all complete/valid factors const crossProduct = [] this.corridors.filter(c=>c.isComplete).forEach( corridor => { this.timeRanges.filter(tr=>tr.isComplete).forEach( timeRange => { @@ -104,17 +105,20 @@ export class SpatialData { } ) } ) }) - // add new travelTimeRequests + // add any new travelTimeRequests crossProduct.forEach( TTQ => { if( ! this.#queries.has(TTQ.URI) ){ this.#queries.set(TTQ.URI,TTQ) } } ) - // remove old/modified travelTimeRequests + // remove any old/modified travelTimeRequests let currentURIs = new Set(crossProduct.map(TTI=>TTI.URI)) let currentKeys = [...this.#queries.keys()] currentKeys.filter( key => ! currentURIs.has(key) ) .forEach( key => this.#queries.delete(key) ) + } + get travelTimeQueries(){ + this.updateQueries() return [...this.#queries.values()].sort((a,b)=> a.URI < b.URI ? -1 : 1) } fetchAllResults(){ From e8cdca806e07dcda1e838b79effcae130ed91e41 Mon Sep 17 00:00:00 2001 From: Nate-Wessel Date: Fri, 12 Jul 2024 18:17:52 +0000 Subject: [PATCH 02/11] extract component into its own file --- frontend/src/Sidebar/ResultsContainer.jsx | 48 +++++++++++++++++++++++ frontend/src/Sidebar/index.jsx | 47 +--------------------- 2 files changed, 50 insertions(+), 45 deletions(-) create mode 100644 frontend/src/Sidebar/ResultsContainer.jsx diff --git a/frontend/src/Sidebar/ResultsContainer.jsx b/frontend/src/Sidebar/ResultsContainer.jsx new file mode 100644 index 0000000..e065c95 --- /dev/null +++ b/frontend/src/Sidebar/ResultsContainer.jsx @@ -0,0 +1,48 @@ +import { useContext, useState } from 'react' +import { DataContext } from '../Layout' +import BigButton from './BigButton' + + +export default function ResultsContainer(){ + const [ results, setResults ] = useState(undefined) + const [ isFetchingData, setIsFetchingData ] = useState(false) + const { data } = useContext(DataContext) + const numResults = data.travelTimeQueries.length + return ( +
+ {numResults} travel time{numResults == 1 ? '' : 's'} to estimate currently + {numResults > 0 && ! isFetchingData && + { + setResults(undefined) + setIsFetchingData(true) + data.fetchAllResults().then( () => { + setIsFetchingData(false) + setResults(data.travelTimeQueries) + } ) + }}> + Submit Query + + } + {isFetchingData && +

Please wait while your request is being processed

+ } + {results && <> + r.resultsRecord('json'))))}`} + > + + Download results as JSON + + + r.resultsRecord('csv')).join('\n'))}`} + > + + Download results as CSV + + + + } +
+ ) +} \ No newline at end of file diff --git a/frontend/src/Sidebar/index.jsx b/frontend/src/Sidebar/index.jsx index 642a6d4..78a2282 100644 --- a/frontend/src/Sidebar/index.jsx +++ b/frontend/src/Sidebar/index.jsx @@ -3,6 +3,7 @@ import { DataContext } from '../Layout' import FactorContainer from './FactorContainer' import BigButton from './BigButton' +import ResultsContainer from './ResultsContainer' import FactorList from './FactorList' import { restoreStateFromFile } from './restoreStateFromFile.js' import './sidebar.css' @@ -29,51 +30,7 @@ export default function SidebarContent(){
×
=
- - - ) -} - -function Results(){ - const [ results, setResults ] = useState(undefined) - const [ isFetchingData, setIsFetchingData ] = useState(false) - const { data } = useContext(DataContext) - const numResults = data.travelTimeQueries.length - return ( -
- {numResults} travel time{numResults == 1 ? '' : 's'} to estimate currently - {numResults > 0 && ! isFetchingData && - { - setResults(undefined) - setIsFetchingData(true) - data.fetchAllResults().then( () => { - setIsFetchingData(false) - setResults(data.travelTimeQueries) - } ) - }}> - Submit Query - - } - {isFetchingData && -

Please wait while your request is being processed

- } - {results && <> - r.resultsRecord('json'))))}`} - > - - Download results as JSON - - - r.resultsRecord('csv')).join('\n'))}`} - > - - Download results as CSV - - - - } +
) } From 5cd1789473cf1e7ffe9c4edd6a4a48d4609954d3 Mon Sep 17 00:00:00 2001 From: Nate-Wessel Date: Fri, 12 Jul 2024 19:08:19 +0000 Subject: [PATCH 03/11] show simple progress bar --- frontend/src/Sidebar/ResultsContainer.jsx | 35 +++++++++++++++-------- frontend/src/spatialData.js | 1 + 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/frontend/src/Sidebar/ResultsContainer.jsx b/frontend/src/Sidebar/ResultsContainer.jsx index e065c95..dc0af43 100644 --- a/frontend/src/Sidebar/ResultsContainer.jsx +++ b/frontend/src/Sidebar/ResultsContainer.jsx @@ -1,16 +1,21 @@ -import { useContext, useState } from 'react' +import { useContext, useState, useEffect } from 'react' import { DataContext } from '../Layout' import BigButton from './BigButton' - export default function ResultsContainer(){ const [ results, setResults ] = useState(undefined) const [ isFetchingData, setIsFetchingData ] = useState(false) + const [ doneCount, setDoneCount ] = useState(-1) const { data } = useContext(DataContext) const numResults = data.travelTimeQueries.length + useEffect(()=>{ + data.queue.on('active',()=>{ + setDoneCount(count => count + 1) + }) + },[]) return (
- {numResults} travel time{numResults == 1 ? '' : 's'} to estimate currently + {numResults} travel time{numResults == 1 ? '' : 's'} to be queried {numResults > 0 && ! isFetchingData && { setResults(undefined) @@ -23,26 +28,32 @@ export default function ResultsContainer(){ Submit Query } - {isFetchingData && -

Please wait while your request is being processed

- } + {isFetchingData && <> +

Finished fetching {doneCount}/{numResults} results

+ + } {results && <> r.resultsRecord('json'))))}`} > - - Download results as JSON - + Download results as JSON r.resultsRecord('csv')).join('\n'))}`} > - - Download results as CSV - + Download results as CSV }
) +} + +function ProgressBar({percentDone}){ + return ( + + + + + ) } \ No newline at end of file diff --git a/frontend/src/spatialData.js b/frontend/src/spatialData.js index 2fbe65b..f17ad41 100644 --- a/frontend/src/spatialData.js +++ b/frontend/src/spatialData.js @@ -128,4 +128,5 @@ export class SpatialData { .map( TTQ => () => TTQ.fetchData() ) ) } + get queue(){ return this.#queue } } From 4723b926a5076aebd5548606bf05ee8a2027d431 Mon Sep 17 00:00:00 2001 From: Nate-Wessel Date: Fri, 12 Jul 2024 19:11:42 +0000 Subject: [PATCH 04/11] only show ttq count once --- frontend/src/Sidebar/ResultsContainer.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/src/Sidebar/ResultsContainer.jsx b/frontend/src/Sidebar/ResultsContainer.jsx index dc0af43..6f0b36e 100644 --- a/frontend/src/Sidebar/ResultsContainer.jsx +++ b/frontend/src/Sidebar/ResultsContainer.jsx @@ -15,7 +15,9 @@ export default function ResultsContainer(){ },[]) return (
- {numResults} travel time{numResults == 1 ? '' : 's'} to be queried + {!isFetchingData && <> + {numResults} travel time{numResults == 1 ? '' : 's'} to be queried + } {numResults > 0 && ! isFetchingData && { setResults(undefined) From 297495803682e74330b407f3d022e0c048df5a7b Mon Sep 17 00:00:00 2001 From: Nate-Wessel Date: Fri, 12 Jul 2024 19:52:02 +0000 Subject: [PATCH 05/11] keep map of queries updated as factors change --- frontend/src/corridor.js | 1 + frontend/src/dateRange.js | 2 ++ frontend/src/days.js | 7 ++++++- frontend/src/factor.js | 4 ++++ frontend/src/spatialData.js | 6 +++++- frontend/src/timeRange.js | 2 ++ 6 files changed, 20 insertions(+), 2 deletions(-) diff --git a/frontend/src/corridor.js b/frontend/src/corridor.js index 47ba0f8..047cebd 100644 --- a/frontend/src/corridor.js +++ b/frontend/src/corridor.js @@ -29,6 +29,7 @@ export class Corridor extends Factor { .then( () => { // notify the layout that the path is ready to be rendered logActivity('shortest path returned') + this.notifyIsUpdated() } ) } get intersections(){ return [...this.#intersections.values()] } diff --git a/frontend/src/dateRange.js b/frontend/src/dateRange.js index bff9576..44ed166 100644 --- a/frontend/src/dateRange.js +++ b/frontend/src/dateRange.js @@ -26,10 +26,12 @@ export class DateRange extends Factor { } setStartDate(inputDate){ this.#startDate = inputDate + this.notifyIsUpdated() return this.#startDate } setEndDate(inputDate){ this.#endDate = inputDate + this.notifyIsUpdated() return this.#endDate } static dateFormatted(datetime){ diff --git a/frontend/src/days.js b/frontend/src/days.js index 933f921..f56916a 100644 --- a/frontend/src/days.js +++ b/frontend/src/days.js @@ -30,10 +30,15 @@ export class Days extends Factor { addDay(number){ if( daylist.map(d=>d.iso).includes(parseInt(number)) ){ this.#days.add(parseInt(number)) + this.notifyIsUpdated() } } removeDay(number){ - this.#days.delete(parseInt(number)) + let dayNum = parseInt(number) + if(this.#days.has(dayNum)){ + this.#days.delete(dayNum) + this.notifyIsUpdated() + } } hasDay(number){ return this.#days.has(parseInt(number)) diff --git a/frontend/src/factor.js b/frontend/src/factor.js index c9d76d9..892f592 100644 --- a/frontend/src/factor.js +++ b/frontend/src/factor.js @@ -27,4 +27,8 @@ export class Factor { render(){ // this will be overwritten but must be implemented return <> } + notifyIsUpdated(){ + // should be called when a factor has been updated and is complete + this.#dataContext.updateQueries() + } } \ No newline at end of file diff --git a/frontend/src/spatialData.js b/frontend/src/spatialData.js index f17ad41..47d4355 100644 --- a/frontend/src/spatialData.js +++ b/frontend/src/spatialData.js @@ -53,6 +53,7 @@ export class SpatialData { let days = new Days(this) this.#factors.push(days) days.activate() + this.updateQueries() // this is the only factor that starts out complete return days } get segments(){ @@ -63,6 +64,7 @@ export class SpatialData { } dropFactor(factor){ this.#factors = this.#factors.filter(f => f != factor) + this.updateQueries() } deactivateOtherFactors(factor){ this.#factors.forEach( f => { @@ -72,15 +74,18 @@ export class SpatialData { includeHolidays(){ this.holidayOptions.forEach(f => this.dropFactor(f)) this.#factors.push(new HolidayOption(this,true)) + this.updateQueries() } excludeHolidays(){ this.holidayOptions.forEach(f => this.dropFactor(f)) this.#factors.push(new HolidayOption(this,false)) + this.updateQueries() } includeAndExcludeHolidays(){ this.holidayOptions.forEach(f => this.dropFactor(f)) this.#factors.push(new HolidayOption(this,true)) this.#factors.push(new HolidayOption(this,false)) + this.updateQueries() } updateQueries(){ // this should be run any time the inputs change to keep the list fresh @@ -118,7 +123,6 @@ export class SpatialData { .forEach( key => this.#queries.delete(key) ) } get travelTimeQueries(){ - this.updateQueries() return [...this.#queries.values()].sort((a,b)=> a.URI < b.URI ? -1 : 1) } fetchAllResults(){ diff --git a/frontend/src/timeRange.js b/frontend/src/timeRange.js index ba0a628..b2b5f44 100644 --- a/frontend/src/timeRange.js +++ b/frontend/src/timeRange.js @@ -45,10 +45,12 @@ export class TimeRange extends Factor { } setStartTime(input){ this.#startTime = TimeRange.parseTime(input) + this.notifyIsUpdated() return this.#startTime } setEndTime(input){ this.#endTime = TimeRange.parseTime(input) + this.notifyIsUpdated() return this.#endTime } static timeFormatted(datetime){ From dcf99356f2a82d8c8359686843466914da15be79 Mon Sep 17 00:00:00 2001 From: Nate-Wessel Date: Fri, 12 Jul 2024 20:00:53 +0000 Subject: [PATCH 06/11] hide results buttons when any results unknown --- frontend/src/Sidebar/ResultsContainer.jsx | 2 +- frontend/src/spatialData.js | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/frontend/src/Sidebar/ResultsContainer.jsx b/frontend/src/Sidebar/ResultsContainer.jsx index 6f0b36e..4bab7c1 100644 --- a/frontend/src/Sidebar/ResultsContainer.jsx +++ b/frontend/src/Sidebar/ResultsContainer.jsx @@ -34,7 +34,7 @@ export default function ResultsContainer(){

Finished fetching {doneCount}/{numResults} results

} - {results && <> + {results && data.allQueriesHaveData && <> r.resultsRecord('json'))))}`} > diff --git a/frontend/src/spatialData.js b/frontend/src/spatialData.js index 47d4355..ef2e602 100644 --- a/frontend/src/spatialData.js +++ b/frontend/src/spatialData.js @@ -133,4 +133,11 @@ export class SpatialData { ) } get queue(){ return this.#queue } + get allQueriesHaveData(){ + return ( // some queries, all with data + this.#queries.size > 0 + && + [...this.#queries.values()].filter(q=>!q.hasData).length == 0 + ) + } } From 67ed3d0881a0958631ca4d1eb93073cbb315ea30 Mon Sep 17 00:00:00 2001 From: Nate-Wessel Date: Fri, 12 Jul 2024 20:22:07 +0000 Subject: [PATCH 07/11] dontcache stale results --- frontend/src/Sidebar/ResultsContainer.jsx | 21 +++++++++------------ frontend/src/spatialData.js | 9 ++++++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/frontend/src/Sidebar/ResultsContainer.jsx b/frontend/src/Sidebar/ResultsContainer.jsx index 4bab7c1..15fc682 100644 --- a/frontend/src/Sidebar/ResultsContainer.jsx +++ b/frontend/src/Sidebar/ResultsContainer.jsx @@ -3,45 +3,42 @@ import { DataContext } from '../Layout' import BigButton from './BigButton' export default function ResultsContainer(){ - const [ results, setResults ] = useState(undefined) const [ isFetchingData, setIsFetchingData ] = useState(false) - const [ doneCount, setDoneCount ] = useState(-1) + const [ progress, setProgress ] = useState(-1) const { data } = useContext(DataContext) - const numResults = data.travelTimeQueries.length useEffect(()=>{ data.queue.on('active',()=>{ - setDoneCount(count => count + 1) + setProgress( 100 * data.queryCountFinished / data.queryCount ) }) },[]) return (
{!isFetchingData && <> - {numResults} travel time{numResults == 1 ? '' : 's'} to be queried + {data.queryCount} travel time{data.queryCount == 1 ? '' : 's'} to be queried } - {numResults > 0 && ! isFetchingData && + {data.queryCount > 0 && ! isFetchingData && { setResults(undefined) setIsFetchingData(true) data.fetchAllResults().then( () => { setIsFetchingData(false) - setResults(data.travelTimeQueries) } ) }}> Submit Query } {isFetchingData && <> -

Finished fetching {doneCount}/{numResults} results

- +

Finished fetching {data.queryCountFinished}/{data.queryCount} results

+ } - {results && data.allQueriesHaveData && <> + {data.allQueriesHaveData && <>
r.resultsRecord('json'))))}`} + href={`data:text/plain;charset=utf-8,${encodeURIComponent(JSON.stringify(data.travelTimeQueries.map(r=>r.resultsRecord('json'))))}`} > Download results as JSON r.resultsRecord('csv')).join('\n'))}`} + href={`data:text/plain;charset=utf-8,${encodeURIComponent([...data.travelTimeQueries[0].resultsRecord('').keys()].join(',') + '\n' + data.travelTimeQueries.map(r=>r.resultsRecord('csv')).join('\n'))}`} > Download results as CSV diff --git a/frontend/src/spatialData.js b/frontend/src/spatialData.js index ef2e602..976c7a9 100644 --- a/frontend/src/spatialData.js +++ b/frontend/src/spatialData.js @@ -135,9 +135,12 @@ export class SpatialData { get queue(){ return this.#queue } get allQueriesHaveData(){ return ( // some queries, all with data - this.#queries.size > 0 - && - [...this.#queries.values()].filter(q=>!q.hasData).length == 0 + this.queryCount > 0 + && this.queryCount == this.queryCountFinished ) } + get queryCount(){ return this.#queries.size } + get queryCountFinished(){ + return [...this.#queries.values()].filter(q=>q.hasData).length + } } From e2c19fa1120be87954816b68a2edaa6640a4ade8 Mon Sep 17 00:00:00 2001 From: Nate-Wessel Date: Fri, 12 Jul 2024 20:26:38 +0000 Subject: [PATCH 08/11] hide request button when nothing needs to be requested --- frontend/src/Sidebar/ResultsContainer.jsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/frontend/src/Sidebar/ResultsContainer.jsx b/frontend/src/Sidebar/ResultsContainer.jsx index 15fc682..1e97309 100644 --- a/frontend/src/Sidebar/ResultsContainer.jsx +++ b/frontend/src/Sidebar/ResultsContainer.jsx @@ -16,16 +16,13 @@ export default function ResultsContainer(){ {!isFetchingData && <> {data.queryCount} travel time{data.queryCount == 1 ? '' : 's'} to be queried } - {data.queryCount > 0 && ! isFetchingData && + {data.queryCount > 0 && !isFetchingData && !data.allQueriesHaveData && { - setResults(undefined) setIsFetchingData(true) data.fetchAllResults().then( () => { setIsFetchingData(false) } ) - }}> - Submit Query - + }}>Submit Query } {isFetchingData && <>

Finished fetching {data.queryCountFinished}/{data.queryCount} results

From 3192d44c7a1f3c90b633ce3ded8abd16ed607a40 Mon Sep 17 00:00:00 2001 From: Nate-Wessel Date: Fri, 12 Jul 2024 20:36:43 +0000 Subject: [PATCH 09/11] remove unused import --- frontend/src/Sidebar/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Sidebar/index.jsx b/frontend/src/Sidebar/index.jsx index 78a2282..7e7ab91 100644 --- a/frontend/src/Sidebar/index.jsx +++ b/frontend/src/Sidebar/index.jsx @@ -1,4 +1,4 @@ -import { useContext, useState } from 'react' +import { useContext } from 'react' import { DataContext } from '../Layout' import FactorContainer from './FactorContainer' From fec031e8030603d09954d6742d2207327d33a1d8 Mon Sep 17 00:00:00 2001 From: Nate-Wessel Date: Fri, 12 Jul 2024 20:45:12 +0000 Subject: [PATCH 10/11] give method a better name --- frontend/src/corridor.js | 2 +- frontend/src/dateRange.js | 4 ++-- frontend/src/days.js | 4 ++-- frontend/src/factor.js | 4 ++-- frontend/src/timeRange.js | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/frontend/src/corridor.js b/frontend/src/corridor.js index 047cebd..431efe4 100644 --- a/frontend/src/corridor.js +++ b/frontend/src/corridor.js @@ -29,7 +29,7 @@ export class Corridor extends Factor { .then( () => { // notify the layout that the path is ready to be rendered logActivity('shortest path returned') - this.notifyIsUpdated() + this.hasUpdated() } ) } get intersections(){ return [...this.#intersections.values()] } diff --git a/frontend/src/dateRange.js b/frontend/src/dateRange.js index 44ed166..96b90ed 100644 --- a/frontend/src/dateRange.js +++ b/frontend/src/dateRange.js @@ -26,12 +26,12 @@ export class DateRange extends Factor { } setStartDate(inputDate){ this.#startDate = inputDate - this.notifyIsUpdated() + this.hasUpdated() return this.#startDate } setEndDate(inputDate){ this.#endDate = inputDate - this.notifyIsUpdated() + this.hasUpdated() return this.#endDate } static dateFormatted(datetime){ diff --git a/frontend/src/days.js b/frontend/src/days.js index f56916a..b798cc2 100644 --- a/frontend/src/days.js +++ b/frontend/src/days.js @@ -30,14 +30,14 @@ export class Days extends Factor { addDay(number){ if( daylist.map(d=>d.iso).includes(parseInt(number)) ){ this.#days.add(parseInt(number)) - this.notifyIsUpdated() + this.hasUpdated() } } removeDay(number){ let dayNum = parseInt(number) if(this.#days.has(dayNum)){ this.#days.delete(dayNum) - this.notifyIsUpdated() + this.hasUpdated() } } hasDay(number){ diff --git a/frontend/src/factor.js b/frontend/src/factor.js index 892f592..e46b1d2 100644 --- a/frontend/src/factor.js +++ b/frontend/src/factor.js @@ -27,8 +27,8 @@ export class Factor { render(){ // this will be overwritten but must be implemented return <> } - notifyIsUpdated(){ - // should be called when a factor has been updated and is complete + hasUpdated(){ + // should be called when a factor has been updated this.#dataContext.updateQueries() } } \ No newline at end of file diff --git a/frontend/src/timeRange.js b/frontend/src/timeRange.js index b2b5f44..22ef535 100644 --- a/frontend/src/timeRange.js +++ b/frontend/src/timeRange.js @@ -45,12 +45,12 @@ export class TimeRange extends Factor { } setStartTime(input){ this.#startTime = TimeRange.parseTime(input) - this.notifyIsUpdated() + this.hasUpdated() return this.#startTime } setEndTime(input){ this.#endTime = TimeRange.parseTime(input) - this.notifyIsUpdated() + this.hasUpdated() return this.#endTime } static timeFormatted(datetime){ From c2e3586de2195e77c5163fafe601dbc6db89604c Mon Sep 17 00:00:00 2001 From: Nate-Wessel Date: Fri, 12 Jul 2024 20:59:49 +0000 Subject: [PATCH 11/11] remember holidays! --- frontend/src/holidayOption.js | 2 +- frontend/src/spatialData.js | 29 +++++++++++++++++++++-------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/frontend/src/holidayOption.js b/frontend/src/holidayOption.js index f9c9d35..8a4773d 100644 --- a/frontend/src/holidayOption.js +++ b/frontend/src/holidayOption.js @@ -3,7 +3,7 @@ import { Factor } from './factor.js' export class HolidayOption extends Factor { #includeHolidays #dataContext - constructor(dataContext,includeHolidays){ + constructor(dataContext, includeHolidays){ super(dataContext) // store this here too to actually access the holiday data this.#dataContext = dataContext diff --git a/frontend/src/spatialData.js b/frontend/src/spatialData.js index 976c7a9..1533af4 100644 --- a/frontend/src/spatialData.js +++ b/frontend/src/spatialData.js @@ -72,20 +72,33 @@ export class SpatialData { } ) } includeHolidays(){ - this.holidayOptions.forEach(f => this.dropFactor(f)) - this.#factors.push(new HolidayOption(this,true)) + this.holidayOptions.forEach( factor => { + if(!factor.holidaysIncluded) this.dropFactor(factor) + } ) + if(this.holidayOptions.length == 0){ + this.#factors.push(new HolidayOption(this,true)) + } this.updateQueries() } excludeHolidays(){ - this.holidayOptions.forEach(f => this.dropFactor(f)) - this.#factors.push(new HolidayOption(this,false)) + this.holidayOptions.forEach( factor => { + if(factor.holidaysIncluded) this.dropFactor(factor) + } ) + if(this.holidayOptions.length == 0){ + this.#factors.push(new HolidayOption(this,false)) + } this.updateQueries() } includeAndExcludeHolidays(){ - this.holidayOptions.forEach(f => this.dropFactor(f)) - this.#factors.push(new HolidayOption(this,true)) - this.#factors.push(new HolidayOption(this,false)) - this.updateQueries() + console.assert(this.holidayOptions.length == 1) + // add a factor for whatever the opposite of the existing one is + this.#factors.push( + new HolidayOption( + this, + ! this.holidayOptions[0].holidaysIncluded + ) + ) + this.updateQueries() } updateQueries(){ // this should be run any time the inputs change to keep the list fresh