mirror of
https://github.com/datahub-project/datahub.git
synced 2025-06-27 05:03:31 +00:00
responding to comments
This commit is contained in:
parent
8e6d2e0daa
commit
58e9604844
@ -101,6 +101,7 @@ public class MeResolver implements DataFetcher<CompletableFuture<AuthenticatedUs
|
||||
AuthorizationUtils.canViewStructuredPropertiesPage(context));
|
||||
platformPrivileges.setManageApplications(
|
||||
ApplicationAuthorizationUtils.canManageApplications(context));
|
||||
platformPrivileges.setManageFeatures(AuthorizationUtils.canManageFeatures(context));
|
||||
// Construct and return authenticated user object.
|
||||
final AuthenticatedUser authUser = new AuthenticatedUser();
|
||||
authUser.setCorpUser(corpUser);
|
||||
|
@ -45,7 +45,7 @@ public class UpdateApplicationsSettingsResolver implements DataFetcher<Completab
|
||||
final com.linkedin.settings.global.ApplicationsSettings newApplicationsSettings =
|
||||
newGlobalSettings.hasApplications()
|
||||
? newGlobalSettings.getApplications()
|
||||
: new com.linkedin.settings.global.ApplicationsSettings().setEnabled(true);
|
||||
: new com.linkedin.settings.global.ApplicationsSettings().setEnabled(false);
|
||||
|
||||
// Next, patch the actions settings.
|
||||
updateApplicationsSettings(newApplicationsSettings, input);
|
||||
|
@ -182,6 +182,11 @@ type PlatformPrivileges {
|
||||
Whether the user can manage applications.
|
||||
"""
|
||||
manageApplications: Boolean!
|
||||
|
||||
"""
|
||||
Whether the user can manage platform features.
|
||||
"""
|
||||
manageFeatures: Boolean!
|
||||
}
|
||||
|
||||
"""
|
||||
|
@ -0,0 +1,113 @@
|
||||
package com.linkedin.datahub.graphql.resolvers.settings.applications;
|
||||
|
||||
import static com.linkedin.datahub.graphql.TestUtils.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
import com.linkedin.data.template.SetMode;
|
||||
import com.linkedin.datahub.graphql.QueryContext;
|
||||
import com.linkedin.datahub.graphql.generated.UpdateApplicationsSettingsInput;
|
||||
import com.linkedin.metadata.service.SettingsService;
|
||||
import com.linkedin.settings.global.ApplicationsSettings;
|
||||
import com.linkedin.settings.global.GlobalSettingsInfo;
|
||||
import graphql.schema.DataFetchingEnvironment;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import org.mockito.Mockito;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
public class UpdateApplicationsSettingsResolverTest {
|
||||
|
||||
private static final UpdateApplicationsSettingsInput TEST_INPUT_ENABLED =
|
||||
new UpdateApplicationsSettingsInput(true);
|
||||
private static final UpdateApplicationsSettingsInput TEST_INPUT_DISABLED =
|
||||
new UpdateApplicationsSettingsInput(false);
|
||||
|
||||
@Test
|
||||
public void testGetSuccessNoExistingSettings() throws Exception {
|
||||
SettingsService mockService = initSettingsService(null);
|
||||
UpdateApplicationsSettingsResolver resolver =
|
||||
new UpdateApplicationsSettingsResolver(mockService);
|
||||
|
||||
QueryContext mockContext = getMockAllowContext();
|
||||
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
|
||||
Mockito.when(mockEnv.getArgument(Mockito.eq("input"))).thenReturn(TEST_INPUT_ENABLED);
|
||||
Mockito.when(mockEnv.getContext()).thenReturn(mockContext);
|
||||
|
||||
assertTrue(resolver.get(mockEnv).get());
|
||||
|
||||
Mockito.verify(mockService, Mockito.times(1))
|
||||
.updateGlobalSettings(
|
||||
any(),
|
||||
Mockito.eq(
|
||||
new GlobalSettingsInfo()
|
||||
.setApplications(new ApplicationsSettings().setEnabled(true))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSuccessExistingSettings() throws Exception {
|
||||
SettingsService mockService = initSettingsService(new ApplicationsSettings().setEnabled(false));
|
||||
UpdateApplicationsSettingsResolver resolver =
|
||||
new UpdateApplicationsSettingsResolver(mockService);
|
||||
|
||||
QueryContext mockContext = getMockAllowContext();
|
||||
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
|
||||
Mockito.when(mockEnv.getArgument(Mockito.eq("input"))).thenReturn(TEST_INPUT_ENABLED);
|
||||
Mockito.when(mockEnv.getContext()).thenReturn(mockContext);
|
||||
|
||||
assertTrue(resolver.get(mockEnv).get());
|
||||
|
||||
Mockito.verify(mockService, Mockito.times(1))
|
||||
.updateGlobalSettings(
|
||||
any(),
|
||||
Mockito.eq(
|
||||
new GlobalSettingsInfo()
|
||||
.setApplications(new ApplicationsSettings().setEnabled(true))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSuccessDisableApplications() throws Exception {
|
||||
SettingsService mockService = initSettingsService(new ApplicationsSettings().setEnabled(true));
|
||||
UpdateApplicationsSettingsResolver resolver =
|
||||
new UpdateApplicationsSettingsResolver(mockService);
|
||||
|
||||
QueryContext mockContext = getMockAllowContext();
|
||||
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
|
||||
Mockito.when(mockEnv.getArgument(Mockito.eq("input"))).thenReturn(TEST_INPUT_DISABLED);
|
||||
Mockito.when(mockEnv.getContext()).thenReturn(mockContext);
|
||||
|
||||
assertTrue(resolver.get(mockEnv).get());
|
||||
|
||||
Mockito.verify(mockService, Mockito.times(1))
|
||||
.updateGlobalSettings(
|
||||
any(),
|
||||
Mockito.eq(
|
||||
new GlobalSettingsInfo()
|
||||
.setApplications(new ApplicationsSettings().setEnabled(false))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUnauthorized() throws Exception {
|
||||
SettingsService mockService = initSettingsService(new ApplicationsSettings().setEnabled(false));
|
||||
UpdateApplicationsSettingsResolver resolver =
|
||||
new UpdateApplicationsSettingsResolver(mockService);
|
||||
|
||||
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
|
||||
QueryContext mockContext = getMockDenyContext();
|
||||
Mockito.when(mockEnv.getArgument(Mockito.eq("input"))).thenReturn(TEST_INPUT_ENABLED);
|
||||
Mockito.when(mockEnv.getContext()).thenReturn(mockContext);
|
||||
|
||||
assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join());
|
||||
}
|
||||
|
||||
private static SettingsService initSettingsService(
|
||||
ApplicationsSettings existingApplicationsSettings) {
|
||||
SettingsService mockService = Mockito.mock(SettingsService.class);
|
||||
|
||||
Mockito.when(mockService.getGlobalSettings(any()))
|
||||
.thenReturn(
|
||||
new GlobalSettingsInfo()
|
||||
.setApplications(existingApplicationsSettings, SetMode.IGNORE_NULL));
|
||||
|
||||
return mockService;
|
||||
}
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
import { NetworkStatus } from '@apollo/client';
|
||||
import { Modal, Table } from '@components';
|
||||
import { Table } from '@components';
|
||||
import { message } from 'antd';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import { ConfirmationModal } from '@app/sharedV2/modals/ConfirmationModal';
|
||||
|
||||
import {
|
||||
ApplicationActionsColumn,
|
||||
ApplicationDescriptionColumn,
|
||||
@ -97,12 +99,20 @@ const ApplicationsTable = ({ searchQuery, searchData, loading: propLoading, netw
|
||||
refetch(); // Refresh the application list
|
||||
})
|
||||
.catch((e: any) => {
|
||||
message.error(`Failed to delete tag: ${e.message}`);
|
||||
message.error(`Failed to delete application: ${e.message}`);
|
||||
});
|
||||
|
||||
setShowDeleteModal(false);
|
||||
setApplicationUrnToDelete('');
|
||||
setApplicationDisplayName('');
|
||||
}, [deleteApplicationMutation, refetch, applicationUrnToDelete, applicationDisplayName]);
|
||||
|
||||
const handleDeleteClose = useCallback(() => {
|
||||
setShowDeleteModal(false);
|
||||
setApplicationUrnToDelete('');
|
||||
setApplicationDisplayName('');
|
||||
}, []);
|
||||
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
@ -190,29 +200,15 @@ const ApplicationsTable = ({ searchQuery, searchData, loading: propLoading, netw
|
||||
onChange={handleTableChange as any}
|
||||
/>
|
||||
|
||||
{/* Delete confirmation modal - simplified */}
|
||||
<Modal
|
||||
title={`Delete application ${applicationDisplayName}`}
|
||||
onCancel={() => setShowDeleteModal(false)}
|
||||
open={showDeleteModal}
|
||||
centered
|
||||
buttons={[
|
||||
{
|
||||
text: 'Cancel',
|
||||
color: 'violet',
|
||||
variant: 'text',
|
||||
onClick: () => setShowDeleteModal(false),
|
||||
},
|
||||
{
|
||||
text: 'Delete',
|
||||
color: 'red',
|
||||
variant: 'filled',
|
||||
onClick: handleDeleteApplication,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<p>Are you sure you want to delete this application? This action cannot be undone.</p>
|
||||
</Modal>
|
||||
<ConfirmationModal
|
||||
isOpen={showDeleteModal}
|
||||
handleClose={handleDeleteClose}
|
||||
handleConfirm={handleDeleteApplication}
|
||||
modalTitle="Delete Application"
|
||||
modalText={`Are you sure you want to delete the application "${applicationDisplayName}"? This action cannot be undone.`}
|
||||
closeButtonText="Cancel"
|
||||
confirmButtonText="Delete"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Button, PageTitle, Pagination, SearchBar, StructuredPopover } from '@components';
|
||||
import { debounce } from 'lodash';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
@ -8,6 +9,7 @@ import EmptyApplications from '@app/applications/EmptyApplications';
|
||||
import { useUserContext } from '@app/context/useUserContext';
|
||||
import { PageContainer } from '@app/govern/structuredProperties/styledComponents';
|
||||
import { Message } from '@src/app/shared/Message';
|
||||
import { DEBOUNCE_SEARCH_MS } from '@src/app/shared/constants';
|
||||
import { useShowNavBarRedesign } from '@src/app/useShowNavBarRedesign';
|
||||
import { useGetSearchResultsForMultipleQuery } from '@src/graphql/search.generated';
|
||||
import { EntityType } from '@src/types.generated';
|
||||
@ -62,13 +64,15 @@ const ManageApplications = () => {
|
||||
const canManageApplications = userContext?.platformPrivileges?.manageApplications;
|
||||
|
||||
// Debounce search query input to reduce unnecessary renders
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setDebouncedSearchQuery(searchQuery);
|
||||
}, 300);
|
||||
const debouncedSetSearchQuery = useMemo(
|
||||
() => debounce((query: string) => setDebouncedSearchQuery(query), DEBOUNCE_SEARCH_MS),
|
||||
[],
|
||||
);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [searchQuery]);
|
||||
useEffect(() => {
|
||||
debouncedSetSearchQuery(searchQuery);
|
||||
return () => debouncedSetSearchQuery.cancel();
|
||||
}, [searchQuery, debouncedSetSearchQuery]);
|
||||
|
||||
// Search query configuration
|
||||
const searchInputs = useMemo(
|
||||
|
@ -80,13 +80,13 @@ export const Preferences = () => {
|
||||
|
||||
const showSimplifiedHomepage = !!user?.settings?.appearance?.showSimplifiedHomepage;
|
||||
|
||||
const canManageApplications = userContext?.platformPrivileges?.manageApplications;
|
||||
const applicationsEnabled = appConfig.config?.visualConfig?.application?.showApplicationInNavigation ?? false;
|
||||
|
||||
const [updateUserSettingMutation] = useUpdateUserSettingMutation();
|
||||
const [updateApplicationsSettingsMutation] = useUpdateApplicationsSettingsMutation();
|
||||
|
||||
const showSimplifiedHomepageSetting = !isThemeV2;
|
||||
const canManageApplicationAppearance = userContext?.platformPrivileges?.manageApplications;
|
||||
|
||||
return (
|
||||
<Page>
|
||||
@ -167,7 +167,7 @@ export const Preferences = () => {
|
||||
</StyledCard>
|
||||
</>
|
||||
)}
|
||||
{canManageApplications && (
|
||||
{canManageApplicationAppearance && (
|
||||
<StyledCard>
|
||||
<UserSettingRow>
|
||||
<TextContainer>
|
||||
@ -195,7 +195,7 @@ export const Preferences = () => {
|
||||
</UserSettingRow>
|
||||
</StyledCard>
|
||||
)}
|
||||
{!showSimplifiedHomepageSetting && !isThemeV2Toggleable && !canManageApplications && (
|
||||
{!showSimplifiedHomepageSetting && !isThemeV2Toggleable && !canManageApplicationAppearance && (
|
||||
<div style={{ color: colors.gray[1700] }}>No appearance settings found.</div>
|
||||
)}
|
||||
</SourceContainer>
|
||||
|
@ -62,6 +62,7 @@ query getMe {
|
||||
manageStructuredProperties
|
||||
viewStructuredPropertiesPage
|
||||
manageApplications
|
||||
manageFeatures
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user