|
@@ -1,98 +1,76 @@
|
|
|
import React from 'react';
|
|
|
-import { useEffect, useState } from 'react';
|
|
|
-import { showDialog } from '@jupyterlab/apputils';
|
|
|
+import { useState } from 'react';
|
|
|
+import { Dialog, showDialog } from '@jupyterlab/apputils';
|
|
|
import TreeView from '@mui/lab/TreeView';
|
|
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|
|
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
|
|
|
import TreeItem from '@mui/lab/TreeItem';
|
|
|
import databaseSvgStr from '../style/icons/database-solid-ghost.svg';
|
|
|
+import {
|
|
|
+ fetchTables,
|
|
|
+ IDatasource,
|
|
|
+ setDatasource,
|
|
|
+ useDatasourceList
|
|
|
+} from './api/datasource';
|
|
|
+import { DatasourceFormDialogBody } from './components/DatasourceForm';
|
|
|
|
|
|
const dragImg = new Image();
|
|
|
dragImg.src = 'data:image/svg+xml;base64,' + btoa(databaseSvgStr);
|
|
|
|
|
|
interface IProps {
|
|
|
- baseUrl: string;
|
|
|
- dataId: string;
|
|
|
- dbType: string;
|
|
|
- onOpenTable: (tableName: string) => void;
|
|
|
+ manager: string;
|
|
|
+ onOpenTable: (datasource: IDatasource, tableName: string) => void;
|
|
|
}
|
|
|
|
|
|
-const DatasourceView = ({
|
|
|
- baseUrl,
|
|
|
- dataId,
|
|
|
- dbType,
|
|
|
+const DatasourceView: React.FunctionComponent<IProps> = ({
|
|
|
+ manager,
|
|
|
onOpenTable
|
|
|
-}: IProps): JSX.Element => {
|
|
|
- const [dbs, setDbs] = useState<string[] | null>(null);
|
|
|
- const [tables, setTables] = useState<Record<string, string[]>>({});
|
|
|
- const [error, setError] = useState<any>(null);
|
|
|
+}) => {
|
|
|
+ const { datasources, loading, error, refresh } = useDatasourceList(manager);
|
|
|
+ const [tables, setTables] = useState<
|
|
|
+ Partial<{
|
|
|
+ [key: string]: string[] | 'error';
|
|
|
+ }>
|
|
|
+ >({});
|
|
|
|
|
|
- useEffect(() => {
|
|
|
- setDbs(null);
|
|
|
- setTables({});
|
|
|
- setError(null);
|
|
|
-
|
|
|
- let abort = false;
|
|
|
- fetch(`${baseUrl}/databases`)
|
|
|
- .then(res => res.json())
|
|
|
- .then(data => {
|
|
|
- if (!abort) {
|
|
|
- setDbs(data);
|
|
|
- }
|
|
|
- })
|
|
|
- .catch(err => {
|
|
|
- if (!abort) {
|
|
|
- console.error(err);
|
|
|
- setError(err);
|
|
|
- }
|
|
|
+ const handleNodeToggle = async (ds: IDatasource) => {
|
|
|
+ if (!tables[ds.sourcename]) {
|
|
|
+ const tables = await fetchTables(ds);
|
|
|
+ setTables(prev => {
|
|
|
+ return { [ds.sourcename]: tables, ...prev };
|
|
|
});
|
|
|
-
|
|
|
- return () => {
|
|
|
- abort = true;
|
|
|
- };
|
|
|
- }, [baseUrl, dataId]);
|
|
|
-
|
|
|
- const handleNodeToggle = (db: string) => {
|
|
|
- if (!tables[db]) {
|
|
|
- const dbUri = encodeURIComponent(db);
|
|
|
- fetch(`${baseUrl}/tables/item=${dbUri}`)
|
|
|
- .then(res => res.json())
|
|
|
- .then(data => {
|
|
|
- setTables(prev => {
|
|
|
- return { [db]: data, ...prev };
|
|
|
- });
|
|
|
- })
|
|
|
- .catch(err => console.error(err));
|
|
|
}
|
|
|
};
|
|
|
|
|
|
let tree: JSX.Element[] | JSX.Element;
|
|
|
if (error) {
|
|
|
tree = <div style={{ padding: '0px 12px' }}>Error</div>;
|
|
|
- } else if (!dbs) {
|
|
|
+ } else if (loading) {
|
|
|
tree = <div style={{ padding: '0px 12px' }}>Loading ...</div>;
|
|
|
} else {
|
|
|
- tree = dbs.map(db => {
|
|
|
+ tree = datasources!.map(ds => {
|
|
|
+ const table = tables[ds.sourcename];
|
|
|
let tableItems;
|
|
|
- if (!tables[db]) {
|
|
|
+ if (!table) {
|
|
|
+ tableItems = (
|
|
|
+ <TreeItem nodeId={`${ds.sourcename}-loading`} label="Loading ..." />
|
|
|
+ );
|
|
|
+ } else if (table === 'error') {
|
|
|
tableItems = (
|
|
|
- <TreeItem
|
|
|
- nodeId={`${dataId}-${dbType}-${db}-loading`}
|
|
|
- label="Loading ..."
|
|
|
- />
|
|
|
+ <TreeItem nodeId={`${ds.sourcename}-error`} label="Error" />
|
|
|
);
|
|
|
- } else if (tables[db].length === 0) {
|
|
|
+ } else if (table.length === 0) {
|
|
|
tableItems = (
|
|
|
- <TreeItem nodeId={`${dataId}-${dbType}-${db}-empty`} label="Empty" />
|
|
|
+ <TreeItem nodeId={`${ds.sourcename}-error`} label="Empty" />
|
|
|
);
|
|
|
} else {
|
|
|
- tableItems = tables[db].map(t => {
|
|
|
+ tableItems = table.map(t => {
|
|
|
return (
|
|
|
<TreeItem
|
|
|
- key={`${dataId}-${dbType}-${db}-${t}`}
|
|
|
- nodeId={`${dataId}-${dbType}-${db}-${t}`}
|
|
|
+ key={`${ds.sourcename}-${t}`}
|
|
|
+ nodeId={`${ds.sourcename}-${t}`}
|
|
|
label={t}
|
|
|
- onDoubleClick={() => onOpenTable(`${db}-${t}`)}
|
|
|
+ onDoubleClick={() => onOpenTable(ds, t)}
|
|
|
draggable="true"
|
|
|
onDragStart={evt => {
|
|
|
const data = {
|
|
@@ -101,8 +79,8 @@ const DatasourceView = ({
|
|
|
editType: 'createNode',
|
|
|
finalized: true,
|
|
|
nodeTemplate: {
|
|
|
- id: `${dataId}-${dbType}-${db}-${t}`,
|
|
|
- op: `database-${dbType}-input`,
|
|
|
+ id: `${ds.manager}-${ds.sourcename}-${t}`,
|
|
|
+ op: `database-${ds.source}-input`,
|
|
|
description: t,
|
|
|
type: 'execution_node',
|
|
|
label: t,
|
|
@@ -142,10 +120,10 @@ const DatasourceView = ({
|
|
|
}
|
|
|
return (
|
|
|
<TreeItem
|
|
|
- key={`${dataId}-${dbType}-${db}`}
|
|
|
- nodeId={`${dataId}-${dbType}-${db}`}
|
|
|
- label={db}
|
|
|
- onClick={() => handleNodeToggle(db)}
|
|
|
+ key={ds.sourcename}
|
|
|
+ nodeId={ds.sourcename}
|
|
|
+ label={ds.databasename}
|
|
|
+ onClick={() => handleNodeToggle(ds)}
|
|
|
>
|
|
|
{tableItems}
|
|
|
</TreeItem>
|
|
@@ -153,17 +131,28 @@ const DatasourceView = ({
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ const handleAddDatasource = async () => {
|
|
|
+ const { value } = await showDialog({
|
|
|
+ title: '添加数据源',
|
|
|
+ body: new DatasourceFormDialogBody(manager),
|
|
|
+ buttons: [
|
|
|
+ Dialog.okButton({ label: '确定' }),
|
|
|
+ Dialog.cancelButton({ label: '取消' })
|
|
|
+ ]
|
|
|
+ });
|
|
|
+ if (!value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ await setDatasource(value);
|
|
|
+ refresh();
|
|
|
+ };
|
|
|
+
|
|
|
return (
|
|
|
<div style={{ flexGrow: 1, display: 'flex', flexDirection: 'column' }}>
|
|
|
<div
|
|
|
style={{ display: 'flex', justifyContent: 'flex-end', padding: '10px' }}
|
|
|
>
|
|
|
- <button
|
|
|
- className="jldbq-btn-add"
|
|
|
- onClick={async () => {
|
|
|
- await showDialog();
|
|
|
- }}
|
|
|
- >
|
|
|
+ <button className="jldbq-btn-add" onClick={handleAddDatasource}>
|
|
|
<svg
|
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
|
width="20"
|