]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-19347 Add synchronize now button for Github
authorMathieu Suen <mathieu.suen@sonarsource.com>
Fri, 26 May 2023 14:58:05 +0000 (16:58 +0200)
committersonartech <sonartech@sonarsource.com>
Tue, 30 May 2023 20:02:52 +0000 (20:02 +0000)
server/sonar-web/src/main/js/api/provisioning.ts
server/sonar-web/src/main/js/app/components/GitHubSynchronisationWarning.tsx
server/sonar-web/src/main/js/apps/settings/components/authentication/GithubAuthenticationTab.tsx
server/sonar-web/src/main/js/apps/settings/components/authentication/queries/IdentityProvider.ts
server/sonar-web/src/main/js/queries/github-sync.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 10220bb92c296448c9f012c37032a788897a450c..fbadc9dee854fee5bb3be4c53a8aac43cbdebbdd 100644 (file)
@@ -46,3 +46,7 @@ export function activateGithubProvisioning(): Promise<void> {
 export function deactivateGithubProvisioning(): Promise<void> {
   return post('/api/github_provisioning/disable').catch(throwGlobalError);
 }
+
+export function syncNowGithubProvisioning(): Promise<void> {
+  return post('/api/github_provisioning/sync').catch(throwGlobalError);
+}
index e011d74d7bba881a1d119724a9a6846f57f58e56..5d7cb2544c748343921e77df2c9ebc6fd14e6d03 100644 (file)
  */
 import { formatDistance } from 'date-fns';
 import * as React from 'react';
-import { useContext } from 'react';
 import { FormattedMessage } from 'react-intl';
 import Link from '../../components/common/Link';
 import CheckIcon from '../../components/icons/CheckIcon';
 import { Alert } from '../../components/ui/Alert';
 import { translate, translateWithParameters } from '../../helpers/l10n';
 import { useSyncStatusQuery } from '../../queries/github-sync';
-import { Feature } from '../../types/features';
 import { GithubStatusEnabled } from '../../types/provisioning';
 import { TaskStatuses } from '../../types/tasks';
 import './SystemAnnouncement.css';
-import { AvailableFeaturesContext } from './available-features/AvailableFeaturesContext';
 
 interface LastSyncProps {
   short?: boolean;
@@ -100,10 +97,7 @@ function LastSyncAlert({ info, short }: LastSyncProps) {
 }
 
 function GitHubSynchronisationWarning({ short }: GitHubSynchronisationWarningProps) {
-  const hasGithubProvisioning = useContext(AvailableFeaturesContext).includes(
-    Feature.GithubProvisioning
-  );
-  const { data } = useSyncStatusQuery({ enabled: hasGithubProvisioning });
+  const { data } = useSyncStatusQuery();
 
   if (!data) {
     return null;
@@ -113,7 +107,7 @@ function GitHubSynchronisationWarning({ short }: GitHubSynchronisationWarningPro
     <>
       {!short && data?.nextSync && (
         <>
-          <Alert variant="loading">
+          <Alert variant="loading" className="spacer-bottom">
             {translate(
               data.nextSync.status === TaskStatuses.Pending
                 ? 'settings.authentication.github.synchronization_pending'
index 5df3bcdc37dede8ea4a9ad978e47e904de978beb..1f2348a1f62022149ced5e4caf1a26a9fe6ab006 100644 (file)
@@ -30,6 +30,7 @@ import DeleteIcon from '../../../../components/icons/DeleteIcon';
 import EditIcon from '../../../../components/icons/EditIcon';
 import { Alert } from '../../../../components/ui/Alert';
 import { translate, translateWithParameters } from '../../../../helpers/l10n';
+import { useSyncNow } from '../../../../queries/github-sync';
 import { AlmKeys } from '../../../../types/alm-settings';
 import { ExtendedSettingDefinition } from '../../../../types/settings';
 import { DOCUMENTATION_LINK_SUFFIXES } from './Authentication';
@@ -78,6 +79,7 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps
   } = useGithubConfiguration(definitions);
 
   const hasDifferentProvider = data?.provider !== undefined && data.provider !== Provider.Github;
+  const { canSyncNow, synchronizeNow } = useSyncNow();
 
   const handleCreateConfiguration = () => {
     setShowEditModal(true);
@@ -220,6 +222,15 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps
                             />
                           </p>
                           {githubProvisioningStatus && <GitHubSynchronisationWarning />}
+                          <div className="sw-flex sw-flex-1 sw-items-end">
+                            <Button
+                              className="spacer-top width-30"
+                              onClick={synchronizeNow}
+                              disabled={!canSyncNow}
+                            >
+                              {translate('settings.authentication.github.synchronize_now')}
+                            </Button>
+                          </div>
                         </>
                       ) : (
                         <p>
index d5b5858339af543f88fd07829b9f9b88622dc51c..1396ec4dc1f3fd8c85d2fe8cec73e11b2637e508 100644 (file)
@@ -52,11 +52,7 @@ export function useScimStatusQuery() {
 }
 
 export function useGithubStatusQuery() {
-  const hasGithubProvisioning = useContext(AvailableFeaturesContext).includes(
-    Feature.GithubProvisioning
-  );
-
-  const res = useSyncStatusQuery({ enabled: hasGithubProvisioning });
+  const res = useSyncStatusQuery();
 
   return { ...res, data: res.data?.enabled };
 }
index d2be13512607a585f56a03de0f444f784a8e1175..67f7e3c8edfb071fc03910ac5d7ee4ad18cd0136 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 { useQuery } from '@tanstack/react-query';
-import { fetchGithubProvisioningStatus } from '../api/provisioning';
+import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
+import { useContext } from 'react';
+import { fetchGithubProvisioningStatus, syncNowGithubProvisioning } from '../api/provisioning';
+import { AvailableFeaturesContext } from '../app/components/available-features/AvailableFeaturesContext';
+import { Feature } from '../types/features';
 
-export const useSyncStatusQuery = ({ enabled }: { enabled?: boolean }) => {
-  return useQuery(['github_sync', 'status'], fetchGithubProvisioningStatus, { enabled });
-};
+export function useSyncStatusQuery() {
+  const hasGithubProvisioning = useContext(AvailableFeaturesContext).includes(
+    Feature.GithubProvisioning
+  );
+  return useQuery(['github_sync', 'status'], fetchGithubProvisioningStatus, {
+    enabled: hasGithubProvisioning,
+    refetchInterval: 10_000,
+  });
+}
+
+export function useSyncNow() {
+  const queryClient = useQueryClient();
+  const { data } = useSyncStatusQuery();
+  const mutation = useMutation(syncNowGithubProvisioning, {
+    onSuccess: () => {
+      queryClient.invalidateQueries(['github_sync']);
+    },
+  });
+
+  return {
+    synchronizeNow: mutation.mutate,
+    canSyncNow: data && data.enabled && !data.nextSync && !mutation.isLoading,
+  };
+}
index 291c3fedba335bb8b858e358d16a5c0a494e8400..246c5c5c0d5c66143241fdbe3953c2a663089d2b 100644 (file)
@@ -1386,6 +1386,7 @@ settings.authentication.github.form.provisioning_with_github=Automatic user and
 settings.authentication.github.form.provisioning_with_github.description=Users and groups are automatically provisioned from your GitHub organizations. Once activated, managed users and groups can only be modified from your GitHub organizations/teams. Existing local users and groups will be kept.
 settings.authentication.github.form.provisioning_with_github.description.doc=For more details, see {documentation}.
 settings.authentication.github.form.provisioning.disabled=Your current edition does not support provisioning with GitHub. See the {documentation} for more information.
+settings.authentication.github.synchronize_now=Synchronize now
 settings.authentication.github.synchronization_in_progress=Synchronization is in progress.
 settings.authentication.github.synchronization_pending=Synchronization is scheduled.
 settings.authentication.github.synchronization_successful=Last synchronization was done {0} ago.