]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-13999 Drop orgs from QualityGates
authorJeremy Davis <jeremy.davis@sonarsource.com>
Thu, 10 Dec 2020 16:55:59 +0000 (17:55 +0100)
committersonartech <sonartech@sonarsource.com>
Tue, 22 Dec 2020 20:09:36 +0000 (20:09 +0000)
21 files changed:
server/sonar-web/src/main/js/api/quality-gates.ts
server/sonar-web/src/main/js/apps/quality-gates/components/App.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/Condition.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/ConditionModal.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/CopyQualityGateForm.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/CreateQualityGateForm.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/DeleteQualityGateForm.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/Details.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/DetailsContent.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/DetailsHeader.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/RenameQualityGateForm.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ConditionModal-test.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/CopyQualityGateForm-test.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/DeleteQualityGateForm-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Projects-test.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/RenameQualityGateForm-test.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/CopyQualityGateForm-test.tsx.snap
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DeleteQualityGateForm-test.tsx.snap [new file with mode: 0644]

index 054e1b63708354472e6936e783923974cf2d74f5..f82e737967ed6206cc32052934ddab37248aeda9 100644 (file)
@@ -22,82 +22,54 @@ import throwGlobalError from '../app/utils/throwGlobalError';
 import { BranchParameters } from '../types/branch-like';
 import { QualityGateApplicationStatus, QualityGateProjectStatus } from '../types/quality-gates';
 
-export function fetchQualityGates(data?: {
-  organization?: string;
-}): Promise<{
+export function fetchQualityGates(): Promise<{
   actions: { create: boolean };
   qualitygates: T.QualityGate[];
 }> {
-  return getJSON('/api/qualitygates/list', data).catch(throwGlobalError);
+  return getJSON('/api/qualitygates/list').catch(throwGlobalError);
 }
 
-export function fetchQualityGate(data: {
-  id: number | string;
-  organization?: string;
-}): Promise<T.QualityGate> {
+export function fetchQualityGate(data: { id: number | string }): Promise<T.QualityGate> {
   return getJSON('/api/qualitygates/show', data).catch(throwGlobalError);
 }
 
-export function createQualityGate(data: {
-  name: string;
-  organization?: string;
-}): Promise<T.QualityGate> {
+export function createQualityGate(data: { name: string }): Promise<T.QualityGate> {
   return postJSON('/api/qualitygates/create', data).catch(throwGlobalError);
 }
 
-export function deleteQualityGate(data: {
-  id: string;
-  organization?: string;
-}): Promise<void | Response> {
+export function deleteQualityGate(data: { id: string }): Promise<void | Response> {
   return post('/api/qualitygates/destroy', data).catch(throwGlobalError);
 }
 
-export function renameQualityGate(data: {
-  id: string;
-  name: string;
-  organization?: string;
-}): Promise<void | Response> {
+export function renameQualityGate(data: { id: string; name: string }): Promise<void | Response> {
   return post('/api/qualitygates/rename', data).catch(throwGlobalError);
 }
 
-export function copyQualityGate(data: {
-  id: string;
-  name: string;
-  organization?: string;
-}): Promise<T.QualityGate> {
+export function copyQualityGate(data: { id: string; name: string }): Promise<T.QualityGate> {
   return postJSON('/api/qualitygates/copy', data).catch(throwGlobalError);
 }
 
-export function setQualityGateAsDefault(data: {
-  id: string;
-  organization?: string;
-}): Promise<void | Response> {
+export function setQualityGateAsDefault(data: { id: string }): Promise<void | Response> {
   return post('/api/qualitygates/set_as_default', data).catch(throwGlobalError);
 }
 
 export function createCondition(
   data: {
     gateId: string;
-    organization?: string;
   } & T.Omit<T.Condition, 'id'>
 ): Promise<T.Condition> {
   return postJSON('/api/qualitygates/create_condition', data).catch(throwGlobalError);
 }
 
-export function updateCondition(
-  data: { organization?: string } & T.Condition
-): Promise<T.Condition> {
+export function updateCondition(data: T.Condition): Promise<T.Condition> {
   return postJSON('/api/qualitygates/update_condition', data).catch(throwGlobalError);
 }
 
-export function deleteCondition(data: { id: number; organization?: string }): Promise<void> {
+export function deleteCondition(data: { id: number }): Promise<void> {
   return post('/api/qualitygates/delete_condition', data);
 }
 
-export function getGateForProject(data: {
-  organization?: string;
-  project: string;
-}): Promise<T.QualityGate | undefined> {
+export function getGateForProject(data: { project: string }): Promise<T.QualityGate | undefined> {
   return getJSON('/api/qualitygates/get_by_project', data).then(
     ({ qualityGate }) =>
       qualityGate && {
@@ -110,7 +82,6 @@ export function getGateForProject(data: {
 
 export function searchProjects(data: {
   gateName: string;
-  organization?: string;
   page?: number;
   pageSize?: number;
   query?: string;
@@ -124,7 +95,6 @@ export function searchProjects(data: {
 
 export function associateGateWithProject(data: {
   gateId: string;
-  organization?: string;
   projectKey: string;
 }): Promise<void | Response> {
   return post('/api/qualitygates/select', data).catch(throwGlobalError);
@@ -132,7 +102,6 @@ export function associateGateWithProject(data: {
 
 export function dissociateGateWithProject(data: {
   gateId: string;
-  organization?: string;
   projectKey: string;
 }): Promise<void | Response> {
   return post('/api/qualitygates/deselect', data).catch(throwGlobalError);
@@ -141,7 +110,6 @@ export function dissociateGateWithProject(data: {
 export function getApplicationQualityGate(data: {
   application: string;
   branch?: string;
-  organization?: string;
 }): Promise<QualityGateApplicationStatus> {
   return getJSON('/api/qualitygates/application_status', data).catch(throwGlobalError);
 }
index 76e2d45004ed51580cd5397978507f900627dc33..7270d953afa28cda0a0823b7649b0820cca9b0b9 100644 (file)
@@ -38,17 +38,13 @@ import Details from './Details';
 import List from './List';
 import ListHeader from './ListHeader';
 
-interface Props extends WithRouterProps {
-  organization?: Pick<T.Organization, 'key'>;
-}
-
 interface State {
   canCreate: boolean;
   loading: boolean;
   qualityGates: T.QualityGate[];
 }
 
-class App extends React.PureComponent<Props, State> {
+class App extends React.PureComponent<WithRouterProps, State> {
   mounted = false;
   state: State = { canCreate: false, loading: true, qualityGates: [] };
 
@@ -59,7 +55,7 @@ class App extends React.PureComponent<Props, State> {
     addSideBarClass();
   }
 
-  componentDidUpdate(prevProps: Props) {
+  componentDidUpdate(prevProps: WithRouterProps) {
     if (prevProps.params.id !== undefined && this.props.params.id === undefined) {
       this.openDefault(this.state.qualityGates);
     }
@@ -72,8 +68,7 @@ class App extends React.PureComponent<Props, State> {
   }
 
   fetchQualityGates = () => {
-    const { organization } = this.props;
-    return fetchQualityGates({ organization: organization && organization.key }).then(
+    return fetchQualityGates().then(
       ({ actions, qualitygates: qualityGates }) => {
         if (this.mounted) {
           this.setState({ canCreate: actions.create, loading: false, qualityGates });
@@ -113,7 +108,6 @@ class App extends React.PureComponent<Props, State> {
     const { id } = this.props.params;
     const { canCreate, qualityGates } = this.state;
     const defaultTitle = translate('quality_gates.page');
-    const organization = this.props.organization && this.props.organization.key;
 
     return (
       <>
@@ -128,7 +122,6 @@ class App extends React.PureComponent<Props, State> {
                   <div className="layout-page-filters">
                     <ListHeader
                       canCreate={canCreate}
-                      organization={organization}
                       refreshQualityGates={this.fetchQualityGates}
                     />
                     <DeferredSpinner loading={this.state.loading}>
@@ -144,7 +137,6 @@ class App extends React.PureComponent<Props, State> {
             <Details
               id={id}
               onSetDefault={this.handleSetDefault}
-              organization={organization}
               qualityGates={this.state.qualityGates}
               refreshQualityGates={this.fetchQualityGates}
             />
index c8f163861782d944c45285a74db2ff097a2d8af6..89f1685552d74e1cfbd1f448bc442a9fae7c8ec5 100644 (file)
@@ -35,7 +35,6 @@ interface Props {
   condition: T.Condition;
   canEdit: boolean;
   metric: T.Metric;
-  organization?: string;
   onRemoveCondition: (Condition: T.Condition) => void;
   onSaveCondition: (newCondition: T.Condition, oldCondition: T.Condition) => void;
   qualityGate: T.QualityGate;
@@ -77,7 +76,7 @@ export default class Condition extends React.PureComponent<Props, State> {
   };
 
   removeCondition = (condition: T.Condition) => {
-    deleteCondition({ id: condition.id, organization: this.props.organization }).then(
+    deleteCondition({ id: condition.id }).then(
       () => this.props.onRemoveCondition(condition),
       () => {}
     );
@@ -92,7 +91,7 @@ export default class Condition extends React.PureComponent<Props, State> {
   }
 
   render() {
-    const { condition, canEdit, metric, organization, qualityGate, updated } = this.props;
+    const { condition, canEdit, metric, qualityGate, updated } = this.props;
     return (
       <tr className={classNames({ highlighted: updated })}>
         <td className="text-middle">
@@ -127,7 +126,6 @@ export default class Condition extends React.PureComponent<Props, State> {
                 metric={metric}
                 onAddCondition={this.handleUpdateCondition}
                 onClose={this.handleUpdateClose}
-                organization={organization}
                 qualityGate={qualityGate}
               />
             )}
index 2a9fb8a5184394fade6fb4d9e5fab927d7d39ba5..bb7b800e444fa4fc33fedc1f54d88cd99292fb5f 100644 (file)
@@ -36,7 +36,6 @@ interface Props {
   header: string;
   onAddCondition: (condition: T.Condition) => void;
   onClose: () => void;
-  organization?: string;
   qualityGate: T.QualityGate;
 }
 
@@ -66,15 +65,15 @@ export default class ConditionModal extends React.PureComponent<Props, State> {
 
   handleFormSubmit = () => {
     if (this.state.metric) {
-      const { condition, qualityGate, organization } = this.props;
+      const { condition, qualityGate } = this.props;
       const newCondition: T.Omit<T.Condition, 'id'> = {
         metric: this.state.metric.key,
         op: this.getSinglePossibleOperator(this.state.metric) || this.state.op,
         error: this.state.error
       };
       const submitPromise = condition
-        ? updateCondition({ organization, id: condition.id, ...newCondition })
-        : createCondition({ gateId: qualityGate.id, organization, ...newCondition });
+        ? updateCondition({ id: condition.id, ...newCondition })
+        : createCondition({ gateId: qualityGate.id, ...newCondition });
       return submitPromise.then(this.props.onAddCondition);
     }
     return Promise.reject();
index d90c53ebe2a4f806484d1a35b590ca060298a6d4..cb3f178d39b31e23332ff5f13a55fe6d36b0cbbd 100644 (file)
@@ -38,7 +38,6 @@ interface Props {
   onAddCondition: (condition: T.Condition) => void;
   onRemoveCondition: (Condition: T.Condition) => void;
   onSaveCondition: (newCondition: T.Condition, oldCondition: T.Condition) => void;
-  organization?: string;
   qualityGate: T.QualityGate;
   updatedConditionId?: number;
 }
@@ -59,7 +58,6 @@ export class Conditions extends React.PureComponent<Props> {
       canEdit,
       onRemoveCondition,
       onSaveCondition,
-      organization,
       updatedConditionId
     } = this.props;
     return (
@@ -88,7 +86,6 @@ export class Conditions extends React.PureComponent<Props> {
               metric={metrics[condition.metric]}
               onRemoveCondition={onRemoveCondition}
               onSaveCondition={onSaveCondition}
-              organization={organization}
               qualityGate={qualityGate}
               updated={condition.id === updatedConditionId}
             />
@@ -150,7 +147,6 @@ export class Conditions extends React.PureComponent<Props> {
                   metrics={availableMetrics}
                   onAddCondition={this.props.onAddCondition}
                   onClose={onClose}
-                  organization={this.props.organization}
                   qualityGate={this.props.qualityGate}
                 />
               )}>
index dd727b4a4903bb88718e028d00db3350b461aa09..11d03bbf83bfb8ba9f4d438e602d3a1597738549 100644 (file)
@@ -27,7 +27,6 @@ import { getQualityGateUrl } from '../../../helpers/urls';
 interface Props {
   onClose: () => void;
   onCopy: () => Promise<void>;
-  organization?: string;
   qualityGate: T.QualityGate;
   router: Pick<Router, 'push'>;
 }
@@ -36,7 +35,7 @@ interface State {
   name: string;
 }
 
-class CopyQualityGateForm extends React.PureComponent<Props, State> {
+export class CopyQualityGateForm extends React.PureComponent<Props, State> {
   constructor(props: Props) {
     super(props);
     this.state = { name: props.qualityGate.name };
@@ -47,14 +46,14 @@ class CopyQualityGateForm extends React.PureComponent<Props, State> {
   };
 
   handleCopy = () => {
-    const { qualityGate, organization } = this.props;
+    const { qualityGate } = this.props;
     const { name } = this.state;
 
     if (!name) {
       return undefined;
     }
 
-    return copyQualityGate({ id: qualityGate.id, name, organization }).then(qualityGate => {
+    return copyQualityGate({ id: qualityGate.id, name }).then(qualityGate => {
       this.props.onCopy();
       this.props.router.push(getQualityGateUrl(String(qualityGate.id)));
     });
index 53f964ee74c5715d5840e66a8abb0a33402a82ed..d209517cfb88d07da26f0a4a900fb013d944de7d 100644 (file)
@@ -27,7 +27,6 @@ import { getQualityGateUrl } from '../../../helpers/urls';
 interface Props {
   onClose: () => void;
   onCreate: () => Promise<void>;
-  organization?: string;
   router: Pick<Router, 'push'>;
 }
 
@@ -43,14 +42,13 @@ class CreateQualityGateForm extends React.PureComponent<Props, State> {
   };
 
   handleCreate = () => {
-    const { organization } = this.props;
     const { name } = this.state;
 
     if (!name) {
       return undefined;
     }
 
-    return createQualityGate({ name, organization })
+    return createQualityGate({ name })
       .then(qualityGate => {
         return this.props.onCreate().then(() => qualityGate);
       })
index 0bfaaaf6668e1c762c50f418e087a6483d8dcf91..a3b76a64d01ff068776ea7cede34d1b8f934c97b 100644 (file)
@@ -27,15 +27,14 @@ import { getQualityGatesUrl } from '../../../helpers/urls';
 
 interface Props {
   onDelete: () => Promise<void>;
-  organization?: string;
   qualityGate: T.QualityGate;
   router: Pick<Router, 'push'>;
 }
 
-class DeleteQualityGateForm extends React.PureComponent<Props> {
+export class DeleteQualityGateForm extends React.PureComponent<Props> {
   onDelete = () => {
-    const { organization, qualityGate } = this.props;
-    return deleteQualityGate({ id: qualityGate.id, organization })
+    const { qualityGate } = this.props;
+    return deleteQualityGate({ id: qualityGate.id })
       .then(this.props.onDelete)
       .then(() => {
         this.props.router.push(getQualityGatesUrl());
index c7967dcaab9bcb0953850e6ebe11e2ccf81dd521..6ebbcea42a353ba6597696bde19f1625d2173145 100644 (file)
@@ -33,7 +33,6 @@ import DetailsHeader from './DetailsHeader';
 interface OwnProps {
   id: string;
   onSetDefault: (qualityGate: T.QualityGate) => void;
-  organization?: string;
   qualityGates: T.QualityGate[];
   refreshQualityGates: () => Promise<void>;
 }
@@ -75,9 +74,9 @@ export class Details extends React.PureComponent<Props, State> {
   }
 
   fetchDetails = () => {
-    const { id, organization } = this.props;
+    const { id } = this.props;
     this.setState({ loading: true });
-    return fetchQualityGate({ id, organization }).then(
+    return fetchQualityGate({ id }).then(
       qualityGate => {
         if (this.mounted) {
           this.setState({ loading: false, qualityGate, updatedConditionId: undefined });
@@ -145,7 +144,7 @@ export class Details extends React.PureComponent<Props, State> {
   };
 
   render() {
-    const { organization, metrics, refreshQualityGates } = this.props;
+    const { metrics, refreshQualityGates } = this.props;
     const { loading, qualityGate, updatedConditionId } = this.state;
 
     return (
@@ -156,7 +155,6 @@ export class Details extends React.PureComponent<Props, State> {
               <Helmet defer={false} title={qualityGate.name} />
               <DetailsHeader
                 onSetDefault={this.handleSetDefault}
-                organization={organization}
                 qualityGate={qualityGate}
                 refreshItem={this.fetchDetails}
                 refreshList={refreshQualityGates}
@@ -167,7 +165,6 @@ export class Details extends React.PureComponent<Props, State> {
                 onAddCondition={this.handleAddCondition}
                 onRemoveCondition={this.handleRemoveCondition}
                 onSaveCondition={this.handleSaveCondition}
-                organization={organization}
                 qualityGate={qualityGate}
                 updatedConditionId={updatedConditionId}
               />
index 5966b0cb1bc1a9c5f34e11fcb0b47a1287e11879..6d299df5a677a81e536422628d0991fa9418fcf2 100644 (file)
@@ -26,7 +26,6 @@ import Projects from './Projects';
 export interface DetailsContentProps {
   isDefault?: boolean;
   metrics: T.Dict<T.Metric>;
-  organization?: string;
   onAddCondition: (condition: T.Condition) => void;
   onRemoveCondition: (Condition: T.Condition) => void;
   onSaveCondition: (newCondition: T.Condition, oldCondition: T.Condition) => void;
@@ -35,7 +34,7 @@ export interface DetailsContentProps {
 }
 
 export function DetailsContent(props: DetailsContentProps) {
-  const { isDefault, metrics, organization, qualityGate, updatedConditionId } = props;
+  const { isDefault, metrics, qualityGate, updatedConditionId } = props;
   const conditions = qualityGate.conditions || [];
   const actions = qualityGate.actions || ({} as any);
 
@@ -48,7 +47,6 @@ export function DetailsContent(props: DetailsContentProps) {
         onAddCondition={props.onAddCondition}
         onRemoveCondition={props.onRemoveCondition}
         onSaveCondition={props.onSaveCondition}
-        organization={organization}
         qualityGate={qualityGate}
         updatedConditionId={updatedConditionId}
       />
@@ -72,7 +70,6 @@ export function DetailsContent(props: DetailsContentProps) {
             canEdit={actions.associateProjects}
             // pass unique key to re-mount the component when the quality gate changes
             key={qualityGate.id}
-            organization={organization}
             qualityGate={qualityGate}
           />
         )}
index 854d8fd4ea975b1e4cf2fb710d9439026160a78d..769ac5d0cd9e8236cc6a89653ee85270bf16af60 100644 (file)
@@ -29,7 +29,6 @@ import RenameQualityGateForm from './RenameQualityGateForm';
 
 interface Props {
   onSetDefault: () => void;
-  organization?: string;
   qualityGate: T.QualityGate;
   refreshItem: () => Promise<void>;
   refreshList: () => Promise<void>;
@@ -45,11 +44,11 @@ export default class DetailsHeader extends React.PureComponent<Props> {
   };
 
   handleSetAsDefaultClick = () => {
-    const { organization, qualityGate } = this.props;
+    const { qualityGate } = this.props;
     if (!qualityGate.isDefault) {
       // Optimistic update
       this.props.onSetDefault();
-      setQualityGateAsDefault({ id: qualityGate.id, organization }).then(
+      setQualityGateAsDefault({ id: qualityGate.id }).then(
         this.handleActionRefresh,
         this.handleActionRefresh
       );
@@ -57,7 +56,7 @@ export default class DetailsHeader extends React.PureComponent<Props> {
   };
 
   render() {
-    const { organization, qualityGate } = this.props;
+    const { qualityGate } = this.props;
     const actions = qualityGate.actions || ({} as any);
     return (
       <div className="layout-page-header-panel layout-page-main-header issues-main-header">
@@ -75,7 +74,6 @@ export default class DetailsHeader extends React.PureComponent<Props> {
                     <RenameQualityGateForm
                       onClose={onClose}
                       onRename={this.handleActionRefresh}
-                      organization={organization}
                       qualityGate={qualityGate}
                     />
                   )}>
@@ -92,7 +90,6 @@ export default class DetailsHeader extends React.PureComponent<Props> {
                     <CopyQualityGateForm
                       onClose={onClose}
                       onCopy={this.handleActionRefresh}
-                      organization={organization}
                       qualityGate={qualityGate}
                     />
                   )}>
@@ -114,7 +111,6 @@ export default class DetailsHeader extends React.PureComponent<Props> {
               {actions.delete && (
                 <DeleteQualityGateForm
                   onDelete={this.props.refreshList}
-                  organization={organization}
                   qualityGate={qualityGate}
                 />
               )}
index 8fc6c24c0b3b0fc0d451cb5d86193d23edb7c2a6..40f2ae8b3db167301b9b1c503a8dc7e3abf903b5 100644 (file)
@@ -27,21 +27,16 @@ import CreateQualityGateForm from './CreateQualityGateForm';
 interface Props {
   canCreate: boolean;
   refreshQualityGates: () => Promise<void>;
-  organization?: string;
 }
 
-export default function ListHeader({ canCreate, refreshQualityGates, organization }: Props) {
+export default function ListHeader({ canCreate, refreshQualityGates }: Props) {
   return (
     <header className="page-header">
       {canCreate && (
         <div className="page-actions">
           <ModalButton
             modal={({ onClose }) => (
-              <CreateQualityGateForm
-                onClose={onClose}
-                onCreate={refreshQualityGates}
-                organization={organization}
-              />
+              <CreateQualityGateForm onClose={onClose} onCreate={refreshQualityGates} />
             )}>
             {({ onClick }) => (
               <Button data-test="quality-gates__add" onClick={onClick}>
index 170f62078e0a2c5b14649ecc25700f92fb69ed44..147e9ba7b42a132ff0a156714f387014580559d2 100644 (file)
@@ -32,7 +32,6 @@ import {
 
 interface Props {
   canEdit?: boolean;
-  organization?: string;
   qualityGate: T.QualityGate;
 }
 
@@ -68,7 +67,6 @@ export default class Projects extends React.PureComponent<Props, State> {
   fetchProjects = (searchParams: SelectListSearchParams) =>
     searchProjects({
       gateName: this.props.qualityGate.name,
-      organization: this.props.organization,
       page: searchParams.page,
       pageSize: searchParams.pageSize,
       query: searchParams.query !== '' ? searchParams.query : undefined,
@@ -100,7 +98,6 @@ export default class Projects extends React.PureComponent<Props, State> {
   handleSelect = (key: string) =>
     associateGateWithProject({
       gateId: this.props.qualityGate.id,
-      organization: this.props.organization,
       projectKey: key
     }).then(() => {
       if (this.mounted) {
@@ -114,7 +111,6 @@ export default class Projects extends React.PureComponent<Props, State> {
   handleUnselect = (key: string) =>
     dissociateGateWithProject({
       gateId: this.props.qualityGate.id,
-      organization: this.props.organization,
       projectKey: key
     }).then(() => {
       if (this.mounted) {
index 3d7f45ff74b79f87fb7d441ba732d782412ddf5d..b52404ca96239dda5fb46d9a0b610584377f86ee 100644 (file)
@@ -25,7 +25,6 @@ import { renameQualityGate } from '../../../api/quality-gates';
 interface Props {
   onClose: () => void;
   onRename: () => Promise<void>;
-  organization?: string;
   qualityGate: T.QualityGate;
 }
 
@@ -44,16 +43,14 @@ export default class RenameQualityGateForm extends React.PureComponent<Props, St
   };
 
   handleRename = () => {
-    const { qualityGate, organization } = this.props;
+    const { qualityGate } = this.props;
     const { name } = this.state;
 
     if (!name) {
       return undefined;
     }
 
-    return renameQualityGate({ id: qualityGate.id, name, organization }).then(() =>
-      this.props.onRename()
-    );
+    return renameQualityGate({ id: qualityGate.id, name }).then(() => this.props.onRename());
   };
 
   render() {
index ab6e843fb9f288dc640e3a8bcecc2cb30bf66058..5b7eb8ff9a4c7c1e729d7f7679291e132e41e10c 100644 (file)
  */
 import { shallow } from 'enzyme';
 import * as React from 'react';
+import { createCondition, updateCondition } from '../../../../api/quality-gates';
 import { mockQualityGate } from '../../../../helpers/mocks/quality-gates';
-import { mockMetric } from '../../../../helpers/testMocks';
+import { mockCondition, mockMetric } from '../../../../helpers/testMocks';
 import { MetricKey } from '../../../../types/metrics';
 import ConditionModal from '../ConditionModal';
 
+jest.mock('../../../../api/quality-gates', () => ({
+  createCondition: jest.fn().mockResolvedValue({}),
+  updateCondition: jest.fn().mockResolvedValue({})
+}));
+
 it('should render correctly', () => {
   expect(shallowRender()).toMatchSnapshot();
   expect(shallowRender({ metric: mockMetric() })).toMatchSnapshot();
@@ -59,6 +65,26 @@ it('should correctly switch scope', () => {
   expect(wrapper).toMatchSnapshot();
 });
 
+it('should handle submission', async () => {
+  const onAddCondition = jest.fn();
+  const wrapper = shallowRender({ onAddCondition });
+
+  wrapper.setState({ metric: mockMetric() });
+
+  await wrapper.instance().handleFormSubmit();
+
+  expect(createCondition).toBeCalled();
+  expect(updateCondition).not.toBeCalled();
+
+  jest.clearAllMocks();
+
+  wrapper.setProps({ condition: mockCondition() });
+  await wrapper.instance().handleFormSubmit();
+
+  expect(createCondition).not.toBeCalled();
+  expect(updateCondition).toBeCalled();
+});
+
 function shallowRender(props: Partial<ConditionModal['props']> = {}) {
   return shallow<ConditionModal>(
     <ConditionModal
index 492e8fa6b2f1541f8529536e2df5002cef6517c9..5f7d9a900c4a6acbd6fbf0fa3437679fd4fa1506 100644 (file)
  */
 import { shallow } from 'enzyme';
 import * as React from 'react';
+import { copyQualityGate } from '../../../../api/quality-gates';
 import { mockQualityGate } from '../../../../helpers/mocks/quality-gates';
-import CopyQualityGateForm from '../CopyQualityGateForm';
+import { mockRouter } from '../../../../helpers/testMocks';
+import { CopyQualityGateForm } from '../CopyQualityGateForm';
+
+jest.mock('../../../../api/quality-gates', () => ({
+  copyQualityGate: jest.fn().mockResolvedValue({})
+}));
 
 it('should render correctly', () => {
-  expect(
-    shallow(
-      <CopyQualityGateForm onClose={jest.fn()} onCopy={jest.fn()} qualityGate={mockQualityGate()} />
-    )
-  ).toMatchSnapshot();
+  expect(shallowRender()).toMatchSnapshot();
+});
+
+it('should handle copy', async () => {
+  const onCopy = jest.fn();
+  const router = mockRouter();
+  const qualityGate = mockQualityGate();
+  const wrapper = shallowRender({ onCopy, qualityGate, router });
+
+  const name = 'name';
+  wrapper.setState({ name });
+
+  await wrapper.instance().handleCopy();
+
+  expect(copyQualityGate).toBeCalledWith({ id: qualityGate.id, name });
+  expect(onCopy).toBeCalled();
+  expect(router.push).toBeCalled();
+
+  jest.clearAllMocks();
+
+  wrapper.setState({ name: '' });
+  await wrapper.instance().handleCopy();
+
+  expect(copyQualityGate).not.toBeCalled();
 });
+
+function shallowRender(overrides: Partial<CopyQualityGateForm['props']> = {}) {
+  return shallow<CopyQualityGateForm>(
+    <CopyQualityGateForm
+      onClose={jest.fn()}
+      onCopy={jest.fn()}
+      qualityGate={mockQualityGate()}
+      router={mockRouter()}
+      {...overrides}
+    />
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/DeleteQualityGateForm-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/DeleteQualityGateForm-test.tsx
new file mode 100644 (file)
index 0000000..b31d51d
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { shallow } from 'enzyme';
+import * as React from 'react';
+import { deleteQualityGate } from '../../../../api/quality-gates';
+import { mockQualityGate } from '../../../../helpers/mocks/quality-gates';
+import { mockRouter } from '../../../../helpers/testMocks';
+import { DeleteQualityGateForm } from '../DeleteQualityGateForm';
+
+jest.mock('../../../../api/quality-gates', () => ({
+  deleteQualityGate: jest.fn().mockResolvedValue({})
+}));
+
+it('should render correctly', () => {
+  expect(shallowRender()).toMatchSnapshot();
+});
+
+it('should handle onDelete', async () => {
+  const onDelete = jest.fn();
+  const router = mockRouter();
+  const qualityGate = mockQualityGate();
+  const wrapper = shallowRender({ onDelete, qualityGate, router });
+
+  await wrapper.instance().onDelete();
+
+  expect(deleteQualityGate).toBeCalledWith({ id: qualityGate.id });
+  expect(onDelete).toBeCalled();
+  expect(router.push).toBeCalled();
+});
+
+function shallowRender(overrides: Partial<DeleteQualityGateForm['props']> = {}) {
+  return shallow<DeleteQualityGateForm>(
+    <DeleteQualityGateForm
+      onDelete={jest.fn()}
+      qualityGate={mockQualityGate()}
+      router={mockRouter()}
+      {...overrides}
+    />
+  );
+}
index f7a76c49793cfc8a5072e5528f1848e30f917947..47472ac1598bd9132ced97ba90fa73d9655047ab 100644 (file)
@@ -30,7 +30,6 @@ import { mockQualityGate } from '../../../../helpers/mocks/quality-gates';
 import Projects from '../Projects';
 
 const qualityGate = mockQualityGate();
-const organization = 'TEST';
 
 jest.mock('../../../../api/quality-gates', () => ({
   searchProjects: jest.fn().mockResolvedValue({
@@ -70,7 +69,6 @@ it('should render correctly', async () => {
   expect(searchProjects).toHaveBeenCalledWith(
     expect.objectContaining({
       gateName: qualityGate.name,
-      organization,
       page: 1,
       pageSize: 100,
       query: undefined,
@@ -110,7 +108,5 @@ it('should handle deselection properly', async () => {
 });
 
 function shallowRender(props: Partial<Projects['props']> = {}) {
-  return shallow<Projects>(
-    <Projects organization={organization} qualityGate={qualityGate} {...props} />
-  );
+  return shallow<Projects>(<Projects qualityGate={qualityGate} {...props} />);
 }
index 40eb1a513bf7e613ea7c3f32cf82074a91c2e479..b060388264ba7dc516fc0673c939f582b0d2fbc1 100644 (file)
  */
 import { shallow } from 'enzyme';
 import * as React from 'react';
+import { renameQualityGate } from '../../../../api/quality-gates';
 import { mockQualityGate } from '../../../../helpers/mocks/quality-gates';
 import RenameQualityGateForm from '../RenameQualityGateForm';
 
+jest.mock('../../../../api/quality-gates', () => ({
+  renameQualityGate: jest.fn().mockResolvedValue({})
+}));
+
 it('should render correctly', () => {
-  expect(
-    shallow(
-      <RenameQualityGateForm
-        onClose={jest.fn()}
-        onRename={jest.fn()}
-        qualityGate={mockQualityGate()}
-      />
-    )
-  ).toMatchSnapshot();
+  expect(shallowRender()).toMatchSnapshot();
+});
+
+it('should handle rename', async () => {
+  const qualityGate = mockQualityGate();
+  const wrapper = shallowRender({ qualityGate });
+
+  const name = 'new name';
+
+  wrapper.setState({ name });
+
+  await wrapper.instance().handleRename();
+
+  expect(renameQualityGate).toBeCalledWith({ ...qualityGate, name });
+
+  jest.clearAllMocks();
+
+  wrapper.setState({ name: '' });
+
+  await wrapper.instance().handleRename();
+
+  expect(renameQualityGate).not.toBeCalled();
 });
+
+function shallowRender(overrides: Partial<RenameQualityGateForm['props']> = {}) {
+  return shallow<RenameQualityGateForm>(
+    <RenameQualityGateForm
+      onClose={jest.fn()}
+      onRename={jest.fn()}
+      qualityGate={mockQualityGate()}
+      {...overrides}
+    />
+  );
+}
index e961412c2074d1f297499653ea527c7bf89daf10..556ab1bdd5e276fe6676405f594380691cb3edc6 100644 (file)
@@ -1,14 +1,37 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`should render correctly 1`] = `
-<CopyQualityGateForm
+<ConfirmModal
+  confirmButtonText="copy"
+  confirmDisable={true}
+  header="quality_gates.copy"
   onClose={[MockFunction]}
-  onCopy={[MockFunction]}
-  qualityGate={
-    Object {
-      "id": "1",
-      "name": "qualitygate",
-    }
-  }
-/>
+  onConfirm={[Function]}
+  size="small"
+>
+  <div
+    className="modal-field"
+  >
+    <label
+      htmlFor="quality-gate-form-name"
+    >
+      name
+      <em
+        className="mandatory"
+      >
+        *
+      </em>
+    </label>
+    <input
+      autoFocus={true}
+      id="quality-gate-form-name"
+      maxLength={100}
+      onChange={[Function]}
+      required={true}
+      size={50}
+      type="text"
+      value="qualitygate"
+    />
+  </div>
+</ConfirmModal>
 `;
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DeleteQualityGateForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DeleteQualityGateForm-test.tsx.snap
new file mode 100644 (file)
index 0000000..d99d750
--- /dev/null
@@ -0,0 +1,13 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<ConfirmButton
+  confirmButtonText="delete"
+  isDestructive={true}
+  modalBody="quality_gates.delete.confirm.message.qualitygate"
+  modalHeader="quality_gates.delete"
+  onConfirm={[Function]}
+>
+  <Component />
+</ConfirmButton>
+`;