Skip to content

Commit 70f6dda

Browse files
feat: metrics using single feature truth (#832)
* metrics using single feature truth
1 parent 30c6096 commit 70f6dda

File tree

5 files changed

+160
-136
lines changed

5 files changed

+160
-136
lines changed

web-app/src/app/screens/Analytics/GTFSFeatureAnalytics/index.tsx

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@ import {
2828
import * as React from 'react';
2929
import { useTheme } from '@mui/material/styles';
3030
import { InfoOutlined, ListAltOutlined } from '@mui/icons-material';
31-
import { featureGroups, getGroupColor } from '../../../utils/analytics';
3231
import { type FeatureMetrics } from '../types';
3332
import { useRemoteConfig } from '../../../context/RemoteConfigProvider';
3433
import MUITooltip from '@mui/material/Tooltip';
3534
import { GTFS_ORG_LINK } from '../../../constants/Navigation';
35+
import {
36+
DATASET_FEATURES,
37+
getComponentDecorators,
38+
} from '../../../utils/consts';
3639

3740
export default function GTFSFeatureAnalytics(): React.ReactElement {
3841
const navigateTo = useNavigate();
@@ -44,6 +47,16 @@ export default function GTFSFeatureAnalytics(): React.ReactElement {
4447
const [error, setError] = useState<string | null>(null);
4548
const { config } = useRemoteConfig();
4649

50+
const getUniqueKeyStringValues = (key: keyof FeatureMetrics): string[] => {
51+
const subGroups = new Set<string>();
52+
data.forEach((item) => {
53+
if (item[key] !== undefined) {
54+
subGroups.add(item[key] as string);
55+
}
56+
});
57+
return Array.from(subGroups);
58+
};
59+
4760
useEffect(() => {
4861
const fetchData = async (): Promise<void> => {
4962
try {
@@ -54,13 +67,15 @@ export default function GTFSFeatureAnalytics(): React.ReactElement {
5467
throw new Error('Network response was not ok');
5568
}
5669
const fetchedData = await response.json();
57-
const dataWithGroups = fetchedData.map((feature: FeatureMetrics) => ({
58-
...feature,
59-
latest_feed_count: feature.feeds_count.slice(-1)[0],
60-
feature_group: Object.keys(featureGroups).find((group) =>
61-
featureGroups[group].includes(feature.feature),
62-
),
63-
}));
70+
const dataWithGroups = fetchedData.map((feature: FeatureMetrics) => {
71+
return {
72+
...feature,
73+
latest_feed_count: feature.feeds_count.slice(-1)[0],
74+
feature_group: DATASET_FEATURES[feature.feature]?.component,
75+
feature_sub_group:
76+
DATASET_FEATURES[feature.feature]?.componentSubgroup,
77+
};
78+
});
6479
setData(dataWithGroups);
6580
} catch (error) {
6681
if (error instanceof Error) {
@@ -118,13 +133,34 @@ export default function GTFSFeatureAnalytics(): React.ReactElement {
118133
header: 'Feature Group',
119134
size: 200,
120135
filterVariant: 'multi-select',
121-
filterSelectOptions: Object.keys(featureGroups),
136+
filterSelectOptions: getUniqueKeyStringValues('feature_group'),
137+
Cell: ({ cell }: { cell: MRT_Cell<FeatureMetrics> }) => {
138+
const group = cell.getValue<string>();
139+
return group == null ? null : (
140+
<span
141+
style={{
142+
backgroundColor: getComponentDecorators(group).color,
143+
borderRadius: '5px',
144+
padding: '2px 8px',
145+
}}
146+
>
147+
{group}
148+
</span>
149+
);
150+
},
151+
},
152+
{
153+
accessorKey: 'feature_sub_group',
154+
header: 'Feature Sub Group',
155+
size: 200,
156+
filterVariant: 'multi-select',
157+
filterSelectOptions: getUniqueKeyStringValues('feature_sub_group'),
122158
Cell: ({ cell }: { cell: MRT_Cell<FeatureMetrics> }) => {
123159
const group = cell.getValue<string>();
124160
return group == null ? null : (
125161
<span
126162
style={{
127-
backgroundColor: getGroupColor(group),
163+
backgroundColor: getComponentDecorators(group).color,
128164
borderRadius: '5px',
129165
padding: '2px 8px',
130166
}}

web-app/src/app/screens/Analytics/GTFSFeedAnalytics/GTFSFeedAnalyticsTable.tsx

Lines changed: 45 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@ import React, { useMemo } from 'react';
22
import { type MRT_Cell, type MRT_ColumnDef } from 'material-react-table';
33
import { format } from 'date-fns';
44
import { type GTFSFeedMetrics } from '../types';
5-
import { groupFeatures, getGroupColor } from '../../../utils/analytics';
65
import { useNavigate } from 'react-router-dom';
7-
import { Box, MenuItem, Stack, Tooltip } from '@mui/material';
6+
import { Box, IconButton, MenuItem, Stack, Tooltip } from '@mui/material';
87
import { OpenInNew } from '@mui/icons-material';
8+
import {
9+
getComponentDecorators,
10+
groupFeaturesByComponent,
11+
} from '../../../utils/consts';
912

1013
/**
1114
* Returns the columns for the feed analytics table.
@@ -285,75 +288,55 @@ export const useTableColumns = (
285288
},
286289
enableSorting: false,
287290
Cell: ({ cell }: { cell: MRT_Cell<GTFSFeedMetrics> }) => {
288-
const { groupedFeatures, otherFeatures } = groupFeatures(
291+
const groupedFeatures = groupFeaturesByComponent(
289292
cell.getValue<string[]>(),
290293
);
291294
return (
292295
<div>
293-
{Object.entries(groupedFeatures).map(
294-
([group, features], index) => (
295-
<div key={index} style={{ marginBottom: '10px' }}>
296-
<div
297-
style={{
298-
background: getGroupColor(group),
299-
color: 'black',
300-
borderRadius: '5px',
301-
padding: 5,
302-
marginLeft: 5,
303-
marginBottom: 5,
304-
width: 'fit-content',
305-
}}
306-
>
307-
{group}:
308-
</div>
309-
{features.map((feature, index) => (
296+
{Object.entries(groupedFeatures)
297+
.sort(([keyA], [keyB]) => keyA.localeCompare(keyB))
298+
.map(([group, features], index) => {
299+
const componentDecorator = getComponentDecorators(group);
300+
return (
301+
<div key={index} style={{ marginBottom: '10px' }}>
310302
<div
311-
key={index}
312-
style={{ cursor: 'pointer', marginLeft: '10px' }}
313-
className={'navigable-list-item'}
314-
onClick={() => {
315-
navigate(
316-
`/metrics/gtfs/features?featureName=${feature}`,
317-
);
303+
style={{
304+
background: componentDecorator.color,
305+
color: 'black',
306+
borderRadius: '5px',
307+
padding: 5,
308+
marginLeft: 5,
309+
marginBottom: 5,
310+
width: 'fit-content',
318311
}}
319312
>
320-
{feature}
313+
{group}
321314
</div>
322-
))}
323-
</div>
324-
),
325-
)}
326-
{otherFeatures.length > 0 && (
327-
<div>
328-
<div
329-
style={{
330-
background: getGroupColor('Other'),
331-
color: 'black',
332-
borderRadius: '5px',
333-
padding: 5,
334-
marginLeft: 5,
335-
marginBottom: 5,
336-
width: 'fit-content',
337-
}}
338-
>
339-
Empty Group:
340-
</div>
341-
{otherFeatures.map((feature, index) => (
342-
<div
343-
key={index}
344-
style={{ cursor: 'pointer', marginLeft: '10px' }}
345-
className={'navigable-list-item'}
346-
onClick={() => {
347-
navigate(
348-
`/metrics/gtfs/features?featureName=${feature}`,
349-
);
350-
}}
351-
>
352-
{feature}
315+
{features.map((featureData, index) => (
316+
<div
317+
key={index}
318+
style={{ cursor: 'pointer', marginLeft: '10px' }}
319+
className={'navigable-list-item'}
320+
onClick={() => {
321+
navigate(
322+
`/metrics/gtfs/features?featureName=${featureData.feature}`,
323+
);
324+
}}
325+
>
326+
{featureData.feature}
327+
{featureData.componentSubgroup !== undefined && (
328+
<Tooltip
329+
title={featureData.componentSubgroup}
330+
placement={'top'}
331+
>
332+
<IconButton>{componentDecorator.icon}</IconButton>
333+
</Tooltip>
334+
)}
335+
</div>
336+
))}
353337
</div>
354-
))}
355-
</div>
356-
)}
338+
);
339+
})}
357340
</div>
358341
);
359342
},

web-app/src/app/screens/Analytics/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export interface FeatureMetrics {
4141
feeds_count: number[];
4242
latest_feed_count: number;
4343
feature_group?: string; // Add a property to handle feature grouping
44+
feature_sub_group?: string;
4445
}
4546

4647
export interface AnalyticsFile {

web-app/src/app/utils/analytics.ts

Lines changed: 0 additions & 62 deletions
This file was deleted.

0 commit comments

Comments
 (0)