mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-19 21:16:00 +00:00
custom markdown pages - basic concept
This commit is contained in:
@@ -177,7 +177,43 @@ export function SavedChartFileAppObject({ data, commonProps }) {
|
||||
);
|
||||
}
|
||||
|
||||
[SavedSqlFileAppObject, SavedShellFileAppObject, SavedChartFileAppObject].forEach((fn) => {
|
||||
export function SavedMarkdownFileAppObject({ data, commonProps }) {
|
||||
const { file, folder } = data;
|
||||
const setOpenedTabs = useSetOpenedTabs();
|
||||
|
||||
const showPage = () => {
|
||||
openNewTab(setOpenedTabs, {
|
||||
title: file,
|
||||
icon: 'img markdown',
|
||||
tabComponent: 'MarkdownViewTab',
|
||||
props: {
|
||||
file,
|
||||
},
|
||||
});
|
||||
};
|
||||
return (
|
||||
<SavedFileAppObjectBase
|
||||
data={data}
|
||||
commonProps={commonProps}
|
||||
format="text"
|
||||
icon="img markdown"
|
||||
onLoad={(data) => {
|
||||
openNewTab(
|
||||
setOpenedTabs,
|
||||
{
|
||||
title: file,
|
||||
icon: 'img markdown',
|
||||
tabComponent: 'MarkdownEditorTab',
|
||||
},
|
||||
data
|
||||
);
|
||||
}}
|
||||
menuExt={<DropDownMenuItem onClick={showPage}>Show page</DropDownMenuItem>}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
[SavedSqlFileAppObject, SavedShellFileAppObject, SavedChartFileAppObject, SavedMarkdownFileAppObject].forEach((fn) => {
|
||||
// @ts-ignore
|
||||
fn.extractKey = (data) => data.file;
|
||||
});
|
||||
|
||||
17
packages/web/src/charts/MarkdownToolbar.js
Normal file
17
packages/web/src/charts/MarkdownToolbar.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import useHasPermission from '../utility/useHasPermission';
|
||||
import ToolbarButton from '../widgets/ToolbarButton';
|
||||
|
||||
export default function MarkdownToolbar({ save }) {
|
||||
const hasPermission = useHasPermission();
|
||||
|
||||
return (
|
||||
<>
|
||||
{hasPermission('files/markdown/write') && (
|
||||
<ToolbarButton onClick={save} icon="icon save">
|
||||
Save
|
||||
</ToolbarButton>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import ToolbarButton from '../widgets/ToolbarButton';
|
||||
import styled from 'styled-components';
|
||||
import { TabPage, TabControl } from '../widgets/TabControl';
|
||||
import dimensions from '../theme/dimensions';
|
||||
import JavaScriptEditor from '../sqleditor/JavaScriptEditor';
|
||||
import GenericEditor from '../sqleditor/GenericEditor';
|
||||
import MacroParameters from './MacroParameters';
|
||||
import { WidgetTitle } from '../widgets/WidgetStyles';
|
||||
import { FormButton } from '../utility/forms';
|
||||
@@ -113,7 +113,7 @@ export default function MacroDetail({ selectedMacro, setSelectedMacro, onChangeV
|
||||
</MacroDetailTabWrapper>
|
||||
</TabPage>
|
||||
<TabPage label="JavaScript" key="javascript">
|
||||
<JavaScriptEditor readOnly value={selectedMacro.code} />
|
||||
<GenericEditor readOnly value={selectedMacro.code} mode="javascript" />
|
||||
</TabPage>
|
||||
</TabControl>
|
||||
</MacroDetailContainer>
|
||||
|
||||
@@ -39,6 +39,7 @@ const iconNames = {
|
||||
'icon theme': 'mdi mdi-brightness-6',
|
||||
'icon error': 'mdi mdi-close-circle',
|
||||
'icon ok': 'mdi mdi-check-circle',
|
||||
'icon markdown': 'mdi mdi-application',
|
||||
|
||||
'icon run': 'mdi mdi-play',
|
||||
'icon chevron-down': 'mdi mdi-chevron-down',
|
||||
@@ -60,6 +61,7 @@ const iconNames = {
|
||||
'img sql-file': 'mdi mdi-file',
|
||||
'img shell': 'mdi mdi-flash color-blue-7',
|
||||
'img chart': 'mdi mdi-chart-bar color-magenta-7',
|
||||
'img markdown': 'mdi mdi-application color-red-7',
|
||||
|
||||
'img free-table': 'mdi mdi-table color-green-7',
|
||||
'img macro': 'mdi mdi-hammer-wrench',
|
||||
|
||||
@@ -10,6 +10,7 @@ import 'ace-builds/src-noconflict/mode-mysql';
|
||||
import 'ace-builds/src-noconflict/mode-pgsql';
|
||||
import 'ace-builds/src-noconflict/mode-sqlserver';
|
||||
import 'ace-builds/src-noconflict/mode-javascript';
|
||||
import 'ace-builds/src-noconflict/mode-markdown';
|
||||
import 'ace-builds/src-noconflict/theme-github';
|
||||
import 'ace-builds/src-noconflict/theme-twilight';
|
||||
import 'ace-builds/src-noconflict/ext-searchbox';
|
||||
|
||||
@@ -12,7 +12,8 @@ const Wrapper = styled.div`
|
||||
bottom: 0;
|
||||
`;
|
||||
|
||||
export default function JavaScriptEditor({
|
||||
export default function GenericEditor({
|
||||
mode,
|
||||
value = undefined,
|
||||
readOnly = false,
|
||||
onChange = undefined,
|
||||
@@ -52,7 +53,7 @@ export default function JavaScriptEditor({
|
||||
<Wrapper ref={containerRef}>
|
||||
<AceEditor
|
||||
ref={currentEditorRef}
|
||||
mode="javascript"
|
||||
mode={mode}
|
||||
theme={theme.aceEditorTheme}
|
||||
onChange={onChange}
|
||||
name="UNIQUE_ID_OF_DIV"
|
||||
54
packages/web/src/tabs/MarkdownEditorTab.js
Normal file
54
packages/web/src/tabs/MarkdownEditorTab.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import _ from 'lodash';
|
||||
import keycodes from '../utility/keycodes';
|
||||
import GenericEditor from '../sqleditor/GenericEditor';
|
||||
import MarkdownToolbar from '../charts/MarkdownToolbar';
|
||||
import useEditorData from '../utility/useEditorData';
|
||||
import SaveTabModal from '../modals/SaveTabModal';
|
||||
import useModalState from '../modals/useModalState';
|
||||
import LoadingInfo from '../widgets/LoadingInfo';
|
||||
|
||||
export default function MarkdownEditorTab({ tabid, tabVisible, toolbarPortalRef, ...other }) {
|
||||
const { editorData, setEditorData, isLoading } = useEditorData({ tabid });
|
||||
const saveFileModalState = useModalState();
|
||||
|
||||
const handleKeyDown = (data, hash, keyString, keyCode, event) => {
|
||||
if (keyCode == keycodes.f5) {
|
||||
event.preventDefault();
|
||||
// handlePreview();
|
||||
}
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div>
|
||||
<LoadingInfo message="Loading markdown page" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<GenericEditor
|
||||
value={editorData || ''}
|
||||
onChange={setEditorData}
|
||||
tabVisible={tabVisible}
|
||||
onKeyDown={handleKeyDown}
|
||||
mode="markdown"
|
||||
/>
|
||||
{toolbarPortalRef &&
|
||||
toolbarPortalRef.current &&
|
||||
tabVisible &&
|
||||
ReactDOM.createPortal(<MarkdownToolbar save={saveFileModalState.open} />, toolbarPortalRef.current)}
|
||||
<SaveTabModal
|
||||
modalState={saveFileModalState}
|
||||
tabVisible={tabVisible}
|
||||
data={editorData}
|
||||
format="text"
|
||||
folder="markdown"
|
||||
tabid={tabid}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
41
packages/web/src/tabs/MarkdownViewTab.js
Normal file
41
packages/web/src/tabs/MarkdownViewTab.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import React from 'react';
|
||||
import axios from '../utility/axios';
|
||||
import LoadingInfo from '../widgets/LoadingInfo';
|
||||
import Markdown from 'markdown-to-jsx';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
padding: 10px;
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
`;
|
||||
|
||||
export default function MarkdownViewTab({ file }) {
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
const [text, setText] = React.useState(null);
|
||||
|
||||
const handleLoad = async () => {
|
||||
setIsLoading(true);
|
||||
const resp = await axios.post('files/load', { folder: 'markdown', file, format: 'text' });
|
||||
setText(resp.data);
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
handleLoad();
|
||||
}, []);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div>
|
||||
<LoadingInfo message="Loading markdown page" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<Markdown>{text || ''}</Markdown>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import { VerticalSplitter } from '../widgets/Splitter';
|
||||
import keycodes from '../utility/keycodes';
|
||||
import { changeTab } from '../utility/common';
|
||||
import useSocket from '../utility/SocketProvider';
|
||||
import JavaScriptEditor from '../sqleditor/JavaScriptEditor';
|
||||
import GenericEditor from '../sqleditor/GenericEditor';
|
||||
import ShellToolbar from '../query/ShellToolbar';
|
||||
import RunnerOutputPane from '../query/RunnerOutputPane';
|
||||
import useShowModal from '../modals/showModal';
|
||||
@@ -104,12 +104,13 @@ export default function ShellTab({ tabid, tabVisible, toolbarPortalRef, ...other
|
||||
return (
|
||||
<>
|
||||
<VerticalSplitter>
|
||||
<JavaScriptEditor
|
||||
<GenericEditor
|
||||
value={editorData || ''}
|
||||
onChange={setEditorData}
|
||||
tabVisible={tabVisible}
|
||||
onKeyDown={handleKeyDown}
|
||||
editorRef={editorRef}
|
||||
mode="javascript"
|
||||
/>
|
||||
<RunnerOutputPane runnerId={runnerId} executeNumber={executeNumber} />
|
||||
</VerticalSplitter>
|
||||
|
||||
@@ -8,6 +8,8 @@ import ArchiveFileTab from './ArchiveFileTab';
|
||||
import FreeTableTab from './FreeTableTab';
|
||||
import PluginTab from './PluginTab';
|
||||
import ChartTab from './ChartTab';
|
||||
import MarkdownEditorTab from './MarkdownEditorTab';
|
||||
import MarkdownViewTab from './MarkdownViewTab';
|
||||
|
||||
export default {
|
||||
TableDataTab,
|
||||
@@ -20,4 +22,6 @@ export default {
|
||||
FreeTableTab,
|
||||
PluginTab,
|
||||
ChartTab,
|
||||
MarkdownEditorTab,
|
||||
MarkdownViewTab,
|
||||
};
|
||||
|
||||
@@ -5,7 +5,12 @@ import { AppObjectList } from '../appobj/AppObjectList';
|
||||
import { useOpenedTabs } from '../utility/globalState';
|
||||
import ClosedTabAppObject from '../appobj/ClosedTabAppObject';
|
||||
import { WidgetsInnerContainer } from './WidgetStyles';
|
||||
import { SavedSqlFileAppObject, SavedShellFileAppObject, SavedChartFileAppObject } from '../appobj/SavedFileAppObject';
|
||||
import {
|
||||
SavedSqlFileAppObject,
|
||||
SavedShellFileAppObject,
|
||||
SavedChartFileAppObject,
|
||||
SavedMarkdownFileAppObject,
|
||||
} from '../appobj/SavedFileAppObject';
|
||||
import WidgetColumnBar, { WidgetColumnBarItem } from './WidgetColumnBar';
|
||||
import { useFiles } from '../utility/metadataLoaders';
|
||||
import useHasPermission from '../utility/useHasPermission';
|
||||
@@ -64,6 +69,18 @@ function SavedChartFilesList() {
|
||||
);
|
||||
}
|
||||
|
||||
function SavedMarkdownFilesList() {
|
||||
const files = useFiles({ folder: 'markdown' });
|
||||
|
||||
return (
|
||||
<>
|
||||
<WidgetsInnerContainer>
|
||||
<AppObjectList list={files} AppObjectComponent={SavedMarkdownFileAppObject} />
|
||||
</WidgetsInnerContainer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default function FilesWidget() {
|
||||
const hasPermission = useHasPermission();
|
||||
return (
|
||||
@@ -72,20 +89,25 @@ export default function FilesWidget() {
|
||||
<ClosedTabsList />
|
||||
</WidgetColumnBarItem>
|
||||
{hasPermission('files/sql/read') && (
|
||||
<WidgetColumnBarItem title="Saved SQL files" name="sqlFiles" height="20%">
|
||||
<WidgetColumnBarItem title="Saved SQL files" name="sqlFiles" height="15%">
|
||||
<SavedSqlFilesList />
|
||||
</WidgetColumnBarItem>
|
||||
)}
|
||||
{hasPermission('files/shell/read') && (
|
||||
<WidgetColumnBarItem title="Saved shell files" name="shellFiles" height="20%">
|
||||
<WidgetColumnBarItem title="Saved shell files" name="shellFiles" height="15%">
|
||||
<SavedShellFilesList />
|
||||
</WidgetColumnBarItem>
|
||||
)}
|
||||
{hasPermission('files/charts/read') && (
|
||||
<WidgetColumnBarItem title="Saved charts" name="charts" height="20%">
|
||||
<WidgetColumnBarItem title="Saved charts" name="charts" height="15%">
|
||||
<SavedChartFilesList />
|
||||
</WidgetColumnBarItem>
|
||||
)}
|
||||
{hasPermission('files/markdown/read') && (
|
||||
<WidgetColumnBarItem title="Saved markdown pages" name="markdown" height="15%">
|
||||
<SavedMarkdownFilesList />
|
||||
</WidgetColumnBarItem>
|
||||
)}
|
||||
</WidgetColumnBar>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -66,6 +66,14 @@ export default function ToolBar({ toolbarPortalRef }) {
|
||||
else setCurrentTheme('light');
|
||||
};
|
||||
|
||||
const newMarkdown = () => {
|
||||
openNewTab(setOpenedTabs, {
|
||||
title: 'Page',
|
||||
tabComponent: 'MarkdownEditorTab',
|
||||
icon: 'img markdown',
|
||||
});
|
||||
};
|
||||
|
||||
function openTabFromButton(button) {
|
||||
if (openedTabs.find((x) => x.tabComponent == 'InfoPageTab' && x.props && x.props.page == button.page)) {
|
||||
setOpenedTabs((tabs) =>
|
||||
@@ -118,6 +126,9 @@ export default function ToolBar({ toolbarPortalRef }) {
|
||||
<ToolbarButton onClick={newFreeTable} icon="icon table">
|
||||
Free table editor
|
||||
</ToolbarButton>
|
||||
<ToolbarButton onClick={newMarkdown} icon="icon markdown">
|
||||
New markdown
|
||||
</ToolbarButton>
|
||||
<ToolbarButton onClick={showImport} icon="icon import">
|
||||
Import data
|
||||
</ToolbarButton>
|
||||
|
||||
Reference in New Issue
Block a user