mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-20 11:16:01 +00:00
remove web
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
import React from 'react';
|
||||
import JslDataGrid from '../sqleditor/JslDataGrid';
|
||||
|
||||
export default function ArchiveFileTab({ archiveFolder, archiveFile, tabVisible, toolbarPortalRef, tabid }) {
|
||||
return <JslDataGrid jslid={`archive://${archiveFolder}/${archiveFile}`} />;
|
||||
}
|
||||
|
||||
ArchiveFileTab.matchingProps = ['archiveFile', 'archiveFolder'];
|
||||
@@ -1,74 +0,0 @@
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import { createFreeTableModel } from 'dbgate-datalib';
|
||||
import useUndoReducer from '../utility/useUndoReducer';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { useUpdateDatabaseForTab } from '../utility/globalState';
|
||||
import LoadingInfo from '../widgets/LoadingInfo';
|
||||
import ErrorInfo from '../widgets/ErrorInfo';
|
||||
import useEditorData from '../utility/useEditorData';
|
||||
import SaveTabModal from '../modals/SaveTabModal';
|
||||
import ChartEditor from '../charts/ChartEditor';
|
||||
import ChartToolbar from '../charts/ChartToolbar';
|
||||
import ToolbarPortal from '../utility/ToolbarPortal';
|
||||
|
||||
export default function ChartTab({ tabVisible, toolbarPortalRef, conid, database, tabid }) {
|
||||
const [modelState, dispatchModel] = useUndoReducer(createFreeTableModel());
|
||||
const { initialData, setEditorData, errorMessage, isLoading } = useEditorData({
|
||||
tabid,
|
||||
});
|
||||
useUpdateDatabaseForTab(tabVisible, conid, database);
|
||||
|
||||
React.useEffect(() => {
|
||||
// @ts-ignore
|
||||
if (initialData) dispatchModel({ type: 'reset', value: initialData });
|
||||
}, [initialData]);
|
||||
|
||||
React.useEffect(() => {
|
||||
setEditorData(modelState.value);
|
||||
}, [modelState]);
|
||||
|
||||
const setConfig = React.useCallback(
|
||||
config =>
|
||||
// @ts-ignore
|
||||
dispatchModel({
|
||||
type: 'compute',
|
||||
compute: v => ({ ...v, config: _.isFunction(config) ? config(v.config) : config }),
|
||||
}),
|
||||
[dispatchModel]
|
||||
);
|
||||
|
||||
if (isLoading) {
|
||||
return <LoadingInfo wrapper message="Loading data" />;
|
||||
}
|
||||
if (errorMessage) {
|
||||
return <ErrorInfo message={errorMessage} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ChartEditor
|
||||
data={modelState.value && modelState.value.data}
|
||||
config={modelState.value ? modelState.value.config || {} : {}}
|
||||
setConfig={setConfig}
|
||||
sql={modelState.value && modelState.value.sql}
|
||||
conid={conid}
|
||||
database={database}
|
||||
/>
|
||||
<SaveTabModal
|
||||
tabVisible={tabVisible}
|
||||
toolbarPortalRef={toolbarPortalRef}
|
||||
data={modelState.value}
|
||||
format="json"
|
||||
folder="charts"
|
||||
tabid={tabid}
|
||||
fileExtension="chart"
|
||||
/>
|
||||
<ToolbarPortal toolbarPortalRef={toolbarPortalRef} tabVisible={tabVisible}>
|
||||
<ChartToolbar modelState={modelState} dispatchModel={dispatchModel} />
|
||||
</ToolbarPortal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
ChartTab.allowAddToFavorites = props => true;
|
||||
@@ -1,100 +0,0 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import _ from 'lodash';
|
||||
import keycodes from '../utility/keycodes';
|
||||
import GenericEditor from '../sqleditor/GenericEditor';
|
||||
import useEditorData from '../utility/useEditorData';
|
||||
import LoadingInfo from '../widgets/LoadingInfo';
|
||||
import { useOpenedTabs, useSetOpenedTabs } from '../utility/globalState';
|
||||
import useOpenNewTab from '../utility/useOpenNewTab';
|
||||
import axios from '../utility/axios';
|
||||
import useHasPermission from '../utility/useHasPermission';
|
||||
import ToolbarButton from '../widgets/ToolbarButton';
|
||||
import useShowModal from '../modals/showModal';
|
||||
import ErrorMessageModal from '../modals/ErrorMessageModal';
|
||||
import { useOpenFavorite } from '../appobj/FavoriteFileAppObject';
|
||||
|
||||
function FavoriteEditorToolbar({ save, showPreview }) {
|
||||
const hasPermission = useHasPermission();
|
||||
|
||||
return (
|
||||
<>
|
||||
{hasPermission('files/favorites/write') && save && (
|
||||
<ToolbarButton onClick={save} icon="icon save">
|
||||
Save
|
||||
</ToolbarButton>
|
||||
)}
|
||||
<ToolbarButton onClick={showPreview} icon="icon preview">
|
||||
Preview
|
||||
</ToolbarButton>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default function FavoriteEditorTab({ tabid, tabVisible, savedFile, toolbarPortalRef, ...other }) {
|
||||
const { editorData, setEditorData, isLoading, saveToStorage } = useEditorData({ tabid });
|
||||
const openNewTab = useOpenNewTab();
|
||||
const showModal = useShowModal();
|
||||
const openFavorite = useOpenFavorite();
|
||||
|
||||
const showPreview = () => {
|
||||
try {
|
||||
const data = JSON.parse(editorData);
|
||||
openFavorite(data);
|
||||
} catch (err) {
|
||||
showModal(modalState => (
|
||||
<ErrorMessageModal modalState={modalState} message={err.message} title="Error parsing JSON" />
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyDown = (data, hash, keyString, keyCode, event) => {
|
||||
if (keyCode == keycodes.f5) {
|
||||
event.preventDefault();
|
||||
showPreview();
|
||||
}
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
try {
|
||||
const data = JSON.parse(editorData);
|
||||
axios.post('files/save', {
|
||||
file: savedFile,
|
||||
folder: 'favorites',
|
||||
format: 'json',
|
||||
data,
|
||||
});
|
||||
} catch (err) {
|
||||
showModal(modalState => (
|
||||
<ErrorMessageModal modalState={modalState} message={err.message} title="Error parsing JSON" />
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div>
|
||||
<LoadingInfo message="Loading favorite page" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<GenericEditor
|
||||
value={editorData || ''}
|
||||
onChange={setEditorData}
|
||||
tabVisible={tabVisible}
|
||||
onKeyDown={handleKeyDown}
|
||||
mode="json"
|
||||
/>
|
||||
{toolbarPortalRef &&
|
||||
toolbarPortalRef.current &&
|
||||
tabVisible &&
|
||||
ReactDOM.createPortal(
|
||||
<FavoriteEditorToolbar save={handleSave} showPreview={showPreview} />,
|
||||
toolbarPortalRef.current
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import React from 'react';
|
||||
import { createFreeTableModel } from 'dbgate-datalib';
|
||||
import useUndoReducer from '../utility/useUndoReducer';
|
||||
import { useSetOpenedTabs } from '../utility/globalState';
|
||||
import useGridConfig from '../utility/useGridConfig';
|
||||
import FreeTableGrid from '../freetable/FreeTableGrid';
|
||||
import SaveArchiveModal from '../modals/SaveArchiveModal';
|
||||
import useModalState from '../modals/useModalState';
|
||||
import axios from '../utility/axios';
|
||||
import LoadingInfo from '../widgets/LoadingInfo';
|
||||
import { changeTab } from '../utility/common';
|
||||
import ErrorInfo from '../widgets/ErrorInfo';
|
||||
import useEditorData from '../utility/useEditorData';
|
||||
|
||||
export default function FreeDataTab({ archiveFolder, archiveFile, tabVisible, toolbarPortalRef, tabid, initialArgs }) {
|
||||
const [config, setConfig] = useGridConfig(tabid);
|
||||
const [modelState, dispatchModel] = useUndoReducer(createFreeTableModel());
|
||||
const saveArchiveModalState = useModalState();
|
||||
const setOpenedTabs = useSetOpenedTabs();
|
||||
const { initialData, setEditorData, errorMessage, isLoading } = useEditorData({
|
||||
tabid,
|
||||
loadFromArgs:
|
||||
initialArgs && initialArgs.functionName
|
||||
? () => axios.post('runners/load-reader', initialArgs).then(x => x.data)
|
||||
: null,
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
// @ts-ignore
|
||||
if (initialData) dispatchModel({ type: 'reset', value: initialData });
|
||||
}, [initialData]);
|
||||
|
||||
React.useEffect(() => {
|
||||
setEditorData(modelState.value);
|
||||
}, [modelState]);
|
||||
|
||||
const handleSave = async (folder, file) => {
|
||||
await axios.post('archive/save-free-table', { folder, file, data: modelState.value });
|
||||
changeTab(tabid, setOpenedTabs, tab => ({
|
||||
...tab,
|
||||
title: file,
|
||||
props: { archiveFile: file, archiveFolder: folder },
|
||||
}));
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return <LoadingInfo wrapper message="Loading data" />;
|
||||
}
|
||||
if (errorMessage) {
|
||||
return <ErrorInfo message={errorMessage} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<FreeTableGrid
|
||||
config={config}
|
||||
setConfig={setConfig}
|
||||
modelState={modelState}
|
||||
dispatchModel={dispatchModel}
|
||||
tabVisible={tabVisible}
|
||||
toolbarPortalRef={toolbarPortalRef}
|
||||
onSave={() => saveArchiveModalState.open()}
|
||||
/>
|
||||
<SaveArchiveModal modalState={saveArchiveModalState} folder={archiveFolder} file={archiveFile} onSave={handleSave} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import resolveApi from '../utility/resolveApi';
|
||||
|
||||
const Frame = styled.iframe`
|
||||
flex: 1;
|
||||
border: 0px solid gray;
|
||||
`;
|
||||
|
||||
export default function InfoPageTab({ page }) {
|
||||
return <Frame src={`${resolveApi()}/pages/${page}`} />;
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
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 '../markdown/MarkdownToolbar';
|
||||
import useEditorData from '../utility/useEditorData';
|
||||
import SaveTabModal from '../modals/SaveTabModal';
|
||||
import useModalState from '../modals/useModalState';
|
||||
import LoadingInfo from '../widgets/LoadingInfo';
|
||||
import { useOpenedTabs, useSetOpenedTabs } from '../utility/globalState';
|
||||
import useOpenNewTab from '../utility/useOpenNewTab';
|
||||
import { setSelectedTabFunc } from '../utility/common';
|
||||
import ToolbarPortal from '../utility/ToolbarPortal';
|
||||
|
||||
export default function MarkdownEditorTab({ tabid, tabVisible, toolbarPortalRef, ...other }) {
|
||||
const { editorData, setEditorData, isLoading, saveToStorage } = useEditorData({ tabid });
|
||||
const openedTabs = useOpenedTabs();
|
||||
const setOpenedTabs = useSetOpenedTabs();
|
||||
const openNewTab = useOpenNewTab();
|
||||
|
||||
const handleKeyDown = (data, hash, keyString, keyCode, event) => {
|
||||
if (keyCode == keycodes.f5) {
|
||||
event.preventDefault();
|
||||
showPreview();
|
||||
}
|
||||
};
|
||||
|
||||
const showPreview = async () => {
|
||||
await saveToStorage();
|
||||
const existing = (openedTabs || []).find(x => x.props && x.props.sourceTabId == tabid && x.closedTime == null);
|
||||
if (existing) {
|
||||
setOpenedTabs(tabs => setSelectedTabFunc(tabs, existing.tabid));
|
||||
} else {
|
||||
const thisTab = (openedTabs || []).find(x => x.tabid == tabid);
|
||||
openNewTab({
|
||||
title: thisTab.title,
|
||||
icon: 'img preview',
|
||||
tabComponent: 'MarkdownPreviewTab',
|
||||
props: {
|
||||
sourceTabId: tabid,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div>
|
||||
<LoadingInfo message="Loading markdown page" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<GenericEditor
|
||||
value={editorData || ''}
|
||||
onChange={setEditorData}
|
||||
tabVisible={tabVisible}
|
||||
onKeyDown={handleKeyDown}
|
||||
mode="markdown"
|
||||
/>
|
||||
<ToolbarPortal toolbarPortalRef={toolbarPortalRef} tabVisible={tabVisible}>
|
||||
<MarkdownToolbar showPreview={showPreview} />
|
||||
</ToolbarPortal>
|
||||
<SaveTabModal
|
||||
tabVisible={tabVisible}
|
||||
toolbarPortalRef={toolbarPortalRef}
|
||||
data={editorData}
|
||||
format="text"
|
||||
folder="markdown"
|
||||
tabid={tabid}
|
||||
fileExtension="md"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
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>;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import React from 'react';
|
||||
import axios from '../utility/axios';
|
||||
import LoadingInfo from '../widgets/LoadingInfo';
|
||||
import MarkdownExtendedView from '../markdown/MarkdownExtendedView';
|
||||
|
||||
export default function MarkdownViewTab({ savedFile }) {
|
||||
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: savedFile,
|
||||
format: 'text',
|
||||
});
|
||||
setText(resp.data);
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
handleLoad();
|
||||
}, []);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div>
|
||||
<LoadingInfo message="Loading markdown page" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <MarkdownExtendedView>{text || ''}</MarkdownExtendedView>;
|
||||
}
|
||||
|
||||
MarkdownViewTab.allowAddToFavorites = props => true;
|
||||
@@ -1,138 +0,0 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import _ from 'lodash';
|
||||
import Markdown from 'markdown-to-jsx';
|
||||
import useTheme from '../theme/useTheme';
|
||||
import useFetch from '../utility/useFetch';
|
||||
import LoadingInfo from '../widgets/LoadingInfo';
|
||||
import compareVersions from 'compare-versions';
|
||||
import { extractPluginIcon, extractPluginAuthor } from '../plugins/manifestExtractors';
|
||||
import FormStyledButton from '../widgets/FormStyledButton';
|
||||
import axios from '../utility/axios';
|
||||
import { useInstalledPlugins } from '../utility/metadataLoaders';
|
||||
import useHasPermission from '../utility/useHasPermission';
|
||||
|
||||
const WhitePage = styled.div`
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: ${props => props.theme.main_background};
|
||||
overflow: auto;
|
||||
padding: 10px;
|
||||
`;
|
||||
|
||||
const Icon = styled.img`
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
`;
|
||||
|
||||
const Header = styled.div`
|
||||
display: flex;
|
||||
border-bottom: 1px solid ${props => props.theme.border};
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 20px;
|
||||
`;
|
||||
|
||||
const HeaderBody = styled.div`
|
||||
margin-left: 10px;
|
||||
`;
|
||||
|
||||
const Title = styled.div`
|
||||
font-size: 20pt;
|
||||
`;
|
||||
|
||||
const HeaderLine = styled.div`
|
||||
margin-top: 5px;
|
||||
`;
|
||||
|
||||
const Author = styled.span`
|
||||
font-weight: bold;
|
||||
`;
|
||||
|
||||
const Version = styled.span``;
|
||||
|
||||
function Delimiter() {
|
||||
return <span> | </span>;
|
||||
}
|
||||
|
||||
function PluginTabCore({ packageName }) {
|
||||
const hasPermission = useHasPermission();
|
||||
const theme = useTheme();
|
||||
const installed = useInstalledPlugins();
|
||||
const info = useFetch({
|
||||
params: { packageName },
|
||||
url: 'plugins/info',
|
||||
defaultValue: null,
|
||||
});
|
||||
let { readme, manifest } = info || {};
|
||||
const handleInstall = async () => {
|
||||
axios.post('plugins/install', { packageName });
|
||||
};
|
||||
const handleUninstall = async () => {
|
||||
axios.post('plugins/uninstall', { packageName });
|
||||
};
|
||||
const handleUpgrade = async () => {
|
||||
axios.post('plugins/upgrade', { packageName });
|
||||
};
|
||||
|
||||
if (info == null) {
|
||||
return <LoadingInfo message="Loading extension detail" />;
|
||||
}
|
||||
|
||||
const installedFound = installed.find(x => x.name == packageName);
|
||||
const onlineFound = manifest;
|
||||
|
||||
if (manifest == null) {
|
||||
if (installedFound) {
|
||||
manifest = installedFound;
|
||||
readme = installedFound.readme;
|
||||
}
|
||||
if (manifest == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header theme={theme}>
|
||||
<Icon src={extractPluginIcon(manifest)} />
|
||||
<HeaderBody>
|
||||
<Title theme={theme}>{packageName}</Title>
|
||||
<HeaderLine>
|
||||
<Author>{extractPluginAuthor(manifest)}</Author>
|
||||
<Delimiter />
|
||||
<Version>{installedFound ? installedFound.version : manifest.version}</Version>
|
||||
</HeaderLine>
|
||||
<HeaderLine>
|
||||
{hasPermission('plugins/install') && !installedFound && (
|
||||
<FormStyledButton type="button" value="Install" onClick={handleInstall} />
|
||||
)}
|
||||
{hasPermission('plugins/install') && !!installedFound && (
|
||||
<FormStyledButton type="button" value="Uninstall" onClick={handleUninstall} />
|
||||
)}
|
||||
{hasPermission('plugins/install') &&
|
||||
installedFound &&
|
||||
onlineFound &&
|
||||
compareVersions(onlineFound.version, installedFound.version) > 0 && (
|
||||
<FormStyledButton type="button" value="Upgrade" onClick={handleUpgrade} />
|
||||
)}
|
||||
</HeaderLine>
|
||||
</HeaderBody>
|
||||
</Header>
|
||||
<Markdown>{readme}</Markdown>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default function PluginTab({ packageName }) {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<WhitePage theme={theme}>
|
||||
<PluginTabCore packageName={packageName} />
|
||||
</WhitePage>
|
||||
);
|
||||
}
|
||||
|
||||
PluginTab.matchingProps = ['packageName'];
|
||||
@@ -1,229 +0,0 @@
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import ReactDOM from 'react-dom';
|
||||
import axios from '../utility/axios';
|
||||
|
||||
import { useConnectionInfo } from '../utility/metadataLoaders';
|
||||
import SqlEditor from '../sqleditor/SqlEditor';
|
||||
import { useUpdateDatabaseForTab, useSetOpenedTabs } from '../utility/globalState';
|
||||
import QueryDesignToolbar from '../designer/QueryDesignToolbar';
|
||||
import SocketMessagesView from '../query/SocketMessagesView';
|
||||
import { TabPage } from '../widgets/TabControl';
|
||||
import ResultTabs from '../sqleditor/ResultTabs';
|
||||
import { VerticalSplitter } from '../widgets/Splitter';
|
||||
import keycodes from '../utility/keycodes';
|
||||
import { changeTab } from '../utility/common';
|
||||
import useSocket from '../utility/SocketProvider';
|
||||
import SaveTabModal from '../modals/SaveTabModal';
|
||||
import sqlFormatter from 'sql-formatter';
|
||||
import useEditorData from '../utility/useEditorData';
|
||||
import LoadingInfo from '../widgets/LoadingInfo';
|
||||
import useExtensions from '../utility/useExtensions';
|
||||
import QueryDesigner from '../designer/QueryDesigner';
|
||||
import QueryDesignColumns from '../designer/QueryDesignColumns';
|
||||
import { findEngineDriver } from 'dbgate-tools';
|
||||
import { generateDesignedQuery } from '../designer/designerTools';
|
||||
import useUndoReducer from '../utility/useUndoReducer';
|
||||
import { StatusBarItem } from '../widgets/StatusBar';
|
||||
import useTimerLabel from '../utility/useTimerLabel';
|
||||
import ToolbarPortal from '../utility/ToolbarPortal';
|
||||
|
||||
export default function QueryDesignTab({
|
||||
tabid,
|
||||
conid,
|
||||
database,
|
||||
tabVisible,
|
||||
toolbarPortalRef,
|
||||
statusbarPortalRef,
|
||||
...other
|
||||
}) {
|
||||
const [sessionId, setSessionId] = React.useState(null);
|
||||
const [visibleResultTabs, setVisibleResultTabs] = React.useState(false);
|
||||
const [executeNumber, setExecuteNumber] = React.useState(0);
|
||||
const setOpenedTabs = useSetOpenedTabs();
|
||||
const socket = useSocket();
|
||||
const [busy, setBusy] = React.useState(false);
|
||||
const extensions = useExtensions();
|
||||
const connection = useConnectionInfo({ conid });
|
||||
const engine = findEngineDriver(connection, extensions);
|
||||
const [sqlPreview, setSqlPreview] = React.useState('');
|
||||
const { initialData, setEditorData, isLoading } = useEditorData({
|
||||
tabid,
|
||||
});
|
||||
const [modelState, dispatchModel] = useUndoReducer(
|
||||
{
|
||||
tables: [],
|
||||
references: [],
|
||||
columns: [],
|
||||
},
|
||||
{ mergeNearActions: true }
|
||||
);
|
||||
const timerLabel = useTimerLabel();
|
||||
|
||||
React.useEffect(() => {
|
||||
// @ts-ignore
|
||||
if (initialData) dispatchModel({ type: 'reset', value: initialData });
|
||||
}, [initialData]);
|
||||
|
||||
React.useEffect(() => {
|
||||
setEditorData(modelState.value);
|
||||
}, [modelState]);
|
||||
|
||||
const handleSessionDone = React.useCallback(() => {
|
||||
setBusy(false);
|
||||
timerLabel.stop();
|
||||
}, []);
|
||||
|
||||
const generatePreview = (value, engine) => {
|
||||
if (!engine || !value) return;
|
||||
const sql = generateDesignedQuery(value, engine);
|
||||
setSqlPreview(sqlFormatter.format(sql));
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
generatePreview(modelState.value, engine);
|
||||
}, [modelState.value, engine]);
|
||||
|
||||
const handleChange = React.useCallback(
|
||||
(value, skipUndoChain) =>
|
||||
// @ts-ignore
|
||||
dispatchModel({
|
||||
type: 'compute',
|
||||
useMerge: skipUndoChain,
|
||||
compute: v => (_.isFunction(value) ? value(v) : value),
|
||||
}),
|
||||
[dispatchModel]
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (sessionId && socket) {
|
||||
socket.on(`session-done-${sessionId}`, handleSessionDone);
|
||||
return () => {
|
||||
socket.off(`session-done-${sessionId}`, handleSessionDone);
|
||||
};
|
||||
}
|
||||
}, [sessionId, socket]);
|
||||
|
||||
React.useEffect(() => {
|
||||
changeTab(tabid, setOpenedTabs, tab => ({ ...tab, busy }));
|
||||
}, [busy]);
|
||||
|
||||
useUpdateDatabaseForTab(tabVisible, conid, database);
|
||||
|
||||
const handleExecute = React.useCallback(async () => {
|
||||
if (busy) return;
|
||||
setExecuteNumber(num => num + 1);
|
||||
setVisibleResultTabs(true);
|
||||
|
||||
let sesid = sessionId;
|
||||
if (!sesid) {
|
||||
const resp = await axios.post('sessions/create', {
|
||||
conid,
|
||||
database,
|
||||
});
|
||||
sesid = resp.data.sesid;
|
||||
setSessionId(sesid);
|
||||
}
|
||||
setBusy(true);
|
||||
timerLabel.start();
|
||||
await axios.post('sessions/execute-query', {
|
||||
sesid,
|
||||
sql: sqlPreview,
|
||||
});
|
||||
}, [busy, conid, sessionId, database, sqlPreview]);
|
||||
|
||||
const handleKill = async () => {
|
||||
await axios.post('sessions/kill', {
|
||||
sesid: sessionId,
|
||||
});
|
||||
setSessionId(null);
|
||||
setBusy(false);
|
||||
timerLabel.stop();
|
||||
};
|
||||
|
||||
const handleKeyDown = React.useCallback(
|
||||
e => {
|
||||
if (e.keyCode == keycodes.f5) {
|
||||
e.preventDefault();
|
||||
handleExecute();
|
||||
}
|
||||
},
|
||||
[handleExecute]
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (tabVisible) {
|
||||
document.addEventListener('keydown', handleKeyDown, false);
|
||||
return () => {
|
||||
document.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
}
|
||||
}, [tabVisible, handleKeyDown]);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div>
|
||||
<LoadingInfo message="Loading SQL script" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<VerticalSplitter initialValue="70%">
|
||||
<QueryDesigner
|
||||
value={modelState.value || {}}
|
||||
conid={conid}
|
||||
database={database}
|
||||
engine={connection && connection.engine}
|
||||
onChange={handleChange}
|
||||
></QueryDesigner>
|
||||
<ResultTabs sessionId={sessionId} executeNumber={executeNumber}>
|
||||
<TabPage label="Columns" key="columns">
|
||||
<QueryDesignColumns value={modelState.value || {}} onChange={handleChange} />
|
||||
</TabPage>
|
||||
<TabPage label="SQL" key="sql">
|
||||
<SqlEditor value={sqlPreview} engine={engine} readOnly />
|
||||
</TabPage>
|
||||
{visibleResultTabs && (
|
||||
<TabPage label="Messages" key="messages">
|
||||
<SocketMessagesView
|
||||
eventName={sessionId ? `session-info-${sessionId}` : null}
|
||||
executeNumber={executeNumber}
|
||||
/>
|
||||
</TabPage>
|
||||
)}
|
||||
</ResultTabs>
|
||||
</VerticalSplitter>
|
||||
<ToolbarPortal toolbarPortalRef={toolbarPortalRef} tabVisible={tabVisible}>
|
||||
<QueryDesignToolbar
|
||||
modelState={modelState}
|
||||
dispatchModel={dispatchModel}
|
||||
isDatabaseDefined={conid && database}
|
||||
execute={handleExecute}
|
||||
busy={busy}
|
||||
// cancel={handleCancel}
|
||||
// format={handleFormatCode}
|
||||
isConnected={!!sessionId}
|
||||
kill={handleKill}
|
||||
/>
|
||||
</ToolbarPortal>
|
||||
{statusbarPortalRef &&
|
||||
statusbarPortalRef.current &&
|
||||
tabVisible &&
|
||||
ReactDOM.createPortal(<StatusBarItem>{timerLabel.text}</StatusBarItem>, statusbarPortalRef.current)}
|
||||
<SaveTabModal
|
||||
// modalState={saveFileModalState}
|
||||
tabVisible={tabVisible}
|
||||
toolbarPortalRef={toolbarPortalRef}
|
||||
data={modelState.value}
|
||||
format="json"
|
||||
folder="query"
|
||||
tabid={tabid}
|
||||
fileExtension="qdesign"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
QueryDesignTab.allowAddToFavorites = props => true;
|
||||
@@ -1,253 +0,0 @@
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import ReactDOM from 'react-dom';
|
||||
import axios from '../utility/axios';
|
||||
|
||||
import { useConnectionInfo } from '../utility/metadataLoaders';
|
||||
import SqlEditor from '../sqleditor/SqlEditor';
|
||||
import { useUpdateDatabaseForTab, useSetOpenedTabs } from '../utility/globalState';
|
||||
import QueryToolbar from '../query/QueryToolbar';
|
||||
import SocketMessagesView from '../query/SocketMessagesView';
|
||||
import { TabPage } from '../widgets/TabControl';
|
||||
import ResultTabs from '../sqleditor/ResultTabs';
|
||||
import { VerticalSplitter } from '../widgets/Splitter';
|
||||
import keycodes from '../utility/keycodes';
|
||||
import { changeTab } from '../utility/common';
|
||||
import useSocket from '../utility/SocketProvider';
|
||||
import SaveTabModal from '../modals/SaveTabModal';
|
||||
import useModalState from '../modals/useModalState';
|
||||
import sqlFormatter from 'sql-formatter';
|
||||
import useEditorData from '../utility/useEditorData';
|
||||
import applySqlTemplate from '../utility/applySqlTemplate';
|
||||
import LoadingInfo from '../widgets/LoadingInfo';
|
||||
import useExtensions from '../utility/useExtensions';
|
||||
import useTimerLabel from '../utility/useTimerLabel';
|
||||
import { StatusBarItem } from '../widgets/StatusBar';
|
||||
import ToolbarPortal from '../utility/ToolbarPortal';
|
||||
import { useShowMenu } from '../modals/showMenu';
|
||||
|
||||
function createSqlPreview(sql) {
|
||||
if (!sql) return undefined;
|
||||
let data = sql.substring(0, 500);
|
||||
data = data.replace(/\[[^\]]+\]\./g, '');
|
||||
data = data.replace(/\[a-zA-Z0-9_]+\./g, '');
|
||||
data = data.replace(/\/\*.*\*\//g, '');
|
||||
data = data.replace(/[\[\]]/g, '');
|
||||
data = data.replace(/--[^\n]*\n/g, '');
|
||||
|
||||
for (let step = 1; step <= 5; step++) {
|
||||
data = data.replace(/\([^\(^\)]+\)/g, '');
|
||||
}
|
||||
data = data.replace(/\s+/g, ' ');
|
||||
data = data.trim();
|
||||
data = data.replace(/^(.{50}[^\s]*).*/, '$1');
|
||||
return data;
|
||||
}
|
||||
|
||||
export default function QueryTab({
|
||||
tabid,
|
||||
conid,
|
||||
database,
|
||||
initialArgs,
|
||||
tabVisible,
|
||||
toolbarPortalRef,
|
||||
statusbarPortalRef,
|
||||
...other
|
||||
}) {
|
||||
const [sessionId, setSessionId] = React.useState(null);
|
||||
const [visibleResultTabs, setVisibleResultTabs] = React.useState(false);
|
||||
const [executeNumber, setExecuteNumber] = React.useState(0);
|
||||
const setOpenedTabs = useSetOpenedTabs();
|
||||
const socket = useSocket();
|
||||
const [busy, setBusy] = React.useState(false);
|
||||
const extensions = useExtensions();
|
||||
const timerLabel = useTimerLabel();
|
||||
const { editorData, setEditorData, isLoading } = useEditorData({
|
||||
tabid,
|
||||
loadFromArgs:
|
||||
initialArgs && initialArgs.sqlTemplate
|
||||
? () => applySqlTemplate(initialArgs.sqlTemplate, extensions, { conid, database, ...other })
|
||||
: null,
|
||||
});
|
||||
|
||||
const editorRef = React.useRef(null);
|
||||
|
||||
const handleSessionDone = React.useCallback(() => {
|
||||
setBusy(false);
|
||||
timerLabel.stop();
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (sessionId && socket) {
|
||||
socket.on(`session-done-${sessionId}`, handleSessionDone);
|
||||
return () => {
|
||||
socket.off(`session-done-${sessionId}`, handleSessionDone);
|
||||
};
|
||||
}
|
||||
}, [sessionId, socket]);
|
||||
|
||||
React.useEffect(() => {
|
||||
changeTab(tabid, setOpenedTabs, tab => ({ ...tab, busy }));
|
||||
}, [busy]);
|
||||
|
||||
useUpdateDatabaseForTab(tabVisible, conid, database);
|
||||
const connection = useConnectionInfo({ conid });
|
||||
|
||||
const updateContentPreviewDebounced = React.useRef(
|
||||
_.debounce(
|
||||
// @ts-ignore
|
||||
sql =>
|
||||
changeTab(tabid, setOpenedTabs, tab => ({
|
||||
...tab,
|
||||
contentPreview: createSqlPreview(sql),
|
||||
})),
|
||||
500
|
||||
)
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
// @ts-ignore
|
||||
updateContentPreviewDebounced.current(editorData);
|
||||
}, [editorData]);
|
||||
|
||||
const handleExecute = async () => {
|
||||
if (busy) return;
|
||||
setExecuteNumber(num => num + 1);
|
||||
setVisibleResultTabs(true);
|
||||
const selectedText = editorRef.current.editor.getSelectedText();
|
||||
|
||||
let sesid = sessionId;
|
||||
if (!sesid) {
|
||||
const resp = await axios.post('sessions/create', {
|
||||
conid,
|
||||
database,
|
||||
});
|
||||
sesid = resp.data.sesid;
|
||||
setSessionId(sesid);
|
||||
}
|
||||
setBusy(true);
|
||||
timerLabel.start();
|
||||
await axios.post('sessions/execute-query', {
|
||||
sesid,
|
||||
sql: selectedText || editorData,
|
||||
});
|
||||
};
|
||||
// const handleExecuteRef = React.useRef(handleExecute);
|
||||
// handleExecuteRef.current = handleExecute;
|
||||
|
||||
// const handleCancel = () => {
|
||||
// axios.post('sessions/cancel', {
|
||||
// sesid: sessionId,
|
||||
// });
|
||||
// };
|
||||
|
||||
const handleKill = async () => {
|
||||
await axios.post('sessions/kill', {
|
||||
sesid: sessionId,
|
||||
});
|
||||
setSessionId(null);
|
||||
setBusy(false);
|
||||
timerLabel.stop();
|
||||
};
|
||||
|
||||
const handleKeyDown = (data, hash, keyString, keyCode, event) => {
|
||||
if (keyCode == keycodes.f5 || (keyCode == keycodes.enter && event.ctrlKey)) {
|
||||
event.preventDefault();
|
||||
handleExecute();
|
||||
}
|
||||
};
|
||||
|
||||
const handleMesageClick = message => {
|
||||
// console.log('EDITOR', editorRef.current.editor);
|
||||
if (editorRef.current && editorRef.current.editor) {
|
||||
editorRef.current.editor.gotoLine(message.line);
|
||||
}
|
||||
};
|
||||
|
||||
const handleFormatCode = () => {
|
||||
editorRef.current.editor.setValue(sqlFormatter.format(editorRef.current.editor.getValue()));
|
||||
editorRef.current.editor.clearSelection();
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div>
|
||||
<LoadingInfo message="Loading SQL script" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<VerticalSplitter>
|
||||
<SqlEditor
|
||||
value={editorData || ''}
|
||||
onChange={setEditorData}
|
||||
tabVisible={tabVisible}
|
||||
engine={connection && connection.engine}
|
||||
onKeyDown={handleKeyDown}
|
||||
editorRef={editorRef}
|
||||
conid={conid}
|
||||
database={database}
|
||||
onExecute={handleExecute}
|
||||
/>
|
||||
{visibleResultTabs && (
|
||||
<ResultTabs sessionId={sessionId} executeNumber={executeNumber}>
|
||||
<TabPage label="Messages" key="messages">
|
||||
<SocketMessagesView
|
||||
eventName={sessionId ? `session-info-${sessionId}` : null}
|
||||
onMessageClick={handleMesageClick}
|
||||
executeNumber={executeNumber}
|
||||
showProcedure
|
||||
showLine
|
||||
/>
|
||||
</TabPage>
|
||||
</ResultTabs>
|
||||
)}
|
||||
</VerticalSplitter>
|
||||
{/* {toolbarPortalRef &&
|
||||
toolbarPortalRef.current &&
|
||||
tabVisible &&
|
||||
ReactDOM.createPortal(
|
||||
<QueryToolbar
|
||||
isDatabaseDefined={conid && database}
|
||||
execute={handleExecute}
|
||||
busy={busy}
|
||||
// cancel={handleCancel}
|
||||
format={handleFormatCode}
|
||||
save={saveFileModalState.open}
|
||||
isConnected={!!sessionId}
|
||||
kill={handleKill}
|
||||
/>,
|
||||
toolbarPortalRef.current
|
||||
)} */}
|
||||
{statusbarPortalRef &&
|
||||
statusbarPortalRef.current &&
|
||||
tabVisible &&
|
||||
ReactDOM.createPortal(<StatusBarItem>{timerLabel.text}</StatusBarItem>, statusbarPortalRef.current)}
|
||||
<ToolbarPortal toolbarPortalRef={toolbarPortalRef} tabVisible={tabVisible}>
|
||||
<QueryToolbar
|
||||
isDatabaseDefined={conid && database}
|
||||
execute={handleExecute}
|
||||
busy={busy}
|
||||
// cancel={handleCancel}
|
||||
format={handleFormatCode}
|
||||
// save={saveFileModalState.open}
|
||||
isConnected={!!sessionId}
|
||||
kill={handleKill}
|
||||
/>
|
||||
</ToolbarPortal>
|
||||
<SaveTabModal
|
||||
toolbarPortalRef={toolbarPortalRef}
|
||||
tabVisible={tabVisible}
|
||||
data={editorData}
|
||||
format="text"
|
||||
folder="sql"
|
||||
tabid={tabid}
|
||||
fileExtension="sql"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
QueryTab.allowAddToFavorites = props => true;
|
||||
@@ -1,148 +0,0 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import _ from 'lodash';
|
||||
import axios from '../utility/axios';
|
||||
import { useSetOpenedTabs } from '../utility/globalState';
|
||||
import { VerticalSplitter } from '../widgets/Splitter';
|
||||
import keycodes from '../utility/keycodes';
|
||||
import { changeTab } from '../utility/common';
|
||||
import useSocket from '../utility/SocketProvider';
|
||||
import GenericEditor from '../sqleditor/GenericEditor';
|
||||
import ShellToolbar from '../query/ShellToolbar';
|
||||
import RunnerOutputPane from '../query/RunnerOutputPane';
|
||||
import useShowModal from '../modals/showModal';
|
||||
import ImportExportModal from '../modals/ImportExportModal';
|
||||
import useEditorData from '../utility/useEditorData';
|
||||
import SaveTabModal from '../modals/SaveTabModal';
|
||||
import LoadingInfo from '../widgets/LoadingInfo';
|
||||
import useTimerLabel from '../utility/useTimerLabel';
|
||||
import { StatusBarItem } from '../widgets/StatusBar';
|
||||
import ToolbarPortal from '../utility/ToolbarPortal';
|
||||
|
||||
const configRegex = /\s*\/\/\s*@ImportExportConfigurator\s*\n\s*\/\/\s*(\{[^\n]+\})\n/;
|
||||
const requireRegex = /\s*(\/\/\s*@require\s+[^\n]+)\n/g;
|
||||
const initRegex = /([^\n]+\/\/\s*@init)/g;
|
||||
|
||||
export default function ShellTab({ tabid, tabVisible, toolbarPortalRef, statusbarPortalRef, ...other }) {
|
||||
const [busy, setBusy] = React.useState(false);
|
||||
const showModal = useShowModal();
|
||||
const { editorData, setEditorData, isLoading } = useEditorData({ tabid });
|
||||
const timerLabel = useTimerLabel();
|
||||
|
||||
const setOpenedTabs = useSetOpenedTabs();
|
||||
|
||||
const [executeNumber, setExecuteNumber] = React.useState(0);
|
||||
const [runnerId, setRunnerId] = React.useState(null);
|
||||
|
||||
const socket = useSocket();
|
||||
|
||||
React.useEffect(() => {
|
||||
changeTab(tabid, setOpenedTabs, tab => ({ ...tab, busy }));
|
||||
}, [busy]);
|
||||
|
||||
const editorRef = React.useRef(null);
|
||||
|
||||
const handleRunnerDone = React.useCallback(() => {
|
||||
setBusy(false);
|
||||
timerLabel.stop();
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (runnerId && socket) {
|
||||
socket.on(`runner-done-${runnerId}`, handleRunnerDone);
|
||||
return () => {
|
||||
socket.off(`runner-done-${runnerId}`, handleRunnerDone);
|
||||
};
|
||||
}
|
||||
}, [runnerId, socket]);
|
||||
|
||||
const handleExecute = async () => {
|
||||
if (busy) return;
|
||||
setExecuteNumber(num => num + 1);
|
||||
const selectedText = editorRef.current.editor.getSelectedText();
|
||||
|
||||
let runid = runnerId;
|
||||
const resp = await axios.post('runners/start', {
|
||||
script: selectedText
|
||||
? [...(editorData || '').matchAll(requireRegex)].map(x => `${x[1]}\n`).join('') +
|
||||
[...(editorData || '').matchAll(initRegex)].map(x => `${x[1]}\n`).join('') +
|
||||
selectedText
|
||||
: editorData,
|
||||
});
|
||||
runid = resp.data.runid;
|
||||
setRunnerId(runid);
|
||||
setBusy(true);
|
||||
timerLabel.start();
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
axios.post('runners/cancel', {
|
||||
runid: runnerId,
|
||||
});
|
||||
timerLabel.stop();
|
||||
};
|
||||
|
||||
const handleKeyDown = (data, hash, keyString, keyCode, event) => {
|
||||
if (keyCode == keycodes.f5) {
|
||||
event.preventDefault();
|
||||
handleExecute();
|
||||
}
|
||||
};
|
||||
|
||||
const handleEdit = () => {
|
||||
const jsonTextMatch = (editorData || '').match(configRegex);
|
||||
if (jsonTextMatch) {
|
||||
showModal(modalState => (
|
||||
<ImportExportModal modalState={modalState} initialValues={JSON.parse(jsonTextMatch[1])} />
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div>
|
||||
<LoadingInfo message="Loading shell script" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<VerticalSplitter>
|
||||
<GenericEditor
|
||||
value={editorData || ''}
|
||||
onChange={setEditorData}
|
||||
tabVisible={tabVisible}
|
||||
onKeyDown={handleKeyDown}
|
||||
editorRef={editorRef}
|
||||
mode="javascript"
|
||||
/>
|
||||
<RunnerOutputPane runnerId={runnerId} executeNumber={executeNumber} />
|
||||
</VerticalSplitter>
|
||||
<ToolbarPortal toolbarPortalRef={toolbarPortalRef} tabVisible={tabVisible}>
|
||||
<ShellToolbar
|
||||
execute={handleExecute}
|
||||
busy={busy}
|
||||
cancel={handleCancel}
|
||||
edit={handleEdit}
|
||||
editAvailable={configRegex.test(editorData || '')}
|
||||
/>
|
||||
</ToolbarPortal>
|
||||
{statusbarPortalRef &&
|
||||
statusbarPortalRef.current &&
|
||||
tabVisible &&
|
||||
ReactDOM.createPortal(<StatusBarItem>{timerLabel.text}</StatusBarItem>, statusbarPortalRef.current)}
|
||||
<SaveTabModal
|
||||
toolbarPortalRef={toolbarPortalRef}
|
||||
tabVisible={tabVisible}
|
||||
data={editorData}
|
||||
format="text"
|
||||
folder="shell"
|
||||
tabid={tabid}
|
||||
fileExtension="js"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
ShellTab.allowAddToFavorites = props => true;
|
||||
@@ -1,31 +0,0 @@
|
||||
import React from 'react';
|
||||
import { createGridCache, createChangeSet, createGridConfig } from 'dbgate-datalib';
|
||||
import useUndoReducer from '../utility/useUndoReducer';
|
||||
import usePropsCompare from '../utility/usePropsCompare';
|
||||
import { useUpdateDatabaseForTab } from '../utility/globalState';
|
||||
import TableDataGrid from '../datagrid/TableDataGrid';
|
||||
import useGridConfig from '../utility/useGridConfig';
|
||||
|
||||
export default function TableDataTab({ conid, database, schemaName, pureName, tabVisible, toolbarPortalRef, tabid }) {
|
||||
const [changeSetState, dispatchChangeSet] = useUndoReducer(createChangeSet());
|
||||
useUpdateDatabaseForTab(tabVisible, conid, database);
|
||||
const [config, setConfig] = useGridConfig(tabid);
|
||||
|
||||
return (
|
||||
<TableDataGrid
|
||||
conid={conid}
|
||||
config={config}
|
||||
setConfig={setConfig}
|
||||
database={database}
|
||||
schemaName={schemaName}
|
||||
pureName={pureName}
|
||||
tabVisible={tabVisible}
|
||||
toolbarPortalRef={toolbarPortalRef}
|
||||
changeSetState={changeSetState}
|
||||
dispatchChangeSet={dispatchChangeSet}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
TableDataTab.matchingProps = ['conid', 'database', 'schemaName', 'pureName'];
|
||||
TableDataTab.allowAddToFavorites = props => true;
|
||||
@@ -1,141 +0,0 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import _ from 'lodash';
|
||||
import ObjectListControl from '../utility/ObjectListControl';
|
||||
import { TableColumn } from '../utility/TableControl';
|
||||
import { useTableInfo, useDbCore } from '../utility/metadataLoaders';
|
||||
import useTheme from '../theme/useTheme';
|
||||
import ColumnLabel from '../datagrid/ColumnLabel';
|
||||
import { FontIcon } from '../icons';
|
||||
|
||||
const WhitePage = styled.div`
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: ${props => props.theme.main_background};
|
||||
overflow: auto;
|
||||
`;
|
||||
|
||||
const IconTextSpan = styled.span`
|
||||
white-space: nowrap;
|
||||
`;
|
||||
|
||||
function getConstraintIcon(data) {
|
||||
if (data.constraintType == 'primaryKey') return 'img primary-key';
|
||||
if (data.constraintType == 'foreignKey') return 'img foreign-key';
|
||||
return null;
|
||||
}
|
||||
|
||||
function ConstraintLabel({ data }) {
|
||||
const icon = getConstraintIcon(data);
|
||||
return (
|
||||
<IconTextSpan>
|
||||
<FontIcon icon={icon} /> {data.constraintName}
|
||||
</IconTextSpan>
|
||||
);
|
||||
}
|
||||
|
||||
export default function TableStructureTab({ conid, database, schemaName, pureName, objectTypeField = 'tables' }) {
|
||||
const theme = useTheme();
|
||||
const tableInfo = useDbCore({ conid, database, schemaName, pureName, objectTypeField });
|
||||
if (!tableInfo) return null;
|
||||
const { columns, primaryKey, foreignKeys, dependencies } = tableInfo;
|
||||
return (
|
||||
<WhitePage theme={theme}>
|
||||
<ObjectListControl
|
||||
collection={columns.map((x, index) => ({ ...x, ordinal: index + 1 }))}
|
||||
NameComponent={({ data }) => <ColumnLabel {...data} forceIcon />}
|
||||
// makeAppObj={columnAppObject}
|
||||
title="Columns"
|
||||
>
|
||||
<TableColumn
|
||||
fieldName="notNull"
|
||||
header="Not NULL"
|
||||
sortable={true}
|
||||
formatter={row => (row.notNull ? 'YES' : 'NO')}
|
||||
/>
|
||||
<TableColumn fieldName="dataType" header="Data Type" sortable={true} />
|
||||
<TableColumn fieldName="defaultValue" header="Default value" sortable={true} />
|
||||
<TableColumn
|
||||
fieldName="isSparse"
|
||||
header="Is Sparse"
|
||||
sortable={true}
|
||||
formatter={row => (row.isSparse ? 'YES' : 'NO')}
|
||||
/>
|
||||
<TableColumn fieldName="computedExpression" header="Computed Expression" sortable={true} />
|
||||
<TableColumn
|
||||
fieldName="isPersisted"
|
||||
header="Is Persisted"
|
||||
sortable={true}
|
||||
formatter={row => (row.isPersisted ? 'YES' : 'NO')}
|
||||
/>
|
||||
{/* {_.includes(dbCaps.columnListOptionalColumns, 'referencedTableNamesFormatted') && (
|
||||
<TableColumn fieldName="referencedTableNamesFormatted" header="References" sortable={true} />
|
||||
)}
|
||||
<TableColumn
|
||||
fieldName="actions"
|
||||
header=""
|
||||
formatter={row => (
|
||||
<span>
|
||||
<Link
|
||||
linkElementId={encodeHtmlId(`button_delete_column_${row.column.name}`)}
|
||||
onClick={() => this.deleteColumn(row)}
|
||||
>
|
||||
Delete
|
||||
</Link>{' '}
|
||||
|{' '}
|
||||
<Link
|
||||
linkElementId={encodeHtmlId(`button_edit_column__${row.column.name}`)}
|
||||
onClick={() => this.editColumn(row)}
|
||||
>
|
||||
Edit
|
||||
</Link>
|
||||
</span>
|
||||
)}
|
||||
/> */}
|
||||
</ObjectListControl>
|
||||
|
||||
<ObjectListControl collection={_.compact([primaryKey])} NameComponent={ConstraintLabel} title="Primary key">
|
||||
<TableColumn
|
||||
fieldName="columns"
|
||||
header="Columns"
|
||||
formatter={row => row.columns.map(x => x.columnName).join(', ')}
|
||||
/>
|
||||
</ObjectListControl>
|
||||
|
||||
<ObjectListControl collection={foreignKeys} NameComponent={ConstraintLabel} title="Foreign keys">
|
||||
<TableColumn
|
||||
fieldName="baseColumns"
|
||||
header="Base columns"
|
||||
formatter={row => row.columns.map(x => x.columnName).join(', ')}
|
||||
/>
|
||||
<TableColumn fieldName="refTable" header="Referenced table" formatter={row => row.refTableName} />
|
||||
<TableColumn
|
||||
fieldName="refColumns"
|
||||
header="Referenced columns"
|
||||
formatter={row => row.columns.map(x => x.refColumnName).join(', ')}
|
||||
/>
|
||||
<TableColumn fieldName="updateAction" header="ON UPDATE" />
|
||||
<TableColumn fieldName="deleteAction" header="ON DELETE" />
|
||||
</ObjectListControl>
|
||||
|
||||
<ObjectListControl collection={dependencies} NameComponent={ConstraintLabel} title="Dependencies">
|
||||
<TableColumn
|
||||
fieldName="baseColumns"
|
||||
header="Base columns"
|
||||
formatter={row => row.columns.map(x => x.columnName).join(', ')}
|
||||
/>
|
||||
<TableColumn fieldName="baseTable" header="Base table" formatter={row => row.pureName} />
|
||||
<TableColumn
|
||||
fieldName="refColumns"
|
||||
header="Referenced columns"
|
||||
formatter={row => row.columns.map(x => x.refColumnName).join(', ')}
|
||||
/>
|
||||
<TableColumn fieldName="updateAction" header="ON UPDATE" />
|
||||
<TableColumn fieldName="deleteAction" header="ON DELETE" />
|
||||
</ObjectListControl>
|
||||
</WhitePage>
|
||||
);
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
import React from 'react';
|
||||
import DataGrid from '../datagrid/DataGrid';
|
||||
import { ViewGridDisplay, createGridCache, createChangeSet } from 'dbgate-datalib';
|
||||
import { useConnectionInfo, useViewInfo } from '../utility/metadataLoaders';
|
||||
import useUndoReducer from '../utility/useUndoReducer';
|
||||
import usePropsCompare from '../utility/usePropsCompare';
|
||||
import { useUpdateDatabaseForTab } from '../utility/globalState';
|
||||
import useGridConfig from '../utility/useGridConfig';
|
||||
import SqlDataGridCore from '../datagrid/SqlDataGridCore';
|
||||
import useExtensions from '../utility/useExtensions';
|
||||
import { findEngineDriver } from 'dbgate-tools';
|
||||
|
||||
export default function ViewDataTab({ conid, database, schemaName, pureName, tabVisible, toolbarPortalRef, tabid }) {
|
||||
const viewInfo = useViewInfo({ conid, database, schemaName, pureName });
|
||||
const [config, setConfig] = useGridConfig(tabid);
|
||||
const [cache, setCache] = React.useState(createGridCache());
|
||||
const [changeSetState, dispatchChangeSet] = useUndoReducer(createChangeSet());
|
||||
const extensions = useExtensions();
|
||||
|
||||
useUpdateDatabaseForTab(tabVisible, conid, database);
|
||||
const connection = useConnectionInfo({ conid });
|
||||
|
||||
// usePropsCompare({ tableInfo, connection, config, cache });
|
||||
|
||||
const display = React.useMemo(
|
||||
() =>
|
||||
viewInfo && connection
|
||||
? new ViewGridDisplay(
|
||||
viewInfo,
|
||||
findEngineDriver(connection, extensions),
|
||||
//@ts-ignore
|
||||
config,
|
||||
setConfig,
|
||||
cache,
|
||||
setCache
|
||||
)
|
||||
: null,
|
||||
[viewInfo, connection, config, cache]
|
||||
);
|
||||
|
||||
if (!display) return null;
|
||||
|
||||
return (
|
||||
<DataGrid
|
||||
// key={`${conid}, ${database}, ${schemaName}, ${pureName}`}
|
||||
conid={conid}
|
||||
database={database}
|
||||
display={display}
|
||||
tabVisible={tabVisible}
|
||||
changeSetState={changeSetState}
|
||||
dispatchChangeSet={dispatchChangeSet}
|
||||
toolbarPortalRef={toolbarPortalRef}
|
||||
GridCore={SqlDataGridCore}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
ViewDataTab.matchingProps = ['conid', 'database', 'schemaName', 'pureName'];
|
||||
ViewDataTab.allowAddToFavorites = props => true;
|
||||
@@ -1,33 +0,0 @@
|
||||
import TableDataTab from './TableDataTab';
|
||||
import ViewDataTab from './ViewDataTab';
|
||||
import TableStructureTab from './TableStructureTab';
|
||||
import QueryTab from './QueryTab';
|
||||
import ShellTab from './ShellTab';
|
||||
import InfoPageTab from './InfoPageTab';
|
||||
import ArchiveFileTab from './ArchiveFileTab';
|
||||
import FreeTableTab from './FreeTableTab';
|
||||
import PluginTab from './PluginTab';
|
||||
import ChartTab from './ChartTab';
|
||||
import MarkdownEditorTab from './MarkdownEditorTab';
|
||||
import MarkdownViewTab from './MarkdownViewTab';
|
||||
import MarkdownPreviewTab from './MarkdownPreviewTab';
|
||||
import FavoriteEditorTab from './FavoriteEditorTab';
|
||||
import QueryDesignTab from './QueryDesignTab';
|
||||
|
||||
export default {
|
||||
TableDataTab,
|
||||
ViewDataTab,
|
||||
TableStructureTab,
|
||||
QueryTab,
|
||||
InfoPageTab,
|
||||
ShellTab,
|
||||
ArchiveFileTab,
|
||||
FreeTableTab,
|
||||
PluginTab,
|
||||
ChartTab,
|
||||
MarkdownEditorTab,
|
||||
MarkdownViewTab,
|
||||
MarkdownPreviewTab,
|
||||
FavoriteEditorTab,
|
||||
QueryDesignTab,
|
||||
};
|
||||
Reference in New Issue
Block a user