From 635b1604537624a052974ef079278618ab645d1d Mon Sep 17 00:00:00 2001 From: Mathieu Suen Date: Tue, 26 Sep 2023 14:54:21 +0200 Subject: [PATCH] SONAR-20532 Add API call for GitHub custom role mapping --- .../sonar-web/src/main/js/api/provisioning.ts | 8 +++ .../src/main/js/queries/identity-provider.ts | 60 +++++++++++-------- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/server/sonar-web/src/main/js/api/provisioning.ts b/server/sonar-web/src/main/js/api/provisioning.ts index b33172edd22..b65ded5c9a2 100644 --- a/server/sonar-web/src/main/js/api/provisioning.ts +++ b/server/sonar-web/src/main/js/api/provisioning.ts @@ -68,3 +68,11 @@ export function updateGithubRolesMapping( ) { return axios.patch(`/api/v2/github-permission-mappings/${role}`, data); } + +export function addGithubRolesMapping(data: Omit) { + return axios.post(`/api/v2/github-permission-mappings/`, data); +} + +export function deleteGithubRolesMapping(role: string) { + return axios.delete(`/api/v2/github-permission-mappings/${role}`); +} diff --git a/server/sonar-web/src/main/js/queries/identity-provider.ts b/server/sonar-web/src/main/js/queries/identity-provider.ts index 7d6702739a7..8a20c11108d 100644 --- a/server/sonar-web/src/main/js/queries/identity-provider.ts +++ b/server/sonar-web/src/main/js/queries/identity-provider.ts @@ -19,14 +19,16 @@ */ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; -import { isEqual, omit } from 'lodash'; +import { isEqual, keyBy, omit, partition } from 'lodash'; import { useContext } from 'react'; import { activateGithubProvisioning, activateScim, + addGithubRolesMapping, checkConfigurationValidity, deactivateGithubProvisioning, deactivateScim, + deleteGithubRolesMapping, fetchGithubProvisioningStatus, fetchGithubRolesMapping, fetchIsScimEnabled, @@ -122,13 +124,14 @@ export function useSyncWithGitHubNow() { }; } +const defaultRoleOrder = ['admin', 'maintain', 'write', 'triage', 'read']; + export function useGithubRolesMappingQuery() { return useQuery(['identity_provider', 'github_mapping'], fetchGithubRolesMapping, { staleTime: MAPPING_STALE_TIME, select: (data) => [...data].sort((a, b) => { // Order is reversed to put non-existing roles at the end (their index is -1) - const defaultRoleOrder = ['admin', 'maintain', 'write', 'triage', 'read']; if (defaultRoleOrder.includes(a.id) || defaultRoleOrder.includes(b.id)) { return defaultRoleOrder.indexOf(b.id) - defaultRoleOrder.indexOf(a.id); } @@ -141,32 +144,37 @@ export function useGithubRolesMappingMutation() { const client = useQueryClient(); const queryKey = ['identity_provider', 'github_mapping']; return useMutation({ - mutationFn: (mapping: GitHubMapping[]) => { - const state = client.getQueryData(queryKey); - const changedRoles = state - ? mapping.filter( - (item) => - !isEqual( - item, - state.find((el) => el.id === item.id), - ), - ) - : mapping; - return Promise.all( - changedRoles.map((data) => updateGithubRolesMapping(data.id, omit(data, 'id', 'roleName'))), + mutationFn: async (mapping: GitHubMapping[]) => { + const [defaultMapping, customMapping] = partition(mapping, (m) => + defaultRoleOrder.includes(m.roleName), + ); + const state = keyBy(client.getQueryData(queryKey), (m) => m.id); + + const [customMaybeChangedmRoles, customNewRoles] = partition( + customMapping, + (m) => state[m.id], + ); + + const changeRole = [...defaultMapping, ...customMaybeChangedmRoles].filter( + (item) => !isEqual(item, state[item.id]), + ); + + const customDeleteRole = Object.values(state).filter( + (m) => !defaultRoleOrder.includes(m.roleName) && !changeRole.some((cm) => m.id === cm.id), ); + + return { + addedOrChange: await Promise.all([ + ...changeRole.map((data) => + updateGithubRolesMapping(data.id, omit(data, 'id', 'roleName')), + ), + ...customNewRoles.map((m) => addGithubRolesMapping(m)), + ]), + delete: await Promise.all([customDeleteRole.map((dm) => deleteGithubRolesMapping(dm.id))]), + }; }, - onSuccess: (data) => { - const state = client.getQueryData(queryKey); - if (state) { - client.setQueryData( - queryKey, - state.map((item) => { - const changed = data.find((el) => el.id === item.id); - return changed ?? item; - }), - ); - } + onSuccess: ({ addedOrChange }) => { + client.setQueryData(queryKey, addedOrChange); }, }); } -- 2.39.5