mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-05-01 14:23:58 +00:00
markdown manifest
This commit is contained in:
@@ -3,16 +3,16 @@ const currentVersion = require('../currentVersion');
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
get_meta: 'get',
|
get_meta: 'get',
|
||||||
async get() {
|
async get() {
|
||||||
const toolbarButtons = process.env.TOOLBAR;
|
// const toolbarButtons = process.env.TOOLBAR;
|
||||||
const toolbar = toolbarButtons
|
// const toolbar = toolbarButtons
|
||||||
? toolbarButtons.split(',').map((name) => ({
|
// ? toolbarButtons.split(',').map((name) => ({
|
||||||
name,
|
// name,
|
||||||
icon: process.env[`ICON_${name}`],
|
// icon: process.env[`ICON_${name}`],
|
||||||
title: process.env[`TITLE_${name}`],
|
// title: process.env[`TITLE_${name}`],
|
||||||
page: process.env[`PAGE_${name}`],
|
// page: process.env[`PAGE_${name}`],
|
||||||
}))
|
// }))
|
||||||
: null;
|
// : null;
|
||||||
const startupPages = process.env.STARTUP_PAGES ? process.env.STARTUP_PAGES.split(',') : [];
|
// const startupPages = process.env.STARTUP_PAGES ? process.env.STARTUP_PAGES.split(',') : [];
|
||||||
const permissions = process.env.PERMISSIONS ? process.env.PERMISSIONS.split(',') : null;
|
const permissions = process.env.PERMISSIONS ? process.env.PERMISSIONS.split(',') : null;
|
||||||
const singleDatabase =
|
const singleDatabase =
|
||||||
process.env.SINGLE_CONNECTION && process.env.SINGLE_DATABASE
|
process.env.SINGLE_CONNECTION && process.env.SINGLE_DATABASE
|
||||||
@@ -24,8 +24,8 @@ module.exports = {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
runAsPortal: !!process.env.CONNECTIONS,
|
runAsPortal: !!process.env.CONNECTIONS,
|
||||||
toolbar,
|
// toolbar,
|
||||||
startupPages,
|
// startupPages,
|
||||||
singleDatabase,
|
singleDatabase,
|
||||||
permissions,
|
permissions,
|
||||||
...currentVersion,
|
...currentVersion,
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ const hasPermission = require('../utility/hasPermission');
|
|||||||
const socket = require('../utility/socket');
|
const socket = require('../utility/socket');
|
||||||
const scheduler = require('./scheduler');
|
const scheduler = require('./scheduler');
|
||||||
|
|
||||||
|
const markdownAutorunRegex = /<\!--.*@autorun\s*(\n.*-->|-->)/s;
|
||||||
|
const markdownButtonRegex = /<\!--.*@button\s+([^\n]+)(\n.*-->|-->)/s;
|
||||||
|
const markdownIconRegex = /<\!--.*@icon\s+([^\n]+)(\n.*-->|-->)/s;
|
||||||
|
|
||||||
function serialize(format, data) {
|
function serialize(format, data) {
|
||||||
if (format == 'text') return data;
|
if (format == 'text') return data;
|
||||||
if (format == 'json') return JSON.stringify(data);
|
if (format == 'json') return JSON.stringify(data);
|
||||||
@@ -61,4 +65,29 @@ module.exports = {
|
|||||||
scheduler.reload();
|
scheduler.reload();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
markdownManifest_meta: 'get',
|
||||||
|
async markdownManifest() {
|
||||||
|
if (!hasPermission(`files/markdown/write`)) return {};
|
||||||
|
const dir = path.join(filesdir(), 'markdown');
|
||||||
|
if (!(await fs.exists(dir))) return {};
|
||||||
|
const files = await fs.readdir(dir);
|
||||||
|
const res = [];
|
||||||
|
for (const file of files) {
|
||||||
|
const filePath = path.join(dir, file);
|
||||||
|
const text = await fs.readFile(filePath, { encoding: 'utf-8' });
|
||||||
|
const autorun = text.match(markdownAutorunRegex);
|
||||||
|
const button = text.match(markdownButtonRegex);
|
||||||
|
const icon = text.match(markdownIconRegex);
|
||||||
|
if (autorun || button) {
|
||||||
|
res.push({
|
||||||
|
file,
|
||||||
|
autorun: !!autorun,
|
||||||
|
button: button ? button[1].trim() : undefined,
|
||||||
|
icon: icon ? icon[1].trim() : undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -72,9 +72,9 @@ function start(argument = null) {
|
|||||||
useController(app, '/files', files);
|
useController(app, '/files', files);
|
||||||
useController(app, '/scheduler', scheduler);
|
useController(app, '/scheduler', scheduler);
|
||||||
|
|
||||||
if (process.env.PAGES_DIRECTORY) {
|
// if (process.env.PAGES_DIRECTORY) {
|
||||||
app.use('/pages', express.static(process.env.PAGES_DIRECTORY));
|
// app.use('/pages', express.static(process.env.PAGES_DIRECTORY));
|
||||||
}
|
// }
|
||||||
|
|
||||||
app.use('/runners/data', express.static(rundir()));
|
app.use('/runners/data', express.static(rundir()));
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ const iconNames = {
|
|||||||
'icon account': 'mdi mdi-account',
|
'icon account': 'mdi mdi-account',
|
||||||
'icon sql-file': 'mdi mdi-file',
|
'icon sql-file': 'mdi mdi-file',
|
||||||
'icon web': 'mdi mdi-web',
|
'icon web': 'mdi mdi-web',
|
||||||
|
'icon home': 'mdi mdi-home',
|
||||||
|
|
||||||
'icon edit': 'mdi mdi-pencil',
|
'icon edit': 'mdi mdi-pencil',
|
||||||
'icon delete': 'mdi mdi-delete',
|
'icon delete': 'mdi mdi-delete',
|
||||||
@@ -40,6 +41,7 @@ const iconNames = {
|
|||||||
'icon error': 'mdi mdi-close-circle',
|
'icon error': 'mdi mdi-close-circle',
|
||||||
'icon ok': 'mdi mdi-check-circle',
|
'icon ok': 'mdi mdi-check-circle',
|
||||||
'icon markdown': 'mdi mdi-application',
|
'icon markdown': 'mdi mdi-application',
|
||||||
|
'icon preview': 'mdi mdi-file-find',
|
||||||
|
|
||||||
'icon run': 'mdi mdi-play',
|
'icon run': 'mdi mdi-play',
|
||||||
'icon chevron-down': 'mdi mdi-chevron-down',
|
'icon chevron-down': 'mdi mdi-chevron-down',
|
||||||
@@ -62,6 +64,7 @@ const iconNames = {
|
|||||||
'img shell': 'mdi mdi-flash color-blue-7',
|
'img shell': 'mdi mdi-flash color-blue-7',
|
||||||
'img chart': 'mdi mdi-chart-bar color-magenta-7',
|
'img chart': 'mdi mdi-chart-bar color-magenta-7',
|
||||||
'img markdown': 'mdi mdi-application color-red-7',
|
'img markdown': 'mdi mdi-application color-red-7',
|
||||||
|
'img preview': 'mdi mdi-file-find color-red-7',
|
||||||
|
|
||||||
'img free-table': 'mdi mdi-table color-green-7',
|
'img free-table': 'mdi mdi-table color-green-7',
|
||||||
'img macro': 'mdi mdi-hammer-wrench',
|
'img macro': 'mdi mdi-hammer-wrench',
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
import Markdown from 'markdown-to-jsx';
|
import Markdown from 'markdown-to-jsx';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import OpenChartLink from './OpenChartLink';
|
import OpenChartLink from './OpenChartLink';
|
||||||
|
import MarkdownLink from './MarkdownLink';
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
const Wrapper = styled.div`
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
@@ -18,6 +19,7 @@ export default function MarkdownExtendedView({ children }) {
|
|||||||
OpenChartLink: {
|
OpenChartLink: {
|
||||||
component: OpenChartLink,
|
component: OpenChartLink,
|
||||||
},
|
},
|
||||||
|
a: MarkdownLink,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
13
packages/web/src/markdown/MarkdownLink.js
Normal file
13
packages/web/src/markdown/MarkdownLink.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import useTheme from '../theme/useTheme';
|
||||||
|
import { StyledThemedLink } from '../widgets/FormStyledButton';
|
||||||
|
|
||||||
|
export default function MarkdownLink({ href, title, children }) {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledThemedLink theme={theme} href={href} title={title} target="_blank">
|
||||||
|
{children}
|
||||||
|
</StyledThemedLink>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import useHasPermission from '../utility/useHasPermission';
|
import useHasPermission from '../utility/useHasPermission';
|
||||||
import ToolbarButton from '../widgets/ToolbarButton';
|
import ToolbarButton from '../widgets/ToolbarButton';
|
||||||
|
|
||||||
export default function MarkdownToolbar({ save }) {
|
export default function MarkdownToolbar({ save, showPreview }) {
|
||||||
const hasPermission = useHasPermission();
|
const hasPermission = useHasPermission();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -12,6 +12,9 @@ export default function MarkdownToolbar({ save }) {
|
|||||||
Save
|
Save
|
||||||
</ToolbarButton>
|
</ToolbarButton>
|
||||||
)}
|
)}
|
||||||
|
<ToolbarButton onClick={showPreview} icon="icon preview">
|
||||||
|
Preview
|
||||||
|
</ToolbarButton>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useCurrentDatabase, useSetOpenedTabs } from '../utility/globalState';
|
import { useCurrentDatabase, useSetOpenedTabs } from '../utility/globalState';
|
||||||
import styled from 'styled-components';
|
|
||||||
import { openNewTab } from '../utility/common';
|
import { openNewTab } from '../utility/common';
|
||||||
import axios from '../utility/axios';
|
import axios from '../utility/axios';
|
||||||
import useTheme from '../theme/useTheme';
|
import useTheme from '../theme/useTheme';
|
||||||
|
import { StyledThemedLink } from '../widgets/FormStyledButton';
|
||||||
const StyledLink = styled.a`
|
|
||||||
text-decoration: none;
|
|
||||||
cursor: pointer;
|
|
||||||
color: ${(props) => props.theme.main_background_blue[7]};
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default function OpenChartLink({ file, children }) {
|
export default function OpenChartLink({ file, children }) {
|
||||||
const setOpenedTabs = useSetOpenedTabs();
|
const setOpenedTabs = useSetOpenedTabs();
|
||||||
@@ -37,8 +28,8 @@ export default function OpenChartLink({ file, children }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledLink theme={theme} onClick={handleClick}>
|
<StyledThemedLink theme={theme} onClick={handleClick}>
|
||||||
{children}
|
{children}
|
||||||
</StyledLink>
|
</StyledThemedLink>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import moment from 'moment';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import getElectron from '../utility/getElectron';
|
import getElectron from '../utility/getElectron';
|
||||||
import useTheme from '../theme/useTheme';
|
import useTheme from '../theme/useTheme';
|
||||||
|
import { StyledThemedLink } from '../widgets/FormStyledButton';
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -24,15 +25,6 @@ const StyledValue = styled.span`
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledLink = styled.a`
|
|
||||||
text-decoration: none;
|
|
||||||
cursor: pointer;
|
|
||||||
color: ${(props) => props.theme.main_background_blue[7]};
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
function Line({ label, children }) {
|
function Line({ label, children }) {
|
||||||
return (
|
return (
|
||||||
<StyledLine>
|
<StyledLine>
|
||||||
@@ -48,13 +40,13 @@ function Link({ label, children, href }) {
|
|||||||
<StyledLine>
|
<StyledLine>
|
||||||
{label}:{' '}
|
{label}:{' '}
|
||||||
{electron ? (
|
{electron ? (
|
||||||
<StyledLink theme={theme} onClick={() => electron.shell.openExternal(href)}>
|
<StyledThemedLink theme={theme} onClick={() => electron.shell.openExternal(href)}>
|
||||||
{children}
|
{children}
|
||||||
</StyledLink>
|
</StyledThemedLink>
|
||||||
) : (
|
) : (
|
||||||
<StyledLink theme={theme} href={href} target="_blank" rel="noopener noreferrer">
|
<StyledThemedLink theme={theme} href={href} target="_blank" rel="noopener noreferrer">
|
||||||
{children}
|
{children}
|
||||||
</StyledLink>
|
</StyledThemedLink>
|
||||||
)}
|
)}
|
||||||
</StyledLine>
|
</StyledLine>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,15 +8,42 @@ import useEditorData from '../utility/useEditorData';
|
|||||||
import SaveTabModal from '../modals/SaveTabModal';
|
import SaveTabModal from '../modals/SaveTabModal';
|
||||||
import useModalState from '../modals/useModalState';
|
import useModalState from '../modals/useModalState';
|
||||||
import LoadingInfo from '../widgets/LoadingInfo';
|
import LoadingInfo from '../widgets/LoadingInfo';
|
||||||
|
import { useOpenedTabs, useSetOpenedTabs } from '../utility/globalState';
|
||||||
|
import { openNewTab } from '../utility/common';
|
||||||
|
|
||||||
export default function MarkdownEditorTab({ tabid, tabVisible, toolbarPortalRef, ...other }) {
|
export default function MarkdownEditorTab({ tabid, tabVisible, toolbarPortalRef, ...other }) {
|
||||||
const { editorData, setEditorData, isLoading } = useEditorData({ tabid });
|
const { editorData, setEditorData, isLoading, saveToStorage } = useEditorData({ tabid });
|
||||||
const saveFileModalState = useModalState();
|
const saveFileModalState = useModalState();
|
||||||
|
const openedTabs = useOpenedTabs();
|
||||||
|
const setOpenedTabs = useSetOpenedTabs();
|
||||||
|
|
||||||
const handleKeyDown = (data, hash, keyString, keyCode, event) => {
|
const handleKeyDown = (data, hash, keyString, keyCode, event) => {
|
||||||
if (keyCode == keycodes.f5) {
|
if (keyCode == keycodes.f5) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
// handlePreview();
|
showPreview();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const showPreview = async () => {
|
||||||
|
await saveToStorage();
|
||||||
|
const existing = (openedTabs || []).find((x) => x.props && x.props.sourceTabId == tabid && x.closedTime == null);
|
||||||
|
if (existing) {
|
||||||
|
setOpenedTabs((tabs) =>
|
||||||
|
tabs.map((x) => ({
|
||||||
|
...x,
|
||||||
|
selected: x.tabid == existing.tabid,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const thisTab = (openedTabs || []).find((x) => x.tabid == tabid);
|
||||||
|
openNewTab(setOpenedTabs, {
|
||||||
|
title: thisTab.title,
|
||||||
|
icon: 'img preview',
|
||||||
|
tabComponent: 'MarkdownPreviewTab',
|
||||||
|
props: {
|
||||||
|
sourceTabId: tabid,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -40,7 +67,10 @@ export default function MarkdownEditorTab({ tabid, tabVisible, toolbarPortalRef,
|
|||||||
{toolbarPortalRef &&
|
{toolbarPortalRef &&
|
||||||
toolbarPortalRef.current &&
|
toolbarPortalRef.current &&
|
||||||
tabVisible &&
|
tabVisible &&
|
||||||
ReactDOM.createPortal(<MarkdownToolbar save={saveFileModalState.open} />, toolbarPortalRef.current)}
|
ReactDOM.createPortal(
|
||||||
|
<MarkdownToolbar save={saveFileModalState.open} showPreview={showPreview} />,
|
||||||
|
toolbarPortalRef.current
|
||||||
|
)}
|
||||||
<SaveTabModal
|
<SaveTabModal
|
||||||
modalState={saveFileModalState}
|
modalState={saveFileModalState}
|
||||||
tabVisible={tabVisible}
|
tabVisible={tabVisible}
|
||||||
|
|||||||
23
packages/web/src/tabs/MarkdownPreviewTab.js
Normal file
23
packages/web/src/tabs/MarkdownPreviewTab.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import LoadingInfo from '../widgets/LoadingInfo';
|
||||||
|
import MarkdownExtendedView from '../markdown/MarkdownExtendedView';
|
||||||
|
import useEditorData from '../utility/useEditorData';
|
||||||
|
|
||||||
|
export default function MarkdownPreviewTab({ sourceTabId, tabVisible }) {
|
||||||
|
const [reloadToken, setReloadToken] = React.useState(0);
|
||||||
|
const { editorData, isLoading } = useEditorData({ tabid: sourceTabId, reloadToken });
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (tabVisible) setReloadToken((x) => x + 1);
|
||||||
|
}, [tabVisible]);
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<LoadingInfo message="Loading markdown page" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <MarkdownExtendedView>{editorData || ''}</MarkdownExtendedView>;
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import PluginTab from './PluginTab';
|
|||||||
import ChartTab from './ChartTab';
|
import ChartTab from './ChartTab';
|
||||||
import MarkdownEditorTab from './MarkdownEditorTab';
|
import MarkdownEditorTab from './MarkdownEditorTab';
|
||||||
import MarkdownViewTab from './MarkdownViewTab';
|
import MarkdownViewTab from './MarkdownViewTab';
|
||||||
|
import MarkdownPreviewTab from './MarkdownPreviewTab';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
TableDataTab,
|
TableDataTab,
|
||||||
@@ -24,4 +25,5 @@ export default {
|
|||||||
ChartTab,
|
ChartTab,
|
||||||
MarkdownEditorTab,
|
MarkdownEditorTab,
|
||||||
MarkdownViewTab,
|
MarkdownViewTab,
|
||||||
|
MarkdownPreviewTab,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -46,6 +46,12 @@ const configLoader = () => ({
|
|||||||
reloadTrigger: 'config-changed',
|
reloadTrigger: 'config-changed',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const markdownManifestLoader = () => ({
|
||||||
|
url: 'files/markdown-manifest',
|
||||||
|
params: {},
|
||||||
|
reloadTrigger: 'files-changed-markdown',
|
||||||
|
});
|
||||||
|
|
||||||
// const sqlObjectListLoader = ({ conid, database }) => ({
|
// const sqlObjectListLoader = ({ conid, database }) => ({
|
||||||
// url: 'metadata/list-objects',
|
// url: 'metadata/list-objects',
|
||||||
// params: { conid, database },
|
// params: { conid, database },
|
||||||
@@ -269,3 +275,10 @@ export function getFiles(args) {
|
|||||||
export function useFiles(args) {
|
export function useFiles(args) {
|
||||||
return useCore(filesLoader, args);
|
return useCore(filesLoader, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getMarkdownManifest(args) {
|
||||||
|
return getCore(markdownManifestLoader, args);
|
||||||
|
}
|
||||||
|
export function useMarkdownManifest(args) {
|
||||||
|
return useCore(markdownManifestLoader, args);
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import localforage from 'localforage';
|
|||||||
import { changeTab } from './common';
|
import { changeTab } from './common';
|
||||||
import { useSetOpenedTabs } from './globalState';
|
import { useSetOpenedTabs } from './globalState';
|
||||||
|
|
||||||
export default function useEditorData({ tabid, loadFromArgs = null }) {
|
export default function useEditorData({ tabid, reloadToken = 0, loadFromArgs = null }) {
|
||||||
const localStorageKey = `tabdata_${tabid}`;
|
const localStorageKey = `tabdata_${tabid}`;
|
||||||
const setOpenedTabs = useSetOpenedTabs();
|
const setOpenedTabs = useSetOpenedTabs();
|
||||||
const changeCounterRef = React.useRef(0);
|
const changeCounterRef = React.useRef(0);
|
||||||
@@ -57,19 +57,20 @@ export default function useEditorData({ tabid, loadFromArgs = null }) {
|
|||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
initialLoad();
|
initialLoad();
|
||||||
}, []);
|
}, [reloadToken]);
|
||||||
|
|
||||||
const saveToStorage = React.useCallback(async () => {
|
const saveToStorage = React.useCallback(async () => {
|
||||||
if (valueRef.current == null) return;
|
if (valueRef.current == null) return;
|
||||||
try {
|
try {
|
||||||
await localforage.setItem(localStorageKey, valueRef.current);
|
await localforage.setItem(localStorageKey, valueRef.current);
|
||||||
|
localStorage.removeItem(localStorageKey);
|
||||||
savedCounterRef.current = changeCounterRef.current;
|
savedCounterRef.current = changeCounterRef.current;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
}, [localStorageKey, valueRef]);
|
}, [localStorageKey, valueRef]);
|
||||||
|
|
||||||
const saveToStorageFallback = React.useCallback(() => {
|
const saveToStorageSync = React.useCallback(() => {
|
||||||
if (valueRef.current == null) return;
|
if (valueRef.current == null) return;
|
||||||
if (savedCounterRef.current == changeCounterRef.current) return; // all saved
|
if (savedCounterRef.current == changeCounterRef.current) return; // all saved
|
||||||
// on window unload must be synchronous actions, save to local storage instead
|
// on window unload must be synchronous actions, save to local storage instead
|
||||||
@@ -86,10 +87,10 @@ export default function useEditorData({ tabid, loadFromArgs = null }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
window.addEventListener('beforeunload', saveToStorageFallback);
|
window.addEventListener('beforeunload', saveToStorageSync);
|
||||||
return () => {
|
return () => {
|
||||||
saveToStorage();
|
saveToStorage();
|
||||||
window.removeEventListener('beforeunload', saveToStorageFallback);
|
window.removeEventListener('beforeunload', saveToStorageSync);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -99,5 +100,7 @@ export default function useEditorData({ tabid, loadFromArgs = null }) {
|
|||||||
isLoading,
|
isLoading,
|
||||||
initialData: initialDataRef.current,
|
initialData: initialDataRef.current,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
|
saveToStorage,
|
||||||
|
saveToStorageSync,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,8 +39,7 @@ const makeStyle = (base) => styled(base)`
|
|||||||
|
|
||||||
const ButtonInput = makeStyle(styled.input``);
|
const ButtonInput = makeStyle(styled.input``);
|
||||||
const FormStyledLabelBase = makeStyle(styled.label``);
|
const FormStyledLabelBase = makeStyle(styled.label``);
|
||||||
export const FormStyledLabel = styled(FormStyledLabelBase)`
|
export const FormStyledLabel = styled(FormStyledLabelBase)``;
|
||||||
`;
|
|
||||||
|
|
||||||
export default function FormStyledButton({
|
export default function FormStyledButton({
|
||||||
onClick = undefined,
|
onClick = undefined,
|
||||||
@@ -67,3 +66,12 @@ export default function FormStyledButton({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const StyledThemedLink = styled.a`
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
color: ${(props) => props.theme.main_background_blue[7]};
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import ConnectionModal from '../modals/ConnectionModal';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import ToolbarButton, { ToolbarButtonExternalImage } from './ToolbarButton';
|
import ToolbarButton, { ToolbarButtonExternalImage } from './ToolbarButton';
|
||||||
import useNewQuery from '../query/useNewQuery';
|
import useNewQuery from '../query/useNewQuery';
|
||||||
import { useConfig } from '../utility/metadataLoaders';
|
import { useConfig, useMarkdownManifest } from '../utility/metadataLoaders';
|
||||||
import { useSetOpenedTabs, useOpenedTabs, useCurrentTheme, useSetCurrentTheme } from '../utility/globalState';
|
import { useSetOpenedTabs, useOpenedTabs, useCurrentTheme, useSetCurrentTheme } from '../utility/globalState';
|
||||||
import { openNewTab } from '../utility/common';
|
import { openNewTab } from '../utility/common';
|
||||||
import useNewFreeTable from '../freetable/useNewFreeTable';
|
import useNewFreeTable from '../freetable/useNewFreeTable';
|
||||||
@@ -25,7 +25,7 @@ export default function ToolBar({ toolbarPortalRef }) {
|
|||||||
const newQuery = useNewQuery();
|
const newQuery = useNewQuery();
|
||||||
const newFreeTable = useNewFreeTable();
|
const newFreeTable = useNewFreeTable();
|
||||||
const config = useConfig();
|
const config = useConfig();
|
||||||
const toolbar = config.toolbar || [];
|
// const toolbar = config.toolbar || [];
|
||||||
const setOpenedTabs = useSetOpenedTabs();
|
const setOpenedTabs = useSetOpenedTabs();
|
||||||
const openedTabs = useOpenedTabs();
|
const openedTabs = useOpenedTabs();
|
||||||
const showModal = useShowModal();
|
const showModal = useShowModal();
|
||||||
@@ -33,6 +33,7 @@ export default function ToolBar({ toolbarPortalRef }) {
|
|||||||
const setCurrentTheme = useSetCurrentTheme();
|
const setCurrentTheme = useSetCurrentTheme();
|
||||||
const extensions = useExtensions();
|
const extensions = useExtensions();
|
||||||
const electron = getElectron();
|
const electron = getElectron();
|
||||||
|
const markdownManifest = useMarkdownManifest();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
window['dbgate_createNewConnection'] = modalState.open;
|
window['dbgate_createNewConnection'] = modalState.open;
|
||||||
@@ -74,47 +75,47 @@ export default function ToolBar({ toolbarPortalRef }) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function openTabFromButton(button) {
|
function openTabFromButton(page) {
|
||||||
if (openedTabs.find((x) => x.tabComponent == 'InfoPageTab' && x.props && x.props.page == button.page)) {
|
if (
|
||||||
|
openedTabs.find(
|
||||||
|
(x) => x.tabComponent == 'MarkdownViewTab' && x.props && x.props.file == page.file && x.closedTime == null
|
||||||
|
)
|
||||||
|
) {
|
||||||
setOpenedTabs((tabs) =>
|
setOpenedTabs((tabs) =>
|
||||||
tabs.map((tab) => ({
|
tabs.map((tab) => ({
|
||||||
...tab,
|
...tab,
|
||||||
selected: tab.tabComponent == 'InfoPageTab' && tab.props && tab.props.page == button.page,
|
selected: tab.tabComponent == 'MarkdownViewTab' && tab.props && tab.props.file == page.file,
|
||||||
closedTime: undefined,
|
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
openNewTab(setOpenedTabs, {
|
openNewTab(setOpenedTabs, {
|
||||||
title: button.title,
|
title: page.button || page.file,
|
||||||
tabComponent: 'InfoPageTab',
|
tabComponent: 'MarkdownViewTab',
|
||||||
icon: button.icon,
|
icon: page.icon || 'img markdown',
|
||||||
props: {
|
props: {
|
||||||
page: button.page,
|
file: page.file,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (config.startupPages) {
|
for (const page of (markdownManifest || []).filter((x) => x.autorun)) {
|
||||||
for (const page of config.startupPages) {
|
openTabFromButton(page);
|
||||||
const button = toolbar.find((x) => x.name == page);
|
|
||||||
if (button) {
|
|
||||||
openTabFromButton(button);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, config && config.startupPages);
|
}, [markdownManifest]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ToolbarContainer>
|
<ToolbarContainer>
|
||||||
<ConnectionModal modalState={modalState} />
|
<ConnectionModal modalState={modalState} />
|
||||||
{!electron && <ToolbarButtonExternalImage image="/logo192.png" onClick={showAbout} />}
|
{!electron && <ToolbarButtonExternalImage image="/logo192.png" onClick={showAbout} />}
|
||||||
{toolbar.map((button) => (
|
{(markdownManifest || [])
|
||||||
<ToolbarButton key={button.name} onClick={() => openTabFromButton(button)} icon={button.icon}>
|
.filter((x) => x.button)
|
||||||
{button.title}
|
.map((x) => (
|
||||||
</ToolbarButton>
|
<ToolbarButton key={x.button} onClick={() => openTabFromButton(x)} icon={x.icon || 'icon markdown'}>
|
||||||
))}
|
{x.button}
|
||||||
|
</ToolbarButton>
|
||||||
|
))}
|
||||||
{config.runAsPortal == false && (
|
{config.runAsPortal == false && (
|
||||||
<ToolbarButton onClick={modalState.open} icon="icon new-connection">
|
<ToolbarButton onClick={modalState.open} icon="icon new-connection">
|
||||||
Add connection
|
Add connection
|
||||||
|
|||||||
Reference in New Issue
Block a user