浏览代码

完善数据预览

herj 2 年之前
父节点
当前提交
53b3a0999e

+ 3 - 3
packages/apputils/src/dialog.tsx

@@ -33,9 +33,9 @@ export function showDialog<T>(
  * @param error - the error to show in the dialog body (either a string
  *   or an object with a string `message` property).
  */
-export function showErrorMessage(
+export function showErrorMessage<E extends { message: string | JSX.Element }>(
   title: string,
-  error: any,
+  error: string | E,
   buttons: ReadonlyArray<Dialog.IButton> = [
     Dialog.okButton({ label: 'Dismiss' })
   ]
@@ -693,7 +693,7 @@ export namespace Dialog {
   /**
    * The default implementation of a dialog renderer.
    */
-  export class Renderer {
+  export class Renderer implements Dialog.IRenderer {
     /**
      * Create the header of the dialog.
      *

+ 17 - 13
packages/apputils/style/dialog.css

@@ -17,7 +17,7 @@
   padding: 0;
   width: 100%;
   height: 100%;
-  background: var(--jp-dialog-background);
+  background: rgba(0, 0, 0, 0.4);
 }
 
 .jp-Dialog-content {
@@ -26,20 +26,18 @@
   margin-left: auto;
   margin-right: auto;
   background: var(--jp-layout-color1);
-  padding: 24px 24px 12px 24px;
   min-width: 300px;
   min-height: 150px;
   max-width: 1000px;
   max-height: 500px;
   box-sizing: border-box;
-  box-shadow: var(--jp-elevation-z20);
+  box-shadow: 0px 0px 12px 0px rgba(0, 0, 0, 0.33);
   word-wrap: break-word;
   border-radius: var(--jp-border-radius);
   /* This is needed so that all font sizing of children done in ems is
    * relative to this base size */
   font-size: var(--jp-ui-font-size1);
   color: var(--jp-ui-font-color1);
-  resize: both;
 }
 
 .jp-Dialog-content.jp-Dialog-content-small {
@@ -75,19 +73,26 @@ button.jp-Dialog-button.jp-mod-styled.jp-mod-reject:focus {
 
 button.jp-Dialog-close-button {
   padding: 0;
-  height: 100%;
+  height: auto;
   min-width: unset;
   min-height: unset;
+  transform: translateY(2px);
+}
+
+button.jp-Dialog-close-button svg {
+  width: 22px;
 }
 
 .jp-Dialog-header {
   display: flex;
   justify-content: space-between;
   flex: 0 0 auto;
-  padding-bottom: 12px;
-  font-size: var(--jp-ui-font-size3);
-  font-weight: 400;
-  color: var(--jp-ui-font-color0);
+  align-items: center;
+  height: 48px;
+  padding: 0 30px;
+  font-weight: bold;
+  color: #4a4a4a;
+  background-color: #edf2f8;
 }
 
 .jp-Dialog-body {
@@ -97,16 +102,15 @@ button.jp-Dialog-close-button {
   font-size: var(--jp-ui-font-size1);
   background: var(--jp-layout-color1);
   overflow: auto;
+  padding: 40px;
 }
 
 .jp-Dialog-footer {
   display: flex;
   flex-direction: row;
-  justify-content: flex-end;
+  justify-content: center;
   flex: 0 0 auto;
-  margin-left: -12px;
-  margin-right: -12px;
-  padding: 12px;
+  padding: 10px 30px 30px;
 }
 
 .jp-Dialog-title {

+ 1 - 1
packages/debugger-extension/src/index.ts

@@ -313,7 +313,7 @@ const sources: JupyterFrontEndPlugin<IDebugger.ISources> = {
  */
 const variables: JupyterFrontEndPlugin<void> = {
   id: '@jupyterlab/debugger-extension:variables',
-  autoStart: true,
+  autoStart: false,
   requires: [IDebugger, IDebuggerHandler, ITranslator],
   optional: [IThemeManager, IRenderMimeRegistry],
   activate: (

+ 1 - 1
packages/jldbq-extenison/schema/plugin.json

@@ -7,7 +7,7 @@
       "title": "Flask Backend address.",
       "description": "Flask Backend address.",
       "type": "string",
-      "default": "http://222.92.101.210:45612/"
+      "default": "http://192.168.51.19:5000"
     }
   },
   "additionalProperties": false

+ 1 - 0
packages/jldbq-extenison/src/DataTable.tsx

@@ -2,6 +2,7 @@ import React from 'react';
 import { Cell, Column, Id, ReactGrid, Row } from '@silevis/reactgrid';
 import { useMemo, useState } from 'react';
 import { ITableData } from './api/datasource';
+import '@silevis/reactgrid/styles.css';
 
 interface IProps {
   data: ITableData;

+ 6 - 9
packages/jldbq-extenison/src/components/DatasourceForm.tsx → packages/jldbq-extenison/src/DatasourceForm.tsx

@@ -1,6 +1,6 @@
 import React from 'react';
 import { Dialog, ReactWidget } from '@jupyterlab/apputils';
-import { IDatasource } from '../api/datasource';
+import { IDatasource } from './api/datasource';
 import { Widget } from '@lumino/widgets';
 
 interface IDatasourceItem {
@@ -26,14 +26,7 @@ const DatasourceForm: React.FunctionComponent<IProps> = ({
     <form className="jldbq-form">
       <label className={error === 'type' ? 'jldbq-form-error' : ''}>
         <span className="jldbq-form-label">选择数据库类型:</span>
-        <div
-          style={{
-            marginLeft: '15px',
-            display: 'flex',
-            justifyContent: 'space-around',
-            alignItems: 'center'
-          }}
-        >
+        <div className="jldbq-form-switcher">
           <button
             type="button"
             className={
@@ -57,6 +50,7 @@ const DatasourceForm: React.FunctionComponent<IProps> = ({
       <label className={error === 'address' ? 'jldbq-form-error' : ''}>
         <span className="jldbq-form-label">数据源地址:</span>
         <input
+          className="jldbq-form-input"
           placeholder="请输入数据源地址"
           value={value.address || ''}
           onChange={evt => onChange({ address: evt.target.value })}
@@ -65,6 +59,7 @@ const DatasourceForm: React.FunctionComponent<IProps> = ({
       <label className={error === 'username' ? 'jldbq-form-error' : ''}>
         <span className="jldbq-form-label">用户名:</span>
         <input
+          className="jldbq-form-input"
           placeholder="请输入用户名"
           value={value.username || ''}
           onChange={evt => onChange({ username: evt.target.value })}
@@ -73,6 +68,7 @@ const DatasourceForm: React.FunctionComponent<IProps> = ({
       <label className={error === 'password' ? 'jldbq-form-error' : ''}>
         <span className="jldbq-form-label">密码:</span>
         <input
+          className="jldbq-form-input"
           type="password"
           placeholder="请输入密码"
           value={value.password || ''}
@@ -82,6 +78,7 @@ const DatasourceForm: React.FunctionComponent<IProps> = ({
       <label className={error === 'databasename' ? 'jldbq-form-error' : ''}>
         <span className="jldbq-form-label">数据库:</span>
         <input
+          className="jldbq-form-input"
           placeholder="请输入数据库名称"
           value={value.databasename || ''}
           onChange={evt => onChange({ databasename: evt.target.value })}

+ 2 - 1
packages/jldbq-extenison/src/DatasourceView.tsx

@@ -12,7 +12,7 @@ import {
   setDatasource,
   useDatasourceList
 } from './api/datasource';
-import { DatasourceFormDialogBody } from './components/DatasourceForm';
+import { DatasourceFormDialogBody } from './DatasourceForm';
 
 const dragImg = new Image();
 dragImg.src = 'data:image/svg+xml;base64,' + btoa(databaseSvgStr);
@@ -135,6 +135,7 @@ const DatasourceView: React.FunctionComponent<IProps> = ({
     const { value } = await showDialog({
       title: '添加数据源',
       body: new DatasourceFormDialogBody(manager),
+      hasClose: true,
       buttons: [
         Dialog.okButton({ label: '确定' }),
         Dialog.cancelButton({ label: '取消' })

+ 0 - 0
packages/jldbq-extenison/src/components/DatasyncForm.tsx → packages/jldbq-extenison/src/DatasyncForm.tsx


+ 1 - 1
packages/jldbq-extenison/src/DatasyncView.tsx

@@ -1,6 +1,6 @@
 import React from 'react';
 import { showDialog } from '@jupyterlab/apputils';
-import DatasyncForm from './components/DatasyncForm';
+import DatasyncForm from './DatasyncForm';
 
 const DatasyncView: React.FunctionComponent = () => {
   return (

+ 122 - 0
packages/jldbq-extenison/src/IDatasyncForm.tsx

@@ -0,0 +1,122 @@
+import React from 'react';
+
+type DbEnc = 'utf8';
+type DbType = 'mysql' | 'hive';
+type FreqUnit = 'day' | 'week' | 'month';
+
+export interface IDatasource {
+  /**
+   * 数据库 IP 或 域名
+   */
+  host: string;
+
+  /**
+   * 数据库用户名
+   */
+  user: string;
+
+  /**
+   * 数据库端口号
+   */
+  port: number;
+
+  /**
+   * 数据库密码 (空)
+   */
+  password: string;
+
+  /**
+   * 编码
+   */
+  charset: DbEnc;
+
+  /**
+   * 当前登录用户
+   */
+  manager: string;
+
+  /**
+   * 数据库类型
+   */
+  source: DbType;
+
+  /**
+   * 数据库显示名称
+   */
+  databasename: string;
+
+  /**
+   * ID
+   */
+  sourcename: string;
+}
+
+interface ISyncMapping {
+  /**
+   * 源数据源
+   */
+  sourceDatasource: IDatasource;
+
+  /**
+   * 源数据表
+   */
+  sourceTableName: string;
+
+  /**
+   * 目标数据源
+   */
+  destDatasource: IDatasource;
+
+  /**
+   * 目标数据表
+   */
+  destTableName: string;
+
+  /**
+   * 同步开始时间
+   */
+  startTime: Date;
+
+  /**
+   * 同步频次
+   */
+  frequency: number;
+
+  /**
+   * 同步频次单位
+   */
+  freqUnit: FreqUnit;
+}
+
+interface IProps {
+  /**
+   * 数据源列表
+   */
+  datasourceList: IDatasource[];
+
+  /**
+   * 获取表的函数, 返回数据库里表的数组
+   */
+  tableListFetcher: (ds: IDatasource) => Promise<string[]>;
+
+  /**
+   * 初始映射数据
+   */
+  initMappings?: ISyncMapping[];
+
+  /**
+   * 确认提交事件
+   */
+  onConfirm: (data: ISyncMapping[]) => void;
+
+  /**
+   * 取消提交事件
+   */
+  onCancel: (data: ISyncMapping[]) => void;
+}
+
+const DatasyncForm: React.FunctionComponent<IProps> = props => {
+  return <div />;
+};
+
+export default DatasyncForm;

+ 2 - 2
packages/jldbq-extenison/src/api/datasource.ts

@@ -64,7 +64,7 @@ export const fetchTables = async (
 ): Promise<'error' | string[]> => {
   const endpoint = config.endpoint;
   const item = encodeURIComponent(
-    `${ds.manager}-${ds.sourcename}-${ds.databasename}`
+    `${ds.manager};${ds.sourcename};${ds.databasename}`
   );
   const url = `${endpoint}/show/${ds.source}/tables/item=${item}`;
   try {
@@ -86,7 +86,7 @@ export const fetchTableContent = async (
 ): Promise<ITableData | 'error'> => {
   const endpoint = config.endpoint;
   const item = encodeURIComponent(
-    `${ds.manager}-${ds.sourcename}-${ds.databasename}-${t}`
+    `${ds.manager};${ds.sourcename};${ds.databasename};${t}`
   );
   const url = `${endpoint}/show/${ds.source}/results/item=${item}`;
   try {

+ 19 - 0
packages/jldbq-extenison/src/icons.ts

@@ -0,0 +1,19 @@
+import { LabIcon } from '@jupyterlab/ui-components';
+import cliSvgStr from '../style/icons/cli.svg';
+import timerSvgStr from '../style/icons/timer.svg';
+import monitorSvgStr from '../style/icons/monitor.svg';
+
+export const cliIcon = new LabIcon({
+  name: 'cli',
+  svgstr: cliSvgStr
+});
+
+export const timerIcon = new LabIcon({
+  name: 'timer',
+  svgstr: timerSvgStr
+});
+
+export const monitorIcon = new LabIcon({
+  name: 'monitor',
+  svgstr: monitorSvgStr
+});

+ 18 - 31
packages/jldbq-extenison/src/index.ts

@@ -10,51 +10,32 @@ import {
   JupyterFrontEndPlugin
 } from '@jupyterlab/application';
 import { MainAreaWidget } from '@jupyterlab/apputils';
-import { LabIcon } from '@jupyterlab/ui-components';
 import { ISettingRegistry } from '@jupyterlab/settingregistry';
 import DataViewWidget from './DataViewWidget';
 import DataTableWidget from './DataTableWidget';
 import TaskViewWidget from './TaskViewWidget';
 import MonitorViewWidget from './MonitorViewWidget';
-import cliSvgStr from '../style/icons/cli.svg';
-import timerSvgStr from '../style/icons/timer.svg';
-import monitorSvgStr from '../style/icons/monitor.svg';
+import { cliIcon, monitorIcon, timerIcon } from './icons';
+import config from './api/config';
 
-const cliIcon = new LabIcon({
-  name: 'cli',
-  svgstr: cliSvgStr
-});
-
-const timerIcon = new LabIcon({
-  name: 'timer',
-  svgstr: timerSvgStr
-});
-
-const monitorIcon = new LabIcon({
-  name: 'monitor',
-  svgstr: monitorSvgStr
-});
+const PLUGIN_ID = '@jupyterlab/jldbq-extension:plugin';
 
 const plugin: JupyterFrontEndPlugin<void> = {
-  id: '@jupyterlab/jldbq-extension:plugin',
+  id: PLUGIN_ID,
   autoStart: true,
   requires: [ISettingRegistry],
   activate: async (app: JupyterFrontEnd, registry: ISettingRegistry) => {
-    // let backend: string;
-    // try {
-    //   const settings = await registry.load(
-    //     '@jupyterlab/jldbq-extension:plugin'
-    //   );
-    //   backend = settings.composite['flaskBackend'] as string;
-    // } catch (err) {
-    //   console.log(err);
-    //   backend = 'http://localhost:5000';
-    // }
+    registry.pluginChanged.connect(async (_sender, plugin) => {
+      if (plugin === PLUGIN_ID) {
+        await updateConfig(registry);
+      }
+    });
+    await updateConfig(registry);
 
-    const manager = 'testlocal';
+    const manager = 'testlocal'; // TODO:
 
     const dataViewWidget = new DataViewWidget(manager);
-    dataViewWidget.id = 'DatabaseView';
+    dataViewWidget.id = 'jldbq-data';
     dataViewWidget.title.icon = cliIcon;
     dataViewWidget.title.caption = '数据开发';
     dataViewWidget.title.label = '数据开发';
@@ -84,3 +65,9 @@ const plugin: JupyterFrontEndPlugin<void> = {
 };
 
 export default plugin;
+
+async function updateConfig(registry: ISettingRegistry) {
+  const settings = await registry.load(PLUGIN_ID);
+  const endpoint = settings.composite['flaskBackend'] as string;
+  config.endpoint = endpoint;
+}

+ 8 - 1
packages/jldbq-extenison/style/base.css

@@ -39,7 +39,6 @@
 .jldbq-form {
   display: flex;
   flex-direction: column;
-  padding: 40px;
 }
 
 .jldbq-form label {
@@ -62,6 +61,14 @@
   text-align: end;
 }
 
+.jldbq-form .jldbq-form-switcher {
+  margin-left: 15px;
+  display: flex;
+  justify-content: space-around;
+  align-items: center;
+  width: 320px;
+}
+
 .jldbq-form .jldbq-form-input {
   font-family: inherit;
   box-sizing: border-box;