-
+
-
+ {showHistoryExpanded && !showAggregatedDataWarning && (
+
+
+
+ )}
+ {showHistoryExpanded && showAggregatedDataWarning && (
+
{"(ATTENTION: Données aggrégées sur l'intervalle, vous pouvez zoomer sur un intervalle plus petit pour voir les données réelles)"}
+ )}
+
{props.box.chart_type && (
-
+
+ {displayVariation && props.box.chart_type !== 'timeline' && emptySeries === false && (
+
+ {notNullNotUndefined(lastValueRounded) && !Number.isNaN(lastValueRounded) && (
+
+ {lastValueRounded}
+ {unit !== undefined && }
+
+ )}
+
0 && !variationDownIsPositive) || (variation < 0 && variationDownIsPositive),
+ [style.textYellow]: variation === 0,
+ [style.textRed]:
+ (variation > 0 && variationDownIsPositive) || (variation < 0 && !variationDownIsPositive)
+ })}
+ >
+ {variation !== undefined && (
+
+ {roundWith2DecimalIfNeeded(variation)}
+
+ {variation > 0 && (
+
)}
-
-
- {props.box.chart_type && (
-
- {displayVariation && props.box.chart_type !== 'timeline' && emptySeries === false && (
-
- {notNullNotUndefined(lastValueRounded) && !Number.isNaN(lastValueRounded) && (
-
- {lastValueRounded}
- {unit !== undefined && }
-
- )}
-
0 && !variationDownIsPositive) || (variation < 0 && variationDownIsPositive),
- [style.textYellow]: variation === 0,
- [style.textRed]:
- (variation > 0 && variationDownIsPositive) || (variation < 0 && !variationDownIsPositive)
- })}
- >
- {variation !== undefined && (
-
- {roundWith2DecimalIfNeeded(variation)}
-
- {variation > 0 && (
-
- )}
- {variation === 0 && (
-
- )}
- {variation < 0 && (
-
- )}
-
- )}
-
-
- )}
- {emptySeries === false && props.box.display_axes && (
-
- )}
+ )}
+ {emptySeries === false && props.box.display_axes && (
+
)}
@@ -555,34 +635,17 @@ class Chartbox extends Component {
)}
- {props.box.chart_type && (
-
- {emptySeries === true && (
-
- )}
- {emptySeries === false && !props.box.display_axes && (
-
- )}
-
+ {emptySeries === false && !props.box.display_axes && (
+
)}
diff --git a/front/src/components/boxs/chart/EditChart.jsx b/front/src/components/boxs/chart/EditChart.jsx
index d40c59f3cd..88f51fc871 100644
--- a/front/src/components/boxs/chart/EditChart.jsx
+++ b/front/src/components/boxs/chart/EditChart.jsx
@@ -573,7 +573,7 @@ class EditChart extends Component {
- {displayPreview &&
}
+ {displayPreview &&
}
{!displayPreview && (
))}
diff --git a/front/src/routes/dashboard/expanded-dashboard/index.js b/front/src/routes/dashboard/expanded-dashboard/index.js
new file mode 100644
index 0000000000..602457cddb
--- /dev/null
+++ b/front/src/routes/dashboard/expanded-dashboard/index.js
@@ -0,0 +1,515 @@
+import { Component } from 'preact';
+import { Text, Localizer } from 'preact-i18n';
+import { connect } from 'unistore/preact';
+import { route } from 'preact-router';
+import { Link } from 'preact-router/match';
+import cx from 'classnames';
+import style from './style.css';
+import Chart from '../../../components/boxs/chart/Chart';
+
+import DatePicker from 'react-datepicker';
+import 'react-datepicker/dist/react-datepicker.css';
+
+import { useState } from 'preact/hooks';
+
+const criteriaDateExpendOptions = [
+ { value: 'all', label:
},
+ { value: 'previous', label:
},
+ { value: 'current', label:
},
+ { value: 'next', label:
},
+ { value: 'before', label:
},
+ { value: 'after', label:
},
+ { value: 'between', label:
},
+ { value: 'custom', label:
}
+];
+const criteriaAggregateExpendOptions = [
+ { value: 'minute', label:
},
+ { value: 'hour', label:
},
+ { value: 'day', label:
},
+ { value: 'week', label:
},
+ { value: 'month', label:
},
+ { value: 'year', label:
},
+ { value: 'quarter', label:
},
+ { value: 'notAggregate', label:
}
+];
+
+const intervalUnit = [
+ { value: 'days', label:
},
+ { value: 'weeks', label:
},
+ { value: 'months', label:
},
+ { value: 'quarter', label:
},
+ { value: 'years', label:
}
+];
+const intervalUnitCurrent = [
+ { value: 'days', label:
},
+ { value: 'weeks', label:
},
+ { value: 'months', label:
},
+ { value: 'quarter', label:
},
+ { value: 'years', label:
}
+];
+
+const ChartBoxExpanded = ({ children, ...props }) => (
+
+ {console.log('props ChartBoxExpanded', props)}
+ {console.log('children ChartBoxExpanded', children)}
+ {console.log('this ChartBoxExpanded', this)}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {props.name} - {props.box.title}
+
+
+ {/* Future description ? */}
+ {/*
+
+
*/}
+ {props.dashboardAlreadyExistError && (
+
+
+
+ )}
+ {props.unknownError && (
+
+
+
+ )}
+ {/* Futures options */}
+ {/*
+
+
+ }
+ value={props.name}
+ onInput={props.updateName}
+ />
+
+
*/}
+
+ {/* Future options / Boutons */}
+ {/* */}
+
+
+
+
+
+
+
+
+
+);
+
+class ExpandedDashboardPage extends Component {
+ toggleDropdownGlobal = () => {
+ this.setState(prevState => ({
+ dropdownOpenGlobal: !prevState.dropdownOpenGlobal
+ }));
+ };
+ applyAndClose = () => {
+ console.log('applyAndClose');
+ this.setState({ dropdownOpenGlobal: false });
+ // Logique supplémentaire si besoin, comme l'appel à une fonction pour appliquer les critères sélectionnés.
+ };
+ toggleDropdownCriteriaDate = () => {
+ this.setState(prevState => ({
+ dropdownOpenCriteriaDate: !prevState.dropdownOpenCriteriaDate
+ }));
+ };
+ handleIntervalUnitChange = (event) => {
+ console.log('handleIntervalUnitChange', event.target.value);
+ this.setState({ boxOptions: { ...this.state.boxOptions, intervalUnit: event.target.value } });
+ };
+
+ handleCriteriaDateChange = (criteria) => {
+ this.setState({ selectedCriteriaDate: criteria, dropdownOpenCriteriaDate: false });
+ };
+ toggleDropdownCriteriaAggregate = () => {
+ this.setState(prevState => ({
+ dropdownOpenCriteriaAggregate: !prevState.dropdownOpenCriteriaAggregate
+ }));
+ };
+ handleCriteriaAggregateChange = (criteria) => {
+ this.setState({ selectedCriteriaAggregate: criteria, dropdownOpenCriteriaAggregate: false });
+ };
+
+ handleStartDateChange = (e) => {
+ let date;
+ if (e.target) {
+ date = e.target.valueAsDate;
+ } else {
+ date = e;
+ }
+ console.log('handleStartDateChange', date);
+ this.setState(prevState => {
+ if (prevState.boxOptions.endDate) {
+ const newEndDate = prevState.boxOptions.endDate || new Date(date.getTime() + prevState.boxOptions.interval * 60000);
+ return {
+ startDate: date,
+ endDate: newEndDate < date ? date : newEndDate
+ };
+ }
+ return {
+ startDate: date,
+ endDate: new Date()
+ };
+ });
+ };
+
+ handleEndDateChange = (e) => {
+ let date;
+ if (e.target) {
+ date = e.target.valueAsDate;
+ } else {
+ date = e;
+ }
+ console.log('handleEndDateChange', date);
+ this.setState(prevState => {
+ const boxOptions = prevState.boxOptions;
+ console.log('handleEndDateChange prevState', prevState);
+ boxOptions.endDate = new Date(date);
+ return boxOptions;
+ if (boxOptions.startDate) {
+ const newStartDate = boxOptions.startDate || new Date(date.getTime() - boxOptions.interval * 60000);
+
+ return {
+ endDate: date,
+ startDate: newStartDate > date ? date : newStartDate
+ };
+ }
+ return {
+ endDate: date
+ };
+ });
+ };
+ calculateNewDates = (startDate, endDate, interval, direction) => {
+ let newStartDate, newEndDate;
+ const multiplier = direction === 'previous' ? -1 : 1;
+
+ if (startDate && !endDate) {
+ newStartDate = new Date(startDate.getTime() + multiplier * interval * 60000);
+ newEndDate = new Date(startDate.getTime());
+ } else if (!startDate && endDate) {
+ newStartDate = new Date(endDate.getTime() + multiplier * interval * 60000);
+ newEndDate = new Date(endDate.getTime());
+ } else if (!startDate && !endDate) {
+ newStartDate = new Date(Date.now() + multiplier * interval * 60000 * 2);
+ newEndDate = new Date(Date.now() + multiplier * interval * 60000);
+ } else {
+ newStartDate = new Date(startDate.getTime() + multiplier * (endDate.getTime() - startDate.getTime()));
+ newEndDate = new Date(endDate.getTime() + multiplier * (endDate.getTime() - startDate.getTime()));
+ }
+
+ return { newStartDate, newEndDate };
+ };
+
+ handlePreviousDate = () => {
+ const { startDate, endDate, interval } = this.state;
+ const { newStartDate, newEndDate } = this.calculateNewDates(startDate, endDate, interval, 'previous');
+ this.setState(
+ {
+ startDate: newStartDate,
+ endDate: newEndDate
+ },
+ this.getData
+ );
+ };
+ handleNextDate = () => {
+ const { startDate, endDate, interval } = this.state;
+ const { newStartDate, newEndDate } = this.calculateNewDates(startDate, endDate, interval, 'next');
+ this.setState(
+ {
+ startDate: newStartDate,
+ endDate: newEndDate
+ },
+ this.getData
+ );
+ };
+ constructor(props) {
+ console.log('constructor props', props);
+ super(props);
+ this.props = props;
+ this.state = {
+ name: '',
+ box: null,
+ loading: true,
+ x: props.x,
+ y: props.y,
+ boxOptions: {
+ startDate: null,
+ endDate: null,
+ interval: 30,
+ intervalUnit: 'days'
+ },
+ dropdownOpenCriteriaDate: false,
+ dropdownOpenCriteriaAggregate: false,
+ selectedGlobalOption: false,
+ selectedCriteriaDate: 'before',
+ selectedCriteriaAggregate: 'notAggregate',
+ };
+ console.log('this.state', this.state);
+ }
+
+ async componentDidMount() {
+ const { x, y, dashboardSelector } = this.props;
+ const currentDashboard = await this.props.httpClient.get(
+ `/api/v1/dashboard/${dashboardSelector}`
+ );
+ const box = currentDashboard.boxes[x][y];
+ const name = currentDashboard.name;
+ this.setState({ box, loading: false, name });
+ }
+ render(props, { loading,
+ boxOptions,
+ dropdownOpenGlobal,
+ dropdownOpenCriteriaDate,
+ dropdownOpenCriteriaAggregate,
+ selectedCriteriaDate,
+ selectedCriteriaAggregate
+ }) {
+ if (!loading) {
+ return (
+
+
+ );
+ }
+ }
+}
+
+export default connect('user,httpClient', {})(ExpandedDashboardPage);
diff --git a/front/src/routes/dashboard/expanded-dashboard/style.css b/front/src/routes/dashboard/expanded-dashboard/style.css
new file mode 100644
index 0000000000..f846518c48
--- /dev/null
+++ b/front/src/routes/dashboard/expanded-dashboard/style.css
@@ -0,0 +1,70 @@
+.containerWithMargin {
+ margin-top: 1rem;
+}
+
+.dropdownMenuUp {
+ top: auto;
+ bottom: 100%;
+ transform: translateY(-1%);
+ z-index: 300;
+}
+.dropdownMenuDown {
+ width: auto;
+ min-width: 150px;
+}
+.dropdownItem {
+ cursor: pointer;
+}
+
+.flexContainer {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.cardFooter {
+ margin-bottom: 1rem;
+ margin-top: 1rem;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+.datePicker {
+ display: flex;
+ align-items: center;
+ margin-right: 0.5rem;
+}
+
+.datePickerChart {
+ display: flex;
+ align-items: center;
+ padding: 0.4rem 0;
+}
+
+.datePickerLabel {
+ margin: 0 1rem;
+ font-size: 0.75rem;
+}
+
+.datePickerInput {
+ height: calc(1.5em + 0.75rem + 2px);
+ padding: 0.375rem 0.75rem;
+ font-size: 0.625rem;
+}
+
+.displacementRaftersChart {
+ margin-left: auto;
+ display: flex;
+ align-items: center;
+}
+
+/* .backButtonDiv {
+ margin-bottom: 1rem;
+ /* max-width: 24rem; */
+/*}
+@media (max-width: 768px) {
+ .backButtonDiv {
+ /* margin-bottom: 1rem; */
+/* max-width: 24rem; */
+/* }
+} */
\ No newline at end of file
diff --git a/server/api/controllers/device.controller.js b/server/api/controllers/device.controller.js
index b04c096e11..23568fda5a 100644
--- a/server/api/controllers/device.controller.js
+++ b/server/api/controllers/device.controller.js
@@ -102,6 +102,8 @@ module.exports = function DeviceController(gladys) {
req.query.device_features.split(','),
req.query.interval,
req.query.max_states,
+ req.query.start_date,
+ req.query.end_date,
);
res.json(states);
}
diff --git a/server/lib/device/device.getDeviceFeaturesAggregates.js b/server/lib/device/device.getDeviceFeaturesAggregates.js
index fc6d6e0ac7..47c5fee3a8 100644
--- a/server/lib/device/device.getDeviceFeaturesAggregates.js
+++ b/server/lib/device/device.getDeviceFeaturesAggregates.js
@@ -6,11 +6,19 @@ const { NotFoundError } = require('../../utils/coreErrors');
* @param {string} selector - Device selector.
* @param {number} intervalInMinutes - Interval.
* @param {number} maxStates - Number of elements to return max.
+ * @param {Date} startDate - Start date.
+ * @param {Date} endDate - End date.
* @returns {Promise