-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[O2B-643] Run duration accept format HH:MM:SS #1464
base: main
Are you sure you want to change the base?
Changes from 55 commits
355ddac
9702196
4b87ce8
d436308
eda937b
8c18794
15b5dac
c3b2f86
e9e7420
5e98f04
3cbb87f
1a61b69
2d1731a
2475d19
b37573a
78950b5
7f03dff
58d31e5
191d434
fbdefc0
3661588
a06640d
21c1cf4
0ab6860
144317c
40b70e2
68a01d7
ff0da59
7d57685
71cb30d
14fc5a8
6dda2bc
e639db8
1d5e0c7
cd9d679
c4c9fc7
b59e0d2
a4933f2
5d6c941
fe67005
f165e23
52e7bf6
318d0a5
7d05396
a4843f3
6b013dd
c353f54
73425be
c4c70dd
2507a4a
e6763c6
a908084
bf412c4
2ea7b4a
76905be
eb7ae9f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,26 +11,76 @@ | |
* or submit itself to any jurisdiction. | ||
*/ | ||
|
||
import { amountFilter } from '../common/filters/amountFilter.js'; | ||
import { h } from '/js/src/index.js'; | ||
import { comparisonOperatorFilter } from '../common/filters/comparisonOperatorFilter.js'; | ||
|
||
/** | ||
* Returns the run duration filter component | ||
* Returns the duration filter component | ||
* | ||
* @param {RunsOverviewModel} runModel the runs model object | ||
* | ||
* @return {vnode} the duration filter | ||
* @param {DurationFilterModel} durationFilterModel the duration filter model | ||
* @return {Component} the duration filter | ||
*/ | ||
export const durationFilter = (runModel) => amountFilter( | ||
runModel.runDurationFilter, | ||
(filter) => { | ||
runModel.runDurationFilter = filter; | ||
}, | ||
{ | ||
operatorAttributes: { | ||
id: 'duration-operator', | ||
}, | ||
limitAttributes: { | ||
id: 'duration-limit', | ||
}, | ||
}, | ||
); | ||
export const durationFilter = (durationFilterModel) => { | ||
const { durationInputModel, operatorSelectionModel } = durationFilterModel; | ||
|
||
const { hours, minutes, seconds } = durationInputModel.raw; | ||
|
||
/** | ||
* Return oninput handler for given time unit | ||
* | ||
* @param {'hours'|'minutes'|'seconds'} unitName time unit | ||
* @return {function(InputEvent, void)} oninput handler for input for given time unit | ||
*/ | ||
const updateInputModelHandlerByTimeUnit = (unitName) => (e) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function seems to add more complexity than it brings value I think |
||
const { value } = e.target; | ||
const parsedValue = Number(value); | ||
if (value.length > 0 || 0 <= parsedValue && (unitName === 'hours' || parsedValue < 60)) { | ||
durationInputModel.update({ [unitName]: value.length > 0 ? parsedValue : null }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doing so, if you delete a value, update will not be triggered, so it will be put back to previous value. |
||
} else { | ||
durationFilterModel.visualChange$.notify(); | ||
} | ||
}; | ||
|
||
const hoursInput = h('input.flex-grow', { | ||
id: 'hours-input', | ||
type: 'number', | ||
min: 0, | ||
value: hours, | ||
oninput: updateInputModelHandlerByTimeUnit('hours'), | ||
}); | ||
const minutesInput = h('input.flex-grow', { | ||
id: 'minutes-input', | ||
type: 'number', | ||
min: 0, | ||
max: 59, | ||
value: minutes, | ||
oninput: updateInputModelHandlerByTimeUnit('minutes'), | ||
}, 'm'); | ||
const secondsInput = h('input.flex-grow', { | ||
id: 'seconds-input', | ||
type: 'number', | ||
min: 0, | ||
max: 59, | ||
value: seconds, | ||
oninput: updateInputModelHandlerByTimeUnit('seconds'), | ||
}, 's'); | ||
|
||
const inputs = h('.flex-row.w-100', [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is w-100 usefull? Can't we use flex-grow or equivalent instead? |
||
hoursInput, | ||
minutesInput, | ||
secondsInput, | ||
h('.flex-row.items-center.p2', [ | ||
h('label', { for: 'hours-input' }, 'h'), | ||
':', | ||
h('label', { for: 'minutes-input' }, 'm'), | ||
':', | ||
h('label', { for: 'seconds-input' }, 's'), | ||
]), | ||
]); | ||
|
||
return comparisonOperatorFilter( | ||
inputs, | ||
operatorSelectionModel.selected[0], | ||
(operator) => operatorSelectionModel.select(operator), | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/** | ||
* @license | ||
* Copyright CERN and copyright holders of ALICE O2. This software is | ||
* distributed under the terms of the GNU General Public License v3 (GPL | ||
* Version 3), copied verbatim in the file "COPYING". | ||
* | ||
* See http://alice-o2.web.cern.ch/license for full licensing information. | ||
* | ||
* In applying this license CERN does not waive the privileges and immunities | ||
* granted to it by virtue of its status as an Intergovernmental Organization | ||
* or submit itself to any jurisdiction. | ||
*/ | ||
|
||
import { SelectionModel } from '../../../common/selection/SelectionModel.js'; | ||
|
||
/** | ||
* Model storing state of a selection of predefined comparison operators | ||
*/ | ||
export class ComparisonOperatorSelectionModel extends SelectionModel { | ||
/** | ||
* Constructor | ||
* @param {string} [defaultOperator = '='] one of ['<', '<=', '=', '>=', '>'] operators | ||
*/ | ||
constructor(defaultOperator = '=') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you don't override this parameter anywhere, simply don't add it |
||
super({ | ||
availableOptions: ['<', '<=', '=', '>=', '>'].map((operator) => ({ value: operator })), | ||
multiple: false, | ||
allowEmpty: false, | ||
defaultSelection: [{ value: defaultOperator }], | ||
}); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/** | ||
* @license | ||
* Copyright CERN and copyright holders of ALICE O2. This software is | ||
* distributed under the terms of the GNU General Public License v3 (GPL | ||
* Version 3), copied verbatim in the file "COPYING". | ||
* | ||
* See http://alice-o2.web.cern.ch/license for full licensing information. | ||
* | ||
* In applying this license CERN does not waive the privileges and immunities | ||
* granted to it by virtue of its status as an Intergovernmental Organization | ||
* or submit itself to any jurisdiction. | ||
*/ | ||
|
||
import { Observable } from '/js/src/index.js'; | ||
|
||
import { DurationInputModel } from '../../../common/form/inputs/DurationInputModel.js'; | ||
import { ComparisonOperatorSelectionModel } from './ComparisonOperatorSelectionModel.js'; | ||
|
||
/** | ||
* Duration filter model which stores time value and selected operator | ||
*/ | ||
export class DurationFilterModel extends Observable { | ||
/** | ||
* Constructor | ||
*/ | ||
constructor() { | ||
super(); | ||
this._visualChange$ = new Observable(); | ||
|
||
this._durationInputModel = new DurationInputModel(); | ||
this._durationInputModel.bubbleTo(this); | ||
this._operatorSelectionModel = new ComparisonOperatorSelectionModel(); | ||
this._operatorSelectionModel.observe(() => { | ||
if (this._durationInputModel.value === null) { | ||
this._visualChange$.notify(); | ||
} else { | ||
this.notify(); | ||
} | ||
}); | ||
Comment on lines
+33
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not how it should work I suppose. If operatorSelectionModel has visualChange you need to bubleUp this to the current visualChange, but not mix the global notify and the visual change |
||
} | ||
|
||
/** | ||
* Returns the observable notified any time there is a visual change which has no impact on the actual filter value | ||
* | ||
* @return {Observable} the observable | ||
*/ | ||
get visualChange$() { | ||
return this._visualChange$; | ||
} | ||
|
||
/** | ||
* Retrun duration input model | ||
* | ||
* @return {DurationInputModel} duration input model | ||
*/ | ||
get durationInputModel() { | ||
return this._durationInputModel; | ||
} | ||
|
||
/** | ||
* Return operator selection model | ||
* | ||
* @return {ComparisonOperatorSelectionModel} operator selection model | ||
*/ | ||
get operatorSelectionModel() { | ||
return this._operatorSelectionModel; | ||
} | ||
|
||
/** | ||
* States if the filter has been filled | ||
* | ||
* @return {boolean} true if the filter has been filled | ||
*/ | ||
isEmpty() { | ||
return this._durationInputModel.value === null; | ||
} | ||
|
||
/** | ||
* Reset the filter to its default value | ||
* | ||
* @return {void} | ||
*/ | ||
reset() { | ||
this._durationInputModel.reset(); | ||
this._operatorSelectionModel.reset(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
/** | ||
* @license | ||
* Copyright CERN and copyright holders of ALICE O2. This software is | ||
* distributed under the terms of the GNU General Public License v3 (GPL | ||
* Version 3), copied verbatim in the file "COPYING". | ||
* | ||
* See http://alice-o2.web.cern.ch/license for full licensing information. | ||
* | ||
* In applying this license CERN does not waive the privileges and immunities | ||
* granted to it by virtue of its status as an Intergovernmental Organization | ||
* or submit itself to any jurisdiction. | ||
*/ | ||
|
||
import { Observable } from '/js/src/index.js'; | ||
|
||
/** | ||
* @typedef DurationInputRawData | ||
* @property {number} hours the number of hours | ||
* @property {number} minutes the number of minutes, from range [0, 59] | ||
* @property {number} seconds the number of seconds, from range [0, 59] | ||
*/ | ||
|
||
/** | ||
* Store the duration input | ||
*/ | ||
export class DurationInputModel extends Observable { | ||
/** | ||
* Constructor | ||
*/ | ||
constructor() { | ||
super(); | ||
|
||
this._raw = { | ||
hours: null, | ||
minutes: null, | ||
seconds: null, | ||
}; | ||
|
||
/** | ||
* Timestamp (ms) | ||
* @type {number|null} | ||
* @private | ||
*/ | ||
this._value = null; | ||
} | ||
|
||
/** | ||
* Update the inputs raw values | ||
* @param {DurationInputRawData} raw the input raw values | ||
* @return {void} | ||
*/ | ||
update(raw) { | ||
try { | ||
this._raw = { ...this._raw, ...raw }; | ||
const { hours, minutes, seconds } = this._raw; | ||
if ((hours ?? minutes ?? seconds ?? null) === null) { | ||
this._value = null; | ||
} else { | ||
this._value = (hours || 0) * 60 * 60 * 1000 | ||
+ (minutes || 0) * 60 * 1000 | ||
+ (seconds || 0) * 1000; | ||
} | ||
} catch { | ||
this._value = null; | ||
} | ||
|
||
this.notify(); | ||
} | ||
|
||
/** | ||
* Reset the inputs to its initial state | ||
* @return {void} | ||
*/ | ||
reset() { | ||
this._raw = { | ||
hours: null, | ||
minutes: null, | ||
seconds: null, | ||
}; | ||
this._value = null; | ||
} | ||
|
||
/** | ||
* Returns the raw input values | ||
* @return {DurationInputRawData} the raw values | ||
*/ | ||
get raw() { | ||
return this._raw; | ||
} | ||
|
||
/** | ||
* Returns the current date represented by the inputs (null if no valid value is represented) | ||
* @return {number|null} the current value | ||
*/ | ||
get value() { | ||
return this._value; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Never mention what the function should be used for, only explain what it does.