@@ -43,11 +43,13 @@ import { | |||
import { | |||
isSameBranchLike, | |||
getBranchLikeQuery, | |||
isLongLivingBranch | |||
isLongLivingBranch, | |||
isMainBranch, | |||
getBranchLikeDisplayName | |||
} from '../../../helpers/branches'; | |||
import { fetchMetrics } from '../../../store/rootActions'; | |||
import { getMetrics, Store } from '../../../store/rootReducer'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import { translate, translateWithParameters } from '../../../helpers/l10n'; | |||
import '../styles.css'; | |||
interface Props { | |||
@@ -160,18 +162,61 @@ export class OverviewApp extends React.PureComponent<Props, State> { | |||
}; | |||
renderEmpty = () => { | |||
const { component } = this.props; | |||
const { branchLike, component } = this.props; | |||
const isApp = component.qualifier === 'APP'; | |||
/* eslint-disable no-lonely-if */ | |||
// - Is App | |||
// - No measures, OR measures, but no projects => empty | |||
// - Else => no lines of code | |||
// - Else | |||
// - No measures => empty | |||
// - Main branch? | |||
// - LLB? | |||
// - No branch info? | |||
// - Measures, but no ncloc (checked in isEmpty()) => no lines of code | |||
// - Main branch? | |||
// - LLB? | |||
// - No branch info? | |||
let title; | |||
if (isApp) { | |||
if ( | |||
this.state.measures === undefined || | |||
this.state.measures.find(measure => measure.metric.key === 'projects') === undefined | |||
) { | |||
title = translate('portfolio.app.empty'); | |||
} else { | |||
title = translate('portfolio.app.no_lines_of_code'); | |||
} | |||
} else { | |||
if (this.state.measures === undefined || this.state.measures.length === 0) { | |||
if (isMainBranch(branchLike)) { | |||
title = translate('overview.project.main_branch_empty'); | |||
} else if (branchLike !== undefined) { | |||
title = translateWithParameters( | |||
'overview.project.branch_X_empty', | |||
getBranchLikeDisplayName(branchLike) | |||
); | |||
} else { | |||
title = translate('overview.project.empty'); | |||
} | |||
} else { | |||
if (isMainBranch(branchLike)) { | |||
title = translate('overview.project.main_branch_no_lines_of_code'); | |||
} else if (branchLike !== undefined) { | |||
title = translateWithParameters( | |||
'overview.project.branch_X_no_lines_of_code', | |||
getBranchLikeDisplayName(branchLike) | |||
); | |||
} else { | |||
title = translate('overview.project.no_lines_of_code'); | |||
} | |||
} | |||
} | |||
/* eslint-enable no-lonely-if */ | |||
return ( | |||
<div className="overview-main page-main"> | |||
<h3> | |||
{!this.state.measures || | |||
!this.state.measures.find(measure => measure.metric.key === 'projects') | |||
? translate(isApp ? 'portfolio.app.empty' : 'overview.project.empty') | |||
: translate( | |||
isApp ? 'portfolio.app.no_lines_of_code' : 'overview.project.no_lines_of_code' | |||
)} | |||
</h3> | |||
<h3>{title}</h3> | |||
</div> | |||
); | |||
}; |
@@ -26,7 +26,8 @@ import { | |||
mockMainBranch, | |||
mockComponent, | |||
mockMetric, | |||
mockMeasure | |||
mockMeasure, | |||
mockLongLivingBranch | |||
} from '../../../../helpers/testMocks'; | |||
import { waitAndUpdate } from '../../../../helpers/testUtils'; | |||
@@ -70,18 +71,75 @@ it('should render correctly', async () => { | |||
expect(getAllTimeMachineData).toBeCalled(); | |||
}); | |||
it('should render correctly if no measures are found', async () => { | |||
it('should show the correct message if the application is empty or has no lines of code', async () => { | |||
(getMeasuresAndMeta as jest.Mock).mockResolvedValue({ | |||
component: { | |||
measures: [mockMeasure({ metric: 'coverage' })], | |||
measures: [mockMeasure({ metric: 'projects' })], | |||
name: 'foo' | |||
}, | |||
metrics: [mockMetric()] | |||
metrics: [mockMetric({ key: 'projects' })] | |||
}); | |||
const wrapper = shallowRender(); | |||
const wrapper = shallowRender({ | |||
component: mockComponent({ key: 'foo', name: 'foo', qualifier: 'APP' }) | |||
}); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper).toMatchSnapshot(); | |||
expect(wrapper.find('h3').text()).toBe('portfolio.app.no_lines_of_code'); | |||
(getMeasuresAndMeta as jest.Mock).mockResolvedValue({ | |||
component: { | |||
measures: [], | |||
name: 'bar' | |||
}, | |||
metrics: [] | |||
}); | |||
wrapper.setProps({ component: mockComponent({ key: 'bar', name: 'bar', qualifier: 'APP' }) }); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.find('h3').text()).toBe('portfolio.app.empty'); | |||
}); | |||
it('should show the correct message if the project is empty', async () => { | |||
(getMeasuresAndMeta as jest.Mock).mockResolvedValue({ | |||
component: { | |||
measures: [], | |||
name: 'foo' | |||
}, | |||
metrics: [] | |||
}); | |||
const wrapper = shallowRender({ branchLike: mockMainBranch() }); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.find('h3').text()).toBe('overview.project.main_branch_empty'); | |||
wrapper.setProps({ branchLike: mockLongLivingBranch({ name: 'branch-foo' }) }); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.find('h3').text()).toBe('overview.project.branch_X_empty.branch-foo'); | |||
wrapper.setProps({ branchLike: undefined }); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.find('h3').text()).toBe('overview.project.empty'); | |||
}); | |||
it('should show the correct message if the project has no lines of code', async () => { | |||
(getMeasuresAndMeta as jest.Mock).mockResolvedValue({ | |||
component: { | |||
measures: [mockMeasure({ metric: 'bugs' })], | |||
name: 'foo' | |||
}, | |||
metrics: [mockMetric({ key: 'bugs' })] | |||
}); | |||
const wrapper = shallowRender({ branchLike: mockMainBranch() }); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.find('h3').text()).toBe('overview.project.main_branch_no_lines_of_code'); | |||
wrapper.setProps({ branchLike: mockLongLivingBranch({ name: 'branch-foo' }) }); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.find('h3').text()).toBe('overview.project.branch_X_no_lines_of_code.branch-foo'); | |||
wrapper.setProps({ branchLike: undefined }); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.find('h3').text()).toBe('overview.project.no_lines_of_code'); | |||
}); | |||
function getMockHelpers() { |
@@ -781,132 +781,3 @@ exports[`should render correctly 2`] = ` | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render correctly if no measures are found 1`] = ` | |||
<div | |||
className="page page-limited" | |||
> | |||
<div | |||
className="overview page-with-sidebar" | |||
> | |||
<A11ySkipTarget | |||
anchor="overview_main" | |||
/> | |||
<div | |||
className="overview-main page-main" | |||
> | |||
<h3> | |||
overview.project.empty | |||
</h3> | |||
</div> | |||
<div | |||
className="overview-sidebar page-sidebar-fixed" | |||
> | |||
<Connect(Meta) | |||
branchLike={ | |||
Object { | |||
"analysisDate": "2018-01-01", | |||
"isMain": true, | |||
"name": "master", | |||
} | |||
} | |||
component={ | |||
Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
"name": "foo", | |||
"organization": "foo", | |||
"qualifier": "TRK", | |||
"qualityGate": Object { | |||
"isDefault": true, | |||
"key": "30", | |||
"name": "Sonar way", | |||
}, | |||
"qualityProfiles": Array [ | |||
Object { | |||
"deleted": false, | |||
"key": "my-qp", | |||
"language": "ts", | |||
"name": "Sonar way", | |||
}, | |||
], | |||
"tags": Array [], | |||
} | |||
} | |||
history={ | |||
Object { | |||
"bugs": Array [ | |||
Object { | |||
"date": "2019-01-05", | |||
"value": "2.0", | |||
}, | |||
], | |||
"coverage": Array [ | |||
Object { | |||
"date": "2019-01-04", | |||
"value": "95.5", | |||
}, | |||
], | |||
"duplicated_lines_density": Array [ | |||
Object { | |||
"date": "2019-01-02", | |||
"value": "1.0", | |||
}, | |||
], | |||
"ncloc": Array [ | |||
Object { | |||
"date": "2019-01-03", | |||
"value": "10000", | |||
}, | |||
], | |||
"sqale_index": Array [ | |||
Object { | |||
"date": "2019-01-01", | |||
"value": "1.0", | |||
}, | |||
], | |||
"vulnerabilities": Array [ | |||
Object { | |||
"date": "2019-01-05", | |||
"value": "0", | |||
}, | |||
], | |||
} | |||
} | |||
measures={ | |||
Array [ | |||
Object { | |||
"bestValue": true, | |||
"metric": Object { | |||
"id": "coverage", | |||
"key": "coverage", | |||
"name": "Coverage", | |||
"type": "PERCENT", | |||
}, | |||
"periods": Array [ | |||
Object { | |||
"bestValue": true, | |||
"index": 1, | |||
"value": "1.0", | |||
}, | |||
], | |||
"value": "1.0", | |||
}, | |||
] | |||
} | |||
metrics={ | |||
Object { | |||
"coverage": Object { | |||
"id": "coverage", | |||
"key": "coverage", | |||
"name": "Coverage", | |||
"type": "PERCENT", | |||
}, | |||
} | |||
} | |||
onComponentChange={[MockFunction]} | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
`; |
@@ -40,7 +40,7 @@ export default function ProjectCardOverallMeasures({ measures }: Props) { | |||
const { ncloc } = measures; | |||
if (!ncloc) { | |||
return <div className="note">{translate('overview.project.empty')}</div>; | |||
return <div className="note">{translate('overview.project.main_branch_empty')}</div>; | |||
} | |||
return ( |
@@ -243,7 +243,7 @@ exports[`should render empty 1`] = ` | |||
<div | |||
className="note" | |||
> | |||
overview.project.empty | |||
overview.project.main_branch_empty | |||
</div> | |||
`; | |||
@@ -2449,8 +2449,12 @@ overview.external_links=External Links | |||
overview.project_key.APP=Application Key | |||
overview.project_key.TRK=Project Key | |||
overview.project.no_lines_of_code=This project as no lines of code. | |||
overview.project.no_lines_of_code=This project has no lines of code. | |||
overview.project.empty=This project is empty. | |||
overview.project.branch_X_no_lines_of_code=The "{0}" branch has no lines of code. | |||
overview.project.branch_X_empty=The "{0}" branch of this project is empty. | |||
overview.project.main_branch_no_lines_of_code=The main branch has no lines of code. | |||
overview.project.main_branch_empty=The main branch of this project is empty. | |||
overview.metric.code_smells=Code Smells | |||
overview.metric.new_code_smells=New Code Smells |