]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-19944 feedback regarding failing organizations - Github Provisioning
authorguillaume-peoch-sonarsource <guillaume.peoch@sonarsource.com>
Tue, 8 Aug 2023 16:07:42 +0000 (18:07 +0200)
committersonartech <sonartech@sonarsource.com>
Wed, 9 Aug 2023 20:03:37 +0000 (20:03 +0000)
server/sonar-web/src/main/js/apps/settings/components/authentication/GitHubConfigurationValidity.tsx
server/sonar-web/src/main/js/apps/settings/components/authentication/GithubAuthenticationTab.tsx
server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-it.tsx
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index d29f6f0452085634e6bbe7db9f857af7cef9ed2b..867d5c7e968d25307384aa3aa0150b83e96fa27a 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+import { TextMuted } from 'design-system';
 import React, { useEffect, useState } from 'react';
-import theme from '../../../../app/theme';
+import theme, { colors } from '../../../../app/theme';
 import Modal from '../../../../components/controls/Modal';
 import { Button } from '../../../../components/controls/buttons';
 import CheckIcon from '../../../../components/icons/CheckIcon';
 import ClearIcon from '../../../../components/icons/ClearIcon';
+import HelpIcon from '../../../../components/icons/HelpIcon';
 import { Alert, AlertVariant } from '../../../../components/ui/Alert';
 import { translate, translateWithParameters } from '../../../../helpers/l10n';
 import { GitHubProvisioningStatus } from '../../../../types/provisioning';
@@ -42,9 +44,13 @@ function ValidityIcon({ valid }: { valid: boolean }) {
 
 interface Props {
   isAutoProvisioning: boolean;
+  selectedOrganizations: string[];
 }
 
-function GitHubConfigurationValidity({ isAutoProvisioning }: Props) {
+export default function GitHubConfigurationValidity({
+  isAutoProvisioning,
+  selectedOrganizations,
+}: Props) {
   const [openDetails, setOpenDetails] = useState(false);
   const [messages, setMessages] = useState<string[]>([]);
   const [alertVariant, setAlertVariant] = useState<AlertVariant>('loading');
@@ -56,6 +62,10 @@ function GitHubConfigurationValidity({ isAutoProvisioning }: Props) {
   const isValidApp =
     data?.application[applicationField].status === GitHubProvisioningStatus.Success;
 
+  const failedOrgs = selectedOrganizations.filter((o) => {
+    return !data?.installations.find((i) => i.organization === o);
+  });
+
   useEffect(() => {
     if (isFetching) {
       setMessages([translate(`${intlPrefix}.loading`)]);
@@ -154,6 +164,15 @@ function GitHubConfigurationValidity({ isAutoProvisioning }: Props) {
                     )}
                 </li>
               ))}
+              {failedOrgs.map((fo) => (
+                <li key={fo}>
+                  <HelpIcon fillInner={colors.gray60} fill={colors.white} role="img" />
+                  <TextMuted
+                    className="sw-ml-2"
+                    text={translateWithParameters(`${intlPrefix}.details.org_not_found`, fo)}
+                  />
+                </li>
+              ))}
             </ul>
           </div>
           <footer className="modal-foot">
@@ -164,5 +183,3 @@ function GitHubConfigurationValidity({ isAutoProvisioning }: Props) {
     </>
   );
 }
-
-export default GitHubConfigurationValidity;
index 1d8acf00f1630e6077d45d23b8e029bcffbda47c..36bce8a1cb2e70132cf4b658e63e446e67299555 100644 (file)
@@ -106,6 +106,9 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps
       </div>
       {enabled && (
         <GitHubConfigurationValidity
+          selectedOrganizations={
+            (values['sonar.auth.github.organizations']?.value as string[]) ?? []
+          }
           isAutoProvisioning={!!(newGithubProvisioningStatus ?? githubProvisioningStatus)}
         />
       )}
index 4cd48c8492b062715054b61e5ad41febe5331990..0b21b2eb99a8ff31b70e9d475c7d489c477da2b7 100644 (file)
@@ -551,6 +551,31 @@ describe('Github tab', () => {
       );
     });
 
+    it('should display that config is valid but some organizatios were not found', async () => {
+      handler.setConfigurationValidity({
+        installations: [
+          { organization: 'org1', autoProvisioning: { status: GitHubProvisioningStatus.Success } },
+        ],
+      });
+
+      renderAuthentication([Feature.GithubProvisioning]);
+      await github.enableConfiguration(user);
+
+      await waitFor(() => expect(github.configurationValiditySuccess.get()).toBeInTheDocument());
+      expect(github.configurationValiditySuccess.get()).toHaveTextContent('1');
+
+      await act(() => user.click(github.viewConfigValidityDetailsButton.get()));
+      expect(github.getConfigDetailsTitle()).toHaveTextContent(
+        'settings.authentication.github.configuration.validation.details.valid_label'
+      );
+      expect(github.getOrgs()[0]).toHaveTextContent(
+        'settings.authentication.github.configuration.validation.details.valid_labelorg1'
+      );
+      expect(github.getOrgs()[1]).toHaveTextContent(
+        'settings.authentication.github.configuration.validation.details.org_not_found.organization1'
+      );
+    });
+
     it('should display that config is invalid', async () => {
       const errorMessage = 'Test error';
       handler.setConfigurationValidity({
@@ -633,11 +658,14 @@ describe('Github tab', () => {
       await waitFor(() => expect(github.configurationValiditySuccess.query()).toBeInTheDocument());
 
       await act(() => user.click(github.viewConfigValidityDetailsButton.get()));
-      github.getOrgs().forEach((org) => {
-        expect(org).toHaveTextContent(
-          'settings.authentication.github.configuration.validation.details.valid_label'
-        );
-      });
+
+      expect(github.getOrgs()[0]).toHaveTextContent(
+        'settings.authentication.github.configuration.validation.details.valid_labelorg1'
+      );
+      expect(github.getOrgs()[1]).toHaveTextContent(
+        'settings.authentication.github.configuration.validation.details.valid_labelorg2'
+      );
+
       await act(() =>
         user.click(within(github.configDetailsDialog.get()).getByRole('button', { name: 'close' }))
       );
index 42629e26805ee56fdb38c1a8dd2d3457fb938317..737a5a5e0bac4d10ffe448d9d8a420dcd2ea5637 100644 (file)
@@ -1434,6 +1434,7 @@ settings.authentication.github.configuration.validation.invalid_org=Organization
 settings.authentication.github.configuration.validation.details.title=Configuration validity:
 settings.authentication.github.configuration.validation.details.valid_label=Valid
 settings.authentication.github.configuration.validation.details.invalid_label=Invalid
+settings.authentication.github.configuration.validation.details.org_not_found={0} (not found or app not installed)
 
 # SAML
 settings.authentication.form.create.saml=New SAML configuration