diff --git a/packages/bruno-app/src/components/Environments/ConfirmCloseEnvironment/index.js b/packages/bruno-app/src/components/Environments/ConfirmCloseEnvironment/index.js index 3aa9215c6..94d036d6b 100644 --- a/packages/bruno-app/src/components/Environments/ConfirmCloseEnvironment/index.js +++ b/packages/bruno-app/src/components/Environments/ConfirmCloseEnvironment/index.js @@ -4,7 +4,14 @@ import Modal from 'components/Modal'; import Portal from 'components/Portal'; import Button from 'ui/Button'; -const ConfirmCloseEnvironment = ({ onCancel, onCloseWithoutSave, onSaveAndClose, isGlobal }) => { +const ConfirmCloseEnvironment = ({ onCancel, onCloseWithoutSave, onSaveAndClose, isGlobal, isDotEnv }) => { + let settingsLabel = 'collection environment settings'; + if (isDotEnv) { + settingsLabel = '.env file'; + } else if (isGlobal) { + settingsLabel = 'global environment settings'; + } + return ( Hold on...
- You have unsaved changes in {isGlobal ? 'global' : 'collection'} environment settings. + You have unsaved changes in {settingsLabel}.
diff --git a/packages/bruno-app/src/components/Environments/DotEnvFileEditor/index.js b/packages/bruno-app/src/components/Environments/DotEnvFileEditor/index.js index c1a821dd9..ecefbadfa 100644 --- a/packages/bruno-app/src/components/Environments/DotEnvFileEditor/index.js +++ b/packages/bruno-app/src/components/Environments/DotEnvFileEditor/index.js @@ -217,10 +217,12 @@ const DotEnvFileEditor = ({ ]; formik.resetForm({ values: newValues }); setIsModified(false); + window.dispatchEvent(new Event('dotenv-save-complete')); }) .catch((error) => { console.error(error); toast.error('An error occurred while saving the changes'); + window.dispatchEvent(new Event('dotenv-save-failed')); }) .finally(() => { setIsSaving(false); @@ -240,10 +242,12 @@ const DotEnvFileEditor = ({ .then(() => { toast.success('Changes saved successfully'); setIsModified(false); + window.dispatchEvent(new Event('dotenv-save-complete')); }) .catch((error) => { console.error(error); toast.error('An error occurred while saving the changes'); + window.dispatchEvent(new Event('dotenv-save-failed')); }) .finally(() => { setIsSaving(false); diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js index 856aaf9ba..4c2b2d07e 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js @@ -22,6 +22,7 @@ import { createDotEnvFile, deleteDotEnvFile } from 'providers/ReduxStore/slices/collections/actions'; +import { setEnvironmentsDraft, clearEnvironmentsDraft } from 'providers/ReduxStore/slices/collections'; import { validateName, validateNameError } from 'utils/common/regex'; import toast from 'react-hot-toast'; import classnames from 'classnames'; @@ -72,11 +73,24 @@ const EnvironmentList = ({ const envUids = environments ? environments.map((env) => env.uid) : []; const prevEnvUids = usePrevious(envUids); + const handleDotEnvModifiedChange = useCallback((modified) => { + setIsDotEnvModified(modified); + if (modified) { + dispatch(setEnvironmentsDraft({ + collectionUid: collection.uid, + environmentUid: `dotenv:${selectedDotEnvFile}`, + variables: [] + })); + } else { + dispatch(clearEnvironmentsDraft({ collectionUid: collection.uid })); + } + }, [dispatch, collection.uid, selectedDotEnvFile]); + useEffect(() => { if (dotEnvFiles.length === 0) { setSelectedDotEnvFile(null); setActiveView('environment'); - setIsDotEnvModified(false); + handleDotEnvModifiedChange(false); return; } @@ -424,7 +438,7 @@ const EnvironmentList = ({ dispatch(deleteDotEnvFile(collection.uid, filename)) .then(() => { toast.success(`${filename} file deleted!`); - setIsDotEnvModified(false); + handleDotEnvModifiedChange(false); if (selectedDotEnvFile === filename) { const remainingFiles = dotEnvFiles.filter((f) => f.filename !== filename); if (remainingFiles.length > 0) { @@ -467,7 +481,7 @@ const EnvironmentList = ({ onSave={handleSaveDotEnv} onSaveRaw={handleSaveDotEnvRaw} isModified={isDotEnvModified} - setIsModified={setIsDotEnvModified} + setIsModified={handleDotEnvModifiedChange} dotEnvExists={selectedDotEnvData?.exists} viewMode={dotEnvViewMode} collection={collection} diff --git a/packages/bruno-app/src/components/RequestTabs/RequestTab/index.js b/packages/bruno-app/src/components/RequestTabs/RequestTab/index.js index 64651a253..759eb88b2 100644 --- a/packages/bruno-app/src/components/RequestTabs/RequestTab/index.js +++ b/packages/bruno-app/src/components/RequestTabs/RequestTab/index.js @@ -236,6 +236,7 @@ const RequestTab = ({ tab, collection, tabIndex, collectionRequestTabs, folderUi {showConfirmEnvironmentClose && tab.type === 'environment-settings' && ( setShowConfirmEnvironmentClose(false)} onCloseWithoutSave={() => { dispatch(clearEnvironmentsDraft({ collectionUid: collection.uid })); @@ -244,7 +245,25 @@ const RequestTab = ({ tab, collection, tabIndex, collectionRequestTabs, folderUi }} onSaveAndClose={() => { const draft = collection.environmentsDraft; - if (draft?.environmentUid && draft?.variables) { + if (draft?.environmentUid?.startsWith('dotenv:')) { + const onSuccess = () => { + cleanup(); + dispatch(clearEnvironmentsDraft({ collectionUid: collection.uid })); + dispatch(closeTabs({ tabUids: [tab.uid] })); + setShowConfirmEnvironmentClose(false); + }; + const onFailed = () => { + cleanup(); + setShowConfirmEnvironmentClose(false); + }; + const cleanup = () => { + window.removeEventListener('dotenv-save-complete', onSuccess); + window.removeEventListener('dotenv-save-failed', onFailed); + }; + window.addEventListener('dotenv-save-complete', onSuccess, { once: true }); + window.addEventListener('dotenv-save-failed', onFailed, { once: true }); + window.dispatchEvent(new Event('dotenv-save')); + } else if (draft?.environmentUid && draft?.variables) { dispatch(saveEnvironment(draft.variables, draft.environmentUid, collection.uid)) .then(() => { dispatch(clearEnvironmentsDraft({ collectionUid: collection.uid })); @@ -263,6 +282,7 @@ const RequestTab = ({ tab, collection, tabIndex, collectionRequestTabs, folderUi {showConfirmGlobalEnvironmentClose && tab.type === 'global-environment-settings' && ( setShowConfirmGlobalEnvironmentClose(false)} onCloseWithoutSave={() => { dispatch(clearGlobalEnvironmentDraft()); @@ -271,7 +291,25 @@ const RequestTab = ({ tab, collection, tabIndex, collectionRequestTabs, folderUi }} onSaveAndClose={() => { const draft = globalEnvironmentDraft; - if (draft?.environmentUid && draft?.variables) { + if (draft?.environmentUid?.startsWith('dotenv:')) { + const onSuccess = () => { + cleanup(); + dispatch(clearGlobalEnvironmentDraft()); + dispatch(closeTabs({ tabUids: [tab.uid] })); + setShowConfirmGlobalEnvironmentClose(false); + }; + const onFailed = () => { + cleanup(); + setShowConfirmGlobalEnvironmentClose(false); + }; + const cleanup = () => { + window.removeEventListener('dotenv-save-complete', onSuccess); + window.removeEventListener('dotenv-save-failed', onFailed); + }; + window.addEventListener('dotenv-save-complete', onSuccess, { once: true }); + window.addEventListener('dotenv-save-failed', onFailed, { once: true }); + window.dispatchEvent(new Event('dotenv-save')); + } else if (draft?.environmentUid && draft?.variables) { dispatch(saveGlobalEnvironment({ variables: draft.variables, environmentUid: draft.environmentUid })) .then(() => { dispatch(clearGlobalEnvironmentDraft()); diff --git a/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/index.js b/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/index.js index 862f71ad8..d514aa1f5 100644 --- a/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/index.js +++ b/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/index.js @@ -13,7 +13,7 @@ import DotEnvFileDetails from 'components/Environments/DotEnvFileDetails'; import ColorBadge from 'components/ColorBadge'; import { isEqual } from 'lodash'; import { useDispatch, useSelector } from 'react-redux'; -import { addGlobalEnvironment, renameGlobalEnvironment, selectGlobalEnvironment } from 'providers/ReduxStore/slices/global-environments'; +import { addGlobalEnvironment, renameGlobalEnvironment, selectGlobalEnvironment, setGlobalEnvironmentDraft, clearGlobalEnvironmentDraft } from 'providers/ReduxStore/slices/global-environments'; import { saveWorkspaceDotEnvVariables, saveWorkspaceDotEnvRaw, @@ -72,9 +72,22 @@ const EnvironmentList = ({ const envUids = environments ? environments.map((env) => env.uid) : []; const prevEnvUids = usePrevious(envUids); + const handleDotEnvModifiedChange = useCallback((modified) => { + setIsDotEnvModified(modified); + if (modified) { + dispatch(setGlobalEnvironmentDraft({ + environmentUid: `dotenv:${selectedDotEnvFile}`, + variables: [] + })); + } else { + dispatch(clearGlobalEnvironmentDraft()); + } + }, [dispatch, selectedDotEnvFile]); + useEffect(() => { if (dotEnvFiles.length === 0) { setSelectedDotEnvFile(null); + handleDotEnvModifiedChange(false); return; } @@ -422,7 +435,7 @@ const EnvironmentList = ({ dispatch(deleteWorkspaceDotEnvFile(workspace.uid, filename)) .then(() => { toast.success(`${filename} file deleted!`); - setIsDotEnvModified(false); + handleDotEnvModifiedChange(false); if (selectedDotEnvFile === filename) { const remainingFiles = dotEnvFiles.filter((f) => f.filename !== filename); if (remainingFiles.length > 0) { @@ -465,7 +478,7 @@ const EnvironmentList = ({ onSave={handleSaveDotEnv} onSaveRaw={handleSaveDotEnvRaw} isModified={isDotEnvModified} - setIsModified={setIsDotEnvModified} + setIsModified={handleDotEnvModifiedChange} dotEnvExists={selectedDotEnvData?.exists} viewMode={dotEnvViewMode} />