-
Notifications
You must be signed in to change notification settings - Fork 4
Add MetricDetails component with chart functionality #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,286 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Box, Button } from '@chakra-ui/react'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useCallback, useEffect, useState } from 'react'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import BottomSection from './BottomSection'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import TopSection from './TopSection'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useLocation, useNavigate, useSearchParams } from 'react-router-dom'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useDetailChartsGql } from '../graphql/index'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { ISelect } from '../../formComponents/customSelect'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { durationData, splitTime } from '../../shared/utils'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import Breadcrumbs from '../../appBreadcrumb'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import useQueryState from '../../hooks/useQueryState'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { removeEmptyQueryParams } from '../../hooks/queryString'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useDashboardStore } from '../../hooks/useDashboardStore'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { SlideInfoDrawer } from '../../infoSlidebar/SlideInfoDrawer'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| controlChartKeys, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getViewForFilter, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from '../helpers/metricCard.utils'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| interface metricDetailProps { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| initialTeam?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const MetricDetails = ({ initialTeam }: metricDetailProps) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+19
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainVerify unused The Search for how this component is used and whether initialTeam is passed: 🏁 Script executed: #!/bin/bash
# Find usages of MetricDetails component
rg -nP --type=tsx --type=ts -C3 '<MetricDetails|MetricDetails\s*\('Length of output: 27 Now let me run the corrected shell script to search for MetricDetails usages and initialTeam prop usage. 🏁 Script executed: #!/bin/bash
# Correct approach: use glob pattern for TypeScript files
# Find MetricDetails component usages
rg -nP -C3 'MetricDetails' -g "*.tsx" -g "*.ts"Length of output: 354 🏁 Script executed: #!/bin/bash
# Search for MetricDetails component instantiation (opening tag)
echo "=== MetricDetails component usages (instantiations) ==="
rg -nP '<MetricDetails' -g "*.tsx" -g "*.ts"
echo -e "\n=== initialTeam references in the file ==="
# Search for initialTeam anywhere in the file
rg -nP 'initialTeam' -g "*.tsx" -g "*.ts"Length of output: 220 Remove unused Verification confirms that the 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [searchParams] = useSearchParams(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const metricType = searchParams.get('type'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const project = searchParams.get('project'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+24
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. XSS via URL ParametersURL parameters extracted without sanitization and used throughout component state. Malicious URL parameters could inject script content through React state management leading to DOM-based XSS. Implement input validation and encoding for all URL parameter usage. Standards
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const location = useLocation(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const navigate = useNavigate(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [startDate, setStartDate] = useQueryState('start'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [endDate, setEndDate] = useQueryState('end'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [duration, setDuration] = useQueryState('duration'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [sprintId, setSprintId] = useQueryState('sprintId'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [sprintName, setSprintName] = useQueryState('sprint'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [team, setTeam] = useQueryState('team'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [view, setView] = useQueryState('view'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [breakdownBy, setBreakdownBy] = useQueryState('breakdown'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [showControlChart, setShowControlChart] = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useQueryState('showControlChart'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { selectedTeam, selected, setSelectedTeam, setSelected } = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useDashboardStore(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [openDrawer, setOpenDrawer] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handleDrawerClose = useCallback( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| () => setOpenDrawer(false), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [openDrawer] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+45
to
+48
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The dependency array for this |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [breakdown, setBreakdown] = useState<ISelect>({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value: '', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| label: '-', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [periodOptions, setPeriodOptions] = useState<any>(durationData); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [viewToggle, setViewToggle] = useState<string>('Week'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [repos, setRepos] = useState<string[]>([]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [filterBy, setFilterBy] = useState<{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| label: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }>({ value: 'team', label: 'Team' }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [controlChart, setControlChart] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { data, isLoading, isFetching, refetch } = useDetailChartsGql( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| selected.startDate, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| selected.endDate, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| metricType as string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| breakdown.value, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| filterBy.value === 'repo' ? '' : selectedTeam.value, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| selected?.sprintId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| project || '', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| filterBy.value === 'team' ? [] : repos.map((el: any) => el.value), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SQL Injection RiskUser-controlled repository values passed directly to GraphQL query without validation. Attackers could inject malicious repository names to access unauthorized data or cause query manipulation. Input validation and sanitization required for repository selection parameters. Standards
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| viewToggle.toUpperCase(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getViewForFilter(metricType, ''), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| undefined, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| showControlChart | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handelReloadClick = async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await refetch(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+80
to
+82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Async Operation RiskAsync refetch operation lacks error handling for network failures or API errors. Unhandled promise rejections during data reload cause silent failures without user feedback. Users experience broken reload functionality with no indication of failure state or recovery options. Standards
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (selected.duration === 'Sprint') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setViewToggle('Day'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setViewToggle('Week'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, [selected.duration]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const modifiedData = [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'MEAN_TIME_TO_RECOVERY', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'LEAD_TIME_FOR_CHANGE', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'PR_CYCLE_TIME', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'CODING_CYCLE_TIME', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'PICKUP_CYCLE_TIME', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'MERGE_CYCLE_TIME', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'TASK_LEAD_TIME', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'BUG_LEAD_TIME', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'ISSUE_CYCLE_TIME', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'MEETING_TIME', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'DEPLOY_CYCLE_TIME', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'DELIVERY_LEAD_TIME', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'BACKLOG_CYCLE_TIME', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'TEST_RUN_TIME', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'CUSTOM', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ].includes(data?.chartMetadata?.chartKey) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+92
to
+108
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...data, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| average: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data?.average && data?.chartMetadata?.dataType == 'INTEGER' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? data?.average | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : data?.average && data?.chartMetadata?.dataType == 'TIME' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? splitTime(parseInt(data?.average) / 60) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : data?.average && data?.chartMetadata?.dataType == 'PERCENTAGE' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? data?.average | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : data?.average && splitTime(parseInt(data?.average) / 60), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+112
to
+118
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use strict equality operators. The Apply this diff: average:
- data?.average && data?.chartMetadata?.dataType == 'INTEGER'
+ data?.average && data?.chartMetadata?.dataType === 'INTEGER'
? data?.average
- : data?.average && data?.chartMetadata?.dataType == 'TIME'
+ : data?.average && data?.chartMetadata?.dataType === 'TIME'
? splitTime(parseInt(data?.average) / 60)
- : data?.average && data?.chartMetadata?.dataType == 'PERCENTAGE'
+ : data?.average && data?.chartMetadata?.dataType === 'PERCENTAGE'
? data?.average
: data?.average && splitTime(parseInt(data?.average) / 60),📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
Comment on lines
+110
to
+118
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Conditional Logic InconsistencyAverage calculation logic uses loose equality (==) instead of strict equality (===) for dataType comparison, potentially causing type coercion issues. The final fallback condition assumes time conversion for all unmatched dataTypes, which may incorrectly process non-time numeric data types. Standards
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| chartMetadata: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...data.chartMetadata, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ylabel: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data?.chartMetadata?.chartKey === 'CUSTOM' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? data?.chartMetadata.ylabel | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : 'Hour', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data: data?.data?.map((item: any) => ({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...item, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| y: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data?.chartMetadata?.chartKey === 'CUSTOM' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? Number(item.y) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : Number(item.y) / 60, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| clusterP90ToP95: Number(item.clusterP90ToP95) / 60 || 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| clusterP95ToP100: Number(item.clusterP95ToP100) / 60 || 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| clusterP0ToP5: Number(item.clusterP0ToP5) / 60 || 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| clusterP5ToP10: Number(item.clusterP5ToP10) / 60 || 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+132
to
+135
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainVerify cluster value transformations for CUSTOM metrics. Lines 132-135 unconditionally divide all cluster percentile values by 60, but lines 129-131 skip this division for Verify whether cluster values should also respect the If cluster values should match the y-value behavior, apply this diff: y:
data?.chartMetadata?.chartKey === 'CUSTOM'
? Number(item.y)
: Number(item.y) / 60,
- clusterP90ToP95: Number(item.clusterP90ToP95) / 60 || 0,
- clusterP95ToP100: Number(item.clusterP95ToP100) / 60 || 0,
- clusterP0ToP5: Number(item.clusterP0ToP5) / 60 || 0,
- clusterP5ToP10: Number(item.clusterP5ToP10) / 60 || 0,
+ clusterP90ToP95: data?.chartMetadata?.chartKey === 'CUSTOM'
+ ? Number(item.clusterP90ToP95) || 0
+ : Number(item.clusterP90ToP95) / 60 || 0,
+ clusterP95ToP100: data?.chartMetadata?.chartKey === 'CUSTOM'
+ ? Number(item.clusterP95ToP100) || 0
+ : Number(item.clusterP95ToP100) / 60 || 0,
+ clusterP0ToP5: data?.chartMetadata?.chartKey === 'CUSTOM'
+ ? Number(item.clusterP0ToP5) || 0
+ : Number(item.clusterP0ToP5) / 60 || 0,
+ clusterP5ToP10: data?.chartMetadata?.chartKey === 'CUSTOM'
+ ? Number(item.clusterP5ToP10) || 0
+ : Number(item.clusterP5ToP10) / 60 || 0,🏁 Script executed: #!/bin/bash
# Search for how clusterP90ToP95 and similar fields are used in chart rendering
rg -nP --type=tsx --type=ts -C3 'clusterP(90|95|0|5)To'Length of output: 27 🏁 Script executed: #!/bin/bash
# Search for clusterP90ToP95 usage with corrected type filter
rg -nP --type ts -C3 'clusterP(90|95|0|5)To'Length of output: 572 🏁 Script executed: #!/bin/bash
# Search for where cluster values are used in chart rendering/consumption
rg -nP --type ts 'clusterP|clusterP90' -A2 -B2 | head -60Length of output: 457 🏁 Script executed: #!/bin/bash
# Find broader context of CUSTOM metric handling and where cluster fields might be used
rg -nP --type ts "CUSTOM|clusterP|clusterP90" -B5 -A5 | grep -E "(chartKey|CUSTOM|render|chart|cluster)" -iLength of output: 770 🏁 Script executed: #!/bin/bash
# Find what happens after the data transformation (after line 136)
rg -nP --type ts -A20 'clusterP5ToP10:' | head -40Length of output: 993 🏁 Script executed: #!/bin/bash
# Find where convertedItem or the return value is consumed
rg -nP --type ts -B10 "return convertedItem" | head -30Length of output: 599 🏁 Script executed: #!/bin/bash
# Find function context and where this data transformation happens
rg -nP --type ts -B30 'clusterP90ToP95:' | grep -E "(function|const|=>|export)" | tail -5Length of output: 60 🏁 Script executed: #!/bin/bash
# Get broader context to find function name and full transformation logic
rg -nP --type ts -B50 'clusterP90ToP95:' | grep -E "^index.tsx-[0-9]+-\s*(export|function|const|if)" | tail -10Length of output: 92 🏁 Script executed: #!/bin/bash
# Search for tests or comments explaining cluster value behavior
rg -nP --type ts "cluster|CUSTOM" -B2 -A2 | grep -E "(test|spec|describe|it\(|TODO|FIXME|NOTE|cluster)" -i | head -40Length of output: 354 Cluster values should respect CUSTOM metric condition like y values do. The inconsistency is confirmed. Lines 129-131 show y values conditionally skip division by 60 when 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| })), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return convertedItem; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+138
to
+139
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Comment on lines
+138
to
+139
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical syntax error: Remove stray return statement. Lines 138-139 contain a Apply this diff to remove the invalid statement: clusterP0ToP5: Number(item.clusterP0ToP5) / 60 || 0,
clusterP5ToP10: Number(item.clusterP5ToP10) / 60 || 0,
})),
-
- return convertedItem;
- }),
keys: data?.keys?.map((key: any) =>
key.name === 'Minutes' ? { ...key, name: 'Hours' } : key
),📝 Committable suggestion
Suggested change
🧰 Tools🪛 Biome (2.1.2)[error] 138-138: expected Remove convertedItem (parse) [error] 138-138: expected Remove ; (parse) [error] 139-139: Expected a semicolon or an implicit semicolon after a statement, but found none An explicit or implicit semicolon is expected here... ...Which is required to end this statement (parse) 🤖 Prompt for AI Agents
Comment on lines
+126
to
+139
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incomplete Data MappingData transformation logic contains incomplete mapping with orphaned return statement on line 138. The convertedItem variable is undefined causing runtime TypeError when processing chart data. This results in chart rendering failures and potential application crashes during metric visualization. Commitable Suggestion
Suggested change
Standards
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| keys: data?.keys?.map((key: any) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| key.name === 'Minutes' ? { ...key, name: 'Hours' } : key | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| refLines: data?.refLines, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : data; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof selected !== 'undefined') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+147
to
+148
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Long useEffect ChainMultiple useEffect hooks with complex dependency arrays and nested conditionals create difficult-to-track side effects. Effect logic spans 73 lines with intricate state synchronization. Extract effect logic into custom hooks with clear responsibilities to improve maintainability and testing. Standards
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| selected.startDate && setStartDate(selected.startDate); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| selected.endDate && setEndDate(selected.endDate); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| selected.duration && setDuration(selected.duration); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| selected?.sprintId === '' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? removeEmptyQueryParams({ sprintId: '' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : setSprintId(selected?.sprintId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| selected?.sprintName === '' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? removeEmptyQueryParams({ sprint: '' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : setSprintName(selected?.sprintName); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof selectedTeam !== 'undefined') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| selectedTeam.value === '' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? removeEmptyQueryParams({ team: '' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : setTeam(selectedTeam.value); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof viewToggle !== 'undefined') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| viewToggle && setView(viewToggle); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof breakdown.value !== 'undefined') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| breakdown.value === '' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? removeEmptyQueryParams({ breakdown: '' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : setBreakdownBy(breakdown.value); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, [selected, selectedTeam.value, viewToggle, breakdown.value]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| team && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSelectedTeam({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value: team === 'Organisation' ? '' : team, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| label: team, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| duration || selected.duration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? setSelected( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| periodOptions | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .filter( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (item: any) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| item.duration === duration || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| item.duration === selected.duration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map((el: any) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| el.duration === 'Custom' || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| el.duration === 'Today' || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| el.duration === 'Month' || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| el.duration === 'Quarter' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...el, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| startDate: startDate || selected.startDate, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endDate: endDate || selected.endDate, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : el.duration === 'Sprint' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...el, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| startDate: startDate || selected.startDate, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endDate: endDate || selected.endDate, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sprintId: sprintId || selected.sprintId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sprintName: sprintName || selected.sprintName, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : el | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )[0] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+186
to
+211
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Chaining |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : setSelected(periodOptions[3]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using a magic number |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| breakdownBy && setBreakdown({ value: breakdownBy, label: breakdownBy }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| view && setViewToggle(view); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| showControlChart && setControlChart(showControlChart); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, []); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (controlChartKeys.includes(metricType as string)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setShowControlChart(controlChart); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, [controlChart]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Box | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| display={'flex'} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| flexDirection={'column'} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| width={'100%'} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| minHeight={'100%'} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {location?.pathname !== '/custom-dashboard' ? ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Breadcrumbs /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) : ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Button | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClick={() => navigate(-1)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size="sm" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| variant="link" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| w={'fit-content'} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Back | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Button> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Box mt={1}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <TopSection | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data={modifiedData} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isLoading={isLoading} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setOpenDrawer={setOpenDrawer} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| openDrawer={openDrawer} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <BottomSection | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| breakdown={breakdown} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setBreakdown={setBreakdown} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| selected={selected} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSelected={setSelected} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| selectedTeam={selectedTeam} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSelectedTeam={setSelectedTeam} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isLoading={isLoading} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isFetching={isFetching} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data={modifiedData} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| viewToggle={viewToggle} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setViewToggle={setViewToggle} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| repos={repos} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setRepos={setRepos} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| filterBy={filterBy} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setFilterBy={setFilterBy} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handelReloadClick={handelReloadClick} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| controlChart={controlChart} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setControlChart={setControlChart} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Box> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {openDrawer && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <SlideInfoDrawer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handelDrawerClose={handleDrawerClose} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| openDrawer={openDrawer} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title={data?.chartMetadata?.chartTitle} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| chartKey={data?.chartMetadata?.chartKey} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| item={data} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Box> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The prop
initialTeamis destructured here but is never used within the component. To keep the component's API clean and avoid confusion, it should be removed from both the component's signature and themetricDetailPropsinterface (line 20).