chore: git mod - adding init saga and connecting components to ctx (#38088)
## Description - Adds more selectors - Adds more sagas - Introduces init steps for git - Improvements upon CtxAwareGitQuickActions Fixes #37800 Fixes #36814 ## Automation /ok-to-test tags="@tag.Git" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/12295168481> > Commit: ea1ab497cad677aac36f044462e623e526d421d1 > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=12295168481&attempt=1" target="_blank">Cypress dashboard</a>. > Tags: `@tag.Git` > Spec: > <hr>Thu, 12 Dec 2024 12:06:09 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Summary by CodeRabbit - **New Features** - Introduced a context provider for managing Git-related state. - Added a `GitQuickActions` component for various Git actions. - Implemented custom hooks for managing Git branches, metadata, operations, and settings. - Added Redux Saga functions for fetching Git metadata and protected branches. - Enhanced autocommit functionality with polling for progress. - Introduced actions for managing the autocommit process and fetching protected branches. - Added new actions to initialize Git for editor context and manage loading states. - **Bug Fixes** - Improved error handling in various action creators and sagas. - **Chores** - Updated action creators and types for better type safety and clarity. - Refined test cases for components to ensure accurate button selection. - Modified request functions to utilize Axios promises directly for better consistency. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
8e30a389e4
commit
0808b279fa
|
|
@ -5,9 +5,13 @@ import useStatusChangeCount from "./hooks/useStatusChangeCount";
|
|||
|
||||
function CtxAwareGitQuickActions() {
|
||||
const {
|
||||
autocommitEnabled,
|
||||
autocommitPolling,
|
||||
discard,
|
||||
discardLoading,
|
||||
fetchStatusLoading,
|
||||
gitConnected,
|
||||
protectedMode,
|
||||
pull,
|
||||
pullError,
|
||||
pullLoading,
|
||||
|
|
@ -17,12 +21,7 @@ function CtxAwareGitQuickActions() {
|
|||
toggleGitSettingsModal,
|
||||
} = useGitContext();
|
||||
|
||||
const isGitConnected = false;
|
||||
const isAutocommitEnabled = true;
|
||||
const isAutocommitPolling = false;
|
||||
const isConnectPermitted = true;
|
||||
const isProtectedMode = false;
|
||||
|
||||
const connectPermitted = true;
|
||||
const isPullFailing = !!pullError;
|
||||
const isStatusClean = status?.isClean ?? false;
|
||||
const statusBehindCount = status?.behindCount ?? 0;
|
||||
|
|
@ -31,13 +30,13 @@ function CtxAwareGitQuickActions() {
|
|||
return (
|
||||
<GitQuickActions
|
||||
discard={discard}
|
||||
isAutocommitEnabled={isAutocommitEnabled}
|
||||
isAutocommitPolling={isAutocommitPolling}
|
||||
isConnectPermitted={isConnectPermitted}
|
||||
isAutocommitEnabled={autocommitEnabled}
|
||||
isAutocommitPolling={autocommitPolling}
|
||||
isConnectPermitted={connectPermitted}
|
||||
isDiscardLoading={discardLoading}
|
||||
isFetchStatusLoading={fetchStatusLoading}
|
||||
isGitConnected={isGitConnected}
|
||||
isProtectedMode={isProtectedMode}
|
||||
isGitConnected={gitConnected}
|
||||
isProtectedMode={protectedMode}
|
||||
isPullFailing={isPullFailing}
|
||||
isPullLoading={pullLoading}
|
||||
isStatusClean={isStatusClean}
|
||||
|
|
|
|||
|
|
@ -113,18 +113,18 @@ export default function useGitBranches({
|
|||
};
|
||||
|
||||
return {
|
||||
branches: branchesState?.value ?? null,
|
||||
branches: branchesState?.value,
|
||||
fetchBranchesLoading: branchesState?.loading ?? false,
|
||||
fetchBranchesError: branchesState?.error ?? null,
|
||||
fetchBranchesError: branchesState?.error,
|
||||
fetchBranches,
|
||||
createBranchLoading: createBranchState?.loading ?? false,
|
||||
createBranchError: createBranchState?.error ?? null,
|
||||
createBranchError: createBranchState?.error,
|
||||
createBranch,
|
||||
deleteBranchLoading: deleteBranchState?.loading ?? false,
|
||||
deleteBranchError: deleteBranchState?.error ?? null,
|
||||
deleteBranchError: deleteBranchState?.error,
|
||||
deleteBranch,
|
||||
checkoutBranchLoading: checkoutBranchState?.loading ?? false,
|
||||
checkoutBranchError: checkoutBranchState?.error ?? null,
|
||||
checkoutBranchError: checkoutBranchState?.error,
|
||||
checkoutBranch,
|
||||
toggleGitBranchListPopup,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import useGitOps from "./useGitOps";
|
|||
import useGitBranches from "./useGitBranches";
|
||||
import useGitSettings from "./useGitSettings";
|
||||
import { useMemo } from "react";
|
||||
import type { UseGitMetadataReturnValue } from "./useGitMetadata";
|
||||
import useGitMetadata from "./useGitMetadata";
|
||||
|
||||
interface UseGitContextValueParams {
|
||||
artifactType: keyof typeof GitArtifactType;
|
||||
|
|
@ -15,7 +17,8 @@ interface UseGitContextValueParams {
|
|||
}
|
||||
|
||||
export interface GitContextValue
|
||||
extends UseGitConnectReturnValue,
|
||||
extends UseGitMetadataReturnValue,
|
||||
UseGitConnectReturnValue,
|
||||
UseGitOpsReturnValue,
|
||||
UseGitSettingsReturnValue,
|
||||
UseGitBranchesReturnValue {}
|
||||
|
|
@ -28,12 +31,14 @@ export default function useGitContextValue({
|
|||
() => ({ artifactType, baseArtifactId }),
|
||||
[artifactType, baseArtifactId],
|
||||
);
|
||||
const useGitMetadataReturnValue = useGitMetadata(basePayload);
|
||||
const useGitConnectReturnValue = useGitConnect(basePayload);
|
||||
const useGitOpsReturnValue = useGitOps(basePayload);
|
||||
const useGitBranchesReturnValue = useGitBranches(basePayload);
|
||||
const useGitSettingsReturnValue = useGitSettings(basePayload);
|
||||
|
||||
return {
|
||||
...useGitMetadataReturnValue,
|
||||
...useGitOpsReturnValue,
|
||||
...useGitBranchesReturnValue,
|
||||
...useGitConnectReturnValue,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
import type { GitArtifactType } from "git/constants/enums";
|
||||
import type { FetchGitMetadataResponseData } from "git/requests/fetchGitMetadataRequest.types";
|
||||
import {
|
||||
selectGitConnected,
|
||||
selectGitMetadata,
|
||||
} from "git/store/selectors/gitSingleArtifactSelectors";
|
||||
import type { GitRootState } from "git/store/types";
|
||||
import { useMemo } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
interface UseGitMetadataParams {
|
||||
artifactType: keyof typeof GitArtifactType;
|
||||
baseArtifactId: string;
|
||||
}
|
||||
|
||||
export interface UseGitMetadataReturnValue {
|
||||
gitMetadata: FetchGitMetadataResponseData | null;
|
||||
fetchGitMetadataLoading: boolean;
|
||||
fetchGitMetadataError: string | null;
|
||||
gitConnected: boolean;
|
||||
}
|
||||
|
||||
export default function useGitMetadata({
|
||||
artifactType,
|
||||
baseArtifactId,
|
||||
}: UseGitMetadataParams): UseGitMetadataReturnValue {
|
||||
const basePayload = useMemo(
|
||||
() => ({ artifactType, baseArtifactId }),
|
||||
[artifactType, baseArtifactId],
|
||||
);
|
||||
|
||||
const gitMetadataState = useSelector((state: GitRootState) =>
|
||||
selectGitMetadata(state, basePayload),
|
||||
);
|
||||
const gitConnected = useSelector((state: GitRootState) =>
|
||||
selectGitConnected(state, basePayload),
|
||||
);
|
||||
|
||||
return {
|
||||
gitMetadata: gitMetadataState.value,
|
||||
fetchGitMetadataLoading: gitMetadataState.loading ?? false,
|
||||
fetchGitMetadataError: gitMetadataState.error,
|
||||
gitConnected: gitConnected ?? false,
|
||||
};
|
||||
}
|
||||
|
|
@ -133,24 +133,24 @@ export default function useGitOps({
|
|||
|
||||
return {
|
||||
commitLoading: commitState?.loading ?? false,
|
||||
commitError: commitState?.error ?? null,
|
||||
commitError: commitState?.error,
|
||||
commit,
|
||||
discardLoading: discardState?.loading ?? false,
|
||||
discardError: discardState?.error ?? null,
|
||||
discardError: discardState?.error,
|
||||
discard,
|
||||
status: statusState?.value ?? null,
|
||||
status: statusState?.value,
|
||||
fetchStatusLoading: statusState?.loading ?? false,
|
||||
fetchStatusError: statusState?.error ?? null,
|
||||
fetchStatusError: statusState?.error,
|
||||
fetchStatus,
|
||||
mergeLoading: mergeState?.loading ?? false,
|
||||
mergeError: mergeState?.error ?? null,
|
||||
mergeError: mergeState?.error,
|
||||
merge,
|
||||
mergeStatus: mergeStatusState?.value ?? null,
|
||||
mergeStatus: mergeStatusState?.value,
|
||||
fetchMergeStatusLoading: mergeStatusState?.loading ?? false,
|
||||
fetchMergeStatusError: mergeStatusState?.error ?? null,
|
||||
fetchMergeStatusError: mergeStatusState?.error,
|
||||
fetchMergeStatus,
|
||||
pullLoading: pullState?.loading ?? false,
|
||||
pullError: pullState?.error ?? null,
|
||||
pullError: pullState?.error,
|
||||
pull,
|
||||
toggleGitOpsModal,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,15 @@
|
|||
import type { GitArtifactType, GitSettingsTab } from "git/constants/enums";
|
||||
import type { FetchProtectedBranchesResponseData } from "git/requests/fetchProtectedBranchesRequest.types";
|
||||
import { gitArtifactActions } from "git/store/gitArtifactSlice";
|
||||
import {
|
||||
selectAutocommitEnabled,
|
||||
selectAutocommitPolling,
|
||||
selectProtectedBranches,
|
||||
selectProtectedMode,
|
||||
} from "git/store/selectors/gitSingleArtifactSelectors";
|
||||
import type { GitRootState } from "git/store/types";
|
||||
import { useMemo } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
interface UseGitSettingsParams {
|
||||
artifactType: keyof typeof GitArtifactType;
|
||||
|
|
@ -9,6 +17,13 @@ interface UseGitSettingsParams {
|
|||
}
|
||||
|
||||
export interface UseGitSettingsReturnValue {
|
||||
autocommitEnabled: boolean;
|
||||
autocommitPolling: boolean;
|
||||
protectedBranches: FetchProtectedBranchesResponseData | null;
|
||||
fetchProtectedBranchesLoading: boolean;
|
||||
fetchProtectedBranchesError: string | null;
|
||||
fetchProtectedBranches: () => void;
|
||||
protectedMode: boolean;
|
||||
toggleGitSettingsModal: (
|
||||
open: boolean,
|
||||
tab: keyof typeof GitSettingsTab,
|
||||
|
|
@ -25,6 +40,33 @@ export default function useGitSettings({
|
|||
[artifactType, baseArtifactId],
|
||||
);
|
||||
|
||||
// autocommit
|
||||
const autocommitEnabled = useSelector((state: GitRootState) =>
|
||||
selectAutocommitEnabled(state, basePayload),
|
||||
);
|
||||
|
||||
const autocommitPolling = useSelector((state: GitRootState) =>
|
||||
selectAutocommitPolling(state, basePayload),
|
||||
);
|
||||
|
||||
// branch protection
|
||||
const protectedBranchesState = useSelector((state: GitRootState) =>
|
||||
selectProtectedBranches(state, basePayload),
|
||||
);
|
||||
|
||||
const fetchProtectedBranches = () => {
|
||||
dispatch(
|
||||
gitArtifactActions.fetchProtectedBranchesInit({
|
||||
...basePayload,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const protectedMode = useSelector((state: GitRootState) =>
|
||||
selectProtectedMode(state, basePayload),
|
||||
);
|
||||
|
||||
// ui
|
||||
const toggleGitSettingsModal = (
|
||||
open: boolean,
|
||||
tab: keyof typeof GitSettingsTab,
|
||||
|
|
@ -39,6 +81,13 @@ export default function useGitSettings({
|
|||
};
|
||||
|
||||
return {
|
||||
autocommitEnabled: autocommitEnabled ?? false,
|
||||
autocommitPolling: autocommitPolling ?? false,
|
||||
protectedBranches: protectedBranchesState.value,
|
||||
fetchProtectedBranchesLoading: protectedBranchesState.loading ?? false,
|
||||
fetchProtectedBranchesError: protectedBranchesState.error,
|
||||
fetchProtectedBranches,
|
||||
protectedMode: protectedMode ?? false,
|
||||
toggleGitSettingsModal,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { createContext, useContext, useEffect } from "react";
|
||||
import React, { createContext, useContext } from "react";
|
||||
import type { GitArtifactType } from "git/constants/enums";
|
||||
import type { GitContextValue } from "./hooks/useGitContextValue";
|
||||
import useGitContextValue from "./hooks/useGitContextValue";
|
||||
|
|
@ -15,24 +15,18 @@ interface GitContextProviderProps {
|
|||
artifactType: keyof typeof GitArtifactType;
|
||||
baseArtifactId: string;
|
||||
children: React.ReactNode;
|
||||
// extra
|
||||
// connectPermitted?: boolean;
|
||||
}
|
||||
|
||||
export default function GitContextProvider({
|
||||
artifactType,
|
||||
baseArtifactId,
|
||||
children,
|
||||
// connectPermitted = true,
|
||||
}: GitContextProviderProps) {
|
||||
const contextValue = useGitContextValue({ artifactType, baseArtifactId });
|
||||
|
||||
const { fetchBranches } = contextValue;
|
||||
|
||||
useEffect(
|
||||
function gitInitEffect() {
|
||||
fetchBranches();
|
||||
},
|
||||
[fetchBranches],
|
||||
);
|
||||
|
||||
return (
|
||||
<GitContext.Provider value={contextValue}>{children}</GitContext.Provider>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ describe("QuickActionButton", () => {
|
|||
<QuickActionButton {...defaultProps} />
|
||||
</ThemeProvider>,
|
||||
);
|
||||
const btn = container.getElementsByClassName("t--test-btn")[0];
|
||||
const btn = container.querySelectorAll(".t--test-btn button")[0];
|
||||
|
||||
fireEvent.click(btn);
|
||||
expect(defaultProps.onClick).toHaveBeenCalledTimes(1);
|
||||
|
|
|
|||
|
|
@ -19,12 +19,11 @@ const SpinnerContainer = styled.div`
|
|||
padding: 0 10px;
|
||||
`;
|
||||
|
||||
const QuickActionButtonContainer = styled.button<{ disabled?: boolean }>`
|
||||
const QuickActionButtonContainer = styled.div<{ disabled?: boolean }>`
|
||||
margin: 0 ${(props) => props.theme.spaces[1]}px;
|
||||
display: block;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
cursor: ${({ disabled = false }) => (disabled ? "not-allowed" : "pointer")};
|
||||
opacity: ${({ disabled = false }) => (disabled ? 0.6 : 1)};
|
||||
`;
|
||||
|
||||
|
|
@ -57,11 +56,7 @@ function QuickActionButton({
|
|||
const content = capitalizeFirstLetter(tooltipText);
|
||||
|
||||
return (
|
||||
<QuickActionButtonContainer
|
||||
className={className}
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
>
|
||||
<QuickActionButtonContainer className={className} disabled={disabled}>
|
||||
{loading ? (
|
||||
<SpinnerContainer className="t--loader-quick-git-action">
|
||||
<SpinnerLoader size="md" />
|
||||
|
|
@ -73,6 +68,7 @@ function QuickActionButton({
|
|||
isDisabled={disabled}
|
||||
isIconButton
|
||||
kind="tertiary"
|
||||
onClick={onClick}
|
||||
size="md"
|
||||
startIcon={icon}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -110,8 +110,8 @@ describe("QuickActions Component", () => {
|
|||
<QuickActions {...props} />
|
||||
</ThemeProvider>,
|
||||
);
|
||||
const commitButton = container.getElementsByClassName(
|
||||
"t--bottom-bar-commit",
|
||||
const commitButton = container.querySelectorAll(
|
||||
".t--bottom-bar-commit button",
|
||||
)[0];
|
||||
|
||||
fireEvent.click(commitButton);
|
||||
|
|
@ -145,8 +145,9 @@ describe("QuickActions Component", () => {
|
|||
<QuickActions {...props} />
|
||||
</ThemeProvider>,
|
||||
);
|
||||
const pullButton =
|
||||
container.getElementsByClassName("t--bottom-bar-pull")[0];
|
||||
const pullButton = container.querySelectorAll(
|
||||
".t--bottom-bar-pull button",
|
||||
)[0];
|
||||
|
||||
fireEvent.click(pullButton);
|
||||
expect(AnalyticsUtil.logEvent).toHaveBeenCalledWith("GS_PULL_GIT_CLICK", {
|
||||
|
|
@ -165,8 +166,8 @@ describe("QuickActions Component", () => {
|
|||
<QuickActions {...props} />
|
||||
</ThemeProvider>,
|
||||
);
|
||||
const mergeButton = container.getElementsByClassName(
|
||||
"t--bottom-bar-merge",
|
||||
const mergeButton = container.querySelectorAll(
|
||||
".t--bottom-bar-merge button",
|
||||
)[0];
|
||||
|
||||
fireEvent.click(mergeButton);
|
||||
|
|
@ -190,8 +191,8 @@ describe("QuickActions Component", () => {
|
|||
<QuickActions {...props} />
|
||||
</ThemeProvider>,
|
||||
);
|
||||
const settingsButton = container.getElementsByClassName(
|
||||
"t--bottom-git-settings",
|
||||
const settingsButton = container.querySelectorAll(
|
||||
".t--bottom-git-settings button",
|
||||
)[0];
|
||||
|
||||
fireEvent.click(settingsButton);
|
||||
|
|
@ -216,8 +217,8 @@ describe("QuickActions Component", () => {
|
|||
<QuickActions {...props} />
|
||||
</ThemeProvider>,
|
||||
);
|
||||
const commitButton = container.getElementsByClassName(
|
||||
"t--bottom-bar-commit",
|
||||
const commitButton = container.querySelectorAll(
|
||||
".t--bottom-bar-commit button",
|
||||
)[0];
|
||||
|
||||
expect(commitButton).toBeDisabled();
|
||||
|
|
@ -298,8 +299,9 @@ describe("QuickActions Component", () => {
|
|||
<QuickActions {...props} />
|
||||
</ThemeProvider>,
|
||||
);
|
||||
const pullButton =
|
||||
container.getElementsByClassName("t--bottom-bar-pull")[0];
|
||||
const pullButton = container.querySelectorAll(
|
||||
".t--bottom-bar-pull button",
|
||||
)[0];
|
||||
|
||||
expect(pullButton).toBeDisabled();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ function GitQuickActions({
|
|||
if (isProtectedMode) {
|
||||
discard();
|
||||
} else {
|
||||
// ! case: why is triggeredFromBottomBar this needed?
|
||||
// pull({ triggeredFromBottomBar: true });
|
||||
pull();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
import type {
|
||||
CheckoutBranchRequestParams,
|
||||
CheckoutBranchResponse,
|
||||
|
|
@ -9,7 +9,7 @@ import Api from "api/Api";
|
|||
export default async function checkoutBranchRequest(
|
||||
branchedApplicationId: string,
|
||||
params: CheckoutBranchRequestParams,
|
||||
): Promise<AxiosResponse<CheckoutBranchResponse>> {
|
||||
): AxiosPromise<CheckoutBranchResponse> {
|
||||
return Api.get(
|
||||
`${GIT_BASE_URL}/checkout-branch/app/${branchedApplicationId}`,
|
||||
params,
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ import type {
|
|||
CommitResponse,
|
||||
} from "./commitRequest.types";
|
||||
import { GIT_BASE_URL } from "./constants";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
|
||||
export default async function commitRequest(
|
||||
branchedApplicationId: string,
|
||||
params: CommitRequestParams,
|
||||
): Promise<AxiosResponse<CommitResponse>> {
|
||||
): AxiosPromise<CommitResponse> {
|
||||
return Api.post(
|
||||
`${GIT_BASE_URL}/commit/app/${branchedApplicationId}`,
|
||||
params,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
import type {
|
||||
CreateBranchRequestParams,
|
||||
CreateBranchResponse,
|
||||
|
|
@ -9,7 +9,7 @@ import Api from "api/Api";
|
|||
export default async function createBranchRequest(
|
||||
branchedApplicationId: string,
|
||||
params: CreateBranchRequestParams,
|
||||
): Promise<AxiosResponse<CreateBranchResponse>> {
|
||||
): AxiosPromise<CreateBranchResponse> {
|
||||
return Api.post(
|
||||
`${GIT_BASE_URL}/create-branch/app/${branchedApplicationId}`,
|
||||
params,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
import type {
|
||||
DeleteBranchRequestParams,
|
||||
DeleteBranchResponse,
|
||||
|
|
@ -9,6 +9,6 @@ import Api from "api/Api";
|
|||
export default async function deleteBranchRequest(
|
||||
baseApplicationId: string,
|
||||
params: DeleteBranchRequestParams,
|
||||
): Promise<AxiosResponse<DeleteBranchResponse>> {
|
||||
): AxiosPromise<DeleteBranchResponse> {
|
||||
return Api.delete(`${GIT_BASE_URL}/branch/app/${baseApplicationId}`, params);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import Api from "api/Api";
|
||||
import { GIT_BASE_URL } from "./constants";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
|
||||
export default async function discardRequest(
|
||||
branchedApplicationId: string,
|
||||
): Promise<AxiosResponse<void>> {
|
||||
): AxiosPromise<void> {
|
||||
return Api.put(`${GIT_BASE_URL}/discard/app/${branchedApplicationId}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
import { GIT_BASE_URL } from "./constants";
|
||||
import type { DisconnectResponse } from "./disconnectRequest.types";
|
||||
import Api from "api/Api";
|
||||
|
||||
export default async function disconnectRequest(
|
||||
baseApplicationId: string,
|
||||
): Promise<AxiosResponse<DisconnectResponse>> {
|
||||
): AxiosPromise<DisconnectResponse> {
|
||||
return Api.post(`${GIT_BASE_URL}/disconnect/app/${baseApplicationId}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import Api from "api/Api";
|
||||
import { GIT_BASE_URL } from "./constants";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
import type { FetchAutocommitProgressResponse } from "./fetchAutocommitProgressRequest.types";
|
||||
|
||||
export default async function fetchAutocommitProgressRequest(
|
||||
baseApplicationId: string,
|
||||
): Promise<AxiosResponse<FetchAutocommitProgressResponse>> {
|
||||
): AxiosPromise<FetchAutocommitProgressResponse> {
|
||||
return Api.get(
|
||||
`${GIT_BASE_URL}/auto-commit/progress/app/${baseApplicationId}`,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
import type { ApiResponse } from "api/types";
|
||||
import type { AutocommitStatus } from "../constants/enums";
|
||||
|
||||
export interface FetchAutocommitProgressResponse {
|
||||
export interface FetchAutocommitProgressResponseData {
|
||||
autoCommitResponse: AutocommitStatus;
|
||||
progress: number;
|
||||
branchName: string;
|
||||
}
|
||||
|
||||
export type FetchAutocommitProgressResponse =
|
||||
ApiResponse<FetchAutocommitProgressResponseData>;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import type { AxiosPromise } from "axios";
|
|||
|
||||
export default async function fetchBranchesRequest(
|
||||
branchedApplicationId: string,
|
||||
params: FetchBranchesRequestParams,
|
||||
params: FetchBranchesRequestParams = { pruneBranches: true },
|
||||
): AxiosPromise<FetchBranchesResponse> {
|
||||
const queryParams = {} as FetchBranchesRequestParams;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { ApiResponse } from "api/ApiResponses";
|
||||
|
||||
export interface FetchBranchesRequestParams {
|
||||
pruneBranches: boolean;
|
||||
pruneBranches?: boolean;
|
||||
}
|
||||
|
||||
interface SingleBranch {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import Api from "api/Api";
|
||||
import { GIT_BASE_URL } from "./constants";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
import type { FetchGitMetadataResponse } from "./fetchGitMetadataRequest.types";
|
||||
|
||||
export default async function fetchGitMetadataRequest(
|
||||
baseApplicationId: string,
|
||||
): Promise<AxiosResponse<FetchGitMetadataResponse>> {
|
||||
): AxiosPromise<FetchGitMetadataResponse> {
|
||||
return Api.get(`${GIT_BASE_URL}/metadata/app/${baseApplicationId}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
export interface FetchGitMetadataResponse {
|
||||
import type { ApiResponse } from "api/types";
|
||||
|
||||
export interface FetchGitMetadataResponseData {
|
||||
branchName: string;
|
||||
defaultBranchName: string;
|
||||
remoteUrl: string;
|
||||
|
|
@ -13,3 +15,6 @@ export interface FetchGitMetadataResponse {
|
|||
};
|
||||
isAutoDeploymentEnabled?: boolean;
|
||||
}
|
||||
|
||||
export type FetchGitMetadataResponse =
|
||||
ApiResponse<FetchGitMetadataResponseData>;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
import type {
|
||||
FetchMergeStatusRequestParams,
|
||||
FetchMergeStatusResponse,
|
||||
|
|
@ -9,7 +9,7 @@ import { GIT_BASE_URL } from "./constants";
|
|||
export default async function fetchMergeStatusRequest(
|
||||
branchedApplicationId: string,
|
||||
params: FetchMergeStatusRequestParams,
|
||||
): Promise<AxiosResponse<FetchMergeStatusResponse>> {
|
||||
): AxiosPromise<FetchMergeStatusResponse> {
|
||||
return Api.post(
|
||||
`${GIT_BASE_URL}/merge/status/app/${branchedApplicationId}`,
|
||||
params,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import Api from "api/Api";
|
||||
import { GIT_BASE_URL } from "./constants";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import type { FetchProtectedBranches } from "./fetchProtectedBranchesRequest.types";
|
||||
import type { AxiosPromise } from "axios";
|
||||
import type { FetchProtectedBranchesResponse } from "./fetchProtectedBranchesRequest.types";
|
||||
|
||||
export default async function fetchProtectedBranchesRequest(
|
||||
baseApplicationId: string,
|
||||
): Promise<AxiosResponse<FetchProtectedBranches>> {
|
||||
): AxiosPromise<FetchProtectedBranchesResponse> {
|
||||
return Api.get(`${GIT_BASE_URL}/branch/app/${baseApplicationId}/protected`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1,6 @@
|
|||
export type FetchProtectedBranches = string[];
|
||||
import type { ApiResponse } from "api/types";
|
||||
|
||||
export type FetchProtectedBranchesResponseData = string[];
|
||||
|
||||
export type FetchProtectedBranchesResponse =
|
||||
ApiResponse<FetchProtectedBranchesResponseData>;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
import type { FetchSSHKeyResponse } from "./fetchSSHKeyRequest.types";
|
||||
import Api from "api/Api";
|
||||
import { APPLICATION_BASE_URL } from "./constants";
|
||||
|
||||
export default async function fetchSSHKeyRequest(
|
||||
baseApplicationId: string,
|
||||
): Promise<AxiosResponse<FetchSSHKeyResponse>> {
|
||||
): AxiosPromise<FetchSSHKeyResponse> {
|
||||
return Api.get(`${APPLICATION_BASE_URL}/ssh-keypair/${baseApplicationId}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ import type {
|
|||
FetchStatusResponse,
|
||||
} from "./fetchStatusRequest.types";
|
||||
import { GIT_BASE_URL } from "./constants";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
|
||||
export default async function fetchStatusRequest(
|
||||
branchedApplicationId: string,
|
||||
params: FetchStatusRequestParams,
|
||||
): Promise<AxiosResponse<FetchStatusResponse>> {
|
||||
params: FetchStatusRequestParams = { compareRemote: true },
|
||||
): AxiosPromise<FetchStatusResponse> {
|
||||
return Api.get(`${GIT_BASE_URL}/status/app/${branchedApplicationId}`, params);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { ApiResponse } from "api/types";
|
||||
|
||||
export interface FetchStatusRequestParams {
|
||||
compareRemote: boolean;
|
||||
compareRemote?: boolean;
|
||||
}
|
||||
export interface FetchStatusResponseData {
|
||||
added: string[];
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
import type {
|
||||
GenerateSSHKeyRequestParams,
|
||||
GenerateSSHKeyResponse,
|
||||
|
|
@ -9,7 +9,7 @@ import Api from "api/Api";
|
|||
export default async function generateSSHKeyRequest(
|
||||
baseApplicationId: string,
|
||||
params: GenerateSSHKeyRequestParams,
|
||||
): Promise<AxiosResponse<GenerateSSHKeyResponse>> {
|
||||
): AxiosPromise<GenerateSSHKeyResponse> {
|
||||
const url = params.isImporting
|
||||
? `${GIT_BASE_URL}/import/keys?keyType=${params.keyType}`
|
||||
: `${APPLICATION_BASE_URL}/ssh-keypair/${baseApplicationId}?keyType=${params.keyType}`;
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ import type {
|
|||
ImportGitRequestParams,
|
||||
ImportGitResponse,
|
||||
} from "./importGitRequest.types";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
|
||||
export default async function importGitRequest(
|
||||
workspaceId: string,
|
||||
params: ImportGitRequestParams,
|
||||
): Promise<AxiosResponse<ImportGitResponse>> {
|
||||
): AxiosPromise<ImportGitResponse> {
|
||||
return Api.post(`${GIT_BASE_URL}/import/${workspaceId}`, params);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import Api from "api/Api";
|
||||
import type { MergeRequestParams, MergeResponse } from "./mergeRequest.types";
|
||||
import { GIT_BASE_URL } from "./constants";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
|
||||
export default async function mergeRequest(
|
||||
branchedApplicationId: string,
|
||||
params: MergeRequestParams,
|
||||
): Promise<AxiosResponse<MergeResponse>> {
|
||||
): AxiosPromise<MergeResponse> {
|
||||
return Api.post(`${GIT_BASE_URL}/merge/app/${branchedApplicationId}`, params);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import Api from "api/Api";
|
||||
import { GIT_BASE_URL } from "./constants";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
import type { PullRequestResponse } from "./pullRequest.types";
|
||||
|
||||
export default async function pullRequest(
|
||||
branchedApplicationId: string,
|
||||
): Promise<AxiosResponse<PullRequestResponse>> {
|
||||
): AxiosPromise<PullRequestResponse> {
|
||||
return Api.get(`${GIT_BASE_URL}/pull/app/${branchedApplicationId}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import Api from "api/Api";
|
||||
import { GIT_BASE_URL } from "./constants";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
import type { ToggleAutocommitResponse } from "./toggleAutocommitRequest.types";
|
||||
|
||||
export default async function toggleAutocommitRequest(
|
||||
baseApplicationId: string,
|
||||
): Promise<AxiosResponse<ToggleAutocommitResponse>> {
|
||||
): AxiosPromise<ToggleAutocommitResponse> {
|
||||
return Api.patch(
|
||||
`${GIT_BASE_URL}/auto-commit/toggle/app/${baseApplicationId}`,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import Api from "api/Api";
|
||||
import { GIT_BASE_URL } from "./constants";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
import type { TriggerAutocommitResponse } from "./triggerAutocommitRequest.types";
|
||||
|
||||
export default async function triggerAutocommitRequest(
|
||||
branchedApplicationId: string,
|
||||
): Promise<AxiosResponse<TriggerAutocommitResponse>> {
|
||||
): AxiosPromise<TriggerAutocommitResponse> {
|
||||
return Api.post(`${GIT_BASE_URL}/auto-commit/app/${branchedApplicationId}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
import type { ApiResponse } from "api/types";
|
||||
import type { AutocommitStatus } from "../constants/enums";
|
||||
|
||||
export interface TriggerAutocommitResponse {
|
||||
export interface TriggerAutocommitResponseData {
|
||||
autoCommitResponse: AutocommitStatus;
|
||||
progress: number;
|
||||
branchName: string;
|
||||
}
|
||||
|
||||
export type TriggerAutocommitResponse =
|
||||
ApiResponse<TriggerAutocommitResponseData>;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
import type {
|
||||
UpdateGlobalProfileRequestParams,
|
||||
UpdateGlobalProfileResponse,
|
||||
|
|
@ -8,6 +8,6 @@ import { GIT_BASE_URL } from "./constants";
|
|||
|
||||
export default async function updateGlobalProfileRequest(
|
||||
params: UpdateGlobalProfileRequestParams,
|
||||
): Promise<AxiosResponse<UpdateGlobalProfileResponse>> {
|
||||
): AxiosPromise<UpdateGlobalProfileResponse> {
|
||||
return Api.post(`${GIT_BASE_URL}/profile/default`, params);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ import type {
|
|||
UpdateProtectedBranchesRequestParams,
|
||||
UpdateProtectedBranchesResponse,
|
||||
} from "./updateProtectedBranchesRequest.types";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import type { AxiosPromise } from "axios";
|
||||
|
||||
export default async function updateProtectedBranchesRequest(
|
||||
baseApplicationId: string,
|
||||
params: UpdateProtectedBranchesRequestParams,
|
||||
): Promise<AxiosResponse<UpdateProtectedBranchesResponse>> {
|
||||
): AxiosPromise<UpdateProtectedBranchesResponse> {
|
||||
return Api.post(
|
||||
`${GIT_BASE_URL}/branch/app/${baseApplicationId}/protected`,
|
||||
params,
|
||||
|
|
|
|||
35
app/client/src/git/sagas/fetchGitMetadataSaga.ts
Normal file
35
app/client/src/git/sagas/fetchGitMetadataSaga.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import fetchGitMetadataRequest from "git/requests/fetchGitMetadataRequest";
|
||||
import type { FetchGitMetadataResponse } from "git/requests/fetchGitMetadataRequest.types";
|
||||
import { gitArtifactActions } from "git/store/gitArtifactSlice";
|
||||
import type { GitArtifactPayloadAction } from "git/store/types";
|
||||
import { call, put } from "redux-saga/effects";
|
||||
import { validateResponse } from "sagas/ErrorSagas";
|
||||
|
||||
export default function* fetchGitMetadataSaga(
|
||||
action: GitArtifactPayloadAction,
|
||||
) {
|
||||
const { artifactType, baseArtifactId } = action.payload;
|
||||
const basePayload = { artifactType, baseArtifactId };
|
||||
let response: FetchGitMetadataResponse | undefined;
|
||||
|
||||
try {
|
||||
response = yield call(fetchGitMetadataRequest, baseArtifactId);
|
||||
const isValidResponse: boolean = yield validateResponse(response, false);
|
||||
|
||||
if (response && isValidResponse) {
|
||||
yield put(
|
||||
gitArtifactActions.fetchGitMetadataSuccess({
|
||||
...basePayload,
|
||||
responseData: response.data,
|
||||
}),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
yield put(
|
||||
gitArtifactActions.fetchGitMetadataError({
|
||||
...basePayload,
|
||||
error: error as string,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
36
app/client/src/git/sagas/fetchProtectedBranchesSaga.ts
Normal file
36
app/client/src/git/sagas/fetchProtectedBranchesSaga.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import fetchProtectedBranchesRequest from "git/requests/fetchProtectedBranchesRequest";
|
||||
import type { FetchProtectedBranchesResponse } from "git/requests/fetchProtectedBranchesRequest.types";
|
||||
import { gitArtifactActions } from "git/store/gitArtifactSlice";
|
||||
import type { GitArtifactPayloadAction } from "git/store/types";
|
||||
import { call, put } from "redux-saga/effects";
|
||||
import { validateResponse } from "sagas/ErrorSagas";
|
||||
|
||||
export default function* fetchProtectedBranchesSaga(
|
||||
action: GitArtifactPayloadAction,
|
||||
) {
|
||||
const { artifactType, baseArtifactId } = action.payload;
|
||||
const basePayload = { artifactType, baseArtifactId };
|
||||
let response: FetchProtectedBranchesResponse | undefined;
|
||||
|
||||
try {
|
||||
response = yield call(fetchProtectedBranchesRequest, baseArtifactId);
|
||||
|
||||
const isValidResponse: boolean = yield validateResponse(response);
|
||||
|
||||
if (response && isValidResponse) {
|
||||
yield put(
|
||||
gitArtifactActions.fetchProtectedBranchesSuccess({
|
||||
...basePayload,
|
||||
responseData: response.data,
|
||||
}),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
yield put(
|
||||
gitArtifactActions.fetchProtectedBranchesError({
|
||||
...basePayload,
|
||||
error: error as string,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
43
app/client/src/git/sagas/fetchStatusSaga.ts
Normal file
43
app/client/src/git/sagas/fetchStatusSaga.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import fetchStatusRequest from "git/requests/fetchStatusRequest";
|
||||
import type { FetchStatusResponse } from "git/requests/fetchStatusRequest.types";
|
||||
import type { FetchStatusInitPayload } from "git/store/actions/fetchStatusActions";
|
||||
import { gitArtifactActions } from "git/store/gitArtifactSlice";
|
||||
import type { GitArtifactPayloadAction } from "git/store/types";
|
||||
import { call, put } from "redux-saga/effects";
|
||||
import { validateResponse } from "sagas/ErrorSagas";
|
||||
|
||||
export default function* fetchStatusSaga(
|
||||
action: GitArtifactPayloadAction<FetchStatusInitPayload>,
|
||||
) {
|
||||
const { artifactType, baseArtifactId } = action.payload;
|
||||
const basePayload = { artifactType, baseArtifactId };
|
||||
let response: FetchStatusResponse | undefined;
|
||||
|
||||
try {
|
||||
response = yield call(fetchStatusRequest, baseArtifactId);
|
||||
const isValidResponse: boolean = yield validateResponse(response);
|
||||
|
||||
if (response && isValidResponse) {
|
||||
yield put(
|
||||
gitArtifactActions.fetchStatusSuccess({
|
||||
...basePayload,
|
||||
responseData: response.data,
|
||||
}),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
yield put(
|
||||
gitArtifactActions.fetchStatusError({
|
||||
...basePayload,
|
||||
error: error as string,
|
||||
}),
|
||||
);
|
||||
|
||||
// ! case: BETTER ERROR HANDLING
|
||||
// if ((error as Error)?.message?.includes("Auth fail")) {
|
||||
// payload.error = new Error(createMessage(ERROR_GIT_AUTH_FAIL));
|
||||
// } else if ((error as Error)?.message?.includes("Invalid remote: origin")) {
|
||||
// payload.error = new Error(createMessage(ERROR_GIT_INVALID_REMOTE));
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +1,99 @@
|
|||
import { gitArtifactActions } from "git/store/gitArtifactSlice";
|
||||
import { all, takeLatest } from "redux-saga/effects";
|
||||
import {
|
||||
actionChannel,
|
||||
call,
|
||||
fork,
|
||||
take,
|
||||
takeLatest,
|
||||
} from "redux-saga/effects";
|
||||
import type { TakeableChannel } from "redux-saga";
|
||||
import type { PayloadAction } from "@reduxjs/toolkit";
|
||||
import { objectKeys } from "@appsmith/utils";
|
||||
import { gitConfigActions } from "../store/gitConfigSlice";
|
||||
import { gitArtifactActions } from "../store/gitArtifactSlice";
|
||||
import connectSaga from "./connectSaga";
|
||||
import commitSaga from "./commitSaga";
|
||||
import { gitConfigActions } from "git/store/gitConfigSlice";
|
||||
import fetchGlobalProfileSaga from "./fetchGlobalProfileSaga";
|
||||
import fetchBranchesSaga from "./fetchBranchesSaga";
|
||||
import fetchLocalProfileSaga from "./fetchLocalProfileSaga";
|
||||
import updateLocalProfileSaga from "./updateLocalProfileSaga";
|
||||
import updateGlobalProfileSaga from "./updateGlobalProfileSaga";
|
||||
import initGitForEditorSaga from "./initGitSaga";
|
||||
import fetchGitMetadataSaga from "./fetchGitMetadataSaga";
|
||||
import triggerAutocommitSaga from "./triggerAutocommitSaga";
|
||||
import fetchStatusSaga from "./fetchStatusSaga";
|
||||
import fetchProtectedBranchesSaga from "./fetchProtectedBranchesSaga";
|
||||
|
||||
export function* gitSagas() {
|
||||
yield all([
|
||||
takeLatest(gitArtifactActions.connectInit.type, connectSaga),
|
||||
const gitRequestBlockingActions: Record<
|
||||
string,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(action: PayloadAction<any>) => Generator<any>
|
||||
> = {
|
||||
// init
|
||||
[gitArtifactActions.fetchGitMetadataInit.type]: fetchGitMetadataSaga,
|
||||
|
||||
// branches
|
||||
takeLatest(gitArtifactActions.fetchBranchesInit.type, fetchBranchesSaga),
|
||||
// connect
|
||||
[gitArtifactActions.connectInit.type]: connectSaga,
|
||||
|
||||
takeLatest(gitArtifactActions.commitInit.type, commitSaga),
|
||||
takeLatest(
|
||||
gitArtifactActions.fetchLocalProfileInit.type,
|
||||
fetchLocalProfileSaga,
|
||||
),
|
||||
takeLatest(
|
||||
gitArtifactActions.updateLocalProfileInit.type,
|
||||
updateLocalProfileSaga,
|
||||
),
|
||||
takeLatest(
|
||||
gitConfigActions.fetchGlobalProfileInit.type,
|
||||
fetchGlobalProfileSaga,
|
||||
),
|
||||
takeLatest(
|
||||
gitConfigActions.updateGlobalProfileInit.type,
|
||||
updateGlobalProfileSaga,
|
||||
),
|
||||
]);
|
||||
// ops
|
||||
[gitArtifactActions.commitInit.type]: commitSaga,
|
||||
[gitArtifactActions.fetchStatusInit.type]: fetchStatusSaga,
|
||||
|
||||
// branches
|
||||
[gitArtifactActions.fetchBranchesInit.type]: fetchBranchesSaga,
|
||||
|
||||
// settings
|
||||
[gitArtifactActions.fetchLocalProfileInit.type]: fetchLocalProfileSaga,
|
||||
[gitArtifactActions.updateLocalProfileInit.type]: updateLocalProfileSaga,
|
||||
[gitConfigActions.fetchGlobalProfileInit.type]: fetchGlobalProfileSaga,
|
||||
[gitConfigActions.updateGlobalProfileInit.type]: updateGlobalProfileSaga,
|
||||
|
||||
// autocommit
|
||||
[gitArtifactActions.triggerAutocommitInit.type]: triggerAutocommitSaga,
|
||||
};
|
||||
|
||||
const gitRequestNonBlockingActions: Record<
|
||||
string,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(action: PayloadAction<any>) => Generator<any>
|
||||
> = {
|
||||
// init
|
||||
[gitArtifactActions.initGitForEditor.type]: initGitForEditorSaga,
|
||||
|
||||
// settings
|
||||
[gitArtifactActions.fetchProtectedBranchesInit.type]:
|
||||
fetchProtectedBranchesSaga,
|
||||
};
|
||||
|
||||
/**
|
||||
* All git actions on the server are behind a lock,
|
||||
* that means that only one action can be performed at once.
|
||||
*
|
||||
* To follow the same principle, we will queue all actions from the client
|
||||
* as well and only perform one action at a time.
|
||||
*
|
||||
* This will ensure that client is not running parallel requests to the server for git
|
||||
* */
|
||||
function* watchGitBlockingRequests() {
|
||||
const gitActionChannel: TakeableChannel<unknown> = yield actionChannel(
|
||||
objectKeys(gitRequestBlockingActions),
|
||||
);
|
||||
|
||||
while (true) {
|
||||
const action: PayloadAction<unknown> = yield take(gitActionChannel);
|
||||
|
||||
yield call(gitRequestBlockingActions[action.type], action);
|
||||
}
|
||||
}
|
||||
|
||||
function* watchGitNonBlockingRequests() {
|
||||
const keys = objectKeys(gitRequestNonBlockingActions);
|
||||
|
||||
for (const actionType of keys) {
|
||||
yield takeLatest(actionType, gitRequestNonBlockingActions[actionType]);
|
||||
}
|
||||
}
|
||||
|
||||
export default function* gitSagas() {
|
||||
yield fork(watchGitNonBlockingRequests);
|
||||
yield fork(watchGitBlockingRequests);
|
||||
}
|
||||
|
|
|
|||
30
app/client/src/git/sagas/initGitSaga.ts
Normal file
30
app/client/src/git/sagas/initGitSaga.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { GitArtifactType } from "git/constants/enums";
|
||||
import type { InitGitForEditorPayload } from "git/store/actions/initGitActions";
|
||||
import { gitArtifactActions } from "git/store/gitArtifactSlice";
|
||||
import type { GitArtifactPayloadAction } from "git/store/types";
|
||||
import { put, take } from "redux-saga/effects";
|
||||
|
||||
export default function* initGitForEditorSaga(
|
||||
action: GitArtifactPayloadAction<InitGitForEditorPayload>,
|
||||
) {
|
||||
const { artifact, artifactType, baseArtifactId } = action.payload;
|
||||
const basePayload = { artifactType, baseArtifactId };
|
||||
|
||||
yield put(gitArtifactActions.mount(basePayload));
|
||||
|
||||
if (artifactType === GitArtifactType.Application) {
|
||||
if (!!artifact.gitApplicationMetadata) {
|
||||
yield put(gitArtifactActions.fetchGitMetadataInit(basePayload));
|
||||
yield take(gitArtifactActions.fetchGitMetadataSuccess.type);
|
||||
yield put(
|
||||
gitArtifactActions.triggerAutocommitInit({
|
||||
...basePayload,
|
||||
artifactId: artifact.id,
|
||||
}),
|
||||
);
|
||||
yield put(gitArtifactActions.fetchBranchesInit(basePayload));
|
||||
yield put(gitArtifactActions.fetchProtectedBranchesInit(basePayload));
|
||||
yield put(gitArtifactActions.fetchStatusInit(basePayload));
|
||||
}
|
||||
}
|
||||
}
|
||||
131
app/client/src/git/sagas/triggerAutocommitSaga.ts
Normal file
131
app/client/src/git/sagas/triggerAutocommitSaga.ts
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
import { triggerAutocommitSuccessAction } from "actions/gitSyncActions";
|
||||
import { AutocommitStatus, type GitArtifactType } from "git/constants/enums";
|
||||
import fetchAutocommitProgressRequest from "git/requests/fetchAutocommitProgressRequest";
|
||||
import type {
|
||||
FetchAutocommitProgressResponse,
|
||||
FetchAutocommitProgressResponseData,
|
||||
} from "git/requests/fetchAutocommitProgressRequest.types";
|
||||
import triggerAutocommitRequest from "git/requests/triggerAutocommitRequest";
|
||||
import type {
|
||||
TriggerAutocommitResponse,
|
||||
TriggerAutocommitResponseData,
|
||||
} from "git/requests/triggerAutocommitRequest.types";
|
||||
import type { TriggerAutocommitInitPayload } from "git/store/actions/triggerAutocommitActions";
|
||||
import { gitArtifactActions } from "git/store/gitArtifactSlice";
|
||||
import { selectAutocommitEnabled } from "git/store/selectors/gitSingleArtifactSelectors";
|
||||
import type { GitArtifactPayloadAction } from "git/store/types";
|
||||
import {
|
||||
call,
|
||||
cancel,
|
||||
delay,
|
||||
fork,
|
||||
put,
|
||||
select,
|
||||
take,
|
||||
} from "redux-saga/effects";
|
||||
import type { Task } from "redux-saga";
|
||||
import { validateResponse } from "sagas/ErrorSagas";
|
||||
|
||||
const AUTOCOMMIT_POLL_DELAY = 1000;
|
||||
const AUTOCOMMIT_WHITELISTED_STATES = [
|
||||
AutocommitStatus.PUBLISHED,
|
||||
AutocommitStatus.IN_PROGRESS,
|
||||
AutocommitStatus.LOCKED,
|
||||
];
|
||||
|
||||
interface PollAutocommitProgressParams {
|
||||
artifactType: keyof typeof GitArtifactType;
|
||||
baseArtifactId: string;
|
||||
artifactId: string;
|
||||
}
|
||||
|
||||
function isAutocommitHappening(
|
||||
responseData:
|
||||
| TriggerAutocommitResponseData
|
||||
| FetchAutocommitProgressResponseData
|
||||
| undefined,
|
||||
): boolean {
|
||||
return (
|
||||
!!responseData &&
|
||||
AUTOCOMMIT_WHITELISTED_STATES.includes(responseData.autoCommitResponse)
|
||||
);
|
||||
}
|
||||
|
||||
function* pollAutocommitProgressSaga(params: PollAutocommitProgressParams) {
|
||||
const { artifactId, artifactType, baseArtifactId } = params;
|
||||
const basePayload = { artifactType, baseArtifactId };
|
||||
let triggerResponse: TriggerAutocommitResponse | undefined;
|
||||
|
||||
try {
|
||||
triggerResponse = yield call(triggerAutocommitRequest, artifactId);
|
||||
const isValidResponse: boolean = yield validateResponse(triggerResponse);
|
||||
|
||||
if (triggerResponse && isValidResponse) {
|
||||
yield put(gitArtifactActions.triggerAutocommitSuccess(basePayload));
|
||||
}
|
||||
} catch (error) {
|
||||
yield put(
|
||||
gitArtifactActions.triggerAutocommitError({
|
||||
...basePayload,
|
||||
error: error as string,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
if (isAutocommitHappening(triggerResponse?.data)) {
|
||||
yield put(gitArtifactActions.pollAutocommitProgressStart(basePayload));
|
||||
|
||||
while (true) {
|
||||
yield put(gitArtifactActions.fetchAutocommitProgressInit(basePayload));
|
||||
const progressResponse: FetchAutocommitProgressResponse = yield call(
|
||||
fetchAutocommitProgressRequest,
|
||||
baseArtifactId,
|
||||
);
|
||||
const isValidResponse: boolean =
|
||||
yield validateResponse(progressResponse);
|
||||
|
||||
if (isValidResponse && !isAutocommitHappening(progressResponse?.data)) {
|
||||
yield put(gitArtifactActions.pollAutocommitProgressStop(basePayload));
|
||||
}
|
||||
|
||||
if (!isValidResponse) {
|
||||
yield put(gitArtifactActions.pollAutocommitProgressStop(basePayload));
|
||||
}
|
||||
|
||||
yield delay(AUTOCOMMIT_POLL_DELAY);
|
||||
}
|
||||
} else {
|
||||
yield put(gitArtifactActions.pollAutocommitProgressStop(basePayload));
|
||||
}
|
||||
} catch (error) {
|
||||
yield put(gitArtifactActions.pollAutocommitProgressStop(basePayload));
|
||||
yield put(
|
||||
gitArtifactActions.fetchAutocommitProgressError({
|
||||
...basePayload,
|
||||
error: error as string,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default function* triggerAutocommitSaga(
|
||||
action: GitArtifactPayloadAction<TriggerAutocommitInitPayload>,
|
||||
) {
|
||||
const { artifactId, artifactType, baseArtifactId } = action.payload;
|
||||
const basePayload = { artifactType, baseArtifactId };
|
||||
const isAutocommitEnabled: boolean = yield select(
|
||||
selectAutocommitEnabled,
|
||||
basePayload,
|
||||
);
|
||||
|
||||
if (isAutocommitEnabled) {
|
||||
const params = { artifactType, baseArtifactId, artifactId };
|
||||
const pollTask: Task = yield fork(pollAutocommitProgressSaga, params);
|
||||
|
||||
yield take(gitArtifactActions.pollAutocommitProgressStop.type);
|
||||
yield cancel(pollTask);
|
||||
} else {
|
||||
yield put(triggerAutocommitSuccessAction());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,4 @@
|
|||
import type {
|
||||
GitArtifactPayloadAction,
|
||||
GitArtifactErrorPayloadAction,
|
||||
GitAutocommitProgress,
|
||||
} from "../types";
|
||||
import type { GitAsyncErrorPayload } from "../types";
|
||||
import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction";
|
||||
|
||||
export const fetchAutocommitProgressInitAction = createSingleArtifactAction(
|
||||
|
|
@ -15,27 +11,19 @@ export const fetchAutocommitProgressInitAction = createSingleArtifactAction(
|
|||
);
|
||||
|
||||
export const fetchAutocommitProgressSuccessAction = createSingleArtifactAction(
|
||||
(
|
||||
state,
|
||||
action: GitArtifactPayloadAction<{
|
||||
autocommitProgress: GitAutocommitProgress;
|
||||
}>,
|
||||
) => {
|
||||
(state) => {
|
||||
state.apiResponses.autocommitProgress.loading = false;
|
||||
state.apiResponses.autocommitProgress.value =
|
||||
action.payload.autocommitProgress;
|
||||
|
||||
return state;
|
||||
},
|
||||
);
|
||||
|
||||
export const fetchAutocommitProgressErrorAction = createSingleArtifactAction(
|
||||
(state, action: GitArtifactErrorPayloadAction) => {
|
||||
export const fetchAutocommitProgressErrorAction =
|
||||
createSingleArtifactAction<GitAsyncErrorPayload>((state, action) => {
|
||||
const { error } = action.payload;
|
||||
|
||||
state.apiResponses.autocommitProgress.loading = false;
|
||||
state.apiResponses.autocommitProgress.error = error;
|
||||
|
||||
return state;
|
||||
},
|
||||
);
|
||||
});
|
||||
|
|
|
|||
31
app/client/src/git/store/actions/fetchGitMetadataActions.ts
Normal file
31
app/client/src/git/store/actions/fetchGitMetadataActions.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import type { GitAsyncErrorPayload, GitAsyncSuccessPayload } from "../types";
|
||||
import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction";
|
||||
import type { FetchGitMetadataResponseData } from "git/requests/fetchGitMetadataRequest.types";
|
||||
|
||||
export const fetchGitMetadataInitAction = createSingleArtifactAction(
|
||||
(state) => {
|
||||
state.apiResponses.metadata.loading = true;
|
||||
state.apiResponses.metadata.error = null;
|
||||
|
||||
return state;
|
||||
},
|
||||
);
|
||||
|
||||
export const fetchGitMetadataSuccessAction = createSingleArtifactAction<
|
||||
GitAsyncSuccessPayload<FetchGitMetadataResponseData>
|
||||
>((state, action) => {
|
||||
state.apiResponses.metadata.loading = false;
|
||||
state.apiResponses.metadata.value = action.payload.responseData;
|
||||
|
||||
return state;
|
||||
});
|
||||
|
||||
export const fetchGitMetadataErrorAction =
|
||||
createSingleArtifactAction<GitAsyncErrorPayload>((state, action) => {
|
||||
const { error } = action.payload;
|
||||
|
||||
state.apiResponses.metadata.loading = false;
|
||||
state.apiResponses.metadata.error = error;
|
||||
|
||||
return state;
|
||||
});
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
import type {
|
||||
GitArtifactPayloadAction,
|
||||
GitArtifactErrorPayloadAction,
|
||||
GitMetadata,
|
||||
} from "../types";
|
||||
import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction";
|
||||
|
||||
export const fetchMetadataInitAction = createSingleArtifactAction((state) => {
|
||||
state.apiResponses.metadata.loading = true;
|
||||
state.apiResponses.metadata.error = null;
|
||||
|
||||
return state;
|
||||
});
|
||||
|
||||
export const fetchMetadataSuccessAction = createSingleArtifactAction(
|
||||
(state, action: GitArtifactPayloadAction<{ metadata: GitMetadata }>) => {
|
||||
state.apiResponses.metadata.loading = false;
|
||||
state.apiResponses.metadata.value = action.payload.metadata;
|
||||
|
||||
return state;
|
||||
},
|
||||
);
|
||||
|
||||
export const fetchMetadataErrorAction = createSingleArtifactAction(
|
||||
(state, action: GitArtifactErrorPayloadAction) => {
|
||||
const { error } = action.payload;
|
||||
|
||||
state.apiResponses.metadata.loading = false;
|
||||
state.apiResponses.metadata.error = error;
|
||||
|
||||
return state;
|
||||
},
|
||||
);
|
||||
|
|
@ -1,9 +1,6 @@
|
|||
import type {
|
||||
GitArtifactPayloadAction,
|
||||
GitArtifactErrorPayloadAction,
|
||||
GitProtectedBranches,
|
||||
} from "../types";
|
||||
import type { GitAsyncSuccessPayload, GitAsyncErrorPayload } from "../types";
|
||||
import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction";
|
||||
import type { FetchProtectedBranchesResponseData } from "git/requests/fetchProtectedBranchesRequest.types";
|
||||
|
||||
export const fetchProtectedBranchesInitAction = createSingleArtifactAction(
|
||||
(state) => {
|
||||
|
|
@ -14,28 +11,21 @@ export const fetchProtectedBranchesInitAction = createSingleArtifactAction(
|
|||
},
|
||||
);
|
||||
|
||||
export const fetchProtectedBranchesSuccessAction = createSingleArtifactAction(
|
||||
(
|
||||
state,
|
||||
action: GitArtifactPayloadAction<{
|
||||
protectedBranches: GitProtectedBranches;
|
||||
}>,
|
||||
) => {
|
||||
state.apiResponses.protectedBranches.loading = false;
|
||||
state.apiResponses.protectedBranches.value =
|
||||
action.payload.protectedBranches;
|
||||
export const fetchProtectedBranchesSuccessAction = createSingleArtifactAction<
|
||||
GitAsyncSuccessPayload<FetchProtectedBranchesResponseData>
|
||||
>((state, action) => {
|
||||
state.apiResponses.protectedBranches.loading = false;
|
||||
state.apiResponses.protectedBranches.value = action.payload.responseData;
|
||||
|
||||
return state;
|
||||
},
|
||||
);
|
||||
return state;
|
||||
});
|
||||
|
||||
export const fetchProtectedBranchesErrorAction = createSingleArtifactAction(
|
||||
(state, action: GitArtifactErrorPayloadAction) => {
|
||||
export const fetchProtectedBranchesErrorAction =
|
||||
createSingleArtifactAction<GitAsyncErrorPayload>((state, action) => {
|
||||
const { error } = action.payload;
|
||||
|
||||
state.apiResponses.protectedBranches.loading = false;
|
||||
state.apiResponses.protectedBranches.error = error;
|
||||
|
||||
return state;
|
||||
},
|
||||
);
|
||||
});
|
||||
|
|
|
|||
15
app/client/src/git/store/actions/initGitActions.ts
Normal file
15
app/client/src/git/store/actions/initGitActions.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import type { FetchGitMetadataResponseData } from "git/requests/fetchGitMetadataRequest.types";
|
||||
import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction";
|
||||
|
||||
export interface InitGitForEditorPayload {
|
||||
artifact: {
|
||||
id: string;
|
||||
baseId: string;
|
||||
gitApplicationMetadata?: Partial<FetchGitMetadataResponseData>;
|
||||
};
|
||||
}
|
||||
|
||||
export const initGitForEditorAction =
|
||||
createSingleArtifactAction<InitGitForEditorPayload>((state) => {
|
||||
return state;
|
||||
});
|
||||
|
|
@ -1,14 +1,17 @@
|
|||
import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction";
|
||||
import type { GitArtifactErrorPayloadAction } from "../types";
|
||||
import type { GitAsyncErrorPayload } from "../types";
|
||||
|
||||
export const triggerAutocommitInitAction = createSingleArtifactAction(
|
||||
(state) => {
|
||||
export interface TriggerAutocommitInitPayload {
|
||||
artifactId: string;
|
||||
}
|
||||
|
||||
export const triggerAutocommitInitAction =
|
||||
createSingleArtifactAction<TriggerAutocommitInitPayload>((state) => {
|
||||
state.apiResponses.triggerAutocommit.loading = true;
|
||||
state.apiResponses.triggerAutocommit.error = null;
|
||||
|
||||
return state;
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
export const triggerAutocommitSuccessAction = createSingleArtifactAction(
|
||||
(state) => {
|
||||
|
|
@ -18,13 +21,28 @@ export const triggerAutocommitSuccessAction = createSingleArtifactAction(
|
|||
},
|
||||
);
|
||||
|
||||
export const triggerAutocommitErrorAction = createSingleArtifactAction(
|
||||
(state, action: GitArtifactErrorPayloadAction) => {
|
||||
export const triggerAutocommitErrorAction =
|
||||
createSingleArtifactAction<GitAsyncErrorPayload>((state, action) => {
|
||||
const { error } = action.payload;
|
||||
|
||||
state.apiResponses.triggerAutocommit.loading = false;
|
||||
state.apiResponses.triggerAutocommit.error = error;
|
||||
|
||||
return state;
|
||||
});
|
||||
|
||||
export const pollAutocommitProgressStartAction = createSingleArtifactAction(
|
||||
(state) => {
|
||||
state.ui.autocommitPolling = true;
|
||||
|
||||
return state;
|
||||
},
|
||||
);
|
||||
|
||||
export const pollAutocommitProgressStopAction = createSingleArtifactAction(
|
||||
(state) => {
|
||||
state.ui.autocommitPolling = false;
|
||||
|
||||
return state;
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ import {
|
|||
connectSuccessAction,
|
||||
} from "./actions/connectActions";
|
||||
import {
|
||||
fetchMetadataErrorAction,
|
||||
fetchMetadataInitAction,
|
||||
fetchMetadataSuccessAction,
|
||||
} from "./actions/fetchMetadataActions";
|
||||
fetchGitMetadataErrorAction,
|
||||
fetchGitMetadataInitAction,
|
||||
fetchGitMetadataSuccessAction,
|
||||
} from "./actions/fetchGitMetadataActions";
|
||||
import {
|
||||
fetchBranchesErrorAction,
|
||||
fetchBranchesInitAction,
|
||||
|
|
@ -79,6 +79,34 @@ import {
|
|||
mergeInitAction,
|
||||
mergeSuccessAction,
|
||||
} from "./actions/mergeActions";
|
||||
import {
|
||||
pollAutocommitProgressStopAction,
|
||||
pollAutocommitProgressStartAction,
|
||||
triggerAutocommitErrorAction,
|
||||
triggerAutocommitInitAction,
|
||||
triggerAutocommitSuccessAction,
|
||||
} from "./actions/triggerAutocommitActions";
|
||||
import {
|
||||
toggleAutocommitErrorAction,
|
||||
toggleAutocommitInitAction,
|
||||
toggleAutocommitSuccessAction,
|
||||
} from "./actions/toggleAutocommitActions";
|
||||
import {
|
||||
fetchProtectedBranchesErrorAction,
|
||||
fetchProtectedBranchesInitAction,
|
||||
fetchProtectedBranchesSuccessAction,
|
||||
} from "./actions/fetchProtectedBranchesActions";
|
||||
import {
|
||||
updateProtectedBranchesErrorAction,
|
||||
updateProtectedBranchesInitAction,
|
||||
updateProtectedBranchesSuccessAction,
|
||||
} from "./actions/updateProtectedBranchesActions";
|
||||
import { initGitForEditorAction } from "./actions/initGitActions";
|
||||
import {
|
||||
fetchAutocommitProgressErrorAction,
|
||||
fetchAutocommitProgressInitAction,
|
||||
fetchAutocommitProgressSuccessAction,
|
||||
} from "./actions/fetchAutocommitProgressActions";
|
||||
|
||||
const initialState: GitArtifactReduxState = {};
|
||||
|
||||
|
|
@ -87,8 +115,13 @@ export const gitArtifactSlice = createSlice({
|
|||
reducerPath: "git.artifact",
|
||||
initialState,
|
||||
reducers: {
|
||||
// init
|
||||
initGitForEditor: initGitForEditorAction,
|
||||
mount: mountAction,
|
||||
unmount: unmountAction,
|
||||
fetchGitMetadataInit: fetchGitMetadataInitAction,
|
||||
fetchGitMetadataSuccess: fetchGitMetadataSuccessAction,
|
||||
fetchGitMetadataError: fetchGitMetadataErrorAction,
|
||||
|
||||
// connect
|
||||
connectInit: connectInitAction,
|
||||
|
|
@ -135,17 +168,31 @@ export const gitArtifactSlice = createSlice({
|
|||
|
||||
// settings
|
||||
toggleGitSettingsModal: toggleGitSettingsModalAction,
|
||||
|
||||
// metadata
|
||||
fetchMetadataInit: fetchMetadataInitAction,
|
||||
fetchMetadataSuccess: fetchMetadataSuccessAction,
|
||||
fetchMetadataError: fetchMetadataErrorAction,
|
||||
fetchLocalProfileInit: fetchLocalProfileInitAction,
|
||||
fetchLocalProfileSuccess: fetchLocalProfileSuccessAction,
|
||||
fetchLocalProfileError: fetchLocalProfileErrorAction,
|
||||
updateLocalProfileInit: updateLocalProfileInitAction,
|
||||
updateLocalProfileSuccess: updateLocalProfileSuccessAction,
|
||||
updateLocalProfileError: updateLocalProfileErrorAction,
|
||||
fetchProtectedBranchesInit: fetchProtectedBranchesInitAction,
|
||||
fetchProtectedBranchesSuccess: fetchProtectedBranchesSuccessAction,
|
||||
fetchProtectedBranchesError: fetchProtectedBranchesErrorAction,
|
||||
updateProtectedBranchesInit: updateProtectedBranchesInitAction,
|
||||
updateProtectedBranchesSuccess: updateProtectedBranchesSuccessAction,
|
||||
updateProtectedBranchesError: updateProtectedBranchesErrorAction,
|
||||
|
||||
// autocommit
|
||||
toggleAutocommitInit: toggleAutocommitInitAction,
|
||||
toggleAutocommitSuccess: toggleAutocommitSuccessAction,
|
||||
toggleAutocommitError: toggleAutocommitErrorAction,
|
||||
triggerAutocommitInit: triggerAutocommitInitAction,
|
||||
triggerAutocommitSuccess: triggerAutocommitSuccessAction,
|
||||
triggerAutocommitError: triggerAutocommitErrorAction,
|
||||
fetchAutocommitProgressInit: fetchAutocommitProgressInitAction,
|
||||
fetchAutocommitProgressSuccess: fetchAutocommitProgressSuccessAction,
|
||||
fetchAutocommitProgressError: fetchAutocommitProgressErrorAction,
|
||||
pollAutocommitProgressStart: pollAutocommitProgressStartAction,
|
||||
pollAutocommitProgressStop: pollAutocommitProgressStopAction,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ const gitSingleArtifactInitialUIState: GitSingleArtifactUIReduxState = {
|
|||
repoLimitErrorModal: {
|
||||
open: false,
|
||||
},
|
||||
autocommitModalOpen: false,
|
||||
autocommitPolling: false,
|
||||
};
|
||||
|
||||
const gitSingleArtifactInitialAPIResponses: GitSingleArtifactAPIResponsesReduxState =
|
||||
|
|
@ -112,7 +114,6 @@ const gitSingleArtifactInitialAPIResponses: GitSingleArtifactAPIResponsesReduxSt
|
|||
error: null,
|
||||
},
|
||||
autocommitProgress: {
|
||||
value: null,
|
||||
loading: false,
|
||||
error: null,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -15,6 +15,17 @@ export const selectSingleArtifact = (
|
|||
];
|
||||
};
|
||||
|
||||
// metadata
|
||||
export const selectGitMetadata = (
|
||||
state: GitRootState,
|
||||
artifactDef: GitArtifactDef,
|
||||
) => selectSingleArtifact(state, artifactDef)?.apiResponses.metadata;
|
||||
|
||||
export const selectGitConnected = (
|
||||
state: GitRootState,
|
||||
artifactDef: GitArtifactDef,
|
||||
) => !!selectGitMetadata(state, artifactDef).value;
|
||||
|
||||
// git ops
|
||||
export const selectCommit = (
|
||||
state: GitRootState,
|
||||
|
|
@ -43,6 +54,16 @@ export const selectPull = (state: GitRootState, artifactDef: GitArtifactDef) =>
|
|||
selectSingleArtifact(state, artifactDef)?.apiResponses?.pull;
|
||||
|
||||
// git branches
|
||||
|
||||
export const selectCurrentBranch = (
|
||||
state: GitRootState,
|
||||
artifactDef: GitArtifactDef,
|
||||
) => {
|
||||
const gitMetadataState = selectGitMetadata(state, artifactDef).value;
|
||||
|
||||
return gitMetadataState?.branchName;
|
||||
};
|
||||
|
||||
export const selectBranches = (
|
||||
state: GitRootState,
|
||||
artifactDef: GitArtifactDef,
|
||||
|
|
@ -62,3 +83,34 @@ export const selectCheckoutBranch = (
|
|||
state: GitRootState,
|
||||
artifactDef: GitArtifactDef,
|
||||
) => selectSingleArtifact(state, artifactDef)?.apiResponses.checkoutBranch;
|
||||
|
||||
// autocommit
|
||||
export const selectAutocommitEnabled = (
|
||||
state: GitRootState,
|
||||
artifactDef: GitArtifactDef,
|
||||
) => {
|
||||
const gitMetadata = selectGitMetadata(state, artifactDef).value;
|
||||
|
||||
return gitMetadata?.autoCommitConfig?.enabled;
|
||||
};
|
||||
|
||||
export const selectAutocommitPolling = (
|
||||
state: GitRootState,
|
||||
artifactDef: GitArtifactDef,
|
||||
) => selectSingleArtifact(state, artifactDef)?.ui.autocommitPolling;
|
||||
|
||||
// protected branches
|
||||
export const selectProtectedBranches = (
|
||||
state: GitRootState,
|
||||
artifactDef: GitArtifactDef,
|
||||
) => selectSingleArtifact(state, artifactDef)?.apiResponses.protectedBranches;
|
||||
|
||||
export const selectProtectedMode = (
|
||||
state: GitRootState,
|
||||
artifactDef: GitArtifactDef,
|
||||
) => {
|
||||
const currentBranch = selectCurrentBranch(state, artifactDef);
|
||||
const protectedBranches = selectProtectedBranches(state, artifactDef).value;
|
||||
|
||||
return protectedBranches?.includes(currentBranch ?? "");
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,13 +11,8 @@ import type { FetchBranchesResponseData } from "../requests/fetchBranchesRequest
|
|||
import type { FetchLocalProfileResponseData } from "../requests/fetchLocalProfileRequest.types";
|
||||
import type { FetchStatusResponseData } from "git/requests/fetchStatusRequest.types";
|
||||
import type { FetchMergeStatusResponseData } from "git/requests/fetchMergeStatusRequest.types";
|
||||
|
||||
// These will be updated when contracts are finalized
|
||||
export type GitMetadata = Record<string, unknown>;
|
||||
|
||||
export type GitProtectedBranches = Record<string, unknown>;
|
||||
|
||||
export type GitAutocommitProgress = Record<string, unknown>;
|
||||
import type { FetchGitMetadataResponseData } from "git/requests/fetchGitMetadataRequest.types";
|
||||
import type { FetchProtectedBranchesResponseData } from "git/requests/fetchProtectedBranchesRequest.types";
|
||||
|
||||
export type GitSSHKey = Record<string, unknown>;
|
||||
|
||||
|
|
@ -32,7 +27,7 @@ interface AsyncStateWithoutValue {
|
|||
error: string | null;
|
||||
}
|
||||
export interface GitSingleArtifactAPIResponsesReduxState {
|
||||
metadata: AsyncState<GitMetadata>;
|
||||
metadata: AsyncState<FetchGitMetadataResponseData>;
|
||||
connect: AsyncStateWithoutValue;
|
||||
status: AsyncState<FetchStatusResponseData>;
|
||||
commit: AsyncStateWithoutValue;
|
||||
|
|
@ -47,9 +42,9 @@ export interface GitSingleArtifactAPIResponsesReduxState {
|
|||
localProfile: AsyncState<FetchLocalProfileResponseData>;
|
||||
updateLocalProfile: AsyncStateWithoutValue;
|
||||
disconnect: AsyncStateWithoutValue;
|
||||
protectedBranches: AsyncState<GitProtectedBranches>;
|
||||
protectedBranches: AsyncState<FetchProtectedBranchesResponseData>;
|
||||
updateProtectedBranches: AsyncStateWithoutValue;
|
||||
autocommitProgress: AsyncState<GitAutocommitProgress>;
|
||||
autocommitProgress: AsyncStateWithoutValue;
|
||||
toggleAutocommit: AsyncStateWithoutValue;
|
||||
triggerAutocommit: AsyncStateWithoutValue;
|
||||
sshKey: AsyncState<GitSSHKey>;
|
||||
|
|
@ -79,6 +74,8 @@ export interface GitSingleArtifactUIReduxState {
|
|||
repoLimitErrorModal: {
|
||||
open: boolean;
|
||||
};
|
||||
autocommitPolling: boolean;
|
||||
autocommitModalOpen: boolean;
|
||||
}
|
||||
export interface GitSingleArtifactReduxState {
|
||||
ui: GitSingleArtifactUIReduxState;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user