mirror of
https://github.com/usebruno/bruno.git
synced 2024-12-23 23:29:47 +01:00
feat: improved handling logic while closing unsaved tabs/requests
This commit is contained in:
parent
3e627522b7
commit
db9aeec498
@ -64,6 +64,7 @@ const Modal = ({
|
|||||||
hideFooter,
|
hideFooter,
|
||||||
disableCloseOnOutsideClick,
|
disableCloseOnOutsideClick,
|
||||||
disableEscapeKey,
|
disableEscapeKey,
|
||||||
|
onClick,
|
||||||
closeModalFadeTimeout = 500
|
closeModalFadeTimeout = 500
|
||||||
}) => {
|
}) => {
|
||||||
const [isClosing, setIsClosing] = useState(false);
|
const [isClosing, setIsClosing] = useState(false);
|
||||||
@ -96,7 +97,7 @@ const Modal = ({
|
|||||||
classes += ' modal-footer-none';
|
classes += ' modal-footer-none';
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<StyledWrapper className={classes}>
|
<StyledWrapper className={classes} onClick={onClick ? (e) => onClick(e) : null}>
|
||||||
<div className={`bruno-modal-card modal-${size}`}>
|
<div className={`bruno-modal-card modal-${size}`}>
|
||||||
<ModalHeader title={title} handleCancel={() => closeModal({ type: 'icon' })} />
|
<ModalHeader title={title} handleCancel={() => closeModal({ type: 'icon' })} />
|
||||||
<ModalContent>{children}</ModalContent>
|
<ModalContent>{children}</ModalContent>
|
||||||
|
@ -1,30 +1,46 @@
|
|||||||
import Modal from 'components/Modal';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { IconAlertTriangle } from '@tabler/icons';
|
||||||
|
import Modal from 'components/Modal';
|
||||||
|
|
||||||
const ConfirmRequestClose = ({ item, onCancel, onCloseWithoutSave, onSaveAndClose }) => {
|
const ConfirmRequestClose = ({ item, onCancel, onCloseWithoutSave, onSaveAndClose }) => {
|
||||||
const _handleCancel = ({ type }) => {
|
|
||||||
if (type === 'button') {
|
|
||||||
return onCloseWithoutSave();
|
|
||||||
}
|
|
||||||
|
|
||||||
return onCancel();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
size="sm"
|
size="md"
|
||||||
title="Unsaved changes"
|
title="Unsaved changes"
|
||||||
confirmText="Save and Close"
|
confirmText="Save and Close"
|
||||||
cancelText="Close without saving"
|
cancelText="Close without saving"
|
||||||
handleConfirm={onSaveAndClose}
|
|
||||||
handleCancel={_handleCancel}
|
|
||||||
disableEscapeKey={true}
|
disableEscapeKey={true}
|
||||||
disableCloseOnOutsideClick={true}
|
disableCloseOnOutsideClick={true}
|
||||||
closeModalFadeTimeout={150}
|
closeModalFadeTimeout={150}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
hideFooter={true}
|
||||||
>
|
>
|
||||||
<div className="font-normal">
|
<div className="flex items-center font-normal">
|
||||||
|
<IconAlertTriangle size={32} strokeWidth={1.5} className="text-yellow-600" />
|
||||||
|
<h1 className="ml-2 text-lg font-semibold">Hold on..</h1>
|
||||||
|
</div>
|
||||||
|
<div className="font-normal mt-4">
|
||||||
You have unsaved changes in request <span className="font-semibold">{item.name}</span>.
|
You have unsaved changes in request <span className="font-semibold">{item.name}</span>.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="flex justify-between mt-6">
|
||||||
|
<div>
|
||||||
|
<button className="btn btn-sm btn-danger" onClick={onCloseWithoutSave}>
|
||||||
|
Don't Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button className="btn btn-close btn-sm mr-2" onClick={onCancel}>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button className="btn btn-secondary btn-sm" onClick={onSaveAndClose}>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -2,6 +2,7 @@ import React, { useState } from 'react';
|
|||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import { closeTabs } from 'providers/ReduxStore/slices/tabs';
|
import { closeTabs } from 'providers/ReduxStore/slices/tabs';
|
||||||
import { saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
import { saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
||||||
|
import { deleteRequestDraft } from 'providers/ReduxStore/slices/collections';
|
||||||
import { useTheme } from 'providers/Theme';
|
import { useTheme } from 'providers/Theme';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import darkTheme from 'themes/dark';
|
import darkTheme from 'themes/dark';
|
||||||
@ -135,6 +136,9 @@ const RequestTab = ({ tab, collection }) => {
|
|||||||
className="flex px-2 close-icon-container"
|
className="flex px-2 close-icon-container"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
if (!item.draft) return handleCloseClick(e);
|
if (!item.draft) return handleCloseClick(e);
|
||||||
|
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
setShowConfirmClose(true);
|
setShowConfirmClose(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -57,6 +57,18 @@ const GlobalStyle = createGlobalStyle`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-danger {
|
||||||
|
color: ${(props) => props.theme.button.danger.color};
|
||||||
|
background: ${(props) => props.theme.button.danger.bg};
|
||||||
|
border: solid 1px ${(props) => props.theme.button.danger.border};
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.btn-secondary {
|
.btn-secondary {
|
||||||
color: ${(props) => props.theme.button.secondary.color};
|
color: ${(props) => props.theme.button.secondary.color};
|
||||||
background: ${(props) => props.theme.button.secondary.bg};
|
background: ${(props) => props.theme.button.secondary.bg};
|
||||||
|
@ -94,7 +94,7 @@ const SaveRequestsModal = ({ onClose }) => {
|
|||||||
|
|
||||||
<div className="flex justify-between mt-6">
|
<div className="flex justify-between mt-6">
|
||||||
<div>
|
<div>
|
||||||
<button className="btn btn-sm btn-close btn-border" onClick={closeWithoutSave}>
|
<button className="btn btn-sm btn-danger" onClick={closeWithoutSave}>
|
||||||
Don't Save
|
Don't Save
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,16 +1,28 @@
|
|||||||
|
import getConfig from 'next/config';
|
||||||
import { configureStore } from '@reduxjs/toolkit';
|
import { configureStore } from '@reduxjs/toolkit';
|
||||||
import tasksMiddleware from './middlewares/tasks/middleware';
|
import tasksMiddleware from './middlewares/tasks/middleware';
|
||||||
|
import debugMiddleware from './middlewares/debug/middleware';
|
||||||
import appReducer from './slices/app';
|
import appReducer from './slices/app';
|
||||||
import collectionsReducer from './slices/collections';
|
import collectionsReducer from './slices/collections';
|
||||||
import tabsReducer from './slices/tabs';
|
import tabsReducer from './slices/tabs';
|
||||||
|
|
||||||
|
const { publicRuntimeConfig } = getConfig();
|
||||||
|
const isDevEnv = () => {
|
||||||
|
return publicRuntimeConfig.ENV === 'dev';
|
||||||
|
};
|
||||||
|
|
||||||
|
let middleware = [tasksMiddleware.middleware];
|
||||||
|
if (isDevEnv()) {
|
||||||
|
middleware = [...middleware, debugMiddleware.middleware];
|
||||||
|
}
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
app: appReducer,
|
app: appReducer,
|
||||||
collections: collectionsReducer,
|
collections: collectionsReducer,
|
||||||
tabs: tabsReducer
|
tabs: tabsReducer
|
||||||
},
|
},
|
||||||
middleware: (getDefaultMiddleware) => getDefaultMiddleware().prepend(tasksMiddleware.middleware)
|
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(middleware)
|
||||||
});
|
});
|
||||||
|
|
||||||
export default store;
|
export default store;
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
import { createListenerMiddleware } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
|
const debugMiddleware = createListenerMiddleware();
|
||||||
|
|
||||||
|
debugMiddleware.startListening({
|
||||||
|
predicate: () => true, // it'll track every change
|
||||||
|
effect: (action, listenerApi) => {
|
||||||
|
console.debug('---redux action---');
|
||||||
|
console.debug('action', action.type); // which action did it
|
||||||
|
console.debug('action.payload', action.payload);
|
||||||
|
console.debug(listenerApi.getState()); // the updated store
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default debugMiddleware;
|
@ -1,9 +1,8 @@
|
|||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import each from 'lodash/each';
|
import each from 'lodash/each';
|
||||||
import filter from 'lodash/filter';
|
import filter from 'lodash/filter';
|
||||||
import { uuid } from 'utils/common';
|
|
||||||
import { createListenerMiddleware } from '@reduxjs/toolkit';
|
import { createListenerMiddleware } from '@reduxjs/toolkit';
|
||||||
import { completeQuitFlow, removeTaskFromQueue, hideHomePage } from 'providers/ReduxStore/slices/app';
|
import { removeTaskFromQueue, hideHomePage } from 'providers/ReduxStore/slices/app';
|
||||||
import { addTab } from 'providers/ReduxStore/slices/tabs';
|
import { addTab } from 'providers/ReduxStore/slices/tabs';
|
||||||
import { collectionAddFileEvent } from 'providers/ReduxStore/slices/collections';
|
import { collectionAddFileEvent } from 'providers/ReduxStore/slices/collections';
|
||||||
import { findCollectionByUid, findItemInCollectionByPathname, getDefaultRequestPaneTab } from 'utils/collections/index';
|
import { findCollectionByUid, findItemInCollectionByPathname, getDefaultRequestPaneTab } from 'utils/collections/index';
|
||||||
|
@ -173,6 +173,11 @@ const darkTheme = {
|
|||||||
color: '#a5a5a5',
|
color: '#a5a5a5',
|
||||||
bg: '#626262',
|
bg: '#626262',
|
||||||
border: '#626262'
|
border: '#626262'
|
||||||
|
},
|
||||||
|
danger: {
|
||||||
|
color: '#fff',
|
||||||
|
bg: '#dc3545',
|
||||||
|
border: '#dc3545'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -177,6 +177,11 @@ const lightTheme = {
|
|||||||
color: '#9f9f9f',
|
color: '#9f9f9f',
|
||||||
bg: '#efefef',
|
bg: '#efefef',
|
||||||
border: 'rgb(234, 234, 234)'
|
border: 'rgb(234, 234, 234)'
|
||||||
|
},
|
||||||
|
danger: {
|
||||||
|
color: '#fff',
|
||||||
|
bg: '#dc3545',
|
||||||
|
border: '#dc3545'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user