Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adding branch persistence #36622

Merged
merged 12 commits into from
Oct 14, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags";
import {
agHelper,
gitSync,
homePage,
} from "../../../../support/Objects/ObjectsCore";

let wsName: string;
let appName: string;
let repoName: string;

describe(
"Git Persist Branch",
{
tags: ["@tag.Git", "@tag.GitPersistBranch"],
},
function () {
before(() => {
agHelper.GenerateUUID();
cy.get("@guid").then((uid) => {
wsName = "GitPB-" + uid;
appName = "GitPB1-" + uid;
homePage.CreateNewWorkspace(wsName, true);
homePage.CreateAppInWorkspace(wsName, appName);
gitSync.CreateNConnectToGit("test-git-perssit-branch", true, true);
cy.get("@gitRepoName").then((resRepoName) => {
repoName = resRepoName.toString();
homePage.NavigateToHome();
});
});
});
it("Check if branch persist after changing branch and exiting the app", function () {
featureFlagIntercept({ release_git_persist_branch_enabled: true }, true);
homePage.EditAppFromAppHover(appName);
gitSync.CreateGitBranch("b1", false);
cy.get("@gitbranchName").then((resBranchName) => {
const branchName = resBranchName.toString();
homePage.NavigateToHome();
homePage.EditAppFromAppHover(appName);
gitSync.AssertBranchName(branchName);
gitSync.AssertBranchNameInUrl(branchName);
});
});
},
);
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { featureFlagIntercept } from "../../../../../support/Objects/FeatureFlags";
import * as _ from "../../../../../support/Objects/ObjectsCore";
import EditorNavigation, {
EntityType,
Expand Down
12 changes: 12 additions & 0 deletions app/client/cypress/support/Pages/GitSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -453,4 +453,16 @@ export class GitSync {
}
this.CloseGitSyncModal();
}

public AssertBranchName(branch: string) {
this.agHelper.AssertElementVisibility(this._branchButton);
this.agHelper.AssertContains(branch);
}

public AssertBranchNameInUrl(branch: string) {
cy.location("search")
.then((searchParams) => new URLSearchParams(searchParams))
.invoke("get", "branch")
.should("equal", branch);
}
}
2 changes: 2 additions & 0 deletions app/client/src/ce/entities/FeatureFlag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const FEATURE_FLAG = {
rollout_side_by_side_enabled: "rollout_side_by_side_enabled",
release_layout_conversion_enabled: "release_layout_conversion_enabled",
release_anvil_toggle_enabled: "release_anvil_toggle_enabled",
release_git_persist_branch_enabled: "release_git_persist_branch_enabled",
release_ide_animations_enabled: "release_ide_animations_enabled",
} as const;

Expand Down Expand Up @@ -71,6 +72,7 @@ export const DEFAULT_FEATURE_FLAG_VALUE: FeatureFlags = {
rollout_side_by_side_enabled: false,
release_layout_conversion_enabled: false,
release_anvil_toggle_enabled: false,
release_git_persist_branch_enabled: false,
release_ide_animations_enabled: false,
};

Expand Down
31 changes: 29 additions & 2 deletions app/client/src/entities/Engine/AppEditorEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ import {
reportSWStatus,
waitForWidgetConfigBuild,
} from "sagas/InitSagas";
import { getCurrentGitBranch } from "selectors/gitSyncSelectors";
import {
getCurrentGitBranch,
isGitPersistBranchEnabledSelector,
} from "selectors/gitSyncSelectors";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import history from "utils/history";
import type { AppEnginePayload } from ".";
Expand All @@ -50,7 +53,7 @@ import {
} from "ee/sagas/userSagas";
import { getFirstTimeUserOnboardingComplete } from "selectors/onboardingSelectors";
import { isAirgapped } from "ee/utils/airgapHelpers";
import { getAIPromptTriggered } from "utils/storage";
import { getAIPromptTriggered, setLatestGitBranchInLocal } from "utils/storage";
import { trackOpenEditorTabs } from "../../utils/editor/browserTabsTracking";
import { EditorModes } from "components/editorComponents/CodeEditor/EditorConfig";
import { waitForFetchEnvironments } from "ee/sagas/EnvironmentSagas";
Expand All @@ -68,6 +71,9 @@ import {
import { getCurrentApplication } from "ee/selectors/applicationSelectors";
import type { Span } from "@opentelemetry/api";
import { endSpan, startNestedSpan } from "UITelemetry/generateTraces";
import { getCurrentUser } from "selectors/usersSelectors";
import type { User } from "constants/userConstants";
import log from "loglevel";

export default class AppEditorEngine extends AppEngine {
constructor(mode: APP_MODE) {
Expand Down Expand Up @@ -269,6 +275,27 @@ export default class AppEditorEngine extends AppEngine {
getCurrentApplication,
);

const isGitPersistBranchEnabled: boolean = yield select(
isGitPersistBranchEnabledSelector,
);

if (isGitPersistBranchEnabled) {
const currentUser: User = yield select(getCurrentUser);
const currentBranch: string = yield select(getCurrentGitBranch);

if (currentUser?.email && currentApplication?.baseId && currentBranch) {
yield setLatestGitBranchInLocal(
currentUser.email,
currentApplication.baseId,
currentBranch,
);
} else {
log.error(
`There was an error setting the latest git branch in local - userEmail: ${!!currentUser?.email}, applicationId: ${currentApplication?.baseId}, branch: ${currentBranch}`,
);
}
}

const [isAnotherEditorTabOpen, currentTabs] = yield call(
trackOpenEditorTabs,
currentApplication.id,
Expand Down
59 changes: 44 additions & 15 deletions app/client/src/pages/Applications/ApplicationCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ import { getCurrentUser } from "actions/authActions";
import Card, { ContextMenuTrigger } from "components/common/Card";
import { generateEditedByText } from "./helpers";
import { noop } from "lodash";
import { getLatestGitBranchFromLocal } from "utils/storage";
import { getCurrentUser as getCurrentUserSelector } from "selectors/usersSelectors";
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
import { FEATURE_FLAG } from "ee/entities/FeatureFlag";

interface ApplicationCardProps {
application: ApplicationPayload;
Expand Down Expand Up @@ -98,6 +102,7 @@ export function ApplicationCard(props: ApplicationCardProps) {
const theme = useContext(ThemeContext);
const isSavingName = useSelector(getIsSavingAppName);
const isErroredSavingName = useSelector(getIsErroredSavingAppName);
const currentUser = useSelector(getCurrentUserSelector);
const initialsAndColorCode = getInitialsAndColorCode(
props.application.name,
theme.colors.appCardColors,
Expand All @@ -116,7 +121,40 @@ export function ApplicationCard(props: ApplicationCardProps) {
const dispatch = useDispatch();

const applicationId = props.application?.id;
const baseApplicationId = props.application?.baseId;
const showGitBadge = props.application?.gitApplicationMetadata?.branchName;
const [editorParams, setEditorParams] = useState({});
const isGitPersistBranchEnabled = useFeatureFlag(
FEATURE_FLAG.release_git_persist_branch_enabled,
);

useEffect(() => {
(async () => {
const storedLatestBranch = await getLatestGitBranchFromLocal(
currentUser?.email ?? "",
baseApplicationId,
);

if (isGitPersistBranchEnabled && storedLatestBranch) {
setEditorParams({ branch: storedLatestBranch });
} else if (showGitBadge) {
setEditorParams({ branch: showGitBadge });
}
})();
}, [
baseApplicationId,
currentUser?.email,
showGitBadge,
isGitPersistBranchEnabled,
]);

const viewerParams = useMemo(() => {
if (showGitBadge) {
return { branch: showGitBadge };
} else {
return {};
}
}, [showGitBadge]);

useEffect(() => {
let colorCode;
Expand Down Expand Up @@ -273,15 +311,6 @@ export function ApplicationCard(props: ApplicationCardProps) {
initials += props.application.name[1].toUpperCase() || "";
}

// should show correct branch of application when edit mode
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const params: any = {};

if (showGitBadge) {
params.branch = showGitBadge;
}

const handleMenuOnClose = (open: boolean) => {
if (!open && !isDeleting) {
setIsMenuOpen(false);
Expand Down Expand Up @@ -437,16 +466,16 @@ export function ApplicationCard(props: ApplicationCardProps) {

if (!basePageId) return "";

return builderURL({ basePageId, params });
}, [props.application.defaultBasePageId, params]);
return builderURL({ basePageId, params: editorParams });
}, [props.application.defaultBasePageId, editorParams]);

const viewModeURL = useMemo(() => {
const basePageId = props.application.defaultBasePageId;

if (!basePageId) return "";

return viewerURL({ basePageId, params });
}, [props.application.defaultBasePageId, params]);
return viewerURL({ basePageId, params: viewerParams });
}, [props.application.defaultBasePageId, viewerParams]);

const launchApp = useCallback(() => {
setURLParams();
Expand All @@ -463,11 +492,11 @@ export function ApplicationCard(props: ApplicationCardProps) {
history.push(
viewerURL({
basePageId: props.application.defaultBasePageId,
params,
params: viewerParams,
}),
);
dispatch(getCurrentUser());
}, [props.application.defaultPageId]);
}, [dispatch, props.application.defaultBasePageId, viewerParams]);

return (
<Card
Expand Down
1 change: 0 additions & 1 deletion app/client/src/sagas/InitSagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,6 @@ export function* getInitResponses({
}: {
applicationId?: string;
basePageId?: string;
branch?: string;
mode?: APP_MODE;
shouldInitialiseUserDetails?: boolean;
// TODO: Fix this the next time the file is edited
Expand Down
6 changes: 6 additions & 0 deletions app/client/src/selectors/gitSyncSelectors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
getCurrentApplication,
} from "ee/selectors/applicationSelectors";
import type { Branch } from "entities/GitSync";
import { selectFeatureFlags } from "ee/selectors/featureFlagsSelectors";

export const getGitSyncState = (state: AppState): GitSyncReducerState =>
state.ui.gitSync;
Expand Down Expand Up @@ -280,3 +281,8 @@ export const isGitSettingsModalOpenSelector = (state: AppState) =>

export const activeGitSettingsModalTabSelector = (state: AppState) =>
state.ui.gitSync.activeGitSettingsModalTab;

export const isGitPersistBranchEnabledSelector = createSelector(
selectFeatureFlags,
(featureFlags) => featureFlags.release_git_persist_branch_enabled ?? false,
);
50 changes: 50 additions & 0 deletions app/client/src/utils/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const STORAGE_KEYS: {
CODE_WIDGET_NAVIGATION_USED: "CODE_WIDGET_NAVIGATION_USED",
OVERRIDDEN_FEATURE_FLAGS: "OVERRIDDEN_FEATURE_FLAGS",
ACTION_TEST_PAYLOAD: "ACTION_TEST_PAYLOAD",
LATEST_GIT_BRANCH: "LATEST_GIT_BRANCH",
};

const store = localforage.createInstance({
Expand Down Expand Up @@ -1087,3 +1088,52 @@ export const storeActionTestPayload = async (payload: {
return false;
}
};

export const setLatestGitBranchInLocal = async (
userEmail: string,
baseApplicationId: string,
branch: string,
) => {
try {
const storedBranches: Record<
string,
Record<string, string>
> = (await store.getItem(STORAGE_KEYS.LATEST_GIT_BRANCH)) ?? {};
const userBranches = storedBranches?.[userEmail] ?? {};
const newBranches = {
...(storedBranches ?? {}),
[userEmail]: {
...userBranches,
[baseApplicationId]: branch,
},
};

await store.setItem(STORAGE_KEYS.LATEST_GIT_BRANCH, newBranches);

return true;
} catch (error) {
log.error("An error occurred while setting LATEST_GIT_BRANCH");
log.error(error);

return false;
}
};

export const getLatestGitBranchFromLocal = async (
userEmail: string,
baseApplicationId: string,
) => {
try {
const storedBranches: Record<string, Record<string, string>> | null =
await store.getItem(STORAGE_KEYS.LATEST_GIT_BRANCH);
const userBranches = storedBranches?.[userEmail] ?? {};
const branch = userBranches?.[baseApplicationId] ?? null;

return branch;
} catch (error) {
log.error("An error occurred while fetching LATEST_GIT_BRANCH");
log.error(error);

return null;
}
};
Loading