mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
search plugins, plugin tab
This commit is contained in:
parent
e2ee1f7561
commit
3771134b1c
@ -46,6 +46,7 @@
|
||||
"mssql": "^6.0.1",
|
||||
"mysql": "^2.17.1",
|
||||
"nedb-promises": "^4.0.1",
|
||||
"node-fetch": "^2.6.1",
|
||||
"pg": "^7.17.0",
|
||||
"pg-query-stream": "^3.1.1",
|
||||
"xlsx": "^0.16.8"
|
||||
|
22
packages/api/src/controllers/plugins.js
Normal file
22
packages/api/src/controllers/plugins.js
Normal file
@ -0,0 +1,22 @@
|
||||
const fs = require('fs-extra');
|
||||
const fetch = require('node-fetch');
|
||||
|
||||
module.exports = {
|
||||
script_meta: 'get',
|
||||
async script({ plugin }) {
|
||||
const data = await fs.readFile('/home/jena/jenasoft/dbgate-plugin-csv/lib/frontend.js', {
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
return data;
|
||||
},
|
||||
|
||||
search_meta: 'get',
|
||||
async search({ filter }) {
|
||||
console.log(`https://api.npms.io/v2/search?q=keywords:dbgate ${encodeURIComponent(filter)}`);
|
||||
const response = await fetch(`https://api.npms.io/v2/search?q=keywords:dbgate ${encodeURIComponent(filter)}`);
|
||||
const json = await response.json();
|
||||
console.log(json);
|
||||
const { results } = json || {};
|
||||
return results || [];
|
||||
},
|
||||
};
|
@ -23,6 +23,7 @@ const config = require('./controllers/config');
|
||||
const files = require('./controllers/files');
|
||||
const archive = require('./controllers/archive');
|
||||
const uploads = require('./controllers/uploads');
|
||||
const plugins = require('./controllers/plugins');
|
||||
|
||||
const { rundir } = require('./utility/directories');
|
||||
|
||||
@ -67,6 +68,7 @@ function start(argument = null) {
|
||||
useController(app, '/files', files);
|
||||
useController(app, '/archive', archive);
|
||||
useController(app, '/uploads', uploads);
|
||||
useController(app, '/plugins', plugins);
|
||||
|
||||
if (process.env.PAGES_DIRECTORY) {
|
||||
app.use('/pages', express.static(process.env.PAGES_DIRECTORY));
|
||||
|
@ -35,6 +35,8 @@ const dirFunc = (dirname, clean = false) => () => {
|
||||
const jsldir = dirFunc('jsl', true);
|
||||
const rundir = dirFunc('run', true);
|
||||
const uploadsdir = dirFunc('uploads', true);
|
||||
const pluginstmpdir = dirFunc('plugins-tmp', true);
|
||||
const pluginsdir = dirFunc('plugins');
|
||||
const archivedir = dirFunc('archive');
|
||||
|
||||
module.exports = {
|
||||
@ -44,4 +46,6 @@ module.exports = {
|
||||
uploadsdir,
|
||||
archivedir,
|
||||
ensureDirectory,
|
||||
pluginstmpdir,
|
||||
pluginsdir,
|
||||
};
|
||||
|
@ -16,6 +16,7 @@ import ConnectionsPinger from './utility/ConnectionsPinger';
|
||||
import { ModalLayerProvider } from './modals/showModal';
|
||||
import UploadsProvider from './utility/UploadsProvider';
|
||||
import ThemeHelmet from './themes/ThemeHelmet';
|
||||
import PluginsProvider from './plugins/PluginsProvider';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
@ -31,7 +32,9 @@ function App() {
|
||||
<CurrentArchiveProvider>
|
||||
<CurrentThemeProvider>
|
||||
<UploadsProvider>
|
||||
<ThemeHelmet />
|
||||
<PluginsProvider>
|
||||
<ThemeHelmet />
|
||||
</PluginsProvider>
|
||||
<Screen />
|
||||
</UploadsProvider>
|
||||
</CurrentThemeProvider>
|
||||
|
@ -42,6 +42,7 @@ const iconNames = {
|
||||
|
||||
'icon run': 'mdi mdi-play',
|
||||
'icon chevron-down': 'mdi mdi-chevron-down',
|
||||
'icon plugin': 'mdi mdi-toy-brick',
|
||||
|
||||
'img green-ok': 'mdi mdi-check-circle color-green-8',
|
||||
'img alert': 'mdi mdi-alert-circle color-blue-6',
|
||||
|
86
packages/web/src/plugins/PluginsList.js
Normal file
86
packages/web/src/plugins/PluginsList.js
Normal file
@ -0,0 +1,86 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import useTheme from '../theme/useTheme';
|
||||
import { openNewTab } from '../utility/common';
|
||||
import { useSetOpenedTabs } from '../utility/globalState';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
margin: 1px 3px 10px 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&:hover {
|
||||
background-color: ${(props) => props.theme.left_background_blue[1]};
|
||||
}
|
||||
`;
|
||||
|
||||
const Texts = styled.div`
|
||||
margin-left: 10px;
|
||||
`;
|
||||
|
||||
const Name = styled.div`
|
||||
font-weight: bold;
|
||||
`;
|
||||
|
||||
const Line = styled.div`
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
const Icon = styled.img`
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
`;
|
||||
|
||||
const Description = styled.div`
|
||||
font-style: italic;
|
||||
`;
|
||||
|
||||
const Author = styled.div`
|
||||
font-weight: bold;
|
||||
`;
|
||||
|
||||
const Version = styled.div`
|
||||
margin-left: 5px;
|
||||
`;
|
||||
|
||||
function openPlugin(setOpenedTabs, plugin) {
|
||||
openNewTab(setOpenedTabs, {
|
||||
title: plugin.package.name,
|
||||
icon: 'icon plugin',
|
||||
tabComponent: 'PluginTab',
|
||||
props: {
|
||||
plugin,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function PluginsListItem({ plugin }) {
|
||||
const setOpenedTabs = useSetOpenedTabs();
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Wrapper onClick={() => openPlugin(setOpenedTabs, plugin)} theme={theme}>
|
||||
<Icon src="https://raw.githubusercontent.com/dbshell/dbgate-plugin-csv/master/icon.svg" />
|
||||
<Texts>
|
||||
<Line>
|
||||
<Name>{plugin.package.name}</Name>
|
||||
<Version>{plugin.package.version}</Version>
|
||||
</Line>
|
||||
<Line>
|
||||
<Description>{plugin.package.description}</Description>
|
||||
</Line>
|
||||
<Line>
|
||||
<Author>{plugin.package.author && plugin.package.author.name}</Author>
|
||||
</Line>
|
||||
</Texts>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default function PluginsList({ plugins }) {
|
||||
return (
|
||||
<>
|
||||
{plugins.map((plugin) => (
|
||||
<PluginsListItem plugin={plugin} key={plugin.package.name} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
23
packages/web/src/plugins/PluginsProvider.js
Normal file
23
packages/web/src/plugins/PluginsProvider.js
Normal file
@ -0,0 +1,23 @@
|
||||
import React from 'react';
|
||||
import axios from '../utility/axios';
|
||||
|
||||
const PluginsContext = React.createContext(null);
|
||||
|
||||
export default function PluginsProvider({ children }) {
|
||||
const [plugins, setPlugins] = React.useState(null);
|
||||
const handleLoadPlugin = async () => {
|
||||
const resp = await axios.request({
|
||||
method: 'get',
|
||||
url: 'plugins/script',
|
||||
params: {
|
||||
plugin: 'csv',
|
||||
},
|
||||
});
|
||||
const module = eval(resp.data);
|
||||
console.log('MODULE', module);
|
||||
};
|
||||
React.useEffect(() => {
|
||||
handleLoadPlugin();
|
||||
}, []);
|
||||
return <PluginsContext.Provider value={{ plugins, setPlugins }}>{children}</PluginsContext.Provider>;
|
||||
}
|
28
packages/web/src/tabs/PluginTab.js
Normal file
28
packages/web/src/tabs/PluginTab.js
Normal file
@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import _ from 'lodash';
|
||||
import ObjectListControl from '../utility/ObjectListControl';
|
||||
import { TableColumn } from '../utility/TableControl';
|
||||
import columnAppObject from '../appobj/columnAppObject';
|
||||
import constraintAppObject from '../appobj/constraintAppObject';
|
||||
import { useTableInfo, useDbCore } from '../utility/metadataLoaders';
|
||||
import useTheme from '../theme/useTheme';
|
||||
|
||||
const WhitePage = styled.div`
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: ${(props) => props.theme.main_background};
|
||||
overflow: auto;
|
||||
`;
|
||||
|
||||
export default function PluginTab({ plugin }) {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<WhitePage theme={theme}>
|
||||
<div>{plugin.package.name}</div>
|
||||
</WhitePage>
|
||||
);
|
||||
}
|
@ -6,6 +6,7 @@ import ShellTab from './ShellTab';
|
||||
import InfoPageTab from './InfoPageTab';
|
||||
import ArchiveFileTab from './ArchiveFileTab';
|
||||
import FreeTableTab from './FreeTableTab';
|
||||
import PluginTab from './PluginTab';
|
||||
|
||||
export default {
|
||||
TableDataTab,
|
||||
@ -16,4 +17,5 @@ export default {
|
||||
ShellTab,
|
||||
ArchiveFileTab,
|
||||
FreeTableTab,
|
||||
PluginTab,
|
||||
};
|
||||
|
@ -1,19 +1,10 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { AppObjectList } from '../appobj/AppObjectList';
|
||||
import { useCurrentArchive, useOpenedTabs, useSavedSqlFiles, useSetCurrentArchive } from '../utility/globalState';
|
||||
import closedTabAppObject from '../appobj/closedTabAppObject';
|
||||
import {
|
||||
SearchBoxWrapper,
|
||||
WidgetsInnerContainer,
|
||||
WidgetsMainContainer,
|
||||
WidgetsOuterContainer,
|
||||
WidgetTitle,
|
||||
} from './WidgetStyles';
|
||||
import { useCurrentArchive, useSetCurrentArchive } from '../utility/globalState';
|
||||
import { SearchBoxWrapper, WidgetsInnerContainer } from './WidgetStyles';
|
||||
import WidgetColumnBar, { WidgetColumnBarItem } from './WidgetColumnBar';
|
||||
import savedSqlFileAppObject from '../appobj/savedSqlFileAppObject';
|
||||
import { useArchiveFiles, useArchiveFolders } from '../utility/metadataLoaders';
|
||||
import archiveFolderAppObject from '../appobj/archiveFolderAppObject';
|
||||
import archiveFileAppObject from '../appobj/archiveFileAppObject';
|
||||
|
73
packages/web/src/widgets/PluginsWidget.js
Normal file
73
packages/web/src/widgets/PluginsWidget.js
Normal file
@ -0,0 +1,73 @@
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { AppObjectList } from '../appobj/AppObjectList';
|
||||
import { useCurrentArchive, useSetCurrentArchive } from '../utility/globalState';
|
||||
import { SearchBoxWrapper, WidgetsInnerContainer } from './WidgetStyles';
|
||||
import WidgetColumnBar, { WidgetColumnBarItem } from './WidgetColumnBar';
|
||||
import { useArchiveFiles, useArchiveFolders } from '../utility/metadataLoaders';
|
||||
import archiveFolderAppObject from '../appobj/archiveFolderAppObject';
|
||||
import archiveFileAppObject from '../appobj/archiveFileAppObject';
|
||||
import SearchInput from './SearchInput';
|
||||
import InlineButton from './InlineButton';
|
||||
import axios from '../utility/axios';
|
||||
import useFetch from '../utility/useFetch';
|
||||
import PluginsList from '../plugins/PluginsList';
|
||||
|
||||
function InstalledPluginsList() {
|
||||
// const folders = useArchiveFolders();
|
||||
// const [filter, setFilter] = React.useState('');
|
||||
|
||||
// const setArchive = useSetCurrentArchive();
|
||||
|
||||
// const handleRefreshFolders = () => {
|
||||
// axios.post('archive/refresh-folders', {});
|
||||
// };
|
||||
|
||||
return (
|
||||
<WidgetsInnerContainer>
|
||||
{/* <AppObjectList
|
||||
list={_.sortBy(folders, 'name')}
|
||||
makeAppObj={archiveFolderAppObject()}
|
||||
onObjectClick={(archive) => setArchive(archive.name)}
|
||||
filter={filter}
|
||||
/> */}
|
||||
</WidgetsInnerContainer>
|
||||
);
|
||||
}
|
||||
|
||||
function AvailablePluginsList() {
|
||||
const [filter, setFilter] = React.useState('');
|
||||
|
||||
const plugins = useFetch({
|
||||
url: 'plugins/search',
|
||||
params: {
|
||||
filter,
|
||||
},
|
||||
defaultValue: [],
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchBoxWrapper>
|
||||
<SearchInput placeholder="Search extensions on web" filter={filter} setFilter={setFilter} />
|
||||
</SearchBoxWrapper>
|
||||
<WidgetsInnerContainer>
|
||||
<PluginsList plugins={plugins} />
|
||||
</WidgetsInnerContainer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default function PluginsWidget() {
|
||||
return (
|
||||
<WidgetColumnBar>
|
||||
<WidgetColumnBarItem title="Installed extensions" name="installed" height="50%">
|
||||
<InstalledPluginsList />
|
||||
</WidgetColumnBarItem>
|
||||
<WidgetColumnBarItem title="Available extensions" name="all">
|
||||
<AvailablePluginsList />
|
||||
</WidgetColumnBarItem>
|
||||
</WidgetColumnBar>
|
||||
);
|
||||
}
|
@ -3,11 +3,13 @@ import { useCurrentWidget } from '../utility/globalState';
|
||||
import ArchiveWidget from './ArchiveWidget';
|
||||
import DatabaseWidget from './DatabaseWidget';
|
||||
import FilesWidget from './FilesWidget';
|
||||
import PluginsWidget from './PluginsWidget';
|
||||
|
||||
export default function WidgetContainer() {
|
||||
const currentWidget = useCurrentWidget();
|
||||
if (currentWidget === 'database') return <DatabaseWidget />;
|
||||
if (currentWidget === 'file') return <FilesWidget />;
|
||||
if (currentWidget === 'archive') return <ArchiveWidget />;
|
||||
if (currentWidget === 'plugins') return <PluginsWidget />;
|
||||
return null;
|
||||
}
|
||||
|
@ -51,6 +51,11 @@ export default function WidgetIconPanel() {
|
||||
name: 'archive',
|
||||
title: 'Archive (saved tabular data)',
|
||||
},
|
||||
{
|
||||
icon: 'icon plugin',
|
||||
name: 'plugins',
|
||||
title: 'Extensions & Plugins',
|
||||
},
|
||||
// {
|
||||
// icon: 'fa-cog',
|
||||
// name: 'settings',
|
||||
|
@ -7960,6 +7960,11 @@ node-fetch@^1.0.1:
|
||||
encoding "^0.1.11"
|
||||
is-stream "^1.0.1"
|
||||
|
||||
node-fetch@^2.6.1:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||
|
||||
node-forge@0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579"
|
||||
|
Loading…
Reference in New Issue
Block a user