diff --git a/web-server/src/components/PRTable/PullRequestTableColumnSelector.tsx b/web-server/src/components/PRTable/PullRequestTableColumnSelector.tsx index a9ab41afc..48828e5f0 100644 --- a/web-server/src/components/PRTable/PullRequestTableColumnSelector.tsx +++ b/web-server/src/components/PRTable/PullRequestTableColumnSelector.tsx @@ -13,10 +13,7 @@ import { FlexBox } from '../FlexBox'; const formatColumnName = ( name: keyof typeof DEFAULT_PR_TABLE_COLUMN_STATE_MAP -) => { - if (name === 'lead_time_as_sum_of_parts') return 'Lead Time'; - return name.split('_').join(' '); -}; +) => name.split('_').join(' '); export const PullRequestTableColumnSelector = () => { const theme = useTheme(); diff --git a/web-server/src/components/PRTable/PullRequestsTable.tsx b/web-server/src/components/PRTable/PullRequestsTable.tsx index 5f3ac9516..27d9e8284 100644 --- a/web-server/src/components/PRTable/PullRequestsTable.tsx +++ b/web-server/src/components/PRTable/PullRequestsTable.tsx @@ -37,8 +37,8 @@ import { Line } from '@/components/Text'; import { SearchInput } from '@/components/TicketsTableAddons/SearchInput'; import { EasyState, useEasyState } from '@/hooks/useEasyState'; import { useTableSort } from '@/hooks/useTableSort'; -import { DEFAULT_PR_TABLE_COLUMN_STATE_MAP } from '@/slices/app'; -import { useSelector } from '@/store'; +import { DEFAULT_PR_TABLE_COLUMN_STATE_MAP, appSlice } from '@/slices/app'; +import { useDispatch, useSelector } from '@/store'; import { brandColors } from '@/theme/schemes/theme'; import { PR } from '@/types/resources'; import { getDurationString } from '@/utils/date'; @@ -110,6 +110,8 @@ export const PullRequestsTable: FC< const enableCsv = true; + useLeadTimeMigration(); + return ( {pageCount > 1 && ( @@ -199,71 +201,60 @@ export const PullRequestsTable: FC< - - - }> + {enabledColumnsSet?.has('commits') && ( + + {enabledColumnsSet?.has('commits') && ( - {enabledColumnsSet?.has('commits') && ( - - - {pr.commits} - - )} - {enabledColumnsSet?.has('lines_changed') && ( - - - - {pr.additions + pr.deletions} - - - )} - {enabledColumnsSet?.has('comments') && ( - - - {pr.comments} - - )} + + {pr.commits} - - - + )} + + )} + {enabledColumnsSet?.has('lines_changed') && ( + + { + + + + {pr.additions + pr.deletions} + + + } + + )} + {enabledColumnsSet?.has('comments') && ( + + { + + + {pr.comments} + + } + + )} {enabledColumnsSet.has('base_branch') && ( {pr.base_branch} )} @@ -384,7 +375,7 @@ export const PullRequestsTable: FC< )} - {enabledColumnsSet.has('lead_time_as_sum_of_parts') && ( + {enabledColumnsSet.has('lead_time') && ( ); }; + +const useLeadTimeMigration = () => { + const prEnabledConfig = useSelector((s) => s.app.prTableColumnsConfig) as any; + const dispatch = useDispatch(); + useEffect(() => { + if (prEnabledConfig?.lead_time_as_sum_of_parts !== undefined) { + const updatedColumns = { ...prEnabledConfig }; + updatedColumns.lead_time = updatedColumns.lead_time_as_sum_of_parts; + delete updatedColumns.lead_time_as_sum_of_parts; + dispatch(appSlice.actions.setPrTableColumnConfig(updatedColumns)); + } + }, [dispatch, prEnabledConfig]); +}; diff --git a/web-server/src/components/PRTable/PullRequestsTableHead.tsx b/web-server/src/components/PRTable/PullRequestsTableHead.tsx index 1fc545ef9..c2fa1cc7b 100644 --- a/web-server/src/components/PRTable/PullRequestsTableHead.tsx +++ b/web-server/src/components/PRTable/PullRequestsTableHead.tsx @@ -1,6 +1,5 @@ import { ScheduleRounded } from '@mui/icons-material'; import { - Box, Checkbox, TableCell, TableHead, @@ -88,53 +87,44 @@ export const PullRequestsTableHead: FC = ({ )} updateSortConf('updated_at')} + direction={conf.field === 'repo_name' ? conf.order : 'asc'} + active={conf.field === 'repo_name'} + onClick={() => updateSortConf('repo_name')} > Pull Request - + + { - if (enabledColumnsSet?.has('commits')) { - return updateSortConf('commits'); - } - if (enabledColumnsSet?.has('lines_changed')) { - return updateSortConf('additions'); - } - if (enabledColumnsSet?.has('comments')) { - return updateSortConf('comments'); - } - }} + onClick={() => updateSortConf('commits')} > - - {enabledColumnsSet?.has('commits') && ( - <> - Commits - / - - )} - {enabledColumnsSet?.has('lines_changed') && ( - <> - Lines - / - - )} - {enabledColumnsSet?.has('comments') && ( - Comments - )} - + Commits + + + updateSortConf('additions')} + > + Lines + + + + + updateSortConf('comments')} + > + Comments + + + {enabledColumnsSet.has('base_branch') && ( = ({ )} - {enabledColumnsSet.has('lead_time_as_sum_of_parts') && ( + {enabledColumnsSet.has('lead_time') && ( updateSortConf('lead_time_as_sum_of_parts')} + direction={conf.field === 'lead_time' ? conf.order : 'asc'} + active={conf.field === 'lead_time'} + onClick={() => updateSortConf('lead_time')} > Lead diff --git a/web-server/src/components/PRTableMini/PullRequestsTableHeadMini.tsx b/web-server/src/components/PRTableMini/PullRequestsTableHeadMini.tsx index e4bd90754..b62a60a9a 100644 --- a/web-server/src/components/PRTableMini/PullRequestsTableHeadMini.tsx +++ b/web-server/src/components/PRTableMini/PullRequestsTableHeadMini.tsx @@ -80,14 +80,14 @@ export const PullRequestsTableHeadMini: FC = ({ )} - {!hideColumns?.has('cycle_time') && ( + {!hideColumns?.has('lead_time') && ( updateSortConf('cycle_time')} + direction={conf.field === 'lead_time' ? conf.order : 'asc'} + active={conf.field === 'lead_time'} + onClick={() => updateSortConf('lead_time')} > - Cycle + Lead )} diff --git a/web-server/src/content/DoraMetrics/DoraCards/SkeletalCard.tsx b/web-server/src/content/DoraMetrics/DoraCards/SkeletalCard.tsx index 205a7ec85..585a4feec 100644 --- a/web-server/src/content/DoraMetrics/DoraCards/SkeletalCard.tsx +++ b/web-server/src/content/DoraMetrics/DoraCards/SkeletalCard.tsx @@ -26,7 +26,7 @@ export const DataStillSyncing = () => { }, [flickerAnimation.toggle]); return ( - + @@ -118,6 +118,7 @@ const ScoreSkeleton: FC<{ animation?: boolean }> = ({ animation }) => { ml={1} sx={{ filter: `brightness(${animation ? 0.7 : 1})`, + opacity: animation ? 0.7 : 1, transition: `all ${ANIMATON_DURATION}ms linear` }} > diff --git a/web-server/src/content/DoraMetrics/Incidents.tsx b/web-server/src/content/DoraMetrics/Incidents.tsx index 2b9fe88f5..cf3bf497e 100644 --- a/web-server/src/content/DoraMetrics/Incidents.tsx +++ b/web-server/src/content/DoraMetrics/Incidents.tsx @@ -184,33 +184,41 @@ export const AllIncidentsBody = () => { {' '} from {dateRangeLabel} across all data sources,{' '} {filteredDeployments.length}{' '} - {pluralize('deployment', filteredDeployments.length)} may have led to - possible incidents. + {pluralize('deployment', filteredDeployments.length)}{' '} + {filteredDeployments.length ? 'may' : ''} have led to possible + incidents. - - - - - - - {filteredDeployments?.map((deployment) => { - return ( - - ); - })} + + {!!filteredDeployments.length && ( + <> + + + + + + + {filteredDeployments?.map((deployment) => { + return ( + + ); + })} + + - + + + - - - - + + )} ); }; diff --git a/web-server/src/hooks/useTableSort.ts b/web-server/src/hooks/useTableSort.ts index 2b513b999..2f756df52 100644 --- a/web-server/src/hooks/useTableSort.ts +++ b/web-server/src/hooks/useTableSort.ts @@ -1,6 +1,5 @@ -import { ascend, descend, partition, propOr, sort } from 'ramda'; +import { ascend, descend, head, partition, propOr, sort } from 'ramda'; import { useCallback, useMemo } from 'react'; -import { snakeCase } from 'voca'; import { track } from '@/constants/events'; import { useEasyState } from '@/hooks/useEasyState'; @@ -29,9 +28,30 @@ export const useTableSort = >( [conf.field, conf.order, sortConfig.set] ); - const sortedList: T[] = useMemo( - () => - sort( + const handleAuthorUsernameSort = useCallback( + (rawList: any[]) => { + if (!head(rawList || [])?.author?.username) return rawList; + + const result = [...rawList]; + if (conf.order === 'asc') { + result.sort((a, b) => { + return a.author.username.localeCompare(b.author.username); + }); + } else { + result.sort((b, a) => { + return a.author.username.localeCompare(b.author.username); + }); + } + return result; + }, + [conf.order] + ); + + const sortedList: T[] = useMemo(() => { + if (conf.field === 'author') { + return handleAuthorUsernameSort(list); + } else + return sort( // @ts-ignore conf.order === 'asc' ? // @ts-ignore @@ -39,9 +59,8 @@ export const useTableSort = >( : // @ts-ignore descend(propOr('', conf.field)), list - ), - [conf.field, conf.order, list] - ); + ); + }, [conf.field, conf.order, handleAuthorUsernameSort, list]); const getCSV = useCallback(() => { createCsvFromList(list); @@ -84,10 +103,6 @@ const EXCLUDED_HEADERS = new Set([ 'priority_order' ]); -const headerNameOverrides: Record = { - lead_time_as_sum_of_parts: 'lead_time_for_changes' -}; - const getNestedValueFromCell = (cell: any) => { if (Array.isArray(cell) && getNestedValueFromCellItem(cell[0])) { const values = cell.map(getNestedValueFromCellItem).filter(Boolean); @@ -110,10 +125,6 @@ const checkIfColumnShouldBeRemoved = (name: string, cell: any) => { return false; }; -const renameColumns = (headers: string[]) => { - return headers.map((name) => snakeCase(headerNameOverrides[name] || name)); -}; - const createCsvFromList = (list: Record[]) => { if (!list.length) return; @@ -144,7 +155,7 @@ const createCsvFromList = (list: Record[]) => { .join(',') ); - const headers = renameColumns([...includedSet.keys()]); + const headers = [...includedSet.keys()]; downloadCSVFromString( [headers.join(','), ...rows].join('\n'), diff --git a/web-server/src/slices/app.ts b/web-server/src/slices/app.ts index 392041aec..4bbd5b943 100644 --- a/web-server/src/slices/app.ts +++ b/web-server/src/slices/app.ts @@ -61,7 +61,7 @@ export const DEFAULT_PR_TABLE_COLUMN_STATE_MAP = { rework_time: false, merge_time: false, merge_to_deploy: false, - lead_time_as_sum_of_parts: true, + lead_time: true, created_at: false, updated_at: false, head_branch: false, diff --git a/web-server/src/types/resources.ts b/web-server/src/types/resources.ts index 2a737b440..556de426e 100644 --- a/web-server/src/types/resources.ts +++ b/web-server/src/types/resources.ts @@ -125,6 +125,7 @@ export interface BasePR { export interface PR extends BasePR { lead_time_as_sum_of_parts?: number; + lead_time?: number; original_reverted_pr?: BasePR; }