Skip to content

Commit c16a693

Browse files
silkeholmebonnenseljaksVIKTORVAV99
authored
feat(web): add 5 min data to the app (#8251)
* wip * set major tick to every hour * use ff to hide or show 5 min granularity * use correct ff name * add translations * show tic every 4 hours * use 5 min atom * remove 24 hour check in routing * use isFineGranularity instead of isHourly * add five minute to allowed historical * remove console log print * remove some ticks * navigate to 72h if five min ff is not on * fix midnight marker * adjust minor ticks * review feedback --------- Co-authored-by: Samo Seljak <[email protected]> Co-authored-by: Viktor Andersson <[email protected]>
1 parent ea0648c commit c16a693

33 files changed

+200
-113
lines changed

mockserver/public/v10/meta.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"features": {
2+
"features": {
33
"72-hours": true,
44
"consumption-only": false,
55
"feedback-micro-survey": false,
@@ -8,7 +8,11 @@
88
"historical-storytelling-popover": true,
99
"more-options-dropdown": true,
1010
"query-materialized-view": true,
11-
"share-button": true
11+
"share-button": true,
12+
"five-minute-granularity": true
1213
},
13-
"callerLocation": [138, 36]
14+
"callerLocation": [
15+
138,
16+
36
17+
]
1418
}

web/src/api/helpers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ export function isValidDate(dateString: string) {
9696
}
9797

9898
export const TIME_RANGE_TO_TIME_AVERAGE: Record<TimeRange, string> = {
99+
[TimeRange.H24]: 'five_minutes',
99100
[TimeRange.H72]: 'hourly',
100101
[TimeRange.M3]: 'daily',
101102
[TimeRange.M12]: 'monthly',
@@ -104,6 +105,7 @@ export const TIME_RANGE_TO_TIME_AVERAGE: Record<TimeRange, string> = {
104105
} as const;
105106

106107
export const TIME_RANGE_TO_BACKEND_PATH: Record<TimeRange, string> = {
108+
[TimeRange.H24]: 'five_minutes',
107109
[TimeRange.H72]: 'hourly',
108110
[TimeRange.M3]: 'daily',
109111
[TimeRange.M12]: 'monthly',

web/src/components/TimeRangeSelector.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
2+
import { useFeatureFlag } from 'features/feature-flags/api';
23
import { TFunction } from 'i18next';
34
import { ChevronsUpDown } from 'lucide-react';
45
import { memo, useMemo } from 'react';
@@ -21,13 +22,22 @@ export interface TimeRangeSelectorProps {
2122
function TimeRangeSelector({ timeRange, onToggleGroupClick }: TimeRangeSelectorProps) {
2223
const { t } = useTranslation();
2324
const { isOpen, onToggleDropdown } = useDropdownCtl();
25+
const is5MinGranularityEnabled = useFeatureFlag('five-minute-granularity');
2426

2527
const options = useMemo(
26-
() => Object.values(TimeRange).map((value) => createOption(value, t)),
27-
[t]
28+
() =>
29+
Object.values(TimeRange)
30+
.filter((value) => {
31+
if (!is5MinGranularityEnabled && value === TimeRange.H24) {
32+
return false;
33+
}
34+
return true;
35+
})
36+
.map((value) => createOption(value, t)),
37+
[t, is5MinGranularityEnabled]
2838
);
2939

30-
const selectedLabel = options.find((opt) => opt.value === timeRange)!.label;
40+
const selectedLabel = options.find((opt) => opt.value === timeRange)?.label;
3141

3242
return (
3343
<DropdownMenu.Root onOpenChange={onToggleDropdown} open={isOpen} modal={false}>

web/src/components/TimeSlider.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { ChevronsLeftRight, Moon, Sun } from 'lucide-react';
77
import { ReactElement } from 'react';
88
import { useParams } from 'react-router-dom';
99
import { RouteParameters } from 'types';
10-
import { isHourlyAtom } from 'utils/state/atoms';
10+
import { isFiveMinuteOrHourlyGranularityAtom } from 'utils/state/atoms';
1111

1212
type NightTimeSet = number[];
1313

@@ -139,8 +139,8 @@ export function TimeSliderWithNight(props: TimeSliderProps) {
139139

140140
function TimeSlider(props: TimeSliderProps) {
141141
const { zoneId } = useParams<RouteParameters>();
142-
const isHourly = useAtomValue(isHourlyAtom);
143-
const showNightTime = zoneId && isHourly;
142+
const isFineGranularity = useAtomValue(isFiveMinuteOrHourlyGranularityAtom);
143+
const showNightTime = zoneId && isFineGranularity;
144144

145145
return showNightTime ? (
146146
<TimeSliderWithNight {...props} />

web/src/features/charts/CarbonChart.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useCo2ColorScale } from 'hooks/theme';
33
import { useAtomValue } from 'jotai';
44
import { useTranslation } from 'react-i18next';
55
import { Charts, TimeRange } from 'utils/constants';
6-
import { isHourlyAtom } from 'utils/state/atoms';
6+
import { isFiveMinuteOrHourlyGranularityAtom } from 'utils/state/atoms';
77

88
import { ChartSubtitle, ChartTitle } from './ChartTitle';
99
import AreaGraph from './elements/AreaGraph';
@@ -24,7 +24,7 @@ function CarbonChart({ datetimes, timeRange }: CarbonChartProps) {
2424
const { data, isLoading, isError } = useCarbonChartData();
2525
const { t } = useTranslation();
2626
const co2ColorScale = useCo2ColorScale();
27-
const isHourly = useAtomValue(isHourlyAtom);
27+
const isFineGranularity = useAtomValue(isFiveMinuteOrHourlyGranularityAtom);
2828
const { estimated, estimationMethod, someEstimated } = useEstimationData(
2929
data?.chartData
3030
);
@@ -58,7 +58,7 @@ function CarbonChart({ datetimes, timeRange }: CarbonChartProps) {
5858
/>
5959
{someEstimated && (
6060
<EstimationLegend
61-
isAggregated={!isHourly}
61+
isAggregated={!isFineGranularity}
6262
estimationMethod={estimationMethod}
6363
valueAxisLabel={valueAxisLabel}
6464
/>

web/src/features/charts/EmissionChart.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useAtomValue } from 'jotai';
22
import { useTranslation } from 'react-i18next';
33
import { Charts, TimeRange } from 'utils/constants';
44
import { formatCo2 } from 'utils/formatting';
5-
import { isHourlyAtom } from 'utils/state/atoms';
5+
import { isFiveMinuteOrHourlyGranularityAtom } from 'utils/state/atoms';
66

77
import { ChartSubtitle, ChartTitle } from './ChartTitle';
88
import AreaGraph from './elements/AreaGraph';
@@ -20,7 +20,7 @@ interface EmissionChartProps {
2020

2121
function EmissionChart({ timeRange, datetimes }: EmissionChartProps) {
2222
const { data, isLoading, isError } = useEmissionChartData();
23-
const isHourly = useAtomValue(isHourlyAtom);
23+
const isFineGranularity = useAtomValue(isFiveMinuteOrHourlyGranularityAtom);
2424
const { estimated, estimationMethod, someEstimated } = useEstimationData(
2525
data?.chartData
2626
);
@@ -46,7 +46,7 @@ function EmissionChart({ timeRange, datetimes }: EmissionChartProps) {
4646
/>
4747
{someEstimated && (
4848
<EstimationLegend
49-
isAggregated={!isHourly}
49+
isAggregated={!isFineGranularity}
5050
estimationMethod={estimationMethod}
5151
valueAxisLabel={valueAxisLabel}
5252
/>

web/src/features/charts/LoadChart.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useAtomValue } from 'jotai';
22
import { useTranslation } from 'react-i18next';
33
import { Charts, TimeRange } from 'utils/constants';
4-
import { isHourlyAtom } from 'utils/state/atoms';
4+
import { isFiveMinuteOrHourlyGranularityAtom } from 'utils/state/atoms';
55

66
import { ChartSubtitle, ChartTitle } from './ChartTitle';
77
import AreaGraph from './elements/AreaGraph';
@@ -21,7 +21,7 @@ interface LoadChartProps {
2121
function LoadChart({ datetimes, timeRange }: LoadChartProps) {
2222
const { data, isLoading, isError } = useLoadChartData();
2323
const { t } = useTranslation();
24-
const isHourly = useAtomValue(isHourlyAtom);
24+
const isFineGranularity = useAtomValue(isFiveMinuteOrHourlyGranularityAtom);
2525
const { estimated, estimationMethod, someEstimated } = useEstimationData(
2626
data?.chartData
2727
);
@@ -58,7 +58,7 @@ function LoadChart({ datetimes, timeRange }: LoadChartProps) {
5858
<div className="relative">
5959
{someEstimated && (
6060
<EstimationLegend
61-
isAggregated={!isHourly}
61+
isAggregated={!isFineGranularity}
6262
estimationMethod={estimationMethod}
6363
valueAxisLabel={valueAxisLabel}
6464
/>

web/src/features/charts/NetExchangeChart.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Charts, TimeRange } from 'utils/constants';
44
import { formatCo2 } from 'utils/formatting';
55
import {
66
displayByEmissionsAtom,
7-
isHourlyAtom,
7+
isFiveMinuteOrHourlyGranularityAtom,
88
productionConsumptionAtom,
99
} from 'utils/state/atoms';
1010

@@ -27,7 +27,7 @@ function NetExchangeChart({ datetimes, timeRange }: NetExchangeChartProps) {
2727
const { data, isLoading, isError } = useNetExchangeChartData();
2828
const productionConsumption = useAtomValue(productionConsumptionAtom);
2929
const displayByEmissions = useAtomValue(displayByEmissionsAtom);
30-
const isHourly = useAtomValue(isHourlyAtom);
30+
const isFineGranularity = useAtomValue(isFiveMinuteOrHourlyGranularityAtom);
3131
const { t } = useTranslation();
3232
const { estimated, estimationMethod, someEstimated } = useEstimationData(
3333
data?.chartData
@@ -64,7 +64,7 @@ function NetExchangeChart({ datetimes, timeRange }: NetExchangeChartProps) {
6464
<div className="relative">
6565
{someEstimated && (
6666
<EstimationLegend
67-
isAggregated={!isHourly}
67+
isAggregated={!isFineGranularity}
6868
estimationMethod={estimationMethod}
6969
valueAxisLabel={valueAxisLabel}
7070
/>

web/src/features/charts/OriginChart.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ import { useTranslation } from 'react-i18next';
55
import { ElectricityModeType } from 'types';
66
import { Charts, TimeRange } from 'utils/constants';
77
import { formatCo2 } from 'utils/formatting';
8-
import { isConsumptionAtom, isHourlyAtom } from 'utils/state/atoms';
8+
import {
9+
isConsumptionAtom,
10+
isFiveMinuteOrHourlyGranularityAtom,
11+
} from 'utils/state/atoms';
912

1013
import { ChartSubtitle, ChartTitle } from './ChartTitle';
1114
import AreaGraph from './elements/AreaGraph';
@@ -70,7 +73,7 @@ function OriginChart({ displayByEmissions, datetimes, timeRange }: OriginChartPr
7073
const { data } = useOriginChartData();
7174
const isConsumption = useAtomValue(isConsumptionAtom);
7275
const { t } = useTranslation();
73-
const isHourly = useAtomValue(isHourlyAtom);
76+
const isFineGranularity = useAtomValue(isFiveMinuteOrHourlyGranularityAtom);
7477
const selectedData = useSelectedData(displayByEmissions);
7578
const { estimated, estimationMethod, someEstimated } = useEstimationData(
7679
data?.chartData
@@ -80,7 +83,7 @@ function OriginChart({ displayByEmissions, datetimes, timeRange }: OriginChartPr
8083
return null;
8184
}
8285

83-
const isConsumptionAndAggregatedResolution = isConsumption && !isHourly;
86+
const isConsumptionAndAggregatedResolution = isConsumption && !isFineGranularity;
8487

8588
const { chartData, valueAxisLabel, layerFill, layerKeys } = data;
8689

@@ -115,7 +118,7 @@ function OriginChart({ displayByEmissions, datetimes, timeRange }: OriginChartPr
115118
<div className="relative">
116119
{someEstimated && (
117120
<EstimationLegend
118-
isAggregated={!isHourly}
121+
isAggregated={!isFineGranularity}
119122
estimationMethod={estimationMethod}
120123
valueAxisLabel={valueAxisLabel}
121124
/>

web/src/features/charts/bar-breakdown/BarBreakdownChart.tsx

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { round } from 'utils/helpers';
2020
import {
2121
displayByEmissionsAtom,
2222
isConsumptionAtom,
23-
isHourlyAtom,
23+
isFiveMinuteOrHourlyGranularityAtom,
2424
productionConsumptionAtom,
2525
timeRangeAtom,
2626
} from 'utils/state/atoms';
@@ -55,15 +55,21 @@ function BarBreakdownChart({
5555
const { ref, width: observerWidth = 0 } = useResizeObserver<HTMLDivElement>();
5656
const { t } = useTranslation();
5757
const isBiggerThanMobile = useBreakpoint('sm');
58-
const isHourly = useAtomValue(isHourlyAtom);
58+
const isFineGranularity = useAtomValue(isFiveMinuteOrHourlyGranularityAtom);
5959
const isConsumption = useAtomValue(isConsumptionAtom);
6060
const width = observerWidth + X_PADDING;
6161
const isMobile = useIsMobile();
6262
const graphUnit = useMemo(
6363
() =>
6464
currentZoneDetail &&
65-
determineUnit(displayByEmissions, currentZoneDetail, isConsumption, isHourly, t),
66-
[currentZoneDetail, displayByEmissions, isConsumption, isHourly, t]
65+
determineUnit(
66+
displayByEmissions,
67+
currentZoneDetail,
68+
isConsumption,
69+
isFineGranularity,
70+
t
71+
),
72+
[currentZoneDetail, displayByEmissions, isConsumption, isFineGranularity, t]
6773
);
6874
const { zoneId } = useParams<RouteParameters>();
6975
const { data } = useGetZone();
@@ -83,7 +89,7 @@ function BarBreakdownChart({
8389
const pillText = getEstimationOrAggregationTranslation(
8490
t,
8591
'pill',
86-
!isHourly,
92+
!isFineGranularity,
8793
estimationMethod,
8894
currentZoneDetail?.estimatedPercentage
8995
);
@@ -154,7 +160,7 @@ function BarBreakdownChart({
154160
<div className="mb-4">
155161
<ZoneHeaderGauges zoneKey={currentZoneDetail.zoneKey} />
156162
</div>
157-
{!displayByEmissions && isHourly && (
163+
{!displayByEmissions && isFineGranularity && (
158164
<CapacityLegend
159165
text={t('country-panel.graph-legends.installed-capacity')}
160166
unit={graphUnit}

0 commit comments

Comments
 (0)