Skip to content

Commit f073b5a

Browse files
committed
feat: Add support for start_date and end_date in device feature aggregates
1 parent 8343bfe commit f073b5a

File tree

6 files changed

+730
-43
lines changed

6 files changed

+730
-43
lines changed

front/src/components/app.jsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import SignupSuccess from '../routes/signup/5-success';
4343
import Dashboard from '../routes/dashboard';
4444
import NewDashboard from '../routes/dashboard/new-dashboard';
4545
import EditDashboard from '../routes/dashboard/edit-dashboard';
46+
import ExpandedDashboard from '../routes/dashboard/expanded-dashboard';
4647

4748
import IntegrationPage from '../routes/integration';
4849
import ChatPage from '../routes/chat';
@@ -230,6 +231,7 @@ const AppRouter = connect(
230231
<Dashboard path="/dashboard" />
231232
<Dashboard path="/dashboard/:dashboardSelector" />
232233
<EditDashboard path="/dashboard/:dashboardSelector/edit" />
234+
<ExpandedDashboard path="/dashboard/:dashboardSelector/expanded/:x/:y" />
233235
<NewDashboard path="/dashboard/create/new" />
234236
<IntegrationPage path="/dashboard/integration" />
235237

@@ -367,7 +369,7 @@ class MainApp extends Component {
367369
this.props.checkSession();
368370
}
369371

370-
render({ user }, {}) {
372+
render({ user }, { }) {
371373
const translationDefinition = get(translations, user.language, { default: translations.en });
372374
return (
373375
<IntlProvider definition={translationDefinition}>

front/src/components/boxs/chart/Chart.jsx

+99-40
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import { Component } from 'preact';
22
import { connect } from 'unistore/preact';
33
import cx from 'classnames';
4-
4+
import { Link } from 'preact-router/match';
55
import { Text, Localizer } from 'preact-i18n';
66
import style from './style.css';
77
import { WEBSOCKET_MESSAGE_TYPES, DEVICE_FEATURE_UNITS } from '../../../../../server/utils/constants';
88
import get from 'get-value';
99
import withIntlAsProp from '../../../utils/withIntlAsProp';
1010
import ApexChartComponent from './ApexChartComponent';
11-
import ChartBoxExpanded from './Chart';
1211

1312
const ONE_HOUR_IN_MINUTES = 60;
1413
const ONE_DAY_IN_MINUTES = 24 * 60;
@@ -26,6 +25,13 @@ const intervalByName = {
2625
'last-year': ONE_YEAR_IN_MINUTES
2726
};
2827

28+
const getTypeByInterval = interval => {
29+
if (interval >= ONE_DAY_IN_MINUTES) return 'hourly';
30+
if (interval >= THIRTY_DAYS_IN_MINUTES) return 'daily';
31+
if (interval >= ONE_YEAR_IN_MINUTES) return 'monthly';
32+
return 'live';
33+
};
34+
2935
const UNITS_WHEN_DOWN_IS_POSITIVE = [DEVICE_FEATURE_UNITS.WATT_HOUR];
3036

3137
const notNullNotUndefined = value => {
@@ -114,6 +120,7 @@ class Chartbox extends Component {
114120
});
115121
this.getData();
116122
};
123+
117124
getData = async () => {
118125
let deviceFeatures = this.props.box.device_features;
119126
if (!deviceFeatures) {
@@ -133,12 +140,42 @@ class Chartbox extends Component {
133140
return;
134141
}
135142
await this.setState({ loading: true });
143+
144+
let type;
145+
if (this.props.showHistoryExpanded) {
146+
let intervalDate;
147+
if (this.state.startDate && this.state.endDate) {
148+
intervalDate = (this.state.endDate - this.state.startDate) / 60000;
149+
} else {
150+
intervalDate = this.state.interval;
151+
}
152+
if (intervalDate <= ONE_DAY_IN_MINUTES) {
153+
type = 'live';
154+
} else {
155+
type = getTypeByInterval(intervalDate, this.props.box.chart_type);
156+
}
157+
} else {
158+
type = getTypeByInterval(this.state.interval, this.props.box.chart_type);
159+
}
136160
try {
137-
const data = await this.props.httpClient.get(`/api/v1/device_feature/aggregated_states`, {
138-
interval: this.state.interval,
139-
max_states: 100,
140-
device_features: deviceFeatures.join(',')
141-
});
161+
let data;
162+
if (type === 'live') {
163+
data = await this.props.httpClient.get(`/api/v1/device_feature/aggregated_states`, {
164+
interval: this.state.interval,
165+
max_states: this.state.maxStatesLive,
166+
device_features: deviceFeatures.join(','),
167+
start_date: this.state.startDate ? this.state.startDate.toISOString() : null,
168+
end_date: this.state.endDate ? this.state.endDate.toISOString() : null
169+
});
170+
} else {
171+
data = await this.props.httpClient.get(`/api/v1/device_feature/aggregated_states`, {
172+
interval: this.state.interval,
173+
max_states: this.state.maxStatesNoLive,
174+
device_features: deviceFeatures.join(','),
175+
start_date: this.state.startDate ? this.state.startDate.toISOString() : undefined,
176+
end_date: this.state.endDate ? this.state.endDate.toISOString() : undefined
177+
});
178+
}
142179

143180
let emptySeries = true;
144181

@@ -284,14 +321,38 @@ class Chartbox extends Component {
284321
interval: intervalByName[this.props.box.interval]
285322
});
286323
};
324+
325+
handleZoom = async (min, max) => {
326+
if (min === null || max === null) {
327+
await this.setState({
328+
startDate: null,
329+
endDate: null
330+
});
331+
this.getData();
332+
} else {
333+
await this.setState({
334+
startDate: new Date(min),
335+
endDate: new Date(max)
336+
});
337+
this.getData();
338+
}
339+
};
340+
287341
constructor(props) {
288342
super(props);
289343
this.props = props;
344+
console.log('props constructor Chart', props);
290345
this.state = {
291346
interval: this.props.box.interval ? intervalByName[this.props.box.interval] : ONE_HOUR_IN_MINUTES,
292347
loading: true,
293348
initialized: false,
294-
height: 'small'
349+
height: 'small',
350+
startDate: null,
351+
endDate: null,
352+
dropdownOpen: false,
353+
selectedCriteria: 'before',
354+
maxStatesLive: 10000,
355+
maxStatesNoLive: 1000
295356
};
296357
}
297358
componentDidMount() {
@@ -320,6 +381,7 @@ class Chartbox extends Component {
320381
this.updateDeviceStateWebsocket
321382
);
322383
}
384+
323385
render(
324386
props,
325387
{
@@ -332,18 +394,26 @@ class Chartbox extends Component {
332394
lastValueRounded,
333395
interval,
334396
emptySeries,
335-
unit
397+
unit,
398+
startDate,
399+
endDate
336400
}
337401
) {
338-
const { box, displayPreview, showCloseButton, showHistoryZoom } = this.props;
402+
const { box, displayPreview, showHistoryExpanded } = this.props;
403+
339404
const displayVariation = box.display_variation;
340405
const nbDeviceFeatures = box.device_features.length;
341406
let heightAdditional = 0;
342-
if (showHistoryZoom) {
407+
if (showHistoryExpanded === true) {
408+
console.log('props render Chart', props);
409+
console.log('this render Chart', this);
410+
}
411+
const showAggregatedDataWarning = this.state.series && this.state.series.some(serie => serie.data.length === this.state.maxStatesNoLive);
412+
if (showHistoryExpanded) {
343413
if (props.box.chart_type === 'timeline' && nbDeviceFeatures > 2) {
344414
heightAdditional = 56 * (nbDeviceFeatures - 2);
345415
} else {
346-
heightAdditional = 200;
416+
heightAdditional = 300;
347417
}
348418
} else if (props.box.chart_type === 'timeline' && nbDeviceFeatures > 3) {
349419
heightAdditional = 38 * (nbDeviceFeatures - 3);
@@ -353,6 +423,14 @@ class Chartbox extends Component {
353423
<div class="card-body">
354424
<div class="d-flex align-items-center justify-content-between">
355425
<div class={cx(style.subheader)}>{props.box.title}</div>
426+
{showHistoryExpanded && !showAggregatedDataWarning && (
427+
<div class={cx("ml-5 mr-5", style.subheader)}>
428+
<Text id="dashboard.boxes.chart.historyExpandedWarningStateLive" />
429+
</div>
430+
)}
431+
{showHistoryExpanded && showAggregatedDataWarning && (
432+
<div class={cx("ml-5 mr-5", style.subheader)}>{"(ATTENTION: Données aggrégées sur l'intervalle, vous pouvez zoomer sur un intervalle plus petit pour voir les données réelles)"}</div>
433+
)}
356434
<div class={cx(style.msAuto, style.lh1, 'd-flex', 'align-items-center')}>
357435
<div class="dropdown">
358436
<a class="dropdown-toggle text-muted text-nowrap" onClick={this.toggleDropdown}>
@@ -384,7 +462,7 @@ class Chartbox extends Component {
384462
>
385463
<Text id="dashboard.boxes.chart.lastDay" />
386464
</a>
387-
{props.box.chart_type !== 'timeline' && (
465+
{(props.box.chart_type !== 'timeline' || showHistoryExpanded) && (
388466
<a
389467
className={cx(style.dropdownItemChart, {
390468
[style.active]: interval === SEVEN_DAYS_IN_MINUTES
@@ -394,7 +472,7 @@ class Chartbox extends Component {
394472
<Text id="dashboard.boxes.chart.lastSevenDays" />
395473
</a>
396474
)}
397-
{props.box.chart_type !== 'timeline' && (
475+
{(props.box.chart_type !== 'timeline' || showHistoryExpanded) && (
398476
<a
399477
className={cx(style.dropdownItemChart, {
400478
[style.active]: interval === THIRTY_DAYS_IN_MINUTES
@@ -404,7 +482,7 @@ class Chartbox extends Component {
404482
<Text id="dashboard.boxes.chart.lastThirtyDays" />
405483
</a>
406484
)}
407-
{props.box.chart_type !== 'timeline' && (
485+
{(props.box.chart_type !== 'timeline' || showHistoryExpanded) && (
408486
<a
409487
className={cx(style.dropdownItemChart, {
410488
[style.active]: interval === THREE_MONTHS_IN_MINUTES
@@ -414,7 +492,7 @@ class Chartbox extends Component {
414492
<Text id="dashboard.boxes.chart.lastThreeMonths" />
415493
</a>
416494
)}
417-
{props.box.chart_type !== 'timeline' && (
495+
{(props.box.chart_type !== 'timeline' || showHistoryExpanded) && (
418496
<a
419497
className={cx(style.dropdownItemChart, {
420498
[style.active]: interval === ONE_YEAR_IN_MINUTES
@@ -426,35 +504,16 @@ class Chartbox extends Component {
426504
)}
427505
</div>
428506
</div>
429-
{this.state.showHistory && (
430-
<div class={cx(style.modalOverlay)}>
431-
<div class={cx('card-body', style.cardBody)}>
432-
<ChartBoxExpanded
433-
{...props}
434-
showHistoryZoom={this.state.showHistory}
435-
showCloseButton={true}
436-
onClose={() => this.setState({ showHistory: false })}
437-
/>
438-
</div>
439-
</div>
440-
)}
441-
{showCloseButton && (
442-
<button
443-
class={cx('btn btn-outline-secondary', style.customBtnCommon, style.closeButton)}
444-
onClick={() => this.props.onClose()}
445-
>
446-
<i class="fe fe-x" />
447-
</button>
448-
)}
449-
{!displayPreview && !showHistoryZoom && (
507+
{!displayPreview && !showHistoryExpanded && (
450508
<Localizer>
451-
<button
509+
510+
<Link
452511
class={cx('btn btn-outline-secondary', style.customBtnCommon, style.customBtn)}
453-
onClick={() => this.setState({ showHistory: true })}
512+
href={`/dashboard/${props.dashboardSelector}/expanded/${props.x}/${props.y}`}
454513
title={<Text id="dashboard.boxes.chart.expandChartButtonDescription" />}
455514
>
456515
<i class="fe fe-airplay" />
457-
</button>
516+
</Link>
458517
</Localizer>
459518
)}
460519
</div>

front/src/config/i18n/fr.json

+42-1
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,48 @@
373373
"preview": "Prévisualisation",
374374
"showPreviewButton": "Afficher une prévisualisation",
375375
"on": "On",
376-
"off": "Off"
376+
"off": "Off",
377+
"startDate": "Date de début :",
378+
"endDate": "Date de fin :",
379+
"historyExpandedWarningStateLive": "Données réelles sur l'intervalle",
380+
"historyExpandedWarningStateAggregated": "ATTENTION: Données aggrégées sur l'intervalle, vous pouvez zoomer sur un intervalle plus petit pour voir les données réelles",
381+
"criteria": {
382+
"criteriaDateExpendOptionsTitle": "Critère de date",
383+
"criteriaAggregateExpendOptionsTitle": "Critère d'agrégation",
384+
"applyAndClose": "Appliquer les modifications",
385+
"date": {
386+
"all": "Toutes les données",
387+
"previous": "Période précédente",
388+
"current": "Période actuelle",
389+
"next": "Période suivante",
390+
"before": "Avant le",
391+
"after": "Après le",
392+
"between": "Entre",
393+
"custom": "Personnalisé"
394+
},
395+
"intervalUnit": {
396+
"days": "Jours",
397+
"weeks": "Semaines",
398+
"months": "Mois",
399+
"quarter": "Trimestre",
400+
"years": "Années",
401+
"thisDays": "Aujourd'hui",
402+
"thisWeeks": "Cette semaine",
403+
"thisMonths": "Ce mois",
404+
"thisQuarter": "Ce trimestre",
405+
"thisYears": "Cette année"
406+
},
407+
"aggregate": {
408+
"minute": "Minute",
409+
"hour": "Heure",
410+
"day": "Jour",
411+
"week": "Semaine",
412+
"month": "Mois",
413+
"quarter": "Trimestre",
414+
"year": "Année",
415+
"notAggregate": "Non aggrégé"
416+
}
417+
}
377418
},
378419
"ecowatt": {
379420
"title": "Ecowatt France",

front/src/routes/dashboard/BoxColumns.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const BoxColumns = ({ children, ...props }) => (
1414
})}
1515
>
1616
{column.map((box, y) => (
17-
<Box key={`${props.homeDashboard.id}-${x}-${y}`} box={box} x={x} y={y} />
17+
<Box key={`${props.homeDashboard.id}-${x}-${y}`} box={box} x={x} y={y} dashboardSelector={props.homeDashboard.selector} />
1818
))}
1919
</div>
2020
))}

0 commit comments

Comments
 (0)