diff --git a/app/client/cypress/support/Pages/GitSync.ts b/app/client/cypress/support/Pages/GitSync.ts index 40dd9f1a76..99139d7211 100644 --- a/app/client/cypress/support/Pages/GitSync.ts +++ b/app/client/cypress/support/Pages/GitSync.ts @@ -474,9 +474,9 @@ export class GitSync { this.agHelper.AssertContains( Cypress.env("MESSAGES").DISCARDING_AND_PULLING_CHANGES(), ); + this.agHelper.AssertContains("Discarded changes successfully"); this.assertHelper.AssertNetworkStatus("@discardChanges"); this.assertHelper.AssertNetworkStatus("@gitStatus"); - this.agHelper.AssertContains("Discarded changes successfully"); this.agHelper.AssertElementExist(this._bottomBarCommit, 0, 30000); } diff --git a/app/client/src/actions/gitSyncActions.ts b/app/client/src/actions/gitSyncActions.ts index c08068a911..1427ac984b 100644 --- a/app/client/src/actions/gitSyncActions.ts +++ b/app/client/src/actions/gitSyncActions.ts @@ -196,8 +196,11 @@ export const fetchGitRemoteStatusSuccess = (payload: GitRemoteStatusData) => ({ payload, }); -export const discardChanges = () => ({ +export const discardChanges = ( + payload: { successToastMessage?: string } | undefined | null = {}, +) => ({ type: ReduxActionTypes.GIT_DISCARD_CHANGES, + payload, }); export const discardChangesSuccess = (payload: any) => ({ diff --git a/app/client/src/ce/constants/messages.ts b/app/client/src/ce/constants/messages.ts index 834c749f47..72a4d68ab7 100644 --- a/app/client/src/ce/constants/messages.ts +++ b/app/client/src/ce/constants/messages.ts @@ -842,6 +842,7 @@ export const COMMITTING_AND_PUSHING_CHANGES = () => export const DISCARDING_AND_PULLING_CHANGES = () => "Discarding and pulling changes..."; export const DISCARD_SUCCESS = () => "Discarded changes successfully."; +export const DISCARD_AND_PULL_SUCCESS = () => "Pulled from remote successfully"; export const IS_MERGING = () => "Merging changes..."; @@ -1087,7 +1088,8 @@ export const NOW_PROTECT_BRANCH = () => "You can now protect your default branch."; export const APPSMITH_ENTERPRISE = () => "Appsmith Enterprise"; export const PROTECT_BRANCH_SUCCESS = () => "Changed protected branches"; -export const UPDATE_DEFAULT_BRANCH_SUCCESS = () => "Updated default branch"; +export const UPDATE_DEFAULT_BRANCH_SUCCESS = (branchName: string) => + `Updated default branch ${!!branchName ? `to ${branchName}` : ""}`; export const CONTACT_ADMIN_FOR_GIT = () => "Please contact your workspace admin to connect your app to a git repo"; // Git Branch Protection end diff --git a/app/client/src/ce/sagas/ApplicationSagas.tsx b/app/client/src/ce/sagas/ApplicationSagas.tsx index f2a50f6ccb..23a7ce406c 100644 --- a/app/client/src/ce/sagas/ApplicationSagas.tsx +++ b/app/client/src/ce/sagas/ApplicationSagas.tsx @@ -65,7 +65,6 @@ import { createMessage, DELETING_APPLICATION, DELETING_MULTIPLE_APPLICATION, - DISCARD_SUCCESS, ERROR_IMPORTING_APPLICATION_TO_WORKSPACE, } from "@appsmith/constants/messages"; import { APP_MODE } from "entities/App"; @@ -300,12 +299,6 @@ export function* fetchAppAndPagesSaga( }, }); - if (localStorage.getItem("GIT_DISCARD_CHANGES") === "success") { - toast.show(createMessage(DISCARD_SUCCESS), { - kind: "success", - }); - localStorage.setItem("GIT_DISCARD_CHANGES", ""); - } yield put({ type: ReduxActionTypes.SET_APP_VERSION_ON_WORKER, payload: response.data.application?.evaluationVersion, diff --git a/app/client/src/pages/Editor/gitSync/QuickGitActions/index.tsx b/app/client/src/pages/Editor/gitSync/QuickGitActions/index.tsx index ad0740799b..5ef6f74b52 100644 --- a/app/client/src/pages/Editor/gitSync/QuickGitActions/index.tsx +++ b/app/client/src/pages/Editor/gitSync/QuickGitActions/index.tsx @@ -13,6 +13,7 @@ import { CONNECTING_TO_REPO_DISABLED, CONTACT_ADMIN_FOR_GIT, createMessage, + DISCARD_AND_PULL_SUCCESS, DURING_ONBOARDING_TOUR, GIT_SETTINGS, MERGE, @@ -136,8 +137,11 @@ const getPullBtnStatus = ( ) => { const { behindCount, isClean } = gitStatus || {}; let message = createMessage(NO_COMMITS_TO_PULL); - let disabled = isProtected ? false : behindCount === 0; - if (!isClean) { + let disabled = behindCount === 0; + if (isProtected) { + disabled = false; + message = createMessage(PULL_CHANGES); + } else if (!isClean) { disabled = true; message = createMessage(CANNOT_PULL_WITH_LOCAL_UNCOMMITTED_CHANGES); } else if (pullFailed) { @@ -189,7 +193,7 @@ const getQuickActionButtons = ({ }, { className: "t--bottom-bar-pull", - count: isProtectedMode ? undefined : gitStatus?.behindCount, + count: gitStatus?.behindCount, icon: "down-arrow-2", onClick: () => !pullDisabled && pull(), tooltipText: pullTooltipMessage, @@ -360,7 +364,11 @@ export default function QuickGitActions() { source: "BOTTOM_BAR_GIT_PULL_BUTTON", }); if (isProtectedMode) { - dispatch(discardChanges()); + dispatch( + discardChanges({ + successToastMessage: createMessage(DISCARD_AND_PULL_SUCCESS), + }), + ); } else { dispatch(gitPullInit({ triggeredFromBottomBar: true })); } diff --git a/app/client/src/pages/Editor/gitSync/Tabs/GitSettings/GitDefaultBranch.tsx b/app/client/src/pages/Editor/gitSync/Tabs/GitSettings/GitDefaultBranch.tsx index 8c7691351e..0380b181f8 100644 --- a/app/client/src/pages/Editor/gitSync/Tabs/GitSettings/GitDefaultBranch.tsx +++ b/app/client/src/pages/Editor/gitSync/Tabs/GitSettings/GitDefaultBranch.tsx @@ -103,6 +103,8 @@ function GitDefaultBranch() { triggerNode.parentNode} isDisabled={!isGitProtectedFeatureLicensed} onChange={(v) => setSelectedValue(v)} value={selectedValue} diff --git a/app/client/src/pages/Editor/gitSync/Tabs/GitSettings/GitProtectedBranches.tsx b/app/client/src/pages/Editor/gitSync/Tabs/GitSettings/GitProtectedBranches.tsx index 123a247191..dc6fd581a3 100644 --- a/app/client/src/pages/Editor/gitSync/Tabs/GitSettings/GitProtectedBranches.tsx +++ b/app/client/src/pages/Editor/gitSync/Tabs/GitSettings/GitProtectedBranches.tsx @@ -7,7 +7,7 @@ import { } from "@appsmith/constants/messages"; import { updateGitProtectedBranchesInit } from "actions/gitSyncActions"; import { Button, Link, Option, Select, Text } from "design-system"; -import { xor } from "lodash"; +import { union, xor } from "lodash"; import React, { useEffect, useMemo, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import { @@ -20,6 +20,7 @@ import styled from "styled-components"; import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; import { useAppsmithEnterpriseLink } from "./hooks"; +import { REMOTE_BRANCH_PREFIX } from "../../constants"; const Container = styled.div` padding-top: 16px; @@ -56,13 +57,33 @@ function GitProtectedBranches() { const dispatch = useDispatch(); const unfilteredBranches = useSelector(getGitBranches); - const branches = unfilteredBranches.filter( - (b) => !b.branchName.includes("origin/"), - ); + const defaultBranch = useSelector(getDefaultGitBranchName); + + const branchNames = useMemo(() => { + const remoteBranchNames = []; + const localBranchNames = []; + for (const unfilteredBranch of unfilteredBranches) { + if (unfilteredBranch.branchName === defaultBranch) { + continue; + } + if (unfilteredBranch.branchName.includes(REMOTE_BRANCH_PREFIX)) { + remoteBranchNames.push( + unfilteredBranch.branchName.replace(REMOTE_BRANCH_PREFIX, ""), + ); + } else { + localBranchNames.push(unfilteredBranch.branchName); + } + } + const branchNames = union(localBranchNames, remoteBranchNames); + if (defaultBranch) { + branchNames.unshift(defaultBranch); + } + return branchNames; + }, [unfilteredBranches, defaultBranch]); + const isGitProtectedFeatureLicensed = useFeatureFlag( FEATURE_FLAG.license_git_branch_protection_enabled, ); - const defaultBranch = useSelector(getDefaultGitBranchName); const protectedBranches = useSelector(getProtectedBranchesSelector); const isUpdateLoading = useSelector(getIsUpdateProtectedBranchesLoading); const [selectedValues, setSelectedValues] = useState(); @@ -114,20 +135,22 @@ function GitProtectedBranches() { triggerNode.parentNode} isMultiSelect maxTagTextLength={8} onChange={(v) => setSelectedValues(v)} value={selectedValues} > - {branches.map((b) => ( + {branchNames.map((branchName) => ( ))} diff --git a/app/client/src/pages/Editor/gitSync/constants.ts b/app/client/src/pages/Editor/gitSync/constants.ts index 8b0b3fd65e..34f93d730d 100644 --- a/app/client/src/pages/Editor/gitSync/constants.ts +++ b/app/client/src/pages/Editor/gitSync/constants.ts @@ -22,3 +22,5 @@ export enum CREDENTIAL_MODE { MANUALLY = "MANUALLY", IMPORT_JSON = "IMPORT_JSON", } + +export const REMOTE_BRANCH_PREFIX = "origin/"; diff --git a/app/client/src/pages/Editor/gitSync/hooks/useIsGitAdmin.ts b/app/client/src/pages/Editor/gitSync/hooks/useIsGitAdmin.ts index b78282426a..172d0b6bad 100644 --- a/app/client/src/pages/Editor/gitSync/hooks/useIsGitAdmin.ts +++ b/app/client/src/pages/Editor/gitSync/hooks/useIsGitAdmin.ts @@ -1,15 +1,8 @@ -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"; +import { getCurrentAppWorkspace } from "@appsmith/selectors/workspaceSelectors"; +import { hasCreateNewAppPermission } from "@appsmith/utils/permissionHelpers"; export const useIsGitAdmin = () => { - const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); - const tenantPermissions = useSelector(getTenantPermissions); - const canCreateWorkspace = getHasCreateWorkspacePermission( - isFeatureEnabled, - tenantPermissions, - ); - return canCreateWorkspace; + const workspace = useSelector(getCurrentAppWorkspace); + return hasCreateNewAppPermission(workspace.userPermissions); }; diff --git a/app/client/src/sagas/GitSyncSagas.ts b/app/client/src/sagas/GitSyncSagas.ts index ee685cdf16..8a0c5a8850 100644 --- a/app/client/src/sagas/GitSyncSagas.ts +++ b/app/client/src/sagas/GitSyncSagas.ts @@ -10,6 +10,7 @@ import { import { actionChannel, call, + delay, fork, put, select, @@ -84,6 +85,7 @@ import { import { createMessage, DELETE_BRANCH_SUCCESS, + DISCARD_SUCCESS, ERROR_GIT_AUTH_FAIL, ERROR_GIT_INVALID_REMOTE, GIT_USER_UPDATED_SUCCESSFULLY, @@ -1024,11 +1026,13 @@ export function* deleteBranch({ payload }: ReduxAction) { yield put(fetchBranchesInit({ pruneBranches: true })); } } catch (error) { - yield put(deleteBranchError(error)); + yield put(deleteBranchError({ error, show: true })); } } -function* discardChanges() { +function* discardChanges({ + payload, +}: ReduxAction<{ successToastMessage: string } | null | undefined>) { let response: ApiResponse; try { const appId: string = yield select(getCurrentApplicationId); @@ -1040,10 +1044,15 @@ function* discardChanges() { ); if (isValidResponse) { yield put(discardChangesSuccess(response.data)); - // const applicationId: string = response.data.id; + const successToastMessage = + payload?.successToastMessage ?? createMessage(DISCARD_SUCCESS); + toast.show(successToastMessage, { + kind: "success", + }); + // adding delay to show toast animation before reloading + yield delay(500); const pageId: string = response.data?.pages?.find((page: any) => page.isDefault)?.id || ""; - localStorage.setItem("GIT_DISCARD_CHANGES", "success"); const branch = response.data.gitApplicationMetadata.branchName; window.open(builderURL({ pageId, branch }), "_self"); } else { @@ -1053,11 +1062,9 @@ function* discardChanges() { show: true, }), ); - localStorage.setItem("GIT_DISCARD_CHANGES", "failure"); } } catch (error) { yield put(discardChangesFailure({ error, show: true })); - localStorage.setItem("GIT_DISCARD_CHANGES", "failure"); } }