mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-05-03 00:13:57 +00:00
electron: save file to custom location
This commit is contained in:
@@ -51,6 +51,12 @@ function buildMenu() {
|
|||||||
mainWindow.webContents.executeJavaScript(`dbgate_newQuery()`);
|
mainWindow.webContents.executeJavaScript(`dbgate_newQuery()`);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Open file',
|
||||||
|
click() {
|
||||||
|
mainWindow.webContents.executeJavaScript(`dbgate_openFile()`);
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'Close all tabs',
|
label: 'Close all tabs',
|
||||||
click() {
|
click() {
|
||||||
|
|||||||
@@ -78,6 +78,11 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
saveAs_meta: 'post',
|
||||||
|
async saveAs({ filePath, data, format }) {
|
||||||
|
await fs.writeFile(filePath, serialize(format, data));
|
||||||
|
},
|
||||||
|
|
||||||
favorites_meta: 'get',
|
favorites_meta: 'get',
|
||||||
async favorites() {
|
async favorites() {
|
||||||
if (!hasPermission(`files/favorites/read`)) return [];
|
if (!hasPermission(`files/favorites/read`)) return [];
|
||||||
|
|||||||
@@ -124,6 +124,15 @@ function getDbIcon(key) {
|
|||||||
return 'icon file';
|
return 'icon file';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildTooltip(tab) {
|
||||||
|
let res = tab.tooltip;
|
||||||
|
if (tab.props && tab.props.savedFilePath) {
|
||||||
|
if (res) res += '\n';
|
||||||
|
res += tab.props.savedFilePath;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
export default function TabsPanel() {
|
export default function TabsPanel() {
|
||||||
// const formatDbKey = (conid, database) => `${database}-${conid}`;
|
// const formatDbKey = (conid, database) => `${database}-${conid}`;
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@@ -252,7 +261,7 @@ export default function TabsPanel() {
|
|||||||
{_.sortBy(tabsByDb[dbKey], ['title', 'tabid']).map(tab => (
|
{_.sortBy(tabsByDb[dbKey], ['title', 'tabid']).map(tab => (
|
||||||
<FileTabItem
|
<FileTabItem
|
||||||
{...tab}
|
{...tab}
|
||||||
title={tab.tooltip}
|
title={buildTooltip(tab)}
|
||||||
key={tab.tabid}
|
key={tab.tabid}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
onClick={e => handleTabClick(e, tab.tabid)}
|
onClick={e => handleTabClick(e, tab.tabid)}
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ export async function openDatabaseObjectDetail(
|
|||||||
|
|
||||||
openNewTab(
|
openNewTab(
|
||||||
{
|
{
|
||||||
title: pureName,
|
title: 'Query #',
|
||||||
tooltip,
|
tooltip,
|
||||||
icon: sqlTemplate ? 'img sql-file' : icons[objectTypeField],
|
icon: sqlTemplate ? 'img sql-file' : icons[objectTypeField],
|
||||||
tabComponent: sqlTemplate ? 'QueryTab' : tabComponent,
|
tabComponent: sqlTemplate ? 'QueryTab' : tabComponent,
|
||||||
|
|||||||
@@ -6,14 +6,52 @@ import ModalHeader from './ModalHeader';
|
|||||||
import ModalContent from './ModalContent';
|
import ModalContent from './ModalContent';
|
||||||
import ModalFooter from './ModalFooter';
|
import ModalFooter from './ModalFooter';
|
||||||
import { FormProvider } from '../utility/FormProvider';
|
import { FormProvider } from '../utility/FormProvider';
|
||||||
|
import FormStyledButton from '../widgets/FormStyledButton';
|
||||||
|
import getElectron from '../utility/getElectron';
|
||||||
|
|
||||||
|
export default function SaveFileModal({
|
||||||
|
data,
|
||||||
|
folder,
|
||||||
|
format,
|
||||||
|
modalState,
|
||||||
|
name,
|
||||||
|
fileExtension,
|
||||||
|
filePath,
|
||||||
|
onSave = undefined,
|
||||||
|
}) {
|
||||||
|
const electron = getElectron();
|
||||||
|
|
||||||
export default function SaveFileModal({ data, folder, format, modalState, name, onSave = undefined }) {
|
|
||||||
const handleSubmit = async values => {
|
const handleSubmit = async values => {
|
||||||
const { name } = values;
|
const { name } = values;
|
||||||
await axios.post('files/save', { folder, file: name, data, format });
|
await axios.post('files/save', { folder, file: name, data, format });
|
||||||
modalState.close();
|
modalState.close();
|
||||||
if (onSave) onSave(name);
|
if (onSave) {
|
||||||
|
onSave(name, {
|
||||||
|
savedFile: name,
|
||||||
|
savedFolder: folder,
|
||||||
|
savedFilePath: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSaveAs = async filePath => {
|
||||||
|
const path = window.require('path');
|
||||||
|
|
||||||
|
const parsed = path.parse(filePath);
|
||||||
|
if (!parsed.ext) filePath += `.${fileExtension}`;
|
||||||
|
|
||||||
|
await axios.post('files/save-as', { filePath, data, format });
|
||||||
|
modalState.close();
|
||||||
|
|
||||||
|
if (onSave) {
|
||||||
|
onSave(parsed.name, {
|
||||||
|
savedFile: null,
|
||||||
|
savedFolder: null,
|
||||||
|
savedFilePath: filePath,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalBase modalState={modalState}>
|
<ModalBase modalState={modalState}>
|
||||||
<ModalHeader modalState={modalState}>Save file</ModalHeader>
|
<ModalHeader modalState={modalState}>Save file</ModalHeader>
|
||||||
@@ -23,6 +61,21 @@ export default function SaveFileModal({ data, folder, format, modalState, name,
|
|||||||
</ModalContent>
|
</ModalContent>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<FormSubmit value="Save" onClick={handleSubmit} />
|
<FormSubmit value="Save" onClick={handleSubmit} />
|
||||||
|
{electron && (
|
||||||
|
<FormStyledButton
|
||||||
|
type="button"
|
||||||
|
value="Save to disk"
|
||||||
|
onClick={() => {
|
||||||
|
const file = electron.remote.dialog.showSaveDialogSync(electron.remote.getCurrentWindow(), {
|
||||||
|
filters: { name: `${fileExtension.toUpperCase()} files`, extensions: [fileExtension] },
|
||||||
|
defaultPath: filePath,
|
||||||
|
});
|
||||||
|
if (file) {
|
||||||
|
handleSaveAs(file);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
</ModalBase>
|
</ModalBase>
|
||||||
|
|||||||
@@ -4,22 +4,22 @@ import { useOpenedTabs, useSetOpenedTabs } from '../utility/globalState';
|
|||||||
import keycodes from '../utility/keycodes';
|
import keycodes from '../utility/keycodes';
|
||||||
import SaveFileModal from './SaveFileModal';
|
import SaveFileModal from './SaveFileModal';
|
||||||
|
|
||||||
export default function SaveTabModal({ data, folder, format, modalState, tabid, tabVisible }) {
|
export default function SaveTabModal({ data, folder, format, modalState, tabid, tabVisible, fileExtension }) {
|
||||||
const setOpenedTabs = useSetOpenedTabs();
|
const setOpenedTabs = useSetOpenedTabs();
|
||||||
const openedTabs = useOpenedTabs();
|
const openedTabs = useOpenedTabs();
|
||||||
|
|
||||||
const { savedFile } = openedTabs.find(x => x.tabid == tabid).props || {};
|
const { savedFile, savedFilePath } = openedTabs.find(x => x.tabid == tabid).props || {};
|
||||||
const onSave = name =>
|
const onSave = (title, newProps) => {
|
||||||
changeTab(tabid, setOpenedTabs, tab => ({
|
changeTab(tabid, setOpenedTabs, tab => ({
|
||||||
...tab,
|
...tab,
|
||||||
title: name,
|
title,
|
||||||
props: {
|
props: {
|
||||||
...tab.props,
|
...tab.props,
|
||||||
savedFile: name,
|
|
||||||
savedFolder: folder,
|
|
||||||
savedFormat: format,
|
savedFormat: format,
|
||||||
|
...newProps,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
const handleKeyboard = React.useCallback(
|
const handleKeyboard = React.useCallback(
|
||||||
e => {
|
e => {
|
||||||
@@ -47,6 +47,8 @@ export default function SaveTabModal({ data, folder, format, modalState, tabid,
|
|||||||
format={format}
|
format={format}
|
||||||
modalState={modalState}
|
modalState={modalState}
|
||||||
name={savedFile || 'newFile'}
|
name={savedFile || 'newFile'}
|
||||||
|
filePath={savedFilePath}
|
||||||
|
fileExtension={fileExtension}
|
||||||
onSave={onSave}
|
onSave={onSave}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ export default function ChartTab({ tabVisible, toolbarPortalRef, conid, database
|
|||||||
format="json"
|
format="json"
|
||||||
folder="charts"
|
folder="charts"
|
||||||
tabid={tabid}
|
tabid={tabid}
|
||||||
|
fileExtension='chart'
|
||||||
/>
|
/>
|
||||||
{toolbarPortalRef &&
|
{toolbarPortalRef &&
|
||||||
toolbarPortalRef.current &&
|
toolbarPortalRef.current &&
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ export default function MarkdownEditorTab({ tabid, tabVisible, toolbarPortalRef,
|
|||||||
format="text"
|
format="text"
|
||||||
folder="markdown"
|
folder="markdown"
|
||||||
tabid={tabid}
|
tabid={tabid}
|
||||||
|
fileExtension='md'
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -225,6 +225,7 @@ export default function QueryDesignTab({
|
|||||||
format="json"
|
format="json"
|
||||||
folder="query"
|
folder="query"
|
||||||
tabid={tabid}
|
tabid={tabid}
|
||||||
|
fileExtension='qdesign'
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -228,6 +228,7 @@ export default function QueryTab({
|
|||||||
format="text"
|
format="text"
|
||||||
folder="sql"
|
folder="sql"
|
||||||
tabid={tabid}
|
tabid={tabid}
|
||||||
|
fileExtension='sql'
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ export default function ShellTab({ tabid, tabVisible, toolbarPortalRef, statusba
|
|||||||
format="text"
|
format="text"
|
||||||
folder="shell"
|
folder="shell"
|
||||||
tabid={tabid}
|
tabid={tabid}
|
||||||
|
fileExtension='js'
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
31
packages/web/src/utility/useOpenElectronFile.js
Normal file
31
packages/web/src/utility/useOpenElectronFile.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import useNewQuery from '../query/useNewQuery';
|
||||||
|
import getElectron from './getElectron';
|
||||||
|
|
||||||
|
export default function useOpenElectronFile() {
|
||||||
|
const electron = getElectron();
|
||||||
|
|
||||||
|
const newQuery = useNewQuery();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
const filePaths = electron.remote.dialog.showOpenDialogSync(electron.remote.getCurrentWindow(), {
|
||||||
|
filters: { name: `SQL files`, extensions: ['sql'] },
|
||||||
|
});
|
||||||
|
const filePath = filePaths && filePaths[0];
|
||||||
|
if (filePath) {
|
||||||
|
if (filePath.match(/.sql$/i)) {
|
||||||
|
const path = window.require('path');
|
||||||
|
const fs = window.require('fs');
|
||||||
|
const parsed = path.parse(filePath);
|
||||||
|
const data = fs.readFileSync(filePath, { encoding: 'utf-8' });
|
||||||
|
|
||||||
|
newQuery({
|
||||||
|
title: parsed.name,
|
||||||
|
initialData: data,
|
||||||
|
// @ts-ignore
|
||||||
|
savedFilePath: filePath,
|
||||||
|
savedFormat: 'text',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -23,11 +23,16 @@ export default function useOpenNewTab() {
|
|||||||
async (newTab, initialData = undefined, options) => {
|
async (newTab, initialData = undefined, options) => {
|
||||||
let existing = null;
|
let existing = null;
|
||||||
|
|
||||||
const { savedFile } = newTab.props || {};
|
const { savedFile, savedFolder, savedFilePath } = newTab.props || {};
|
||||||
if (savedFile) {
|
if (savedFile || savedFilePath) {
|
||||||
existing = openedTabs.find(
|
existing = openedTabs.find(
|
||||||
x =>
|
x =>
|
||||||
x.props && x.tabComponent == newTab.tabComponent && x.closedTime == null && x.props.savedFile == savedFile
|
x.props &&
|
||||||
|
x.tabComponent == newTab.tabComponent &&
|
||||||
|
x.closedTime == null &&
|
||||||
|
x.props.savedFile == savedFile &&
|
||||||
|
x.props.savedFolder == savedFolder &&
|
||||||
|
x.props.savedFilePath == savedFilePath
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import tabs from '../tabs';
|
|||||||
import FavoriteModal from '../modals/FavoriteModal';
|
import FavoriteModal from '../modals/FavoriteModal';
|
||||||
import { useOpenFavorite } from '../appobj/FavoriteFileAppObject';
|
import { useOpenFavorite } from '../appobj/FavoriteFileAppObject';
|
||||||
import ErrorMessageModal from '../modals/ErrorMessageModal';
|
import ErrorMessageModal from '../modals/ErrorMessageModal';
|
||||||
|
import useOpenElectronFile from '../utility/useOpenElectronFile';
|
||||||
|
|
||||||
const ToolbarContainer = styled.div`
|
const ToolbarContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -48,6 +49,7 @@ export default function ToolBar({ toolbarPortalRef }) {
|
|||||||
const electron = getElectron();
|
const electron = getElectron();
|
||||||
const favorites = useFavorites();
|
const favorites = useFavorites();
|
||||||
const openFavorite = useOpenFavorite();
|
const openFavorite = useOpenFavorite();
|
||||||
|
const openElectronFile = useOpenElectronFile();
|
||||||
|
|
||||||
const currentTab = openedTabs.find(x => x.selected);
|
const currentTab = openedTabs.find(x => x.selected);
|
||||||
|
|
||||||
@@ -58,6 +60,7 @@ export default function ToolBar({ toolbarPortalRef }) {
|
|||||||
window['dbgate_newQuery'] = newQuery;
|
window['dbgate_newQuery'] = newQuery;
|
||||||
window['dbgate_closeAll'] = () => setOpenedTabs([]);
|
window['dbgate_closeAll'] = () => setOpenedTabs([]);
|
||||||
window['dbgate_showAbout'] = showAbout;
|
window['dbgate_showAbout'] = showAbout;
|
||||||
|
window['dbgate_openFile'] = openElectronFile;
|
||||||
});
|
});
|
||||||
|
|
||||||
const showAbout = () => {
|
const showAbout = () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user