aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorAmbroise C <ambroise.christea@sonarsource.com>2023-12-07 17:09:43 +0100
committersonartech <sonartech@sonarsource.com>2023-12-11 20:02:55 +0000
commit802e72275499a78b01f57f9ae60bb5df52078ed0 (patch)
tree68a5fedcb31dff1389d3228be0974918e3b8ba57 /server
parent6874d8004f4e3b059abdf9ad38e0458397caae67 (diff)
downloadsonarqube-802e72275499a78b01f57f9ae60bb5df52078ed0.tar.gz
sonarqube-802e72275499a78b01f57f9ae60bb5df52078ed0.zip
SONAR-20982 Align display of issue's data/execution flows with SC
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/design-system/src/components/ExecutionFlowAccordion.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/issues/issues-subnavigation/IssueItemLocationsQuantity.tsx8
-rw-r--r--server/sonar-web/src/main/js/apps/issues/issues-subnavigation/IssueLocationsNavigator.tsx86
4 files changed, 66 insertions, 38 deletions
diff --git a/server/sonar-web/design-system/src/components/ExecutionFlowAccordion.tsx b/server/sonar-web/design-system/src/components/ExecutionFlowAccordion.tsx
index 73ca6d46a08..e324b4dd558 100644
--- a/server/sonar-web/design-system/src/components/ExecutionFlowAccordion.tsx
+++ b/server/sonar-web/design-system/src/components/ExecutionFlowAccordion.tsx
@@ -29,19 +29,21 @@ interface Props {
children: ReactNode;
expanded?: boolean;
header: ReactNode;
+ hidden?: boolean;
id: string;
innerRef?: (node: HTMLDivElement) => void;
onClick?: () => void;
}
export function ExecutionFlowAccordion(props: Props) {
- const { children, expanded, header, id, innerRef, onClick } = props;
+ const { children, expanded, header, hidden, id, innerRef, onClick } = props;
return (
- <Accordion className={classNames({ expanded })} ref={innerRef}>
+ <Accordion className={classNames({ expanded, 'sw-hidden': hidden })} ref={innerRef}>
<Expander
aria-controls={`${id}-flow-accordion`}
aria-expanded={expanded}
+ aria-hidden={hidden}
id={`${id}-flow-accordion-button`}
onClick={onClick}
>
diff --git a/server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx b/server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx
index 3b94be4800e..fdc438e8319 100644
--- a/server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx
@@ -93,8 +93,8 @@ describe('issue app', () => {
const dataFlowButton = await screen.findByRole('button', {
name: 'issue.flow.x_steps.2 Backtracking 1',
});
- const exectionFlowButton = screen.getByRole('button', {
- name: 'issue.flow.x_steps.3 issue.full_execution_flow',
+ const exectionFlowButton = screen.getByRole('link', {
+ name: 'issue.show_full_execution_flow.3',
});
let dataLocation1Button = screen.getByLabelText('Data location 1');
diff --git a/server/sonar-web/src/main/js/apps/issues/issues-subnavigation/IssueItemLocationsQuantity.tsx b/server/sonar-web/src/main/js/apps/issues/issues-subnavigation/IssueItemLocationsQuantity.tsx
index 112e5c575a6..36e73763ed2 100644
--- a/server/sonar-web/src/main/js/apps/issues/issues-subnavigation/IssueItemLocationsQuantity.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/issues-subnavigation/IssueItemLocationsQuantity.tsx
@@ -20,7 +20,7 @@
import { ExecutionFlowIcon } from 'design-system';
import * as React from 'react';
import { translate } from '../../../helpers/l10n';
-import { Issue } from '../../../types/types';
+import { FlowType, Issue } from '../../../types/types';
interface Props {
issue: Pick<Issue, 'flows' | 'flowsWithType' | 'secondaryLocations'>;
@@ -50,7 +50,11 @@ function getLocationsText(issue: Props['issue']) {
} else if (flows.length > 1) {
return { quantity: flows.length, message: translate('issues.execution_flows') };
} else if (flowsWithType.length > 1) {
- return { quantity: flowsWithType.length, message: translate('issues.execution_flows') };
+ const dataFlows = flowsWithType.filter(({ type }) => type === FlowType.DATA);
+ return {
+ quantity: dataFlows.length,
+ message: translate(dataFlows.length > 1 ? 'issues.data_flows' : 'issues.data_flow'),
+ };
} else if (secondaryLocations.length === 1) {
return { quantity: secondaryLocations.length, message: translate('issues.location') };
} else if (secondaryLocations.length > 1) {
diff --git a/server/sonar-web/src/main/js/apps/issues/issues-subnavigation/IssueLocationsNavigator.tsx b/server/sonar-web/src/main/js/apps/issues/issues-subnavigation/IssueLocationsNavigator.tsx
index e8fc6b62493..4e9906ffcf7 100644
--- a/server/sonar-web/src/main/js/apps/issues/issues-subnavigation/IssueLocationsNavigator.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/issues-subnavigation/IssueLocationsNavigator.tsx
@@ -17,8 +17,8 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { ExecutionFlowAccordion, SubnavigationFlowSeparator } from 'design-system';
-import React, { useCallback, useRef } from 'react';
+import { DiscreetLink, ExecutionFlowAccordion, SubnavigationFlowSeparator } from 'design-system';
+import React, { Fragment, useCallback, useRef } from 'react';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { Flow, FlowType, Issue } from '../../../types/types';
import { getLocations } from '../utils';
@@ -98,32 +98,56 @@ export default function IssueLocationsNavigator(props: Props) {
<>
<div className="sw-flex sw-flex-col sw-gap-4 sw-mt-4">
{flows.map((flow, index) => (
- <ExecutionFlowAccordion
- expanded={index === selectedFlowIndex}
- header={
- <span>
- <strong>
- {flow.locations.length > 1
- ? translateWithParameters('issue.flow.x_steps', flow.locations.length)
- : translate('issue.flow.1_step')}
- </strong>{' '}
- {getExecutionFlowLabel(flow, hasFlowsWithType)}
- </span>
- }
- id={`${issue.key}-flow-${index}`}
- innerRef={(n) => (accordionElement.current = n)}
- key={`${issue.key}-flow-${index}`}
- onClick={() => {
- handleAccordionClick(index);
- }}
- >
- <IssueLocations
- issue={issue}
- locations={flow.locations}
- onLocationSelect={onLocationSelect}
- selectedLocationIndex={selectedLocationIndex}
- />
- </ExecutionFlowAccordion>
+ <Fragment key={`${issue.key}-flow-${index}`}>
+ <ExecutionFlowAccordion
+ expanded={index === selectedFlowIndex}
+ header={
+ <span>
+ <strong>
+ {flow.locations.length > 1
+ ? translateWithParameters('issue.flow.x_steps', flow.locations.length)
+ : translate('issue.flow.1_step')}
+ </strong>{' '}
+ {getExecutionFlowLabel(flow, hasFlowsWithType)}
+ </span>
+ }
+ hidden={
+ index !== selectedFlowIndex &&
+ flow.type === FlowType.EXECUTION &&
+ hasFlowsWithType
+ }
+ id={`${issue.key}-flow-${index}`}
+ innerRef={(n) => (accordionElement.current = n)}
+ onClick={() => {
+ handleAccordionClick(index);
+ }}
+ >
+ <IssueLocations
+ issue={issue}
+ locations={flow.locations}
+ onLocationSelect={onLocationSelect}
+ selectedLocationIndex={selectedLocationIndex}
+ />
+ </ExecutionFlowAccordion>
+ {index !== selectedFlowIndex &&
+ flow.type === FlowType.EXECUTION &&
+ hasFlowsWithType && (
+ <div>
+ <DiscreetLink
+ onClick={() => {
+ handleAccordionClick(index);
+ }}
+ preventDefault
+ to="{{}}"
+ >
+ {translateWithParameters(
+ 'issue.show_full_execution_flow',
+ flow.locations.length,
+ )}
+ </DiscreetLink>
+ </div>
+ )}
+ </Fragment>
))}
</div>
<IssueLocationsNavigatorKeyboardHint showLeftRightHint />
@@ -135,10 +159,8 @@ export default function IssueLocationsNavigator(props: Props) {
}
function getExecutionFlowLabel(flow: Flow, hasFlowsWithType: boolean) {
- if (hasFlowsWithType) {
- return flow.type === FlowType.EXECUTION
- ? translate('issue.full_execution_flow')
- : flow.description;
+ if (hasFlowsWithType && flow.type !== FlowType.EXECUTION) {
+ return flow.description;
}
return translate('issues.execution_flow');