From 44c644eb559067d2d5716ae9e72dec07080d8b4d Mon Sep 17 00:00:00 2001 From: Rudraprasad Das Date: Mon, 28 Apr 2025 16:49:47 +0200 Subject: [PATCH 1/9] chore: adding override modal --- .../src/ce/pages/Applications/index.tsx | 2 + .../components/ImportOverrideModal/index.tsx | 48 +++++++++++++++++++ app/client/src/git/index.ts | 1 + 3 files changed, 51 insertions(+) create mode 100644 app/client/src/git/components/ImportOverrideModal/index.tsx diff --git a/app/client/src/ce/pages/Applications/index.tsx b/app/client/src/ce/pages/Applications/index.tsx index 85b1174f9e56..742ee2703a69 100644 --- a/app/client/src/ce/pages/Applications/index.tsx +++ b/app/client/src/ce/pages/Applications/index.tsx @@ -135,6 +135,7 @@ import { useGitModEnabled } from "pages/Editor/gitSync/hooks/modHooks"; import { GitRepoLimitErrorModal as NewGitRepoLimitErrorModal, GitImportModal as NewGitImportModal, + GitImportOverrideModal, } from "git"; import OldRepoLimitExceededErrorModal from "pages/Editor/gitSync/RepoLimitExceededErrorModal"; @@ -145,6 +146,7 @@ function GitModals() { <> + ) : ( <> diff --git a/app/client/src/git/components/ImportOverrideModal/index.tsx b/app/client/src/git/components/ImportOverrideModal/index.tsx new file mode 100644 index 000000000000..7d830159dab9 --- /dev/null +++ b/app/client/src/git/components/ImportOverrideModal/index.tsx @@ -0,0 +1,48 @@ +import { + Button, + Callout, + Modal, + ModalBody, + ModalContent, + ModalFooter, + ModalHeader, + Text, +} from "@appsmith/ads"; +import React from "react"; +import styled from "styled-components"; + +const StyledModalContent = styled(ModalContent)` + width: 640px; +`; + +interface ImportOverrideModalProps { + artifactType?: string; +} + +function ImportOverrideModal({ + artifactType = "artifact", +}: ImportOverrideModalProps) { + return ( + + + Override existing {artifactType}? + + + + You're trying to import a {artifactType} that already exists + in this workspace as my-app. Do you want to override it? + + + + + + + + + + ); +} + +export default ImportOverrideModal; diff --git a/app/client/src/git/index.ts b/app/client/src/git/index.ts index c210c1a07596..8a4ef343cb5b 100644 --- a/app/client/src/git/index.ts +++ b/app/client/src/git/index.ts @@ -6,6 +6,7 @@ export { useHotKeys } from "./components/HotKeys"; export { default as GitContextProvider } from "./components/GitContextProvider"; export { default as GitModals } from "./ee/components/GitModals"; export { default as GitImportModal } from "./components/ImportModal"; +export { default as GitImportOverrideModal } from "./components/ImportOverrideModal"; export { default as GitRepoLimitErrorModal } from "./components/RepoLimitErrorModal"; export { default as GitQuickActions } from "./components/QuickActions"; export { default as GitProtectedBranchCallout } from "./components/ProtectedBranchCallout"; From 2b05ddfcc42eb5bbcc6f6f7d4c5f6577a881e210 Mon Sep 17 00:00:00 2001 From: Rudraprasad Das Date: Mon, 28 Apr 2025 18:01:31 +0200 Subject: [PATCH 2/9] chore: adding functionality to import modal --- app/client/src/git/ce/constants/messages.tsx | 8 +++ .../ImportOverrideModalView.tsx | 72 +++++++++++++++++++ .../components/ImportOverrideModal/index.tsx | 70 ++++++++---------- app/client/src/git/hooks/useImport.ts | 21 ++++++ app/client/src/git/hooks/useMessage.ts | 12 ++++ .../src/git/requests/gitImportRequest.ts | 5 +- .../git/requests/gitImportRequest.types.ts | 1 + app/client/src/git/store/actions/uiActions.ts | 17 +++++ app/client/src/git/store/gitGlobalSlice.ts | 8 ++- .../src/git/store/helpers/initialState.ts | 1 + .../git/store/selectors/gitGlobalSelectors.ts | 6 ++ app/client/src/git/store/types.ts | 2 + 12 files changed, 181 insertions(+), 42 deletions(-) create mode 100644 app/client/src/git/components/ImportOverrideModal/ImportOverrideModalView.tsx create mode 100644 app/client/src/git/hooks/useMessage.ts diff --git a/app/client/src/git/ce/constants/messages.tsx b/app/client/src/git/ce/constants/messages.tsx index 200e109bb360..a2c1ba68eac8 100644 --- a/app/client/src/git/ce/constants/messages.tsx +++ b/app/client/src/git/ce/constants/messages.tsx @@ -4,6 +4,14 @@ export const IMPORT_GIT = { WAIT_TEXT: "Please wait while we import via Git..", }; +export const IMPORT_OVERRIDE_MODAL = { + TITLE: "Override existing {{artifactType}}?", + DESCRIPTION: + "You're trying to import a {{artifactType}} that already exists in this workspace as my-app. Do you want to override it?", + CANCEL_BTN: "Cancel", + OVERRIDE_BTN: "Import and override {{artifactType}}", +}; + export const CONNECT_GIT = { MODAL_TITLE: "Configure Git", CHOOSE_PROVIDER_CTA: "Configure Git", diff --git a/app/client/src/git/components/ImportOverrideModal/ImportOverrideModalView.tsx b/app/client/src/git/components/ImportOverrideModal/ImportOverrideModalView.tsx new file mode 100644 index 000000000000..2fa80d0d228f --- /dev/null +++ b/app/client/src/git/components/ImportOverrideModal/ImportOverrideModalView.tsx @@ -0,0 +1,72 @@ +import { + Button, + Callout, + Modal, + ModalBody, + ModalContent, + ModalFooter, + ModalHeader, + Text, +} from "@appsmith/ads"; +import { IMPORT_OVERRIDE_MODAL } from "git/ee/constants/messages"; +import useMessage from "git/hooks/useMessage"; +import noop from "lodash/noop"; +import React, { useCallback } from "react"; +import styled from "styled-components"; + +const StyledModalContent = styled(ModalContent)` + width: 640px; +`; + +interface ImportOverrideModalViewProps { + artifactType?: string; + isOpen: boolean; + onOpenChange: (open: boolean) => void; + onImport: () => void; +} + +function ImportOverrideModalView({ + artifactType = "artifact", + isOpen = false, + onImport = noop, + onOpenChange = noop, +}: ImportOverrideModalViewProps) { + const modalTitle = useMessage(IMPORT_OVERRIDE_MODAL.TITLE, { artifactType }); + const modalDescription = useMessage(IMPORT_OVERRIDE_MODAL.DESCRIPTION, { + artifactType, + }); + const ctaBtnText = useMessage(IMPORT_OVERRIDE_MODAL.OVERRIDE_BTN, { + artifactType, + }); + + const handleCancel = useCallback(() => { + onOpenChange(false); + }, [onOpenChange]); + + const handleImport = useCallback(() => { + onImport(); + }, [onImport]); + + return ( + + + {modalTitle} + + + {modalDescription} + + + + + + + + + ); +} + +export default ImportOverrideModalView; diff --git a/app/client/src/git/components/ImportOverrideModal/index.tsx b/app/client/src/git/components/ImportOverrideModal/index.tsx index 7d830159dab9..ca1472ad5e7a 100644 --- a/app/client/src/git/components/ImportOverrideModal/index.tsx +++ b/app/client/src/git/components/ImportOverrideModal/index.tsx @@ -1,47 +1,37 @@ -import { - Button, - Callout, - Modal, - ModalBody, - ModalContent, - ModalFooter, - ModalHeader, - Text, -} from "@appsmith/ads"; -import React from "react"; -import styled from "styled-components"; +import React, { useCallback } from "react"; +import ImportOverrideModalView from "./ImportOverrideModalView"; +import useImport from "git/hooks/useImport"; -const StyledModalContent = styled(ModalContent)` - width: 640px; -`; +function ImportOverrideModal() { + const { + gitImport, + importOverrideParams, + isImportOverrideModalOpen, + resetImportOverrideParams, + } = useImport(); -interface ImportOverrideModalProps { - artifactType?: string; -} + const handleOpenChange = useCallback( + (open: boolean) => { + if (!open) { + resetImportOverrideParams(); + } + }, + [resetImportOverrideParams], + ); + + const handleImport = useCallback(() => { + if (importOverrideParams) { + gitImport(importOverrideParams); + } + }, [gitImport, importOverrideParams]); -function ImportOverrideModal({ - artifactType = "artifact", -}: ImportOverrideModalProps) { return ( - - - Override existing {artifactType}? - - - - You're trying to import a {artifactType} that already exists - in this workspace as my-app. Do you want to override it? - - - - - - - - - + ); } diff --git a/app/client/src/git/hooks/useImport.ts b/app/client/src/git/hooks/useImport.ts index 62069b888d68..529e7ef17bf1 100644 --- a/app/client/src/git/hooks/useImport.ts +++ b/app/client/src/git/hooks/useImport.ts @@ -3,6 +3,8 @@ import { useDispatch, useSelector } from "react-redux"; import { selectGitImportState, selectImportModalOpen, + selectImportOverrideModalOpen, + selectImportOverrideParams, } from "git/store/selectors/gitGlobalSelectors"; import { gitGlobalActions } from "git/store/gitGlobalSlice"; import type { GitImportRequestParams } from "git/requests/gitImportRequest.types"; @@ -28,11 +30,30 @@ export default function useImport() { [dispatch], ); + const isImportOverrideModalOpen = useSelector(selectImportOverrideModalOpen); + + const importOverrideParams = useSelector(selectImportOverrideParams); + + const setImportOverrideParams = useCallback( + (params: GitImportRequestParams) => { + dispatch(gitGlobalActions.setImportOverrideParams(params)); + }, + [dispatch], + ); + + const resetImportOverrideParams = useCallback(() => { + dispatch(gitGlobalActions.resetImportOverrideParams()); + }, [dispatch]); + return { isGitImportLoading: gitImportState?.loading ?? false, gitImportError: gitImportState?.error ?? null, gitImport, isImportModalOpen: isImportModalOpen ?? false, toggleImportModal, + isImportOverrideModalOpen: isImportOverrideModalOpen ?? false, + importOverrideParams, + setImportOverrideParams, + resetImportOverrideParams, }; } diff --git a/app/client/src/git/hooks/useMessage.ts b/app/client/src/git/hooks/useMessage.ts new file mode 100644 index 000000000000..73845168aff6 --- /dev/null +++ b/app/client/src/git/hooks/useMessage.ts @@ -0,0 +1,12 @@ +import { useMemo } from "react"; + +export default function useMessage(msg: string, args: Record) { + return useMemo(() => { + const msgWithArgs = msg.replace(/\{\{([^}]+)\}\}/g, (match, p1) => { + // p1 is the key from {{key}} in the message + return args[p1] || match; + }); + + return msgWithArgs; + }, [msg, args]); +} diff --git a/app/client/src/git/requests/gitImportRequest.ts b/app/client/src/git/requests/gitImportRequest.ts index 3ee6dcdfcba7..ec6dd3ab3a12 100644 --- a/app/client/src/git/requests/gitImportRequest.ts +++ b/app/client/src/git/requests/gitImportRequest.ts @@ -17,7 +17,10 @@ async function gitImportRequestNew( workspaceId: string, params: GitImportRequestParams, ): AxiosPromise { - return Api.post(`${GIT_BASE_URL}/artifacts/import`, params, { workspaceId }); + const { override = false, ...restParams } = params; + const body = { override, ...restParams }; + + return Api.post(`${GIT_BASE_URL}/artifacts/import`, body, { workspaceId }); } export default async function gitImportRequest( diff --git a/app/client/src/git/requests/gitImportRequest.types.ts b/app/client/src/git/requests/gitImportRequest.types.ts index bfa4def95548..6c2b599c6103 100644 --- a/app/client/src/git/requests/gitImportRequest.types.ts +++ b/app/client/src/git/requests/gitImportRequest.types.ts @@ -9,6 +9,7 @@ export interface GitImportRequestParams { authorEmail: string; useDefaultProfile?: boolean; }; + override?: boolean; } export interface GitImportResponseData { diff --git a/app/client/src/git/store/actions/uiActions.ts b/app/client/src/git/store/actions/uiActions.ts index b08267ba95cc..611f4a3544ad 100644 --- a/app/client/src/git/store/actions/uiActions.ts +++ b/app/client/src/git/store/actions/uiActions.ts @@ -3,6 +3,7 @@ import { createArtifactAction } from "../helpers/createArtifactAction"; import type { GitGlobalReduxState } from "../types"; import type { PayloadAction } from "@reduxjs/toolkit"; import type { GitArtifactDef } from "git/types"; +import type { GitImportRequestParams } from "git/requests/gitImportRequest.types"; // connect modal export interface ToggleConnectModalPayload { @@ -31,6 +32,7 @@ export const toggleConnectSuccessModalAction = return state; }); +// import export interface ToggleImportModalPayload { open: boolean; } @@ -46,6 +48,21 @@ export const toggleImportModalAction = ( return state; }; +export const resetImportOverrideParamsAction = (state: GitGlobalReduxState) => { + state.importOverrideParams = null; + + return state; +}; + +export const setImportOverrideParamsAction = ( + state: GitGlobalReduxState, + action: PayloadAction, +) => { + state.importOverrideParams = { ...action.payload }; + + return state; +}; + // disconnect modal export interface OpenDisconnectModalPayload { targetArtifactDef: GitArtifactDef; diff --git a/app/client/src/git/store/gitGlobalSlice.ts b/app/client/src/git/store/gitGlobalSlice.ts index 3d38b14aa492..38d9feed98bb 100644 --- a/app/client/src/git/store/gitGlobalSlice.ts +++ b/app/client/src/git/store/gitGlobalSlice.ts @@ -10,7 +10,11 @@ import { updateGlobalProfileSuccessAction, } from "./actions/updateGlobalProfileActions"; import { gitGlobalInitialState } from "./helpers/initialState"; -import { toggleImportModalAction } from "./actions/uiActions"; +import { + resetImportOverrideParamsAction, + setImportOverrideParamsAction, + toggleImportModalAction, +} from "./actions/uiActions"; import { gitImportErrorAction, gitImportInitAction, @@ -42,6 +46,8 @@ export const gitGlobalSlice = createSlice({ gitImportSuccess: gitImportSuccessAction, gitImportError: gitImportErrorAction, toggleImportModal: toggleImportModalAction, + resetImportOverrideParams: resetImportOverrideParamsAction, + setImportOverrideParams: setImportOverrideParamsAction, toggleRepoLimitErrorModal: toggleRepoLimitErrorModalAction, }, }); diff --git a/app/client/src/git/store/helpers/initialState.ts b/app/client/src/git/store/helpers/initialState.ts index 2a602efb2fab..b48d2d0b3d90 100644 --- a/app/client/src/git/store/helpers/initialState.ts +++ b/app/client/src/git/store/helpers/initialState.ts @@ -168,5 +168,6 @@ export const gitGlobalInitialState: GitGlobalReduxState = { error: null, }, isImportModalOpen: false, + importOverrideParams: null, repoLimitErrorModalOpen: false, }; diff --git a/app/client/src/git/store/selectors/gitGlobalSelectors.ts b/app/client/src/git/store/selectors/gitGlobalSelectors.ts index 57e5c5123036..cfa2a13b5f4d 100644 --- a/app/client/src/git/store/selectors/gitGlobalSelectors.ts +++ b/app/client/src/git/store/selectors/gitGlobalSelectors.ts @@ -14,6 +14,12 @@ export const selectUpdateGlobalProfileState = (state: GitRootState) => export const selectImportModalOpen = (state: GitRootState) => selectGitGlobal(state).isImportModalOpen; +export const selectImportOverrideModalOpen = (state: GitRootState) => + !!selectGitGlobal(state).importOverrideParams; + +export const selectImportOverrideParams = (state: GitRootState) => + selectGitGlobal(state).importOverrideParams ?? null; + export const selectGitImportState = (state: GitRootState) => selectGitGlobal(state).gitImport; diff --git a/app/client/src/git/store/types.ts b/app/client/src/git/store/types.ts index da80f539a2e8..96975bad0223 100644 --- a/app/client/src/git/store/types.ts +++ b/app/client/src/git/store/types.ts @@ -20,6 +20,7 @@ import type { FetchGlobalSSHKeyResponseData } from "git/requests/fetchGlobalSSHK import type { FetchRefsResponseData } from "git/requests/fetchRefsRequest.types"; import type { GitArtifactDef } from "git/types"; import type { PretagResponseData } from "git/requests/pretagRequest.types"; +import type { GitImportRequestParams } from "git/requests/gitImportRequest.types"; export interface GitApiError extends ApiResponseError { errorType?: string; @@ -98,6 +99,7 @@ export interface GitGlobalReduxState { globalSSHKey: GitAsyncState; // ui isImportModalOpen: boolean; + importOverrideParams: GitImportRequestParams | null; repoLimitErrorModalOpen: boolean; } From 6c53a10fb2aa4847f755cea0cf473e53784d2bb3 Mon Sep 17 00:00:00 2001 From: Rudraprasad Das Date: Mon, 28 Apr 2025 18:13:37 +0200 Subject: [PATCH 3/9] chore: integrating override with import api --- app/client/src/git/components/ImportModal/index.tsx | 2 +- app/client/src/git/components/ImportOverrideModal/index.tsx | 2 +- app/client/src/git/constants/enums.ts | 1 + app/client/src/git/sagas/gitImportSaga.ts | 5 +++++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/client/src/git/components/ImportModal/index.tsx b/app/client/src/git/components/ImportModal/index.tsx index 2dd82b71bbad..0f8db29140a7 100644 --- a/app/client/src/git/components/ImportModal/index.tsx +++ b/app/client/src/git/components/ImportModal/index.tsx @@ -24,7 +24,7 @@ function ImportModal() { const onSubmit = useCallback( (params: GitImportRequestParams) => { - gitImport(params); + gitImport({ ...params, override: false }); }, [gitImport], ); diff --git a/app/client/src/git/components/ImportOverrideModal/index.tsx b/app/client/src/git/components/ImportOverrideModal/index.tsx index ca1472ad5e7a..1d2ef274ef13 100644 --- a/app/client/src/git/components/ImportOverrideModal/index.tsx +++ b/app/client/src/git/components/ImportOverrideModal/index.tsx @@ -21,7 +21,7 @@ function ImportOverrideModal() { const handleImport = useCallback(() => { if (importOverrideParams) { - gitImport(importOverrideParams); + gitImport({ ...importOverrideParams, override: true }); } }, [gitImport, importOverrideParams]); diff --git a/app/client/src/git/constants/enums.ts b/app/client/src/git/constants/enums.ts index b979b66645ed..4afd9a625ed8 100644 --- a/app/client/src/git/constants/enums.ts +++ b/app/client/src/git/constants/enums.ts @@ -37,4 +37,5 @@ export enum GitErrorCodes { REPO_NOT_EMPTY = "AE-GIT-4033", REPO_LIMIT_REACHED = "AE-GIT-4043", PUSH_FAILED_REMOTE_COUNTERPART_IS_AHEAD = "AE-GIT-4048", + DUPLICATE_ARTIFACT_OVERRIDE = "AE-GIT-5003", } diff --git a/app/client/src/git/sagas/gitImportSaga.ts b/app/client/src/git/sagas/gitImportSaga.ts index 5f55c4772ebc..274294f05d42 100644 --- a/app/client/src/git/sagas/gitImportSaga.ts +++ b/app/client/src/git/sagas/gitImportSaga.ts @@ -47,6 +47,11 @@ export default function* gitImportSaga( yield put(gitGlobalActions.toggleImportModal({ open: false })); yield put(gitGlobalActions.toggleRepoLimitErrorModal({ open: true })); } + + if (GitErrorCodes.DUPLICATE_ARTIFACT_OVERRIDE === error.code) { + yield put(gitGlobalActions.setImportOverrideParams(params)); + yield put(gitGlobalActions.toggleImportModal({ open: false })); + } } } } From 73ac3d75a190d4941af775d39a253e9e7b4deab6 Mon Sep 17 00:00:00 2001 From: Rudraprasad Das Date: Mon, 28 Apr 2025 19:22:23 +0200 Subject: [PATCH 4/9] chore: adding proper messaging --- app/client/src/git/ce/constants/messages.tsx | 2 +- .../ImportOverrideModalView.tsx | 30 ++++++++++++++----- .../components/ImportOverrideModal/index.tsx | 24 ++++++++++++++- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/app/client/src/git/ce/constants/messages.tsx b/app/client/src/git/ce/constants/messages.tsx index a2c1ba68eac8..a69144c0f6f3 100644 --- a/app/client/src/git/ce/constants/messages.tsx +++ b/app/client/src/git/ce/constants/messages.tsx @@ -7,7 +7,7 @@ export const IMPORT_GIT = { export const IMPORT_OVERRIDE_MODAL = { TITLE: "Override existing {{artifactType}}?", DESCRIPTION: - "You're trying to import a {{artifactType}} that already exists in this workspace as my-app. Do you want to override it?", + "{{newArtifactName}} already exists in this workspace as {{oldArtifactName}}. Do you want to override it with the imported {{artifactType}}?", CANCEL_BTN: "Cancel", OVERRIDE_BTN: "Import and override {{artifactType}}", }; diff --git a/app/client/src/git/components/ImportOverrideModal/ImportOverrideModalView.tsx b/app/client/src/git/components/ImportOverrideModal/ImportOverrideModalView.tsx index 2fa80d0d228f..ae5c56014ad6 100644 --- a/app/client/src/git/components/ImportOverrideModal/ImportOverrideModalView.tsx +++ b/app/client/src/git/components/ImportOverrideModal/ImportOverrideModalView.tsx @@ -1,6 +1,5 @@ import { Button, - Callout, Modal, ModalBody, ModalContent, @@ -20,19 +19,27 @@ const StyledModalContent = styled(ModalContent)` interface ImportOverrideModalViewProps { artifactType?: string; + isImportLoading: boolean; isOpen: boolean; - onOpenChange: (open: boolean) => void; + newArtifactName: string | null; + oldArtifactName: string | null; onImport: () => void; + onOpenChange: (open: boolean) => void; } function ImportOverrideModalView({ artifactType = "artifact", + isImportLoading = false, isOpen = false, + newArtifactName = null, + oldArtifactName = null, onImport = noop, onOpenChange = noop, }: ImportOverrideModalViewProps) { const modalTitle = useMessage(IMPORT_OVERRIDE_MODAL.TITLE, { artifactType }); const modalDescription = useMessage(IMPORT_OVERRIDE_MODAL.DESCRIPTION, { + newArtifactName: newArtifactName ?? "", + oldArtifactName: oldArtifactName ?? "", artifactType, }); const ctaBtnText = useMessage(IMPORT_OVERRIDE_MODAL.OVERRIDE_BTN, { @@ -44,23 +51,30 @@ function ImportOverrideModalView({ }, [onOpenChange]); const handleImport = useCallback(() => { - onImport(); - }, [onImport]); + if (!isImportLoading) { + onImport(); + } + }, [isImportLoading, onImport]); return ( {modalTitle} - - {modalDescription} - + + {modalDescription} + - diff --git a/app/client/src/git/components/ImportOverrideModal/index.tsx b/app/client/src/git/components/ImportOverrideModal/index.tsx index 1d2ef274ef13..c995b2deefc5 100644 --- a/app/client/src/git/components/ImportOverrideModal/index.tsx +++ b/app/client/src/git/components/ImportOverrideModal/index.tsx @@ -1,11 +1,13 @@ -import React, { useCallback } from "react"; +import React, { useCallback, useMemo } from "react"; import ImportOverrideModalView from "./ImportOverrideModalView"; import useImport from "git/hooks/useImport"; function ImportOverrideModal() { const { gitImport, + gitImportError, importOverrideParams, + isGitImportLoading, isImportOverrideModalOpen, resetImportOverrideParams, } = useImport(); @@ -25,10 +27,30 @@ function ImportOverrideModal() { } }, [gitImport, importOverrideParams]); + const { newArtifactName, oldArtifactName } = useMemo(() => { + let artifactNames = { newArtifactName: null, oldArtifactName: null }; + + if (gitImportError?.message) { + const jsonMatch = gitImportError.message.match(/\{.*\}/); + const jsonStr = jsonMatch ? jsonMatch[0] : null; + + if (jsonStr) { + try { + artifactNames = JSON.parse(jsonStr); + } catch {} + } + } + + return artifactNames; + }, [gitImportError]); + return ( From 11abd6b06d637b19613994dd91390a3b2f2b9452 Mon Sep 17 00:00:00 2001 From: Rudraprasad Das Date: Mon, 28 Apr 2025 19:52:05 +0200 Subject: [PATCH 5/9] chore: minor fixes --- app/client/src/git/ce/constants/messages.tsx | 2 +- app/client/src/git/components/ImportModal/index.tsx | 8 +++++++- .../src/git/components/ImportOverrideModal/index.tsx | 6 ++++-- app/client/src/git/hooks/useImport.ts | 5 +++++ app/client/src/git/store/actions/gitImportActions.ts | 7 +++++++ app/client/src/git/store/gitGlobalSlice.ts | 2 ++ 6 files changed, 26 insertions(+), 4 deletions(-) diff --git a/app/client/src/git/ce/constants/messages.tsx b/app/client/src/git/ce/constants/messages.tsx index a69144c0f6f3..24d183fb7581 100644 --- a/app/client/src/git/ce/constants/messages.tsx +++ b/app/client/src/git/ce/constants/messages.tsx @@ -9,7 +9,7 @@ export const IMPORT_OVERRIDE_MODAL = { DESCRIPTION: "{{newArtifactName}} already exists in this workspace as {{oldArtifactName}}. Do you want to override it with the imported {{artifactType}}?", CANCEL_BTN: "Cancel", - OVERRIDE_BTN: "Import and override {{artifactType}}", + OVERRIDE_BTN: "Override", }; export const CONNECT_GIT = { diff --git a/app/client/src/git/components/ImportModal/index.tsx b/app/client/src/git/components/ImportModal/index.tsx index 0f8db29140a7..31932d55d925 100644 --- a/app/client/src/git/components/ImportModal/index.tsx +++ b/app/client/src/git/components/ImportModal/index.tsx @@ -11,6 +11,7 @@ function ImportModal() { gitImportError, isGitImportLoading, isImportModalOpen, + resetGitImport, toggleImportModal, } = useImport(); const { @@ -29,6 +30,11 @@ function ImportModal() { [gitImport], ); + const resetConnectState = useCallback(() => { + resetGlobalSSHKey(); + resetGitImport(); + }, [resetGitImport, resetGlobalSSHKey]); + return ( diff --git a/app/client/src/git/components/ImportOverrideModal/index.tsx b/app/client/src/git/components/ImportOverrideModal/index.tsx index c995b2deefc5..57d62aba6101 100644 --- a/app/client/src/git/components/ImportOverrideModal/index.tsx +++ b/app/client/src/git/components/ImportOverrideModal/index.tsx @@ -9,16 +9,18 @@ function ImportOverrideModal() { importOverrideParams, isGitImportLoading, isImportOverrideModalOpen, + resetGitImport, resetImportOverrideParams, } = useImport(); const handleOpenChange = useCallback( (open: boolean) => { - if (!open) { + if (!open && !isGitImportLoading) { resetImportOverrideParams(); + resetGitImport(); } }, - [resetImportOverrideParams], + [isGitImportLoading, resetGitImport, resetImportOverrideParams], ); const handleImport = useCallback(() => { diff --git a/app/client/src/git/hooks/useImport.ts b/app/client/src/git/hooks/useImport.ts index 529e7ef17bf1..b1d014650050 100644 --- a/app/client/src/git/hooks/useImport.ts +++ b/app/client/src/git/hooks/useImport.ts @@ -21,6 +21,10 @@ export default function useImport() { [dispatch], ); + const resetGitImport = useCallback(() => { + dispatch(gitGlobalActions.resetGitImport()); + }, [dispatch]); + const isImportModalOpen = useSelector(selectImportModalOpen); const toggleImportModal = useCallback( @@ -49,6 +53,7 @@ export default function useImport() { isGitImportLoading: gitImportState?.loading ?? false, gitImportError: gitImportState?.error ?? null, gitImport, + resetGitImport, isImportModalOpen: isImportModalOpen ?? false, toggleImportModal, isImportOverrideModalOpen: isImportOverrideModalOpen ?? false, diff --git a/app/client/src/git/store/actions/gitImportActions.ts b/app/client/src/git/store/actions/gitImportActions.ts index a823ca7b6d4b..748e921fd9c6 100644 --- a/app/client/src/git/store/actions/gitImportActions.ts +++ b/app/client/src/git/store/actions/gitImportActions.ts @@ -48,3 +48,10 @@ export const gitImportErrorAction = ( return state; }; + +export const resetGitImportAction = (state: GitGlobalReduxState) => { + state.gitImport.loading = false; + state.gitImport.error = null; + + return state; +}; diff --git a/app/client/src/git/store/gitGlobalSlice.ts b/app/client/src/git/store/gitGlobalSlice.ts index 38d9feed98bb..7864aed9d867 100644 --- a/app/client/src/git/store/gitGlobalSlice.ts +++ b/app/client/src/git/store/gitGlobalSlice.ts @@ -19,6 +19,7 @@ import { gitImportErrorAction, gitImportInitAction, gitImportSuccessAction, + resetGitImportAction, } from "./actions/gitImportActions"; import { fetchGlobalSSHKeyErrorAction, @@ -45,6 +46,7 @@ export const gitGlobalSlice = createSlice({ gitImportInit: gitImportInitAction, gitImportSuccess: gitImportSuccessAction, gitImportError: gitImportErrorAction, + resetGitImport: resetGitImportAction, toggleImportModal: toggleImportModalAction, resetImportOverrideParams: resetImportOverrideParamsAction, setImportOverrideParams: setImportOverrideParamsAction, From 8e3e342feb1ba093e4debca8460b850432881ada Mon Sep 17 00:00:00 2001 From: Rudraprasad Das Date: Mon, 28 Apr 2025 20:34:15 +0200 Subject: [PATCH 6/9] chore: retain name while importing --- .../components/ImportOverrideModal/index.tsx | 38 ++++++------------- app/client/src/git/hooks/useImport.ts | 21 +++++----- app/client/src/git/sagas/gitImportSaga.ts | 38 +++++++++++++++++-- app/client/src/git/store/actions/uiActions.ts | 18 ++++++--- app/client/src/git/store/gitGlobalSlice.ts | 8 ++-- .../git/store/selectors/gitGlobalSelectors.ts | 6 +-- app/client/src/git/store/types.ts | 6 ++- 7 files changed, 82 insertions(+), 53 deletions(-) diff --git a/app/client/src/git/components/ImportOverrideModal/index.tsx b/app/client/src/git/components/ImportOverrideModal/index.tsx index 57d62aba6101..cee5161dbf35 100644 --- a/app/client/src/git/components/ImportOverrideModal/index.tsx +++ b/app/client/src/git/components/ImportOverrideModal/index.tsx @@ -1,58 +1,42 @@ -import React, { useCallback, useMemo } from "react"; +import React, { useCallback } from "react"; import ImportOverrideModalView from "./ImportOverrideModalView"; import useImport from "git/hooks/useImport"; function ImportOverrideModal() { const { gitImport, - gitImportError, - importOverrideParams, + importOverrideDetails, isGitImportLoading, isImportOverrideModalOpen, resetGitImport, - resetImportOverrideParams, + resetImportOverrideDetails, } = useImport(); const handleOpenChange = useCallback( (open: boolean) => { if (!open && !isGitImportLoading) { - resetImportOverrideParams(); + resetImportOverrideDetails(); resetGitImport(); } }, - [isGitImportLoading, resetGitImport, resetImportOverrideParams], + [isGitImportLoading, resetGitImport, resetImportOverrideDetails], ); const handleImport = useCallback(() => { - if (importOverrideParams) { - gitImport({ ...importOverrideParams, override: true }); - } - }, [gitImport, importOverrideParams]); - - const { newArtifactName, oldArtifactName } = useMemo(() => { - let artifactNames = { newArtifactName: null, oldArtifactName: null }; - - if (gitImportError?.message) { - const jsonMatch = gitImportError.message.match(/\{.*\}/); - const jsonStr = jsonMatch ? jsonMatch[0] : null; + if (importOverrideDetails) { + const params = { ...importOverrideDetails.params, override: true }; - if (jsonStr) { - try { - artifactNames = JSON.parse(jsonStr); - } catch {} - } + gitImport(params); } - - return artifactNames; - }, [gitImportError]); + }, [gitImport, importOverrideDetails]); return ( diff --git a/app/client/src/git/hooks/useImport.ts b/app/client/src/git/hooks/useImport.ts index b1d014650050..50d4beb26c34 100644 --- a/app/client/src/git/hooks/useImport.ts +++ b/app/client/src/git/hooks/useImport.ts @@ -3,11 +3,12 @@ import { useDispatch, useSelector } from "react-redux"; import { selectGitImportState, selectImportModalOpen, + selectImportOverrideDetails, selectImportOverrideModalOpen, - selectImportOverrideParams, } from "git/store/selectors/gitGlobalSelectors"; import { gitGlobalActions } from "git/store/gitGlobalSlice"; import type { GitImportRequestParams } from "git/requests/gitImportRequest.types"; +import type { SetImportOverrideDetailsPayload } from "git/store/actions/uiActions"; export default function useImport() { const dispatch = useDispatch(); @@ -36,17 +37,17 @@ export default function useImport() { const isImportOverrideModalOpen = useSelector(selectImportOverrideModalOpen); - const importOverrideParams = useSelector(selectImportOverrideParams); + const importOverrideDetails = useSelector(selectImportOverrideDetails); - const setImportOverrideParams = useCallback( - (params: GitImportRequestParams) => { - dispatch(gitGlobalActions.setImportOverrideParams(params)); + const setImportOverrideDetails = useCallback( + (details: SetImportOverrideDetailsPayload) => { + dispatch(gitGlobalActions.setImportOverrideDetails(details)); }, [dispatch], ); - const resetImportOverrideParams = useCallback(() => { - dispatch(gitGlobalActions.resetImportOverrideParams()); + const resetImportOverrideDetails = useCallback(() => { + dispatch(gitGlobalActions.resetImportOverrideDetails()); }, [dispatch]); return { @@ -57,8 +58,8 @@ export default function useImport() { isImportModalOpen: isImportModalOpen ?? false, toggleImportModal, isImportOverrideModalOpen: isImportOverrideModalOpen ?? false, - importOverrideParams, - setImportOverrideParams, - resetImportOverrideParams, + importOverrideDetails, + setImportOverrideDetails, + resetImportOverrideDetails, }; } diff --git a/app/client/src/git/sagas/gitImportSaga.ts b/app/client/src/git/sagas/gitImportSaga.ts index 274294f05d42..4709245d686c 100644 --- a/app/client/src/git/sagas/gitImportSaga.ts +++ b/app/client/src/git/sagas/gitImportSaga.ts @@ -2,13 +2,17 @@ import { call, put, select } from "redux-saga/effects"; import { validateResponse } from "sagas/ErrorSagas"; import type { PayloadAction } from "@reduxjs/toolkit"; import gitImportRequest from "git/requests/gitImportRequest"; -import type { GitImportResponse } from "git/requests/gitImportRequest.types"; +import type { + GitImportRequestParams, + GitImportResponse, +} from "git/requests/gitImportRequest.types"; import type { GitImportInitPayload } from "git/store/actions/gitImportActions"; import { gitGlobalActions } from "git/store/gitGlobalSlice"; import { getWorkspaceIdForImport } from "ee/selectors/applicationSelectors"; import { GitErrorCodes } from "git/constants/enums"; import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors"; import handleApiErrors from "./helpers/handleApiErrors"; +import type { GitApiError } from "git/store/types"; export default function* gitImportSaga( action: PayloadAction, @@ -36,6 +40,7 @@ export default function* gitImportSaga( gitGlobalActions.gitImportSuccess({ responseData: response.data }), ); yield put(gitGlobalActions.toggleImportModal({ open: false })); + yield put(gitGlobalActions.resetImportOverrideDetails()); } } catch (e) { const error = handleApiErrors(e as Error, response); @@ -49,9 +54,36 @@ export default function* gitImportSaga( } if (GitErrorCodes.DUPLICATE_ARTIFACT_OVERRIDE === error.code) { - yield put(gitGlobalActions.setImportOverrideParams(params)); - yield put(gitGlobalActions.toggleImportModal({ open: false })); + yield call(handleDuplicateArtifactOverride, error, params); } } } } + +function* handleDuplicateArtifactOverride( + error: GitApiError, + params: GitImportRequestParams, +) { + yield put(gitGlobalActions.toggleImportModal({ open: false })); + + let artifactNames = { newArtifactName: null, oldArtifactName: null }; + + if (error?.message) { + const jsonMatch = error.message.match(/\{.*\}/); + const jsonStr = jsonMatch ? jsonMatch[0] : null; + + if (jsonStr) { + try { + artifactNames = JSON.parse(jsonStr); + } catch {} + } + } + + yield put( + gitGlobalActions.setImportOverrideDetails({ + params, + oldArtifactName: artifactNames.oldArtifactName ?? "", + newArtifactName: artifactNames.newArtifactName ?? "", + }), + ); +} diff --git a/app/client/src/git/store/actions/uiActions.ts b/app/client/src/git/store/actions/uiActions.ts index 611f4a3544ad..ebf205366e99 100644 --- a/app/client/src/git/store/actions/uiActions.ts +++ b/app/client/src/git/store/actions/uiActions.ts @@ -48,17 +48,25 @@ export const toggleImportModalAction = ( return state; }; -export const resetImportOverrideParamsAction = (state: GitGlobalReduxState) => { - state.importOverrideParams = null; +export const resetImportOverrideDetailsAction = ( + state: GitGlobalReduxState, +) => { + state.importOverrideDetails = null; return state; }; -export const setImportOverrideParamsAction = ( +export interface SetImportOverrideDetailsPayload { + params: GitImportRequestParams; + oldArtifactName: string; + newArtifactName: string; +} + +export const setImportOverrideDetailsAction = ( state: GitGlobalReduxState, - action: PayloadAction, + action: PayloadAction, ) => { - state.importOverrideParams = { ...action.payload }; + state.importOverrideDetails = { ...action.payload }; return state; }; diff --git a/app/client/src/git/store/gitGlobalSlice.ts b/app/client/src/git/store/gitGlobalSlice.ts index 7864aed9d867..2dc8d0028393 100644 --- a/app/client/src/git/store/gitGlobalSlice.ts +++ b/app/client/src/git/store/gitGlobalSlice.ts @@ -11,8 +11,8 @@ import { } from "./actions/updateGlobalProfileActions"; import { gitGlobalInitialState } from "./helpers/initialState"; import { - resetImportOverrideParamsAction, - setImportOverrideParamsAction, + resetImportOverrideDetailsAction, + setImportOverrideDetailsAction, toggleImportModalAction, } from "./actions/uiActions"; import { @@ -48,8 +48,8 @@ export const gitGlobalSlice = createSlice({ gitImportError: gitImportErrorAction, resetGitImport: resetGitImportAction, toggleImportModal: toggleImportModalAction, - resetImportOverrideParams: resetImportOverrideParamsAction, - setImportOverrideParams: setImportOverrideParamsAction, + resetImportOverrideDetails: resetImportOverrideDetailsAction, + setImportOverrideDetails: setImportOverrideDetailsAction, toggleRepoLimitErrorModal: toggleRepoLimitErrorModalAction, }, }); diff --git a/app/client/src/git/store/selectors/gitGlobalSelectors.ts b/app/client/src/git/store/selectors/gitGlobalSelectors.ts index cfa2a13b5f4d..84d320cd4c22 100644 --- a/app/client/src/git/store/selectors/gitGlobalSelectors.ts +++ b/app/client/src/git/store/selectors/gitGlobalSelectors.ts @@ -15,10 +15,10 @@ export const selectImportModalOpen = (state: GitRootState) => selectGitGlobal(state).isImportModalOpen; export const selectImportOverrideModalOpen = (state: GitRootState) => - !!selectGitGlobal(state).importOverrideParams; + !!selectGitGlobal(state).importOverrideDetails; -export const selectImportOverrideParams = (state: GitRootState) => - selectGitGlobal(state).importOverrideParams ?? null; +export const selectImportOverrideDetails = (state: GitRootState) => + selectGitGlobal(state).importOverrideDetails ?? null; export const selectGitImportState = (state: GitRootState) => selectGitGlobal(state).gitImport; diff --git a/app/client/src/git/store/types.ts b/app/client/src/git/store/types.ts index 96975bad0223..93d26e5b440d 100644 --- a/app/client/src/git/store/types.ts +++ b/app/client/src/git/store/types.ts @@ -99,7 +99,11 @@ export interface GitGlobalReduxState { globalSSHKey: GitAsyncState; // ui isImportModalOpen: boolean; - importOverrideParams: GitImportRequestParams | null; + importOverrideDetails: { + params: GitImportRequestParams; + oldArtifactName: string; + newArtifactName: string; + } | null; repoLimitErrorModalOpen: boolean; } From 91b03e0df6af2aaf791a7c9b244d3cf061384380 Mon Sep 17 00:00:00 2001 From: Rudraprasad Das Date: Mon, 28 Apr 2025 20:43:35 +0200 Subject: [PATCH 7/9] chore: fixing build --- app/client/src/git/store/helpers/initialState.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/client/src/git/store/helpers/initialState.ts b/app/client/src/git/store/helpers/initialState.ts index b48d2d0b3d90..324cace8d9bd 100644 --- a/app/client/src/git/store/helpers/initialState.ts +++ b/app/client/src/git/store/helpers/initialState.ts @@ -168,6 +168,6 @@ export const gitGlobalInitialState: GitGlobalReduxState = { error: null, }, isImportModalOpen: false, - importOverrideParams: null, + importOverrideDetails: null, repoLimitErrorModalOpen: false, }; From 84b16ad22444e5c98b92914057363a7a1a8f3033 Mon Sep 17 00:00:00 2001 From: sondermanish Date: Tue, 29 Apr 2025 14:14:38 +0530 Subject: [PATCH 8/9] ce changes --- .../appsmith/git/files/FileUtilsCEImpl.java | 10 +- .../appsmith/external/git/FileInterface.java | 2 + .../appsmith/external/models/ErrorType.java | 1 + .../appsmith/server/dtos/GitConnectDTO.java | 9 + .../server/exceptions/AppsmithError.java | 8 + .../server/exceptions/AppsmithErrorCode.java | 2 + .../git/central/CentralGitServiceCE.java | 3 - .../git/central/CentralGitServiceCEImpl.java | 220 +++--------------- .../git/central/GitHandlingServiceCE.java | 6 + .../git/fs/GitFSServiceCECompatibleImpl.java | 39 ---- .../server/git/fs/GitFSServiceCEImpl.java | 50 ++-- .../server/git/fs/GitFSServiceImpl.java | 39 ---- .../helpers/ce/CommonGitFileUtilsCE.java | 4 +- .../imports/internal/ImportServiceCEImpl.java | 6 + 14 files changed, 98 insertions(+), 301 deletions(-) diff --git a/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java b/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java index 9e50cac97a58..e36eea10f825 100644 --- a/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java +++ b/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java @@ -84,7 +84,7 @@ @Import({GitServiceConfig.class}) public class FileUtilsCEImpl implements FileInterface { - private final GitServiceConfig gitServiceConfig; + protected final GitServiceConfig gitServiceConfig; protected final FSGitHandler fsGitHandler; private final GitExecutor gitExecutor; protected final FileOperations fileOperations; @@ -98,7 +98,7 @@ public class FileUtilsCEImpl implements FileInterface { private static final Pattern ALLOWED_FILE_EXTENSION_PATTERN = Pattern.compile("(.*?)\\.(md|MD|git|gitignore|github|yml|yaml)$"); - private final Scheduler scheduler = Schedulers.boundedElastic(); + protected final Scheduler scheduler = Schedulers.boundedElastic(); private static final String CANVAS_WIDGET = "(Canvas)[0-9]*."; @@ -1250,6 +1250,12 @@ public Mono reconstructMetadataFromGitRepo( return metadataMono.subscribeOn(scheduler); } + @Override + public Mono reconstructPackageJsonFromGitRepository(Path repoSuffix) { + return Mono.error( + new AppsmithPluginException(AppsmithPluginError.PLUGIN_UNSUPPORTED_OPERATION, "package json creation")); + } + @Override public Mono reconstructMetadataFromGitRepository(Path repoSuffix) { Mono metadataMono = Mono.fromCallable(() -> { diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/FileInterface.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/FileInterface.java index 3f48d2880d6b..7d4443f9a2bd 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/FileInterface.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/FileInterface.java @@ -77,6 +77,8 @@ Mono reconstructMetadataFromGitRepo( Mono reconstructMetadataFromGitRepository(Path repoSuffix); + Mono reconstructPackageJsonFromGitRepository(Path repoSuffix); + Mono reconstructPageFromGitRepo( String pageName, String branchName, Path repoSuffixPath, Boolean checkoutRequired); diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/ErrorType.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/ErrorType.java index 8b578a05251e..22bec7da04b0 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/ErrorType.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/ErrorType.java @@ -12,6 +12,7 @@ public enum ErrorType { BAD_REQUEST, INTERNAL_ERROR, ACTION_CONFIGURATION_ERROR, + ARTIFACT_IMPORT_ERROR, GIT_CONFIGURATION_ERROR, GIT_ACTION_EXECUTION_ERROR, GIT_UPSTREAM_CHANGES_PUSH_EXECUTION_ERROR, diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/GitConnectDTO.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/GitConnectDTO.java index 42b2c0d36b57..726e988ded25 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/GitConnectDTO.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/GitConnectDTO.java @@ -11,4 +11,13 @@ public class GitConnectDTO { String remoteUrl; GitProfile gitProfile; + + /** + * This attribute has been placed specifically for packages, + * In multi instance setup, the packages in PROD are present in non git connected state. + * Once the DEV package connects to git, the prod would also require the git connected package + * however importing a new package in PROD workspace would cause problems, and we can't delete existing + * consumed packages, hence we would override prod package with same UUID. + */ + Boolean override; } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithError.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithError.java index 5eccc61ec14c..b3f2be785949 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithError.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithError.java @@ -876,6 +876,14 @@ public enum AppsmithError { "Duplicate Configuration", ErrorType.BAD_REQUEST, null), + ARTIFACT_IMPORT_DUPLICATE_KEY_WRITE_ERROR( + 500, + AppsmithErrorCode.ARTIFACT_IMPORT_DUPLICATE_KEY_WRITE_ERROR.getCode(), + "Duplicate key detected while importing artifact into the workspace during a write operation to the server.. Details: {0}", + AppsmithErrorAction.DEFAULT, + "Import operation failed because of a duplicate key error.", + ErrorType.ARTIFACT_IMPORT_ERROR, + null), INVALID_PROPERTIES_CONFIGURATION( 500, AppsmithErrorCode.INVALID_PROPERTIES_CONFIGURATION.getCode(), diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithErrorCode.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithErrorCode.java index 667438a61f84..c493a05a19da 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithErrorCode.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithErrorCode.java @@ -103,6 +103,8 @@ public enum AppsmithErrorCode { JSON_PROCESSING_ERROR("AE-JSN-4001", "Json processing error"), INCOMPATIBLE_IMPORTED_JSON("AE-JSN-4045", "Incompatible imported json"), GENERIC_JSON_IMPORT_ERROR("AE-JSN-4049", "Generic json import error"), + ARTIFACT_IMPORT_DUPLICATE_KEY_WRITE_ERROR( + "AE-JSN-5001", "Artifact import failed due to a duplicate key conflict during write operation"), INVALID_LOGIN_METHOD("AE-LGN-4000", "Invalid login method"), PLUGIN_NOT_INSTALLED("AE-PLG-4001", "Plugin not installed"), PLUGIN_ID_NOT_GIVEN("AE-PLG-4002", "Plugin id not given"), diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java index 988ed7a00939..5c84188dec40 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java @@ -21,9 +21,6 @@ public interface CentralGitServiceCE { - Mono importArtifactFromGit( - String workspaceId, GitConnectDTO gitConnectDTO, ArtifactType artifactType, GitType gitType); - Mono importArtifactFromGit( String workspaceId, GitConnectDTO gitConnectDTO, GitType gitType); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java index 2b4139a62293..d7bfc5961f10 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java @@ -161,11 +161,11 @@ public Mono importArtifactFromGit( final String repoName = gitHandlingService.getRepoName(gitConnectDTO); // since at this point in the import flow, there is no context about the artifact type - // it needs to be retrieved from the fetched repository itself. however, in order to retrieve - // the artifact type from repository, the repository needs to be saved. - // for saving the repo an identifier is required (which usually is the artifact id); + // it needs to be retrieved from the fetched repository itself. however, to retrieve + // the artifact type from the repository, the repository needs to be saved. + // for saving the repository, an identifier is required (which usually is the artifact id); // however, the artifact could only be generated after the artifact type is known. - // hence this is a temporary placeholder to hold the repository and it's components + // hence this is a temporary placeholder to hold the repository and its components String placeholder = "temp" + UUID.randomUUID(); ArtifactJsonTransformationDTO tempJsonTransformationDTO = new ArtifactJsonTransformationDTO(workspaceId, placeholder, repoName); @@ -203,7 +203,7 @@ public Mono importArtifactFromGit( .flatMap(defaultBranch -> { return Mono.zip( Mono.just(defaultBranch), - gitHandlingService.obtainArtifactTypeFromGitRepository( + gitHandlingService.obtainArtifactTypeAndIdentifierFromGitRepository( tempJsonTransformationDTO), isRepositoryPrivateMonoCached, Mono.just(gitAuth)); @@ -211,7 +211,8 @@ public Mono importArtifactFromGit( }) .flatMap(tuple4 -> { String defaultBranch = tuple4.getT1(); - ArtifactType artifactType = tuple4.getT2(); + ArtifactType artifactType = tuple4.getT2().getT1(); + String uniqueIdentifier = tuple4.getT2().getT2(); Boolean isRepoPrivate = tuple4.getT3(); GitAuth gitAuth = tuple4.getT4(); @@ -224,7 +225,8 @@ public Mono importArtifactFromGit( AppsmithError.NO_RESOURCE_FOUND, FieldName.WORKSPACE, workspaceId))); return workspaceMono - .flatMap(workspace -> contextHelper.createArtifactForImport(workspaceId, repoName)) + .flatMap(workspace -> createArtifactForGitConnect( + gitConnectDTO, artifactType, workspaceId, repoName, uniqueIdentifier)) .map(baseArtifact -> { GitArtifactMetadata gitArtifactMetadata = new GitArtifactMetadata(); gitArtifactMetadata.setGitAuth(gitAuth); @@ -240,6 +242,12 @@ public Mono importArtifactFromGit( baseArtifact.setGitArtifactMetadata(gitArtifactMetadata); return baseArtifact; }); + }) + .onErrorResume(error -> { + Mono removeRepositoryMono = + gitHandlingService.removeRepository(tempJsonTransformationDTO, TRUE); + + return removeRepositoryMono.then(Mono.error(error)); }); Mono containerArtifactForImport = Mono.usingWhen( @@ -267,7 +275,7 @@ public Mono importArtifactFromGit( GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(baseArtifact.getArtifactType()); - Mono> datasourceMono = datasourceService + Mono> existingWorkspaceDatasourceMono = datasourceService .getAllByWorkspaceIdWithStorages(workspaceId, datasourcePermission.getEditPermission()) .collectList(); @@ -282,7 +290,7 @@ public Mono importArtifactFromGit( new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR, error.getMessage())); }); - return Mono.zip(artifactExchangeJsonMono, datasourceMono, pluginMono) + return Mono.zip(artifactExchangeJsonMono, existingWorkspaceDatasourceMono, pluginMono) .flatMap(data -> { ArtifactExchangeJson artifactExchangeJson = data.getT1(); List datasourceList = data.getT2(); @@ -312,7 +320,14 @@ public Mono importArtifactFromGit( .importArtifactInWorkspaceFromGit( workspaceId, baseArtifact.getId(), artifactExchangeJson, defaultBranch) .onErrorResume(throwable -> { - log.error("Error in importing the artifact {}", baseArtifact.getId()); + log.error( + "Error in importing the artifact {}", + baseArtifact.getId(), + throwable); + if (throwable instanceof AppsmithException) { + return Mono.error(throwable); + } + return Mono.error(new AppsmithException( AppsmithError.GIT_FILE_SYSTEM_ERROR, throwable.getMessage())); }); @@ -343,183 +358,18 @@ public Mono importArtifactFromGit( sink -> importGitArtifactMono.subscribe(sink::success, sink::error, null, sink.currentContext())); } - protected Mono hydrateLatest(Artifact artifact) { - return Mono.just(artifact); + protected Mono createArtifactForGitConnect( + GitConnectDTO gitConnectDTO, + ArtifactType artifactType, + String workspaceId, + String repoName, + String uniqueIdentifier) { + GitArtifactHelper contextHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); + return contextHelper.createArtifactForImport(workspaceId, repoName); } - @Override - public Mono importArtifactFromGit( - String workspaceId, GitConnectDTO gitConnectDTO, ArtifactType artifactType, GitType gitType) { - // 1. Check private repo limit for workspace - // 2. Create dummy artifact, clone repo from remote - // 3. Re-hydrate artifact to DB from local repo - // a. Save the ssh keys in artifact object with other details - // b. During import-export need to handle the DS(empty vs non-empty) - // 4. Return artifact - - if (!StringUtils.hasText(workspaceId)) { - return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, "Invalid workspace id")); - } - - GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType); - Set errors = gitHandlingService.validateGitConnectDTO(gitConnectDTO); - - if (!CollectionUtils.isEmpty(errors)) { - return Mono.error(new AppsmithException( - AppsmithError.INVALID_PARAMETER, errors.stream().findAny().get())); - } - - GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); - AclPermission artifactCreatePermission = gitArtifactHelper.getWorkspaceArtifactCreationPermission(); - - // TODO: permission bit deferred to gitArtifactHelper - Mono workspaceMono = workspaceService - .findById(workspaceId, artifactCreatePermission) - .switchIfEmpty(Mono.error( - new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.WORKSPACE, workspaceId))); - - final String repoName = gitHandlingService.getRepoName(gitConnectDTO); - Mono isRepositoryPrivateMono = - gitHandlingService.isRepoPrivate(gitConnectDTO).cache(); - Mono isRepositoryLimitReachedForWorkspaceMono = isRepositoryPrivateMono.flatMap( - isRepositoryPrivate -> isRepositoryLimitReachedForWorkspace(workspaceId, isRepositoryPrivate)); - - Mono importedArtifactMono = workspaceMono - .then(Mono.defer(() -> isRepositoryLimitReachedForWorkspaceMono)) - .flatMap(isRepositoryLimitReached -> { - Mono gitAuthForUserMono = - gitHandlingService.getGitAuthForUser().cache(); - Mono createArtifactMono = gitArtifactHelper - .createArtifactForImport(workspaceId, repoName) - .cache(); - - if (FALSE.equals(isRepositoryLimitReached)) { - return gitAuthForUserMono.zipWith(createArtifactMono); - } - - // TODO: Change errors to artifact level. - return gitAnalyticsUtils - .addAnalyticsForGitOperation( - AnalyticsEvents.GIT_IMPORT, - gitArtifactHelper.getNewArtifact(workspaceId, repoName), - AppsmithError.GIT_APPLICATION_LIMIT_ERROR.getErrorType(), - AppsmithError.GIT_APPLICATION_LIMIT_ERROR.getMessage(), - true) - .then(Mono.error(new AppsmithException(AppsmithError.GIT_APPLICATION_LIMIT_ERROR))); - }) - .flatMap(tuple2 -> { - GitAuth gitAuth = tuple2.getT1(); - Artifact artifact = tuple2.getT2(); - - Mono> profileMono = gitProfileUtils.updateOrCreateGitProfileForCurrentUser( - gitConnectDTO.getGitProfile(), artifact.getId()); - - Mono fetchRemoteRepository = - gitHandlingService.fetchRemoteRepository(gitConnectDTO, gitAuth, artifact, repoName); - - return fetchRemoteRepository - .zipWith(isRepositoryPrivateMono) - .flatMap(tuple -> { - String defaultBranch = tuple.getT1(); - Boolean isRepoPrivate = tuple.getT2(); - - GitArtifactMetadata gitArtifactMetadata = new GitArtifactMetadata(); - gitArtifactMetadata.setGitAuth(gitAuth); - gitArtifactMetadata.setDefaultArtifactId(artifact.getId()); - gitArtifactMetadata.setDefaultBranchName(defaultBranch); - gitArtifactMetadata.setRefName(defaultBranch); - gitArtifactMetadata.setRepoName(repoName); - gitArtifactMetadata.setIsRepoPrivate(isRepoPrivate); - gitArtifactMetadata.setLastCommittedAt(Instant.now()); - - gitHandlingService.setRepositoryDetailsInGitArtifactMetadata( - gitConnectDTO, gitArtifactMetadata); - artifact.setGitArtifactMetadata(gitArtifactMetadata); - return Mono.just(artifact).zipWith(profileMono); - }); - }) - .flatMap(tuple2 -> { - Artifact artifact = tuple2.getT1(); - GitArtifactMetadata gitArtifactMetadata = artifact.getGitArtifactMetadata(); - String defaultBranch = gitArtifactMetadata.getDefaultBranchName(); - - Mono> datasourceMono = datasourceService - .getAllByWorkspaceIdWithStorages(workspaceId, datasourcePermission.getEditPermission()) - .collectList(); - - Mono> pluginMono = - pluginService.getDefaultPlugins().collectList(); - - ArtifactJsonTransformationDTO jsonMorphDTO = new ArtifactJsonTransformationDTO(); - jsonMorphDTO.setWorkspaceId(workspaceId); - jsonMorphDTO.setBaseArtifactId(artifact.getId()); - jsonMorphDTO.setArtifactType(artifactType); - jsonMorphDTO.setRepoName(gitArtifactMetadata.getRepoName()); - jsonMorphDTO.setRefType(RefType.branch); - jsonMorphDTO.setRefName(defaultBranch); - - Mono artifactExchangeJsonMono = gitHandlingService - .reconstructArtifactJsonFromGitRepository(jsonMorphDTO) - .onErrorResume(error -> { - log.error("Error while constructing artifact from git repo", error); - return deleteArtifactCreatedFromGitImport(jsonMorphDTO, gitType) - .then(Mono.error(new AppsmithException( - AppsmithError.GIT_FILE_SYSTEM_ERROR, error.getMessage()))); - }); - - return Mono.zip(artifactExchangeJsonMono, datasourceMono, pluginMono) - .flatMap(data -> { - ArtifactExchangeJson artifactExchangeJson = data.getT1(); - List datasourceList = data.getT2(); - List pluginList = data.getT3(); - - if (artifactExchangeJson.getArtifact() == null - || gitArtifactHelper.isContextInArtifactEmpty(artifactExchangeJson)) { - return deleteArtifactCreatedFromGitImport(jsonMorphDTO, gitType) - .then(Mono.error(new AppsmithException( - AppsmithError.GIT_ACTION_FAILED, - "import", - "Cannot import artifact from an empty repo"))); - } - // If there is an existing datasource with the same name but a different type from that - // in the repo, the import api should fail - // TODO: change the implementation to compare datasource with gitSyncIds instead. - if (checkIsDatasourceNameConflict( - datasourceList, artifactExchangeJson.getDatasourceList(), pluginList)) { - return deleteArtifactCreatedFromGitImport(jsonMorphDTO, gitType) - .then(Mono.error(new AppsmithException( - AppsmithError.GIT_ACTION_FAILED, - "import", - "Datasource already exists with the same name"))); - } - - artifactExchangeJson.getArtifact().setGitArtifactMetadata(gitArtifactMetadata); - return importService - .importArtifactInWorkspaceFromGit( - workspaceId, artifact.getId(), artifactExchangeJson, defaultBranch) - .onErrorResume(throwable -> deleteArtifactCreatedFromGitImport( - jsonMorphDTO, gitType) - .then(Mono.error(new AppsmithException( - AppsmithError.GIT_FILE_SYSTEM_ERROR, throwable.getMessage())))); - }); - }) - .flatMap(artifact -> gitArtifactHelper.publishArtifact(artifact, false)) - // Add un-configured datasource to the list to response - .flatMap(artifact -> importService.getArtifactImportDTO( - artifact.getWorkspaceId(), artifact.getId(), artifact, artifactType)) - // Add analytics event - .flatMap(artifactImportDTO -> { - Artifact artifact = artifactImportDTO.getArtifact(); - return gitAnalyticsUtils - .addAnalyticsForGitOperation( - AnalyticsEvents.GIT_IMPORT, - artifact, - artifact.getGitArtifactMetadata().getIsRepoPrivate()) - .thenReturn(artifactImportDTO); - }); - - return Mono.create( - sink -> importedArtifactMono.subscribe(sink::success, sink::error, null, sink.currentContext())); + protected Mono hydrateLatest(Artifact artifact) { + return Mono.just(artifact); } private Mono deleteArtifactCreatedFromGitImport( diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java index f19a7a4b8943..3dd660ba6eb5 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java @@ -41,6 +41,9 @@ Mono updateImportedRepositoryDetails( Mono obtainArtifactTypeFromGitRepository(ArtifactJsonTransformationDTO jsonTransformationDTO); + Mono> obtainArtifactTypeAndIdentifierFromGitRepository( + ArtifactJsonTransformationDTO jsonTransformationDTO); + Mono fetchRemoteRepository( GitConnectDTO gitConnectDTO, GitAuth gitAuth, ArtifactJsonTransformationDTO jsonTransformationDTO); @@ -53,6 +56,9 @@ Mono reconstructArtifactJsonFromGitRepository( void setRepositoryDetailsInGitArtifactMetadata( GitConnectDTO gitConnectDTO, GitArtifactMetadata gitArtifactMetadata); + Mono removeRepository( + ArtifactJsonTransformationDTO artifactJsonTransformationDTO, Boolean isArtifactTypeUnknown); + Mono removeRepository(ArtifactJsonTransformationDTO artifactJsonTransformationDTO); Mono> listBranches( diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCECompatibleImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCECompatibleImpl.java index 4589487e3190..c78337d6032a 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCECompatibleImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCECompatibleImpl.java @@ -1,31 +1,18 @@ package com.appsmith.server.git.fs; import com.appsmith.external.git.handler.FSGitHandler; -import com.appsmith.server.configurations.EmailConfig; -import com.appsmith.server.datasources.base.DatasourceService; -import com.appsmith.server.exports.internal.ExportService; import com.appsmith.server.git.GitRedisUtils; -import com.appsmith.server.git.autocommit.helpers.GitAutoCommitHelper; import com.appsmith.server.git.central.GitHandlingServiceCECompatible; import com.appsmith.server.git.resolver.GitArtifactHelperResolver; import com.appsmith.server.git.utils.GitAnalyticsUtils; -import com.appsmith.server.git.utils.GitProfileUtils; import com.appsmith.server.helpers.CommonGitFileUtils; -import com.appsmith.server.helpers.GitPrivateRepoHelper; -import com.appsmith.server.imports.internal.ImportService; -import com.appsmith.server.plugins.base.PluginService; import com.appsmith.server.repositories.GitDeployKeysRepository; import com.appsmith.server.services.AnalyticsService; import com.appsmith.server.services.FeatureFlagService; import com.appsmith.server.services.SessionUserService; -import com.appsmith.server.services.UserDataService; -import com.appsmith.server.services.UserService; -import com.appsmith.server.services.WorkspaceService; -import com.appsmith.server.solutions.DatasourcePermission; import io.micrometer.observation.ObservationRegistry; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import org.springframework.transaction.reactive.TransactionalOperator; @Slf4j @Service @@ -33,49 +20,23 @@ public class GitFSServiceCECompatibleImpl extends GitFSServiceCEImpl implements public GitFSServiceCECompatibleImpl( GitDeployKeysRepository gitDeployKeysRepository, - GitPrivateRepoHelper gitPrivateRepoHelper, CommonGitFileUtils commonGitFileUtils, GitRedisUtils gitRedisUtils, SessionUserService sessionUserService, - UserDataService userDataService, - UserService userService, - EmailConfig emailConfig, - TransactionalOperator transactionalOperator, AnalyticsService analyticsService, ObservationRegistry observationRegistry, - WorkspaceService workspaceService, - DatasourceService datasourceService, - DatasourcePermission datasourcePermission, - PluginService pluginService, - ExportService exportService, - ImportService importService, FSGitHandler fsGitHandler, - GitAutoCommitHelper gitAutoCommitHelper, - GitProfileUtils gitProfileUtils, GitAnalyticsUtils gitAnalyticsUtils, GitArtifactHelperResolver gitArtifactHelperResolver, FeatureFlagService featureFlagService) { super( gitDeployKeysRepository, - gitPrivateRepoHelper, commonGitFileUtils, gitRedisUtils, sessionUserService, - userDataService, - userService, - emailConfig, - transactionalOperator, analyticsService, observationRegistry, - workspaceService, - datasourceService, - datasourcePermission, - pluginService, - exportService, - importService, fsGitHandler, - gitAutoCommitHelper, - gitProfileUtils, gitAnalyticsUtils, gitArtifactHelperResolver, featureFlagService); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java index 59e69f75b9cf..d87615a1c097 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java @@ -11,9 +11,7 @@ import com.appsmith.external.git.dtos.FetchRemoteDTO; import com.appsmith.external.git.handler.FSGitHandler; import com.appsmith.git.dto.CommitDTO; -import com.appsmith.server.configurations.EmailConfig; import com.appsmith.server.constants.ArtifactType; -import com.appsmith.server.datasources.base.DatasourceService; import com.appsmith.server.domains.Artifact; import com.appsmith.server.domains.GitArtifactMetadata; import com.appsmith.server.domains.GitAuth; @@ -23,29 +21,19 @@ import com.appsmith.server.dtos.GitMergeDTO; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; -import com.appsmith.server.exports.internal.ExportService; import com.appsmith.server.git.GitRedisUtils; -import com.appsmith.server.git.autocommit.helpers.GitAutoCommitHelper; import com.appsmith.server.git.central.GitHandlingServiceCE; import com.appsmith.server.git.dtos.ArtifactJsonTransformationDTO; import com.appsmith.server.git.resolver.GitArtifactHelperResolver; import com.appsmith.server.git.utils.GitAnalyticsUtils; -import com.appsmith.server.git.utils.GitProfileUtils; import com.appsmith.server.helpers.CollectionUtils; import com.appsmith.server.helpers.CommonGitFileUtils; -import com.appsmith.server.helpers.GitPrivateRepoHelper; import com.appsmith.server.helpers.GitUtils; -import com.appsmith.server.imports.internal.ImportService; -import com.appsmith.server.plugins.base.PluginService; import com.appsmith.server.repositories.GitDeployKeysRepository; import com.appsmith.server.services.AnalyticsService; import com.appsmith.server.services.FeatureFlagService; import com.appsmith.server.services.GitArtifactHelper; import com.appsmith.server.services.SessionUserService; -import com.appsmith.server.services.UserDataService; -import com.appsmith.server.services.UserService; -import com.appsmith.server.services.WorkspaceService; -import com.appsmith.server.solutions.DatasourcePermission; import io.micrometer.observation.ObservationRegistry; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -55,7 +43,6 @@ import org.eclipse.jgit.api.errors.TransportException; import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.springframework.stereotype.Service; -import org.springframework.transaction.reactive.TransactionalOperator; import org.springframework.util.StringUtils; import reactor.core.observability.micrometer.Micrometer; import reactor.core.publisher.Flux; @@ -79,30 +66,14 @@ public class GitFSServiceCEImpl implements GitHandlingServiceCE { private final GitDeployKeysRepository gitDeployKeysRepository; - private final GitPrivateRepoHelper gitPrivateRepoHelper; - private final CommonGitFileUtils commonGitFileUtils; - private final GitRedisUtils gitRedisUtils; + protected final CommonGitFileUtils commonGitFileUtils; + protected final GitRedisUtils gitRedisUtils; protected final SessionUserService sessionUserService; - private final UserDataService userDataService; - protected final UserService userService; - private final EmailConfig emailConfig; - private final TransactionalOperator transactionalOperator; protected final AnalyticsService analyticsService; private final ObservationRegistry observationRegistry; - private final WorkspaceService workspaceService; - private final DatasourceService datasourceService; - private final DatasourcePermission datasourcePermission; - private final PluginService pluginService; - - private final ExportService exportService; - private final ImportService importService; - protected final FSGitHandler fsGitHandler; - private final GitAutoCommitHelper gitAutoCommitHelper; - - private final GitProfileUtils gitProfileUtils; private final GitAnalyticsUtils gitAnalyticsUtils; protected final GitArtifactHelperResolver gitArtifactHelperResolver; @@ -202,6 +173,12 @@ public Mono fetchRemoteRepository( }); } + @Override + public Mono> obtainArtifactTypeAndIdentifierFromGitRepository( + ArtifactJsonTransformationDTO jsonTransformationDTO) { + return obtainArtifactTypeFromGitRepository(jsonTransformationDTO).zipWith(Mono.just("")); + } + public Mono obtainArtifactTypeFromGitRepository(ArtifactJsonTransformationDTO jsonTransformationDTO) { String workspaceId = jsonTransformationDTO.getWorkspaceId(); String placeHolder = jsonTransformationDTO.getBaseArtifactId(); @@ -292,6 +269,17 @@ public Mono reconstructArtifactJsonFromGitReposi artifactJsonTransformationDTO)); } + @Override + public Mono removeRepository( + ArtifactJsonTransformationDTO artifactJsonTransformationDTO, Boolean isArtifactTypeUnknown) { + // Since the artifact type is unknown, we can assume that the repository is yet to be + if (TRUE.equals(isArtifactTypeUnknown)) { + artifactJsonTransformationDTO.setArtifactType(ArtifactType.APPLICATION); + } + + return removeRepository(artifactJsonTransformationDTO); + } + @Override public Mono removeRepository(ArtifactJsonTransformationDTO artifactJsonTransformationDTO) { GitArtifactHelper gitArtifactHelper = diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceImpl.java index 476702dbba6b..18c21d864e2a 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceImpl.java @@ -1,31 +1,18 @@ package com.appsmith.server.git.fs; import com.appsmith.external.git.handler.FSGitHandler; -import com.appsmith.server.configurations.EmailConfig; -import com.appsmith.server.datasources.base.DatasourceService; -import com.appsmith.server.exports.internal.ExportService; import com.appsmith.server.git.GitRedisUtils; -import com.appsmith.server.git.autocommit.helpers.GitAutoCommitHelper; import com.appsmith.server.git.central.GitHandlingService; import com.appsmith.server.git.resolver.GitArtifactHelperResolver; import com.appsmith.server.git.utils.GitAnalyticsUtils; -import com.appsmith.server.git.utils.GitProfileUtils; import com.appsmith.server.helpers.CommonGitFileUtils; -import com.appsmith.server.helpers.GitPrivateRepoHelper; -import com.appsmith.server.imports.internal.ImportService; -import com.appsmith.server.plugins.base.PluginService; import com.appsmith.server.repositories.GitDeployKeysRepository; import com.appsmith.server.services.AnalyticsService; import com.appsmith.server.services.FeatureFlagService; import com.appsmith.server.services.SessionUserService; -import com.appsmith.server.services.UserDataService; -import com.appsmith.server.services.UserService; -import com.appsmith.server.services.WorkspaceService; -import com.appsmith.server.solutions.DatasourcePermission; import io.micrometer.observation.ObservationRegistry; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import org.springframework.transaction.reactive.TransactionalOperator; @Slf4j @Service @@ -33,49 +20,23 @@ public class GitFSServiceImpl extends GitFSServiceCECompatibleImpl implements Gi public GitFSServiceImpl( GitDeployKeysRepository gitDeployKeysRepository, - GitPrivateRepoHelper gitPrivateRepoHelper, CommonGitFileUtils commonGitFileUtils, GitRedisUtils gitRedisUtils, SessionUserService sessionUserService, - UserDataService userDataService, - UserService userService, - EmailConfig emailConfig, - TransactionalOperator transactionalOperator, AnalyticsService analyticsService, ObservationRegistry observationRegistry, - WorkspaceService workspaceService, - DatasourceService datasourceService, - DatasourcePermission datasourcePermission, - PluginService pluginService, - ExportService exportService, - ImportService importService, FSGitHandler fsGitHandler, - GitAutoCommitHelper gitAutoCommitHelper, - GitProfileUtils gitProfileUtils, GitAnalyticsUtils gitAnalyticsUtils, GitArtifactHelperResolver gitArtifactHelperResolver, FeatureFlagService featureFlagService) { super( gitDeployKeysRepository, - gitPrivateRepoHelper, commonGitFileUtils, gitRedisUtils, sessionUserService, - userDataService, - userService, - emailConfig, - transactionalOperator, analyticsService, observationRegistry, - workspaceService, - datasourceService, - datasourcePermission, - pluginService, - exportService, - importService, fsGitHandler, - gitAutoCommitHelper, - gitProfileUtils, gitAnalyticsUtils, gitArtifactHelperResolver, featureFlagService); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java index aa78434d9f6c..fdeae3e1ba21 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java @@ -95,7 +95,7 @@ public class CommonGitFileUtilsCE { protected final ArtifactGitFileUtils applicationGitFileUtils; protected final GitServiceConfig gitServiceConfig; - private final FileInterface fileUtils; + protected final FileInterface fileUtils; private final FileOperations fileOperations; private final AnalyticsService analyticsService; private final SessionUserService sessionUserService; @@ -830,7 +830,7 @@ public Mono moveRepositoryFromTemporaryStorage(Path temporaryPath, Path ab "Error while moving repository from temporary storage {} to permanent storage {}", currentGitPath, targetPath, - error.getMessage()); + error); return Mono.error(error); }) .subscribeOn(Schedulers.boundedElastic()); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/ImportServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/ImportServiceCEImpl.java index ae87724b776a..142ff1fd8e30 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/ImportServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/ImportServiceCEImpl.java @@ -37,6 +37,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.dao.DuplicateKeyException; import org.springframework.http.MediaType; import org.springframework.http.codec.multipart.Part; import org.springframework.stereotype.Service; @@ -530,6 +531,11 @@ private Mono importArtifactInWorkspace( .onErrorResume(throwable -> { String errorMessage = ImportExportUtils.getErrorMessage(throwable); log.error("Error importing {}. Error: {}", artifactContextString, errorMessage, throwable); + + if (throwable instanceof DuplicateKeyException) { + return Mono.error(new AppsmithException( + AppsmithError.ARTIFACT_IMPORT_DUPLICATE_KEY_WRITE_ERROR, "Duplicate artifact key")); + } return Mono.error(new AppsmithException( AppsmithError.GENERIC_JSON_IMPORT_ERROR, workspaceId, errorMessage)); }) From d5435a2664a06e45375c593bd40ec19bd621ae1c Mon Sep 17 00:00:00 2001 From: Rudraprasad Das Date: Tue, 29 Apr 2025 10:57:25 +0200 Subject: [PATCH 9/9] chore: fixing error code --- app/client/src/git/constants/enums.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/client/src/git/constants/enums.ts b/app/client/src/git/constants/enums.ts index 4afd9a625ed8..1b2fe9084e88 100644 --- a/app/client/src/git/constants/enums.ts +++ b/app/client/src/git/constants/enums.ts @@ -37,5 +37,5 @@ export enum GitErrorCodes { REPO_NOT_EMPTY = "AE-GIT-4033", REPO_LIMIT_REACHED = "AE-GIT-4043", PUSH_FAILED_REMOTE_COUNTERPART_IS_AHEAD = "AE-GIT-4048", - DUPLICATE_ARTIFACT_OVERRIDE = "AE-GIT-5003", + DUPLICATE_ARTIFACT_OVERRIDE = "AE-GIT-5004", }