aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIsmail Cherri <ismail.cherri@sonarsource.com>2024-11-28 17:52:19 +0100
committersonartech <sonartech@sonarsource.com>2024-11-29 20:03:08 +0000
commit2183264c5d8cf31afc1fe8c54c32e59d9ebe118c (patch)
treefde0a1b80d3a3c243010ae47fe8a48ed8723b6cc
parent326ba4497003b65eea83f55087ca79df9bd2a6ad (diff)
downloadsonarqube-2183264c5d8cf31afc1fe8c54c32e59d9ebe118c.tar.gz
sonarqube-2183264c5d8cf31afc1fe8c54c32e59d9ebe118c.zip
SONAR-23619 Invalidate project list cache when updating AI code status for project
-rw-r--r--server/sonar-web/src/main/js/apps/projectQualityGate/ProjectQualityGateApp.tsx40
-rw-r--r--server/sonar-web/src/main/js/apps/projectQualityGate/ProjectQualityGateAppRenderer.tsx46
-rw-r--r--server/sonar-web/src/main/js/queries/quality-gates.ts30
3 files changed, 71 insertions, 45 deletions
diff --git a/server/sonar-web/src/main/js/apps/projectQualityGate/ProjectQualityGateApp.tsx b/server/sonar-web/src/main/js/apps/projectQualityGate/ProjectQualityGateApp.tsx
index 73440e8f568..6456062b96b 100644
--- a/server/sonar-web/src/main/js/apps/projectQualityGate/ProjectQualityGateApp.tsx
+++ b/server/sonar-web/src/main/js/apps/projectQualityGate/ProjectQualityGateApp.tsx
@@ -21,8 +21,6 @@
import * as React from 'react';
import { addGlobalSuccessMessage } from '~design-system';
import {
- associateGateWithProject,
- dissociateGateWithProject,
fetchQualityGate,
fetchQualityGates,
getGateForProject,
@@ -46,7 +44,6 @@ interface State {
currentQualityGate?: QualityGate;
loading: boolean;
selectedQualityGateName: string;
- submitting: boolean;
}
class ProjectQualityGateApp extends React.PureComponent<Props, State> {
@@ -54,7 +51,6 @@ class ProjectQualityGateApp extends React.PureComponent<Props, State> {
state: State = {
loading: true,
selectedQualityGateName: USE_SYSTEM_DEFAULT,
- submitting: false,
};
componentDidMount() {
@@ -140,41 +136,19 @@ class ProjectQualityGateApp extends React.PureComponent<Props, State> {
this.setState({ selectedQualityGateName });
};
- handleSubmit = async () => {
- const { component } = this.props;
- const { allQualityGates, currentQualityGate, selectedQualityGateName } = this.state;
-
- if (allQualityGates === undefined || currentQualityGate === undefined) {
- return;
- }
-
- this.setState({ submitting: true });
-
- if (selectedQualityGateName === USE_SYSTEM_DEFAULT) {
- await dissociateGateWithProject({
- projectKey: component.key,
- }).catch(() => {
- /* noop */
- });
- } else {
- await associateGateWithProject({
- gateName: selectedQualityGateName,
- projectKey: component.key,
- }).catch(() => {
- /* noop */
- });
- }
+ handleSubmit = () => {
+ const { allQualityGates, selectedQualityGateName } = this.state;
if (this.mounted) {
addGlobalSuccessMessage(translate('project_quality_gate.successfully_updated'));
const newGate =
selectedQualityGateName === USE_SYSTEM_DEFAULT
- ? allQualityGates.find((gate) => gate.isDefault)
- : allQualityGates.find((gate) => gate.name === selectedQualityGateName);
+ ? allQualityGates?.find((gate) => gate.isDefault)
+ : allQualityGates?.find((gate) => gate.name === selectedQualityGateName);
if (newGate) {
- this.setState({ currentQualityGate: newGate, submitting: false });
+ this.setState({ currentQualityGate: newGate });
this.props.onComponentChange({ qualityGate: newGate });
}
}
@@ -187,8 +161,7 @@ class ProjectQualityGateApp extends React.PureComponent<Props, State> {
const { component } = this.props;
- const { allQualityGates, currentQualityGate, loading, selectedQualityGateName, submitting } =
- this.state;
+ const { allQualityGates, currentQualityGate, loading, selectedQualityGateName } = this.state;
return (
<ProjectQualityGateAppRenderer
@@ -199,7 +172,6 @@ class ProjectQualityGateApp extends React.PureComponent<Props, State> {
onSubmit={this.handleSubmit}
onSelect={this.handleSelect}
selectedQualityGateName={selectedQualityGateName}
- submitting={submitting}
/>
);
}
diff --git a/server/sonar-web/src/main/js/apps/projectQualityGate/ProjectQualityGateAppRenderer.tsx b/server/sonar-web/src/main/js/apps/projectQualityGate/ProjectQualityGateAppRenderer.tsx
index 40f9711c118..0f45c794ee7 100644
--- a/server/sonar-web/src/main/js/apps/projectQualityGate/ProjectQualityGateAppRenderer.tsx
+++ b/server/sonar-web/src/main/js/apps/projectQualityGate/ProjectQualityGateAppRenderer.tsx
@@ -53,6 +53,10 @@ import { isDiffMetric } from '../../helpers/measures';
import { LabelValueSelectOption } from '../../helpers/search';
import { getQualityGateUrl } from '../../helpers/urls';
import { useProjectAiCodeAssuranceStatusQuery } from '../../queries/ai-code-assurance';
+import {
+ useAssociateGateWithProjectMutation,
+ useDissociateGateWithProjectMutation,
+} from '../../queries/quality-gates';
import { ComponentQualifier } from '../../sonar-aligned/types/component';
import { Feature } from '../../types/features';
import { Component, QualityGate } from '../../types/types';
@@ -67,9 +71,8 @@ export interface ProjectQualityGateAppRendererProps extends WithAvailableFeature
currentQualityGate?: QualityGate;
loading: boolean;
onSelect: (id: string) => void;
- onSubmit: () => Promise<void>;
+ onSubmit: () => void;
selectedQualityGateName: string;
- submitting: boolean;
}
function hasConditionOnNewCode(qualityGate: QualityGate): boolean {
@@ -123,14 +126,8 @@ function singleValueRenderer(props: SingleValueProps<QualityGateOption, false>)
}
function ProjectQualityGateAppRenderer(props: Readonly<ProjectQualityGateAppRendererProps>) {
- const {
- allQualityGates,
- component,
- currentQualityGate,
- loading,
- selectedQualityGateName,
- submitting,
- } = props;
+ const { allQualityGates, component, currentQualityGate, loading, selectedQualityGateName } =
+ props;
const defaultQualityGate = allQualityGates?.find((g) => g.isDefault);
const [isUserEditing, setIsUserEditing] = useState(false);
@@ -144,6 +141,33 @@ function ProjectQualityGateAppRenderer(props: Readonly<ProjectQualityGateAppRend
},
);
+ const { mutateAsync: associateGateWithProject, isPending: associateIsPending } =
+ useAssociateGateWithProjectMutation();
+ const { mutateAsync: dissociateGateWithProject, isPending: dissociateisPending } =
+ useDissociateGateWithProjectMutation();
+ const submitting = associateIsPending || dissociateisPending;
+
+ const handleSubmit = async () => {
+ const { allQualityGates, currentQualityGate, selectedQualityGateName } = props;
+
+ if (allQualityGates === undefined || currentQualityGate === undefined) {
+ return;
+ }
+
+ if (selectedQualityGateName === USE_SYSTEM_DEFAULT) {
+ await dissociateGateWithProject({
+ projectKey: component.key,
+ });
+ } else {
+ await associateGateWithProject({
+ gateName: selectedQualityGateName,
+ projectKey: component.key,
+ });
+ }
+
+ props.onSubmit();
+ };
+
if (loading) {
return <Spinner />;
}
@@ -272,7 +296,7 @@ function ProjectQualityGateAppRenderer(props: Readonly<ProjectQualityGateAppRend
<form
onSubmit={async (e) => {
e.preventDefault();
- await props.onSubmit();
+ await handleSubmit();
setIsUserEditing(false);
refetchAiCodeAssuranceStatus();
}}
diff --git a/server/sonar-web/src/main/js/queries/quality-gates.ts b/server/sonar-web/src/main/js/queries/quality-gates.ts
index caff5bb8257..448755f2872 100644
--- a/server/sonar-web/src/main/js/queries/quality-gates.ts
+++ b/server/sonar-web/src/main/js/queries/quality-gates.ts
@@ -23,11 +23,13 @@ import { useIntl } from 'react-intl';
import { addGlobalSuccessMessage } from '~design-system';
import { BranchParameters } from '~sonar-aligned/types/branch-like';
import {
+ associateGateWithProject,
copyQualityGate,
createCondition,
createQualityGate,
deleteCondition,
deleteQualityGate,
+ dissociateGateWithProject,
fetchQualityGate,
fetchQualityGates,
getAllQualityGateProjects,
@@ -200,6 +202,34 @@ export function useSetAiSupportedQualityGateMutation(name: string) {
});
}
+export function useAssociateGateWithProjectMutation() {
+ const queryClient = useQueryClient();
+
+ return useMutation({
+ mutationFn: (data: { gateName: string; projectKey: string }) => {
+ return associateGateWithProject(data);
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: qualityQuery.projectsAssoc() });
+ queryClient.invalidateQueries({ queryKey: ['project', 'list'] });
+ },
+ });
+}
+
+export function useDissociateGateWithProjectMutation() {
+ const queryClient = useQueryClient();
+
+ return useMutation({
+ mutationFn: (data: { projectKey: string }) => {
+ return dissociateGateWithProject(data);
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: qualityQuery.projectsAssoc() });
+ queryClient.invalidateQueries({ queryKey: ['project', 'list'] });
+ },
+ });
+}
+
export function useFixQualityGateMutation(gateName: string) {
const queryClient = useQueryClient();