Skip to content
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

Enable reading validation via admin input #989

Merged
merged 103 commits into from
Aug 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
e4600f3
Merge remote-tracking branch 'spearec/reactstrap' into new_UI_setChecks
codehomie1 Jul 24, 2023
c59f419
Set conditionSet through UI (Draft)
carlsonrob Jul 25, 2023
e85111a
Update
carlsonrob Jul 25, 2023
35c355d
Update
carlsonrob Jul 25, 2023
cfa6b71
added minVal condset val
codehomie1 Jul 25, 2023
53c6294
Merge branch 'new_UI_setChecks' of https://github.com/TrongQuocLe/OED…
codehomie1 Jul 25, 2023
197b8b8
change conditionSetMap to conditionSet
carlsonrob Jul 26, 2023
e79a85c
add default condset vals to admin Panel
codehomie1 Jul 27, 2023
0846e18
meter values default to admin values
codehomie1 Jul 27, 2023
eb3c78f
Merge branch 'OpenEnergyDashboard:development' into new_UI_setChecks
carlsonrob Jul 31, 2023
3cabd02
changed Meter Page UI
TrongQuocLe Jul 31, 2023
45cb757
resolve bugs
TrongQuocLe Jul 31, 2023
232d40c
Include disableChecks in db
carlsonrob Jul 31, 2023
2e67753
Add conditionSet objet to Mamac
carlsonrob Jul 31, 2023
b96b5cd
Update Mamac w/ disabledChecks
carlsonrob Jul 31, 2023
f252b4c
Add conditionSet object to Obvius
carlsonrob Jul 31, 2023
3bd3a60
Add conditionSet object to Egauge
carlsonrob Jul 31, 2023
406f19e
fix bugs
TrongQuocLe Jul 31, 2023
7178f68
test preference api to save admin minval to db
codehomie1 Jul 31, 2023
21e1af4
fixed merge conflict in createmetermodalcomponent
codehomie1 Jul 31, 2023
c631155
update UI
TrongQuocLe Aug 1, 2023
6cdbd82
Add disableChecks to conditionSet for Mamac, Obvius and Egauge
carlsonrob Aug 1, 2023
d8764da
Validate data if checks are enabled
carlsonrob Aug 1, 2023
bebe268
Define conditionSet inline
carlsonrob Aug 1, 2023
6138189
Update meter field names
carlsonrob Aug 1, 2023
dc0ff3c
default database for
TrongQuocLe Aug 1, 2023
761cdce
error to errors
TrongQuocLe Aug 1, 2023
ab039fc
fix name values
TrongQuocLe Aug 1, 2023
e83ad9b
made adminstate default same as db default
codehomie1 Aug 1, 2023
9600ad0
DB Update
carlsonrob Aug 1, 2023
93d379a
remove all disable checks in admin
TrongQuocLe Aug 1, 2023
beab172
test
TrongQuocLe Aug 2, 2023
7dc327e
test debug
TrongQuocLe Aug 2, 2023
382c3c3
threshold to reading gap
TrongQuocLe Aug 2, 2023
ceea178
remove todo regarding add conditionSet params
TrongQuocLe Aug 2, 2023
42a45cf
change wording
codehomie1 Aug 2, 2023
236c596
update preferences stuff
codehomie1 Aug 2, 2023
36bc969
Set default parameters for Meter
carlsonrob Aug 3, 2023
3eb6c20
Modified default values
carlsonrob Aug 3, 2023
b37a17d
added required, assigned moment for conditionSet
TrongQuocLe Aug 3, 2023
4141829
Update sql with default values
carlsonrob Aug 3, 2023
b4b9018
added default conditionSet in Meter.js models
TrongQuocLe Aug 3, 2023
8b116df
trying to debug
TrongQuocLe Aug 3, 2023
ede98d7
working admin.js
TrongQuocLe Aug 3, 2023
d3962fe
added moment default in admin.js
TrongQuocLe Aug 3, 2023
d6eeb8d
Placeholder update
carlsonrob Aug 3, 2023
bc36e85
update minval and maxval values
codehomie1 Aug 3, 2023
493ebaf
update create meters minval minval to bigint
codehomie1 Aug 3, 2023
72af2ec
Update minVal, maxVal default parameter in Meter constructor
carlsonrob Aug 3, 2023
293cd41
Update minVal, maxVal to bigInt in routes/meter
carlsonrob Aug 3, 2023
032b7d0
added bound validation maxError, minVal, maxVal
TrongQuocLe Aug 3, 2023
3f7b786
trying to git pull
TrongQuocLe Aug 3, 2023
7c66d01
added minVal, maxVal, maxError bounds validation
TrongQuocLe Aug 4, 2023
0676531
updated meter validation commennts
TrongQuocLe Aug 4, 2023
03f1f1f
added default conditionSet validation in admin pannel
TrongQuocLe Aug 4, 2023
e4274b2
removed debug console.log
TrongQuocLe Aug 4, 2023
abe3f8f
removed used comment in routes/meters.js
TrongQuocLe Aug 7, 2023
847a3f2
added a space removed on an import in PreferencesComponent.tsx
TrongQuocLe Aug 7, 2023
0e889e8
Reverse merging of tooltipmarkercomponent from eb3c78f74bc5e29a421b6c…
carlsonrob Aug 7, 2023
5ab3645
Change minError to maxError in meter.js
carlsonrob Aug 7, 2023
781c5bb
update validate meter params type
codehomie1 Aug 7, 2023
259a7ff
db validation for min_val , max_val
codehomie1 Aug 8, 2023
f221813
fix type to bigint
codehomie1 Aug 8, 2023
e29aada
Change minVal,maxVal to bigint to prevent error
carlsonrob Aug 8, 2023
4ee7c63
added maxDate and minDate validation in MeterModalComponent
TrongQuocLe Aug 8, 2023
907dc69
fix default reading value check type being string
TrongQuocLe Aug 9, 2023
ea82fb3
fixed code as suggested format
TrongQuocLe Aug 11, 2023
c7dca54
remove validIntervals as it's redundant in processData with msReading…
carlsonrob Aug 14, 2023
82121f3
remove comment for validIntervals
carlsonrob Aug 14, 2023
adcfc5e
try to resolve test
TrongQuocLe Aug 11, 2023
6b7ea04
Real Precision Change
carlsonrob Aug 11, 2023
5185ea2
remove unused comments
TrongQuocLe Aug 14, 2023
d6079a0
removed changes while testing
TrongQuocLe Aug 14, 2023
98f1807
Remove space
carlsonrob Aug 14, 2023
7fdb08f
Added default meter min date, max date validation
TrongQuocLe Aug 17, 2023
33230ee
Merge remote-tracking branch 'origin/development' into pr/carlsonrob/989
huss Aug 20, 2023
df9cfc8
add migration
huss Aug 20, 2023
e0d8522
split line to meet 150-character limit
TrongQuocLe Aug 22, 2023
9dfd12f
add braces and TODO for preferences
TrongQuocLe Aug 22, 2023
2835942
Remove tab
carlsonrob Aug 22, 2023
6340b00
Put UpdateDefaultMeterMaximumErrorsAction after UpdateDefaultMeterRea…
carlsonrob Aug 22, 2023
cfa4da9
Print meterName variable
carlsonrob Aug 22, 2023
788c20a
parseFloat to parseInt
carlsonrob Aug 22, 2023
dc224cf
create and rename constants
TrongQuocLe Aug 22, 2023
c6bc1e5
utilize moment functions for validation in Meter
TrongQuocLe Aug 22, 2023
6c84e37
apply similar changes in Meter to preferences
TrongQuocLe Aug 22, 2023
28e1746
Merge branch 'OpenEnergyDashboard:development' into new_UI_setChecks
TrongQuocLe Aug 22, 2023
c2b6896
Add new translation keys in other languages.
TrongQuocLe Aug 22, 2023
ff35fb8
Change data type for min and max value in database
TrongQuocLe Aug 22, 2023
e63321b
Correct timestamp reference in error message
TrongQuocLe Aug 22, 2023
6d721aa
Integrate site preferences when instantiating a new Meter object
carlsonrob Aug 22, 2023
752d941
Add meterName parameter to validateReadings
carlsonrob Aug 23, 2023
8f20f9c
Append errMsg from validateReadings onto msgTotal in processData
carlsonrob Aug 24, 2023
10b0d8d
Remove comment
carlsonrob Aug 24, 2023
ebd5f9d
Add default disable checks
TrongQuocLe Aug 23, 2023
5992b92
Add default disable checks
TrongQuocLe Aug 24, 2023
dcd0a8b
Fix TypeScript error by adding type guard for 'min' and 'max' properties
carlsonrob Aug 24, 2023
8f8b7db
reuse value set in variable
huss Aug 24, 2023
07fac64
non-en has same order
huss Aug 24, 2023
5a21bdb
Fix lint error
huss Aug 24, 2023
a59ab93
update migrations
huss Aug 24, 2023
48bd778
add missing JSDoc param
huss Aug 24, 2023
c90e2c5
blank line in validate html
huss Aug 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
73 changes: 72 additions & 1 deletion src/client/app/actions/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,34 @@ export function updateDefaultMeterReadingFrequency(defaultMeterReadingFrequency:
return { type: ActionType.UpdateDefaultMeterReadingFrequency, defaultMeterReadingFrequency };
}

export function updateDefaultMeterMinimumValue(defaultMeterMinimumValue: number): t.UpdateDefaultMeterMinimumValueAction {
return { type: ActionType.UpdateDefaultMeterMinimumValue, defaultMeterMinimumValue };
}

export function updateDefaultMeterMaximumValue(defaultMeterMaximumValue: number): t.UpdateDefaultMeterMaximumValueAction {
return { type: ActionType.UpdateDefaultMeterMaximumValue, defaultMeterMaximumValue };
}

export function updateDefaultMeterMinimumDate(defaultMeterMinimumDate: string): t.UpdateDefaultMeterMinimumDateAction {
return { type: ActionType.UpdateDefaultMeterMinimumDate, defaultMeterMinimumDate };
}

export function updateDefaultMeterMaximumDate(defaultMeterMaximumDate: string): t.UpdateDefaultMeterMaximumDateAction {
return { type: ActionType.UpdateDefaultMeterMaximumDate, defaultMeterMaximumDate };
}

export function updateDefaultMeterReadingGap(defaultMeterReadingGap: number): t.UpdateDefaultMeterReadingGapAction {
return { type: ActionType.UpdateDefaultMeterReadingGap, defaultMeterReadingGap };
}

export function updateDefaultMeterMaximumErrors(defaultMeterMaximumErrors: number): t.UpdateDefaultMeterMaximumErrorsAction {
return { type: ActionType.UpdateDefaultMeterMaximumErrors, defaultMeterMaximumErrors };
}

export function updateDefaultMeterDisableChecks(defaultMeterDisableChecks: boolean): t.UpdateDefaultMeterDisableChecksAction {
return { type: ActionType.UpdateDefaultMeterDisableChecks, defaultMeterDisableChecks };
}

function requestPreferences(): t.RequestPreferencesAction {
return { type: ActionType.RequestPreferences };
}
Expand Down Expand Up @@ -103,14 +131,50 @@ function fetchPreferences(): Thunk {
}
};
}
// TODO: Add warning for invalid data in admin panel src/client/app/components/admin/PreferencesComponent.tsx
/* Validates preferences
Create Preferences Validation:
Mininum Value cannot bigger than Maximum Value
Minimum Value and Maximum Value must be between valid input
Minimum Date and Maximum cannot be blank
Minimum Date cannot be after Maximum Date
Minimum Date and Maximum Value must be between valid input
Maximum No of Error must be between 0 and valid input
*/

function validPreferences(state: State) {
const MIN_VAL = Number.MIN_SAFE_INTEGER;
const MAX_VAL = Number.MAX_SAFE_INTEGER;
const MIN_DATE_MOMENT = moment(0).utc();
const MAX_DATE_MOMENT = moment(0).utc().add(5000, 'years');
const MAX_ERRORS = 75;
if (state.admin.defaultMeterReadingGap >= 0 &&
state.admin.defaultMeterMinimumValue >= MIN_VAL &&
state.admin.defaultMeterMinimumValue <= state.admin.defaultMeterMaximumValue &&
state.admin.defaultMeterMinimumValue <= MAX_VAL &&
state.admin.defaultMeterMinimumDate !== '' &&
state.admin.defaultMeterMaximumDate !== '' &&
moment(state.admin.defaultMeterMinimumDate).isValid() &&
moment(state.admin.defaultMeterMaximumDate).isValid() &&
moment(state.admin.defaultMeterMinimumDate).isSameOrAfter(MIN_DATE_MOMENT) &&
moment(state.admin.defaultMeterMinimumDate).isSameOrBefore(moment(state.admin.defaultMeterMaximumDate)) &&
moment(state.admin.defaultMeterMaximumDate).isSameOrBefore(MAX_DATE_MOMENT) &&
(state.admin.defaultMeterMaximumErrors >= 0 && state.admin.defaultMeterMaximumErrors <= MAX_ERRORS)) {
return true;
} else {
return false;
}
}
/**
* Submits preferences stored in the state to the API to be stored in the database
*/
export function submitPreferences() {
return async (dispatch: Dispatch, getState: GetState) => {
const state = getState();
try {
if (!validPreferences(state)) {
throw new Error('invalid input');
}
const preferences = await preferencesApi.submitPreferences({
displayTitle: state.admin.displayTitle,
defaultChartToRender: state.admin.defaultChartToRender,
Expand All @@ -121,7 +185,14 @@ export function submitPreferences() {
defaultFileSizeLimit: state.admin.defaultFileSizeLimit,
defaultAreaNormalization: state.admin.defaultAreaNormalization,
defaultAreaUnit: state.admin.defaultAreaUnit,
defaultMeterReadingFrequency: state.admin.defaultMeterReadingFrequency
defaultMeterReadingFrequency: state.admin.defaultMeterReadingFrequency,
defaultMeterMinimumValue: state.admin.defaultMeterMinimumValue,
defaultMeterMaximumValue: state.admin.defaultMeterMaximumValue,
defaultMeterMinimumDate: state.admin.defaultMeterMinimumDate,
defaultMeterMaximumDate: state.admin.defaultMeterMaximumDate,
defaultMeterReadingGap: state.admin.defaultMeterReadingGap,
defaultMeterMaximumErrors: state.admin.defaultMeterMaximumErrors,
defaultMeterDisableChecks: state.admin.defaultMeterDisableChecks
});
// Only return the defaultMeterReadingFrequency because the value from the DB
// generally differs from what the user input so update state with DB value.
Expand Down
2 changes: 1 addition & 1 deletion src/client/app/components/GraphicRateMenuComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,4 @@ export default function GraphicRateMenuComponent() {
}
</div>
);
}
}
149 changes: 148 additions & 1 deletion src/client/app/components/admin/PreferencesComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@ import {
UpdateDefaultFileSizeLimit,
ToggleDefaultAreaNormalizationAction,
UpdateDefaultAreaUnitAction,
UpdateDefaultMeterReadingFrequencyAction
UpdateDefaultMeterReadingFrequencyAction,
UpdateDefaultMeterMinimumValueAction,
UpdateDefaultMeterMaximumValueAction,
UpdateDefaultMeterMinimumDateAction,
UpdateDefaultMeterMaximumDateAction,
UpdateDefaultMeterReadingGapAction,
UpdateDefaultMeterMaximumErrorsAction,
UpdateDefaultMeterDisableChecksAction

} from '../../types/redux/admin';
import { removeUnsavedChanges, updateUnsavedChanges } from '../../actions/unsavedWarning';
import { defineMessages, FormattedMessage, injectIntl, WrappedComponentProps } from 'react-intl';
Expand All @@ -24,6 +32,8 @@ import TimeZoneSelect from '../TimeZoneSelect';
import store from '../../index';
import { fetchPreferencesIfNeeded, submitPreferences } from '../../actions/admin';
import { AreaUnitType } from '../../utils/getAreaUnitConversion';
import translate from '../../utils/translate';
import { TrueFalseType } from '../../types/items';

interface PreferencesProps {
displayTitle: string;
Expand All @@ -37,6 +47,13 @@ interface PreferencesProps {
defaultFileSizeLimit: number;
defaultAreaUnit: AreaUnitType;
defaultMeterReadingFrequency: string;
defaultMeterMinimumValue: number;
defaultMeterMaximumValue: number;
defaultMeterMinimumDate: string;
defaultMeterMaximumDate: string;
defaultMeterReadingGap: number;
defaultMeterMaximumErrors: number;
defaultMeterDisableChecks: boolean;
updateDisplayTitle(title: string): UpdateDisplayTitleAction;
updateDefaultChartType(defaultChartToRender: ChartTypes): UpdateDefaultChartToRenderAction;
toggleDefaultBarStacking(): ToggleDefaultBarStackingAction;
Expand All @@ -48,10 +65,18 @@ interface PreferencesProps {
updateDefaultFileSizeLimit(defaultFileSizeLimit: number): UpdateDefaultFileSizeLimit;
updateDefaultAreaUnit(defaultAreaUnit: AreaUnitType): UpdateDefaultAreaUnitAction;
updateDefaultMeterReadingFrequency(defaultMeterReadingFrequency: string): UpdateDefaultMeterReadingFrequencyAction;
updateDefaultMeterMinimumValue(defaultMeterMinimumValue : number): UpdateDefaultMeterMinimumValueAction;
updateDefaultMeterMaximumValue(defaultMeterMaximumValue: number): UpdateDefaultMeterMaximumValueAction;
updateDefaultMeterMinimumDate(defaultMeterMinimumDate: string): UpdateDefaultMeterMinimumDateAction;
updateDefaultMeterMaximumDate(defaultMeterMaximumDate: string): UpdateDefaultMeterMaximumDateAction;
updateDefaultMeterReadingGap(defaultMeterReadingGap: number): UpdateDefaultMeterReadingGapAction;
updateDefaultMeterMaximumErrors(defaultMeterMaximumErrors: number): UpdateDefaultMeterMaximumErrorsAction;
updateDefaultMeterDisableChecks(defaultMeterDisableChecks: boolean): UpdateDefaultMeterDisableChecksAction;
}

type PreferencesPropsWithIntl = PreferencesProps & WrappedComponentProps;

// TODO: Add warning for invalid data
class PreferencesComponent extends React.Component<PreferencesPropsWithIntl> {
constructor(props: PreferencesPropsWithIntl) {
super(props);
Expand All @@ -66,6 +91,13 @@ class PreferencesComponent extends React.Component<PreferencesPropsWithIntl> {
this.handleDefaultAreaNormalizationChange = this.handleDefaultAreaNormalizationChange.bind(this);
this.handleDefaultAreaUnitChange = this.handleDefaultAreaUnitChange.bind(this);
this.handleDefaultMeterReadingFrequencyChange = this.handleDefaultMeterReadingFrequencyChange.bind(this);
this.handleDefaultMeterMinimumValueChange = this.handleDefaultMeterMinimumValueChange.bind(this);
this.handleDefaultMeterMaximumValueChange = this.handleDefaultMeterMaximumValueChange.bind(this);
this.handleDefaultMeterMinimumDateChange = this.handleDefaultMeterMinimumDateChange.bind(this);
this.handleDefaultMeterMaximumDateChange = this.handleDefaultMeterMaximumDateChange.bind(this);
this.handleDefaultMeterReadingGapChange = this.handleDefaultMeterReadingGapChange.bind(this);
this.handleDefaultMeterMaximumErrorsChange = this.handleDefaultMeterMaximumErrorsChange.bind(this);
this.handleDefaultMeterDisableChecksChange = this.handleDefaultMeterDisableChecksChange.bind(this);
}

public render() {
Expand Down Expand Up @@ -294,6 +326,85 @@ class PreferencesComponent extends React.Component<PreferencesPropsWithIntl> {
onChange={this.handleDefaultMeterReadingFrequencyChange}
/>
</div>
<div style={bottomPaddingStyle}>
<p style={titleStyle}>
<FormattedMessage id='default.meter.minimum.value' />:
</p>
<Input
type='number'
value={this.props.defaultMeterMinimumValue}
onChange={this.handleDefaultMeterMinimumValueChange}
maxLength={50}
/>
</div>
<div style={bottomPaddingStyle}>
<p style={titleStyle}>
<FormattedMessage id='default.meter.maximum.value' />:
</p>
<Input
type='number'
value={this.props.defaultMeterMaximumValue}
onChange={this.handleDefaultMeterMaximumValueChange}
maxLength={50}
/>
</div>
<div style={bottomPaddingStyle}>
<p style={titleStyle}>
<FormattedMessage id='default.meter.minimum.date' />:
</p>
<Input
type='text'
value={this.props.defaultMeterMinimumDate}
onChange={this.handleDefaultMeterMinimumDateChange}
placeholder='YYYY-MM-DD HH:MM:SS'
/>
</div>
<div style={bottomPaddingStyle}>
<p style={titleStyle}>
<FormattedMessage id='default.meter.maximum.date' />:
</p>
<Input
type='text'
value={this.props.defaultMeterMaximumDate}
onChange={this.handleDefaultMeterMaximumDateChange}
placeholder='YYYY-MM-DD HH:MM:SS'
/>
</div>
<div style={bottomPaddingStyle}>
<p style={titleStyle}>
<FormattedMessage id='default.meter.reading.gap' />:
</p>
<Input
type='number'
value={this.props.defaultMeterReadingGap}
onChange={this.handleDefaultMeterReadingGapChange}
maxLength={50}
/>
</div>
<div style={bottomPaddingStyle}>
<p style={titleStyle}>
<FormattedMessage id='default.meter.maximum.errors' />:
</p>
<Input
type='number'
value={this.props.defaultMeterMaximumErrors}
onChange={this.handleDefaultMeterMaximumErrorsChange}
maxLength={50}
/>
</div>
<div style={bottomPaddingStyle}>
<p style={titleStyle}>
<FormattedMessage id='default.meter.disable.checks' />:
</p>
<Input
type='select'
value={this.props.defaultMeterDisableChecks?.toString()}
onChange={this.handleDefaultMeterDisableChecksChange}>
{Object.keys(TrueFalseType).map(key => {
return (<option value={key} key={key}>{translate(`TrueFalseType.${key}`)}</option>)
})}
</Input>
</div>
<Button
type='submit'
onClick={this.handleSubmitPreferences}
Expand Down Expand Up @@ -379,6 +490,42 @@ class PreferencesComponent extends React.Component<PreferencesPropsWithIntl> {
this.props.updateDefaultMeterReadingFrequency(e.target.value);
this.updateUnsavedChanges();
}

private handleDefaultMeterMinimumValueChange(e: { target: HTMLInputElement; }) {
this.props.updateDefaultMeterMinimumValue(parseFloat(e.target.value));
this.updateUnsavedChanges();
}

private handleDefaultMeterMaximumValueChange(e: { target: HTMLInputElement; }) {
this.props.updateDefaultMeterMaximumValue(parseFloat(e.target.value));
this.updateUnsavedChanges();
}

private handleDefaultMeterMinimumDateChange(e: { target: HTMLInputElement; }) {
this.props.updateDefaultMeterMinimumDate(e.target.value);
this.updateUnsavedChanges();
}

private handleDefaultMeterMaximumDateChange(e: { target: HTMLInputElement; }) {
this.props.updateDefaultMeterMaximumDate(e.target.value);
this.updateUnsavedChanges();
}

private handleDefaultMeterReadingGapChange(e: { target: HTMLInputElement; }) {
this.props.updateDefaultMeterReadingGap(parseFloat(e.target.value));
this.updateUnsavedChanges();
}

private handleDefaultMeterMaximumErrorsChange(e: { target: HTMLInputElement; }) {
this.props.updateDefaultMeterMaximumErrors(parseInt(e.target.value));
this.updateUnsavedChanges();
}

private handleDefaultMeterDisableChecksChange(e: { target: HTMLInputElement; }) {
this.props.updateDefaultMeterDisableChecks(JSON.parse(e.target.value))
this.updateUnsavedChanges();
}

}

export default injectIntl(PreferencesComponent);