diff --git a/front/src/config/i18n/en.json b/front/src/config/i18n/en.json index a384f33efd..f979d58c49 100644 --- a/front/src/config/i18n/en.json +++ b/front/src/config/i18n/en.json @@ -2052,7 +2052,9 @@ "paused": "Paused", "exited": "Exited", "dead": "Dead" - } + }, + "batteryLevel": "Battery level alert", + "batteryLevelDescription": "At 09:00 AM, only on Saturday, a message will be sent to all admins as soon as the battery level drops below the chosen percentage" }, "newArea": { "createNewZoneButton": "Create new zone", diff --git a/front/src/config/i18n/fr.json b/front/src/config/i18n/fr.json index b8bf98d7bf..f80bf628c2 100644 --- a/front/src/config/i18n/fr.json +++ b/front/src/config/i18n/fr.json @@ -2053,7 +2053,9 @@ "paused": "En Pause", "exited": "Arrêté", "dead": "Mort" - } + }, + "batteryLevel": "Alerte sur le niveau de batterie", + "batteryLevelDescription": "A 09h00, uniquement le samedi, un message sera envoyer à tous les admins dès que le niveau du batterie parsera en dessous du pourcentage choisi" }, "newArea": { "createNewZoneButton": "Créer une zone", diff --git a/front/src/routes/settings/settings-system/SettingsSystemBatteryLevelWarning.jsx b/front/src/routes/settings/settings-system/SettingsSystemBatteryLevelWarning.jsx new file mode 100644 index 0000000000..20f65516e4 --- /dev/null +++ b/front/src/routes/settings/settings-system/SettingsSystemBatteryLevelWarning.jsx @@ -0,0 +1,130 @@ +import cx from 'classnames'; +import { Text } from 'preact-i18n'; +import { Component } from 'preact'; +import { SYSTEM_VARIABLE_NAMES } from '../../../../../server/utils/constants'; +import debounce from 'debounce'; +import { connect } from 'unistore/preact'; + +class SettingsSystemBatteryLevelWarning extends Component { + getBatteryLevelUnderWarning = async () => { + try { + const { value: batteryLevelUnderWarningThreshold } = await this.props.httpClient.get( + `/api/v1/variable/${SYSTEM_VARIABLE_NAMES.DEVICE_BATTERY_LEVEL_WARNING_THRESHOLD}` + ); + + const { value: batteryLevelUnderWarningEnabled } = await this.props.httpClient.get( + `/api/v1/variable/${SYSTEM_VARIABLE_NAMES.DEVICE_BATTERY_LEVEL_WARNING_ENABLED}` + ); + + this.setState({ + batteryLevelUnderWarningThreshold, + batteryLevelUnderWarningEnabled: batteryLevelUnderWarningEnabled === '1' + }); + } catch (e) { + console.error(e); + } + }; + + updateBatteryLevelUnderWarningThreshold = async e => { + await this.setState({ + batteryLevelUnderWarningThreshold: e.target.value, + savingBatteryLevelUnderWarning: true + }); + try { + await this.props.httpClient.post( + `/api/v1/variable/${SYSTEM_VARIABLE_NAMES.DEVICE_BATTERY_LEVEL_WARNING_THRESHOLD}`, + { + value: e.target.value + } + ); + } catch (e) { + console.error(e); + } + await this.setState({ + savingBatteryLevelUnderWarning: false + }); + }; + + debouncedUpdateBatteryLevelUnderWarningThreshold = debounce(this.updateBatteryLevelUnderWarningThreshold, 200); + + updateBatteryLevelUnderWarningEnabled = async () => { + const value = !this.state.batteryLevelUnderWarningEnabled; + await this.setState({ + batteryLevelUnderWarningEnabled: value, + savingBatteryLevelUnderWarning: true + }); + try { + await this.props.httpClient.post( + `/api/v1/variable/${SYSTEM_VARIABLE_NAMES.DEVICE_BATTERY_LEVEL_WARNING_ENABLED}`, + { + value + } + ); + } catch (e) { + console.error(e); + } + await this.setState({ + savingBatteryLevelUnderWarning: false + }); + }; + + componentDidMount() { + this.getBatteryLevelUnderWarning(); + } + + render({}, { batteryLevelUnderWarningThreshold, batteryLevelUnderWarningEnabled, savingBatteryLevelUnderWarning }) { + return ( +
+

+ + +

+
+
+

+ +

+
+ +
+ + + +
+
+
+
+
+ ); + } +} + +export default connect('httpClient', null)(SettingsSystemBatteryLevelWarning); diff --git a/front/src/routes/settings/settings-system/SettingsSystemContainers.jsx b/front/src/routes/settings/settings-system/SettingsSystemContainers.jsx new file mode 100644 index 0000000000..006326f053 --- /dev/null +++ b/front/src/routes/settings/settings-system/SettingsSystemContainers.jsx @@ -0,0 +1,54 @@ +import { connect } from 'unistore/preact'; +import { Component } from 'preact'; +import { Text } from 'preact-i18n'; +import cx from 'classnames'; + +class SettingsSystemContainers extends Component { + render({ systemContainers }, {}) { + return ( +
+

+ +

+
+ + + + + + + + + + {systemContainers && + systemContainers.map(container => ( + + + + + + ))} + +
+ + + + + +
{container.name}{container.created_at_formatted} + + + +
+
+
+ ); + } +} + +export default connect('systemContainers', null)(SettingsSystemContainers); diff --git a/front/src/routes/settings/settings-system/SettingsSystemDatabaseCleaning.jsx b/front/src/routes/settings/settings-system/SettingsSystemDatabaseCleaning.jsx new file mode 100644 index 0000000000..1f790f34b0 --- /dev/null +++ b/front/src/routes/settings/settings-system/SettingsSystemDatabaseCleaning.jsx @@ -0,0 +1,54 @@ +import { connect } from 'unistore/preact'; +import { Component } from 'preact'; +import { Text } from 'preact-i18n'; + +class SettingsSystemDatabaseCleaning extends Component { + constructor(props) { + super(props); + this.state = { + vacuumStarted: false + }; + } + + vacuumDatabase = async e => { + e.preventDefault(); + this.setState({ + vacuumStarted: true + }); + try { + await this.props.httpClient.post('/api/v1/system/vacuum'); + } catch (e) { + console.error(e); + } + }; + + render({}, { vacuumStarted }) { + return ( +
+

+ +

+ +
+
+

+ +

+

+ {vacuumStarted && ( +

+ +
+ )} + +

+
+
+
+ ); + } +} + +export default connect('httpClient', null)(SettingsSystemDatabaseCleaning); diff --git a/front/src/routes/settings/settings-system/SettingsSystemKeepAggregatedStates.jsx b/front/src/routes/settings/settings-system/SettingsSystemKeepAggregatedStates.jsx new file mode 100644 index 0000000000..ded8ce8a76 --- /dev/null +++ b/front/src/routes/settings/settings-system/SettingsSystemKeepAggregatedStates.jsx @@ -0,0 +1,98 @@ +import { connect } from 'unistore/preact'; +import { Component } from 'preact'; +import { Text } from 'preact-i18n'; +import { SYSTEM_VARIABLE_NAMES } from '../../../../../server/utils/constants'; +import get from 'get-value'; + +class SettingsSystemKeepAggregatedStates extends Component { + getDeviceAggregateStateHistoryPreference = async () => { + try { + const { value } = await this.props.httpClient.get( + `/api/v1/variable/${SYSTEM_VARIABLE_NAMES.DEVICE_AGGREGATE_STATE_HISTORY_IN_DAYS}` + ); + this.setState({ + deviceAggregateStateHistoryInDays: value + }); + } catch (e) { + console.error(e); + const status = get(e, 'response.status'); + if (status === 404) { + // Default value is -1 + this.setState({ + deviceAggregateStateHistoryInDays: '-1' + }); + } + } + }; + + updateDeviceAggregateStateHistory = async e => { + await this.setState({ + deviceAggregateStateHistoryInDays: e.target.value, + savingDeviceStateHistory: true + }); + try { + await this.props.httpClient.post( + `/api/v1/variable/${SYSTEM_VARIABLE_NAMES.DEVICE_AGGREGATE_STATE_HISTORY_IN_DAYS}`, + { + value: e.target.value + } + ); + } catch (e) { + console.error(e); + } + await this.setState({ + savingDeviceStateHistory: false + }); + }; + + componentDidMount() { + this.getDeviceAggregateStateHistoryPreference(); + } + + render({}, { deviceAggregateStateHistoryInDays }) { + return ( +
+

+ +

+ +
+
+

+ +

+ +
+
+
+ ); + } +} + +export default connect('httpClient', null)(SettingsSystemKeepAggregatedStates); diff --git a/front/src/routes/settings/settings-system/SettingsSystemKeepDeviceHistory.jsx b/front/src/routes/settings/settings-system/SettingsSystemKeepDeviceHistory.jsx new file mode 100644 index 0000000000..eed8498fb9 --- /dev/null +++ b/front/src/routes/settings/settings-system/SettingsSystemKeepDeviceHistory.jsx @@ -0,0 +1,83 @@ +import { connect } from 'unistore/preact'; +import { Component } from 'preact'; +import { Text } from 'preact-i18n'; +import { SYSTEM_VARIABLE_NAMES } from '../../../../../server/utils/constants'; + +class SettingsSystemKeepDeviceHistory extends Component { + getDeviceStateHistoryPreference = async () => { + try { + const { value } = await this.props.httpClient.get( + `/api/v1/variable/${SYSTEM_VARIABLE_NAMES.DEVICE_STATE_HISTORY_IN_DAYS}` + ); + this.setState({ + deviceStateHistoryInDays: value + }); + } catch (e) { + console.error(e); + } + }; + + updateDeviceStateHistory = async e => { + await this.setState({ + deviceStateHistoryInDays: e.target.value, + savingDeviceStateHistory: true + }); + try { + await this.props.httpClient.post(`/api/v1/variable/${SYSTEM_VARIABLE_NAMES.DEVICE_STATE_HISTORY_IN_DAYS}`, { + value: e.target.value + }); + } catch (e) { + console.error(e); + } + await this.setState({ + savingDeviceStateHistory: false + }); + }; + + componentDidMount() { + this.getDeviceStateHistoryPreference(); + } + + render({}, { deviceStateHistoryInDays }) { + return ( +
+

+ +

+ +
+
+

+ +

+ +
+
+
+ ); + } +} + +export default connect('httpClient', null)(SettingsSystemKeepDeviceHistory); diff --git a/front/src/routes/settings/settings-system/SettingsSystemOperations.jsx b/front/src/routes/settings/settings-system/SettingsSystemOperations.jsx new file mode 100644 index 0000000000..4aeef229cc --- /dev/null +++ b/front/src/routes/settings/settings-system/SettingsSystemOperations.jsx @@ -0,0 +1,49 @@ +import { connect } from 'unistore/preact'; +import { Component } from 'preact'; +import { Text } from 'preact-i18n'; + +class SettingsSystemOperations extends Component { + render({ systemInfos }, {}) { + return ( +
+

+ +

+ + {systemInfos && systemInfos.new_release_available === true && ( +
+
+

+ +

+

+ +

+
+
+ )} + + {systemInfos && systemInfos.new_release_available === false && ( +
+ + + + + + + +
+ + + + + +
+
+ )} +
+ ); + } +} + +export default connect('systemInfos', null)(SettingsSystemOperations); diff --git a/front/src/routes/settings/settings-system/SettingsSystemPage.jsx b/front/src/routes/settings/settings-system/SettingsSystemPage.jsx index 73ca6502c4..35901fada5 100644 --- a/front/src/routes/settings/settings-system/SettingsSystemPage.jsx +++ b/front/src/routes/settings/settings-system/SettingsSystemPage.jsx @@ -1,7 +1,13 @@ import { Text } from 'preact-i18n'; import SettingsLayout from '../SettingsLayout'; -import cx from 'classnames'; -import Select from 'react-select'; +import SettingsSystemBatteryLevelWarning from './SettingsSystemBatteryLevelWarning'; +import SettingsSystemContainers from './SettingsSystemContainers'; +import SettingsSystemOperations from './SettingsSystemOperations'; +import SettingsSystemTimezone from './SettingsSystemTimezone'; +import SettingsSystemKeepDeviceHistory from './SettingsSystemKeepDeviceHistory'; +import SettingsSystemKeepAggregatedStates from './SettingsSystemKeepAggregatedStates'; +import SettingsSystemTimeExpiryState from './SettingsSystemTimeExpiryState'; +import SettingsSystemDatabaseCleaning from './SettingsSystemDatabaseCleaning'; const SystemPage = ({ children, ...props }) => ( @@ -79,227 +85,16 @@ const SystemPage = ({ children, ...props }) => (
-
-

- -

- - {props.systemInfos && props.systemInfos.new_release_available === true && ( -
-
-

- -

-

- -

-
-
- )} - - {props.systemInfos && props.systemInfos.new_release_available === false && ( -
- - - - - - - -
- - - - - -
-
- )} -
- -
-

- -

-
-
- -

- - - -

- - - - - - - - - -
-
- -

- - - -

- -
-
- -

- - - -

-
- -
- - - -
-
-
-
- -

- - - -

-

- {props.vacuumStarted && ( -

- -
- )} - -

-
-
-
+ + + +
-
-

- -

-
- - - - - - - - - - {props.systemContainers && - props.systemContainers.map(container => ( - - - - - - ))} - -
- - - - - -
{container.name}{container.created_at_formatted} - - - -
-
-
+ + + +
diff --git a/front/src/routes/settings/settings-system/SettingsSystemTimeExpiryState.jsx b/front/src/routes/settings/settings-system/SettingsSystemTimeExpiryState.jsx new file mode 100644 index 0000000000..ff755910cf --- /dev/null +++ b/front/src/routes/settings/settings-system/SettingsSystemTimeExpiryState.jsx @@ -0,0 +1,82 @@ +import { connect } from 'unistore/preact'; +import { Component } from 'preact'; +import { Text } from 'preact-i18n'; +import { SYSTEM_VARIABLE_NAMES } from '../../../../../server/utils/constants'; + +class SettingsSystemTimeExpiryState extends Component { + getNumberOfHoursBeforeStateIsOutdated = async () => { + try { + const { value } = await this.props.httpClient.get( + `/api/v1/variable/${SYSTEM_VARIABLE_NAMES.DEVICE_STATE_NUMBER_OF_HOURS_BEFORE_STATE_IS_OUTDATED}` + ); + this.setState({ + numberOfHoursBeforeStateIsOutdated: value + }); + } catch (e) { + console.error(e); + // if variable doesn't exist, value is 48 + this.setState({ + numberOfHoursBeforeStateIsOutdated: 48 + }); + } + }; + + updateNumberOfHoursBeforeStateIsOutdated = async e => { + await this.setState({ + numberOfHoursBeforeStateIsOutdated: e.target.value, + savingNumberOfHourseBeforeStateIsOutdated: true + }); + try { + await this.props.httpClient.post( + `/api/v1/variable/${SYSTEM_VARIABLE_NAMES.DEVICE_STATE_NUMBER_OF_HOURS_BEFORE_STATE_IS_OUTDATED}`, + { + value: e.target.value + } + ); + } catch (e) { + console.error(e); + } + await this.setState({ + savingNumberOfHourseBeforeStateIsOutdated: false + }); + }; + + componentDidMount() { + this.getNumberOfHoursBeforeStateIsOutdated(); + } + + render({}, { numberOfHoursBeforeStateIsOutdated, savingNumberOfHourseBeforeStateIsOutdated }) { + return ( +
+

+ +

+ +
+
+

+ +

+
+ +
+ + + +
+
+
+
+
+ ); + } +} + +export default connect('httpClient', null)(SettingsSystemTimeExpiryState); diff --git a/front/src/routes/settings/settings-system/SettingsSystemTimezone.jsx b/front/src/routes/settings/settings-system/SettingsSystemTimezone.jsx new file mode 100644 index 0000000000..692c551657 --- /dev/null +++ b/front/src/routes/settings/settings-system/SettingsSystemTimezone.jsx @@ -0,0 +1,61 @@ +import { connect } from 'unistore/preact'; +import { Component } from 'preact'; +import { Text } from 'preact-i18n'; +import Select from 'react-select'; +import timezones from '../../../config/timezones'; +import { SYSTEM_VARIABLE_NAMES } from '../../../../../server/utils/constants'; + +class SettingsSystemTimezone extends Component { + getTimezone = async () => { + try { + const { value } = await this.props.httpClient.get(`/api/v1/variable/${SYSTEM_VARIABLE_NAMES.TIMEZONE}`); + const selectedTimezone = timezones.find(tz => tz.value === value); + if (selectedTimezone) { + this.setState({ + selectedTimezone + }); + } + } catch (e) { + console.error(e); + } + }; + + updateTimezone = async option => { + this.setState({ + savingTimezone: true, + selectedTimezone: option + }); + try { + await this.props.httpClient.post(`/api/v1/variable/${SYSTEM_VARIABLE_NAMES.TIMEZONE}`, { + value: option.value + }); + } catch (e) { + console.error(e); + } + }; + + componentDidMount() { + this.getTimezone(); + } + + render({}, { selectedTimezone }) { + return ( +
+

+ +

+ +
+
+

+ +

+