diff --git a/docs/en_US/images/preferences_sql_options.png b/docs/en_US/images/preferences_sql_options.png index 547dd7e7c..452b9b631 100644 Binary files a/docs/en_US/images/preferences_sql_options.png and b/docs/en_US/images/preferences_sql_options.png differ diff --git a/docs/en_US/images/query_toolbar.png b/docs/en_US/images/query_toolbar.png index 19079cec9..caeac2037 100644 Binary files a/docs/en_US/images/query_toolbar.png and b/docs/en_US/images/query_toolbar.png differ diff --git a/docs/en_US/preferences.rst b/docs/en_US/preferences.rst index 65e15a718..fe2986169 100644 --- a/docs/en_US/preferences.rst +++ b/docs/en_US/preferences.rst @@ -474,6 +474,9 @@ Use the fields on the *Options* panel to manage editor preferences. editor will prompt the user to saved unsaved data when exiting the data editor. +* When the *Open the file in a new tab?* switch is set to *True*, the + editor will open the new file in new tab of the Query Tool. + * When the *Prompt to save unsaved query changes?* switch is set to *True*, the editor will prompt the user to saved unsaved query modifications when exiting the Query Tool. diff --git a/docs/en_US/query_tool_toolbar.rst b/docs/en_US/query_tool_toolbar.rst index 9c693f0ad..31a28b36c 100644 --- a/docs/en_US/query_tool_toolbar.rst +++ b/docs/en_US/query_tool_toolbar.rst @@ -29,7 +29,8 @@ File Options +----------------------+---------------------------------------------------------------------------------------------------+----------------+ | Icon | Behavior | Shortcut | +======================+===================================================================================================+================+ - | *Open File* | Click the *Open File* icon to display a previously saved query in the SQL Editor. | Cmd/Ctrl + O | + | *Open File* | Click the *Open File* icon to display a previously saved query in the same tab of the SQL Editor. | | + | | To open the file in a new tab, select *Open in a new tab?* option from the dropdown. | Cmd/Ctrl + O | +----------------------+---------------------------------------------------------------------------------------------------+----------------+ | *Save File* | Click the *Save* icon to perform a quick-save of a previously saved query, or to access the | Cmd/Ctrl + S | | | *Save* menu: | | diff --git a/web/pgadmin/misc/file_manager/__init__.py b/web/pgadmin/misc/file_manager/__init__.py index c8d1bc1d7..022f6d0cc 100644 --- a/web/pgadmin/misc/file_manager/__init__.py +++ b/web/pgadmin/misc/file_manager/__init__.py @@ -380,6 +380,12 @@ class Filemanager(): True, gettext("Select Folder") ), + 'open_file': ( + ['open_file'], + True, + False, + gettext("Select File") + ), 'create_file': ( ['select_file', 'rename', 'create'], True, diff --git a/web/pgadmin/misc/file_manager/static/js/FileManagerModule.jsx b/web/pgadmin/misc/file_manager/static/js/FileManagerModule.jsx index 83a8fe146..0e6be6291 100644 --- a/web/pgadmin/misc/file_manager/static/js/FileManagerModule.jsx +++ b/web/pgadmin/misc/file_manager/static/js/FileManagerModule.jsx @@ -61,7 +61,9 @@ export default class FileManagerModule { if(!title) { if(params.dialog_type == 'create_file') { title = gettext('Save File'); - } else if(params.dialog_type == 'select_file') { + } else if(params.dialog_type == 'open_file'){ + title = gettext('Open File'); + }else if(params.dialog_type == 'select_file') { title = gettext('Select File'); } else { title = gettext('Storage Manager'); diff --git a/web/pgadmin/misc/file_manager/static/js/components/FileManager.jsx b/web/pgadmin/misc/file_manager/static/js/components/FileManager.jsx index 6834d72aa..198c0630b 100644 --- a/web/pgadmin/misc/file_manager/static/js/components/FileManager.jsx +++ b/web/pgadmin/misc/file_manager/static/js/components/FileManager.jsx @@ -645,7 +645,8 @@ export default function FileManager({params, closeModal, onOK, onCancel, sharedS } else if(selectedRowIdx.current >= 0 && row) { let selectedfileType = row?.file_type; if(((selectedfileType == 'dir' || selectedfileType == 'drive') && fmUtilsObj.hasCapability('select_folder')) - || (selectedfileType != 'dir' && selectedfileType != 'drive' && fmUtilsObj.hasCapability('select_file'))) { + || (selectedfileType != 'dir' && selectedfileType != 'drive' && fmUtilsObj.hasCapability('select_file')) + || (selectedfileType != 'dir' && selectedfileType != 'drive' && fmUtilsObj.hasCapability('open_file'))) { disabled = false; } } @@ -695,6 +696,8 @@ export default function FileManager({params, closeModal, onOK, onCancel, sharedS okBtnText = gettext('Select'); if(params.dialog_type == 'create_file' || params.dialog_type == 'create_folder') { okBtnText = gettext('Create'); + }else if(params.dialog_type == 'open_file'){ + okBtnText = gettext('Open'); } } @@ -862,4 +865,4 @@ FileManager.propTypes = { onCancel: PropTypes.func, sharedStorages: PropTypes.array, restrictedSharedStorage: PropTypes.array, -}; +}; \ No newline at end of file diff --git a/web/pgadmin/static/js/components/ExternalIcon.jsx b/web/pgadmin/static/js/components/ExternalIcon.jsx index 9f12fd833..a026ef18e 100644 --- a/web/pgadmin/static/js/components/ExternalIcon.jsx +++ b/web/pgadmin/static/js/components/ExternalIcon.jsx @@ -117,4 +117,4 @@ export const MSAzureIcon = ({style})=>; -SchemaDiffIcon.propTypes = {style: PropTypes.object}; \ No newline at end of file +SchemaDiffIcon.propTypes = {style: PropTypes.object}; diff --git a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx index c40cd3d5a..2125f512c 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx +++ b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx @@ -261,6 +261,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN } }, pollTime); + let defaultLayout = { dockbox: { mode: 'vertical', @@ -378,6 +379,10 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN let msg = `${selectedConn['server_name']}/${selectedConn['database_name']} - Database connected`; pgAdmin.Browser.notifier.success(_.escape(msg)); } + // Open the file if filename passed on the parameters. + if(qtState.params.fileName){ + eventBus.current.fireEvent(QUERY_TOOL_EVENTS.LOAD_FILE, params.fileName, params.storage); + } }).catch((error)=>{ if(error.response?.request?.responseText?.search('Ticket expired') !== -1) { Kerberos.fetch_ticket() @@ -577,14 +582,20 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN eventBus.current.fireEvent(QUERY_TOOL_EVENTS.EDITOR_LAST_FOCUS); }; const events = [ - [QUERY_TOOL_EVENTS.TRIGGER_LOAD_FILE, ()=>{ + [QUERY_TOOL_EVENTS.TRIGGER_LOAD_FILE, (openInNewTab=false)=>{ let fileParams = { 'supported_types': ['sql', '*'], // file types allowed - 'dialog_type': 'select_file', // open select file dialog + 'dialog_type': 'open_file', // open select file dialog }; - pgAdmin.Tools.FileManager.show(fileParams, (fileName, storage)=>{ - eventBus.current.fireEvent(QUERY_TOOL_EVENTS.LOAD_FILE, fileName, storage); - }, null, modal); + if(openInNewTab){ + pgAdmin.Tools.FileManager.show(fileParams, (fileName, storage)=>{ + onNewQueryToolClick(null, fileName, storage); + }, null, modal, openInNewTab); + }else{ + pgAdmin.Tools.FileManager.show(fileParams,(fileName, storage)=>{ + eventBus.current.fireEvent(QUERY_TOOL_EVENTS.LOAD_FILE, fileName, storage); + }, null, modal); + } }], [QUERY_TOOL_EVENTS.TRIGGER_SAVE_FILE, (isSaveAs=false)=>{ if(!isSaveAs && qtState.current_file) { @@ -783,8 +794,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN }); }, [qtState.preferences.browser, qtState.connection_list, qtState.params]); - - const onNewQueryToolClick = ()=>{ + const onNewQueryToolClick = (event, fileName, storage)=>{ const transId = commonUtils.getRandomInt(1, 9999999); let selectedConn = _.find(qtState.connection_list, (c)=>c.is_selected); let parentData = { @@ -807,6 +817,8 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN showQueryTool.launchQueryTool(pgWindow.pgAdmin.Tools.SQLEditor, transId, gridUrl, title, { user: selectedConn.user, role: selectedConn.role, + fileName: fileName, + storage: storage }); }; @@ -982,6 +994,8 @@ QueryToolComponent.propTypes = { server_name: PropTypes.string, database_name: PropTypes.string, layout: PropTypes.string, + fileName: PropTypes.string, + storage: PropTypes.string, }), pgWindow: PropTypes.object.isRequired, pgAdmin: PropTypes.object.isRequired, diff --git a/web/pgadmin/tools/sqleditor/static/js/components/sections/MainToolBar.jsx b/web/pgadmin/tools/sqleditor/static/js/components/sections/MainToolBar.jsx index 7e01500ea..0b7eb2149 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/sections/MainToolBar.jsx +++ b/web/pgadmin/tools/sqleditor/static/js/components/sections/MainToolBar.jsx @@ -74,6 +74,7 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros, onAddT const [checkedMenuItems, setCheckedMenuItems] = React.useState({}); /* Menu button refs */ const saveAsMenuRef = React.useRef(null); + const openInNewTabMenuRef = React.useRef(null); const editMenuRef = React.useRef(null); const autoCommitMenuRef = React.useRef(null); const explainMenuRef = React.useRef(null); @@ -138,9 +139,9 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros, onAddT const openFile = useCallback(()=>{ confirmDiscard(()=>{ - eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_LOAD_FILE); + eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_LOAD_FILE, Boolean(checkedMenuItems['open_in_new_tab'])); }, true); - }, [buttonsDisabled['save']]); + }, [buttonsDisabled['save'], checkedMenuItems]); const saveFile = useCallback((saveAs=false)=>{ eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_SAVE_FILE, saveAs); @@ -337,6 +338,7 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros, onAddT explain_summary: queryToolPref.explain_summary, explain_settings: queryToolPref.explain_settings, explain_wal: queryToolPref.explain_wal, + open_in_new_tab: queryToolPref.open_in_new_tab, }); } } @@ -501,6 +503,11 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros, onAddT } disabled={!queryToolCtx.params.is_query_tool} shortcut={queryToolPref.btn_open_file} onClick={openFile} /> + } splitButton disabled={!queryToolCtx.params.is_query_tool} + name="menu-openfileintab" ref={openInNewTabMenuRef} onClick={toggleMenu} + /> + + } shortcut={queryToolPref.btn_save_file} disabled={buttonsDisabled['save'] || !queryToolCtx.params.is_query_tool} onClick={()=>{saveFile(false);}} /> @@ -562,13 +569,22 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros, onAddT } onClick={onHelpClick} /> + + {gettext('Open in a new tab?')} + - {saveFile(true);}}>{gettext('Save as')} + {saveFile(true);}}>{gettext('Save As')}