fix: adding git admin permissions (#28719)

## Description
- Derives isGitAdmin from workspace permissions
- Disables connect to git if not git admin
- Disables disconnect, default branch and branch protection if not git
admin

#### PR fixes following issue(s)
Fixes #28020 

#### Media
<img width="1728" alt="image"
src="https://github.com/appsmithorg/appsmith/assets/8724051/22d133e6-4836-4184-86ce-c2ab1eff26c5">

#### Type of change
- New feature (non-breaking change which adds functionality)

## Testing
>
#### How Has This Been Tested?
> Please describe the tests that you ran to verify your changes. Also
list any relevant details for your test configuration.
> Delete anything that is not relevant
- [x] Manual
- [ ] JUnit
- [ ] Jest
- [ ] Cypress
>
>
#### Test Plan
> Add Testsmith test cases links that relate to this PR
>
>
#### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
>
>
>
## Checklist:
#### Dev activity
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag


#### QA activity:
- [ ] [Speedbreak
features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-)
have been covered
- [ ] Test plan covers all impacted features and [areas of
interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-)
- [ ] Test plan has been peer reviewed by project stakeholders and other
QA members
- [ ] Manually tested functionality on DP
- [ ] We had an implementation alignment call with stakeholders post QA
Round 2
- [ ] Cypress test cases have been added and approved by SDET/manual QA
- [ ] Added `Test Plan Approved` label after Cypress tests were reviewed
- [ ] Added `Test Plan Approved` label after JUnit tests were reviewed
This commit is contained in:
Rudraprasad Das 2023-11-08 15:26:45 +05:30 committed by Nayan
parent 89601117b6
commit 0238a8adc8
7 changed files with 80 additions and 17 deletions

View File

@ -1088,6 +1088,8 @@ export const NOW_PROTECT_BRANCH = () =>
export const APPSMITH_ENTERPRISE = () => "Appsmith Enterprise"; export const APPSMITH_ENTERPRISE = () => "Appsmith Enterprise";
export const PROTECT_BRANCH_SUCCESS = () => "Changed protected branches"; export const PROTECT_BRANCH_SUCCESS = () => "Changed protected branches";
export const UPDATE_DEFAULT_BRANCH_SUCCESS = () => "Updated default branch"; export const UPDATE_DEFAULT_BRANCH_SUCCESS = () => "Updated default branch";
export const CONTACT_ADMIN_FOR_GIT = () =>
"Please contact your workspace admin to connect your app to a git repo";
// Git Branch Protection end // Git Branch Protection end
export const NAV_DESCRIPTION = () => export const NAV_DESCRIPTION = () =>

View File

@ -12,6 +12,7 @@ import {
} from "@appsmith/constants/messages"; } from "@appsmith/constants/messages";
import { Button } from "design-system"; import { Button } from "design-system";
import { KBEditorMenuItem } from "@appsmith/pages/Editor/KnowledgeBase/KBEditorMenuItem"; import { KBEditorMenuItem } from "@appsmith/pages/Editor/KnowledgeBase/KBEditorMenuItem";
import { useIsGitAdmin } from "pages/Editor/gitSync/hooks/useIsGitAdmin";
interface Props { interface Props {
trigger: ReactNode; trigger: ReactNode;
@ -21,6 +22,7 @@ interface Props {
export const DeployLinkButton = (props: Props) => { export const DeployLinkButton = (props: Props) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const isGitConnected = useSelector(getIsGitConnected); const isGitConnected = useSelector(getIsGitConnected);
const isGitAdmin = useIsGitAdmin();
const goToGitConnectionPopup = () => { const goToGitConnectionPopup = () => {
AnalyticsUtil.logEvent("GS_CONNECT_GIT_CLICK", { AnalyticsUtil.logEvent("GS_CONNECT_GIT_CLICK", {
@ -46,7 +48,7 @@ export const DeployLinkButton = (props: Props) => {
/> />
</MenuTrigger> </MenuTrigger>
<MenuContent> <MenuContent>
{!isGitConnected && ( {!isGitConnected && isGitAdmin && (
<MenuItem <MenuItem
className="t--connect-to-git-btn" className="t--connect-to-git-btn"
onClick={goToGitConnectionPopup} onClick={goToGitConnectionPopup}

View File

@ -1,4 +1,4 @@
import React from "react"; import React, { useMemo } from "react";
import styled from "styled-components"; import styled from "styled-components";
import BranchButton from "./BranchButton"; import BranchButton from "./BranchButton";
@ -11,6 +11,7 @@ import {
CONNECT_GIT, CONNECT_GIT,
CONNECT_GIT_BETA, CONNECT_GIT_BETA,
CONNECTING_TO_REPO_DISABLED, CONNECTING_TO_REPO_DISABLED,
CONTACT_ADMIN_FOR_GIT,
createMessage, createMessage,
DURING_ONBOARDING_TOUR, DURING_ONBOARDING_TOUR,
GIT_SETTINGS, GIT_SETTINGS,
@ -44,6 +45,7 @@ import { Button, Icon, Tooltip } from "design-system";
import AnalyticsUtil from "utils/AnalyticsUtil"; import AnalyticsUtil from "utils/AnalyticsUtil";
import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
import { useIsGitAdmin } from "../hooks/useIsGitAdmin";
interface QuickActionButtonProps { interface QuickActionButtonProps {
className?: string; className?: string;
@ -236,21 +238,35 @@ const OuterContainer = styled.div`
height: 100%; height: 100%;
`; `;
const CenterDiv = styled.div`
text-align: center;
`;
function ConnectGitPlaceholder() { function ConnectGitPlaceholder() {
const dispatch = useDispatch(); const dispatch = useDispatch();
const isInGuidedTour = useSelector(inGuidedTour); const isInGuidedTour = useSelector(inGuidedTour);
const isTooltipEnabled = isInGuidedTour; const isGitAdmin = useIsGitAdmin();
const tooltipContent = !isInGuidedTour ? ( const isTooltipEnabled = isInGuidedTour || !isGitAdmin;
<> const tooltipContent = useMemo(() => {
<div>{createMessage(NOT_LIVE_FOR_YOU_YET)}</div> if (!isGitAdmin) {
<div>{createMessage(COMING_SOON)}</div> return <CenterDiv>{createMessage(CONTACT_ADMIN_FOR_GIT)}</CenterDiv>;
</> }
) : ( if (isInGuidedTour) {
<> return (
<div>{createMessage(CONNECTING_TO_REPO_DISABLED)}</div> <>
<div>{createMessage(DURING_ONBOARDING_TOUR)}</div> <div>{createMessage(CONNECTING_TO_REPO_DISABLED)}</div>
</> <div>{createMessage(DURING_ONBOARDING_TOUR)}</div>
); </>
);
}
return (
<>
<div>{createMessage(NOT_LIVE_FOR_YOU_YET)}</div>
<div>{createMessage(COMING_SOON)}</div>
</>
);
}, [isInGuidedTour, isGitAdmin]);
const isGitConnectionEnabled = !isInGuidedTour; const isGitConnectionEnabled = !isInGuidedTour;
return ( return (
@ -265,6 +281,7 @@ function ConnectGitPlaceholder() {
{isGitConnectionEnabled ? ( {isGitConnectionEnabled ? (
<Button <Button
className="t--connect-git-bottom-bar" className="t--connect-git-bottom-bar"
isDisabled={!isGitAdmin}
kind="secondary" kind="secondary"
onClick={() => { onClick={() => {
AnalyticsUtil.logEvent("GS_CONNECT_GIT_CLICK", { AnalyticsUtil.logEvent("GS_CONNECT_GIT_CLICK", {

View File

@ -74,7 +74,12 @@ function GitDisconnect() {
</Text> </Text>
<Text renderAs="p">{createMessage(DISCONNECT_GIT_MESSAGE)}</Text> <Text renderAs="p">{createMessage(DISCONNECT_GIT_MESSAGE)}</Text>
</BodyInnerContainer> </BodyInnerContainer>
<Button kind="error" onClick={handleDisconnect} size="md"> <Button
data-testid="t--git-disconnect-btn"
kind="error"
onClick={handleDisconnect}
size="md"
>
{createMessage(DISCONNECT_GIT)} {createMessage(DISCONNECT_GIT)}
</Button> </Button>
</BodyContainer> </BodyContainer>

View File

@ -0,0 +1,19 @@
/* eslint-disable jest/no-focused-tests */
import React from "react";
import { render, screen } from "test/testUtils";
import GitSettings from ".";
import type { AppState } from "@appsmith/reducers";
jest.mock("../../hooks/useIsGitAdmin", () => ({
useIsGitAdmin: () => false,
}));
describe("GitSettings test for git admin disabled", () => {
it("Branch protection, default branch and disconnect disabled when not ", () => {
const initialState: Partial<AppState> = {};
render(<GitSettings />, { initialState });
expect(screen.queryByTestId("t--git-protected-branches-select")).toBe(null);
expect(screen.queryByTestId("t--git-default-branch-select")).toBe(null);
expect(screen.queryByTestId("t--git-disconnect-btn")).toBe(null);
});
});

View File

@ -7,6 +7,7 @@ import GitDefaultBranch from "./GitDefaultBranch";
import GitProtectedBranches from "./GitProtectedBranches"; import GitProtectedBranches from "./GitProtectedBranches";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { getIsGitProtectedFeatureEnabled } from "selectors/gitSyncSelectors"; import { getIsGitProtectedFeatureEnabled } from "selectors/gitSyncSelectors";
import { useIsGitAdmin } from "../../hooks/useIsGitAdmin";
const Container = styled.div` const Container = styled.div`
overflow: auto; overflow: auto;
@ -23,18 +24,20 @@ function GitSettings() {
const isGitProtectedFeatureEnabled = useSelector( const isGitProtectedFeatureEnabled = useSelector(
getIsGitProtectedFeatureEnabled, getIsGitProtectedFeatureEnabled,
); );
const isGitAdmin = useIsGitAdmin();
return ( return (
<ModalBody> <ModalBody>
<Container> <Container>
<GitUserSettings /> <GitUserSettings />
{isGitProtectedFeatureEnabled ? ( {isGitProtectedFeatureEnabled && isGitAdmin ? (
<> <>
<StyledDivider /> <StyledDivider />
<GitDefaultBranch /> <GitDefaultBranch />
<GitProtectedBranches /> <GitProtectedBranches />
</> </>
) : null} ) : null}
<GitDisconnect /> {isGitAdmin && <GitDisconnect />}
</Container> </Container>
</ModalBody> </ModalBody>
); );

View File

@ -0,0 +1,15 @@
import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
import { getTenantPermissions } from "@appsmith/selectors/tenantSelectors";
import { getHasCreateWorkspacePermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers";
import { useSelector } from "react-redux";
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
export const useIsGitAdmin = () => {
const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled);
const tenantPermissions = useSelector(getTenantPermissions);
const canCreateWorkspace = getHasCreateWorkspacePermission(
isFeatureEnabled,
tenantPermissions,
);
return canCreateWorkspace;
};