二次开发的代码修改基于 JupyterLab v3.4.3 版本进行. 这里主要针对代码部分的 diff 进行说明, 省略了 eslint 等的配置改动, 以及文档相关改动. 使用如下命令查看改动:
git diff v3.4.3 HEAD packages
diff --git a/packages/application-extension/src/index.tsx b/packages/application-extension/src/index.tsx
index 5da68f494d..403607bd1a 100644
--- a/packages/application-extension/src/index.tsx
+++ b/packages/application-extension/src/index.tsx
@@ -40,7 +40,8 @@ import { ITranslator, TranslationBundle } from '@jupyterlab/translation';
import {
buildIcon,
ContextMenuSvg,
- jupyterIcon,
+ // jupyterIcon,
+ LabIcon,
RankedMenu
} from '@jupyterlab/ui-components';
import { each, iter, toArray } from '@lumino/algorithm';
@@ -48,6 +49,12 @@ import { JSONExt, PromiseDelegate } from '@lumino/coreutils';
import { DisposableDelegate, DisposableSet } from '@lumino/disposable';
import { DockLayout, DockPanel, Widget } from '@lumino/widgets';
import * as React from 'react';
+import yiliLogoSvgStr from '../style/icons/YiliLogo.svg';
+
+const yiliLogoIcon = new LabIcon({
+ name: 'yili-logo',
+ svgstr: yiliLogoSvgStr
+});
/**
* Default context menu item rank
@@ -941,14 +948,15 @@ const JupyterLogo: JupyterFrontEndPlugin<void> = {
requires: [ILabShell],
activate: (app: JupyterFrontEnd, shell: ILabShell) => {
const logo = new Widget();
- jupyterIcon.element({
+ yiliLogoIcon.element({
container: logo.node,
elementPosition: 'center',
- margin: '2px 2px 2px 8px',
+ marginRight: '10px',
+ marginLeft: '10px',
height: 'auto',
- width: '16px'
+ width: '54px'
});
- logo.id = 'jp-MainLogo';
+ logo.id = 'jp-YiliLogo';
shell.add(logo, 'top', { rank: 0 });
}
};
diff --git a/packages/application/src/shell.ts b/packages/application/src/shell.ts
index c87c901fb3..931ccd369a 100644
--- a/packages/application/src/shell.ts
+++ b/packages/application/src/shell.ts
@@ -306,7 +306,7 @@ export class LabShell extends Widget implements JupyterFrontEnd.IShell {
dockPanel.node.setAttribute('role', 'main');
- hboxPanel.spacing = 0;
+ hboxPanel.spacing = 2;
vsplitPanel.spacing = 1;
dockPanel.spacing = 5;
hsplitPanel.spacing = 1;
@@ -330,14 +330,14 @@ export class LabShell extends Widget implements JupyterFrontEnd.IShell {
hsplitPanel.addWidget(leftHandler.stackedPanel);
hsplitPanel.addWidget(dockPanel);
- hsplitPanel.addWidget(rightHandler.stackedPanel);
+ // hsplitPanel.addWidget(rightHandler.stackedPanel);
vsplitPanel.addWidget(hsplitPanel);
- vsplitPanel.addWidget(downPanel);
+ // vsplitPanel.addWidget(downPanel);
hboxPanel.addWidget(leftHandler.sideBar);
hboxPanel.addWidget(vsplitPanel);
- hboxPanel.addWidget(rightHandler.sideBar);
+ // hboxPanel.addWidget(rightHandler.sideBar);
rootLayout.direction = 'top-to-bottom';
rootLayout.spacing = 0; // TODO make this configurable?
@@ -353,10 +353,12 @@ export class LabShell extends Widget implements JupyterFrontEnd.IShell {
BoxLayout.setStretch(hboxPanel, 1);
BoxLayout.setStretch(bottomPanel, 0);
+ BoxLayout.setSizeBasis(topHandler.panel, 60);
+
rootLayout.addWidget(headerPanel);
rootLayout.addWidget(topHandler.panel);
rootLayout.addWidget(hboxPanel);
- rootLayout.addWidget(bottomPanel);
+ // rootLayout.addWidget(bottomPanel);
// initially hiding header and bottom panel when no elements inside,
this._headerPanel.hide();
@@ -1498,7 +1500,7 @@ namespace Private {
/**
* Get the panel managed by the handler.
*/
- get panel() {
+ get panel(): Panel {
return this._panel;
}
@@ -1653,12 +1655,12 @@ namespace Private {
if (title.icon instanceof LabIcon) {
// bind an appropriate style to the icon
- title.icon = title.icon.bindprops({
- stylesheet: 'sideBar'
- });
+ // title.icon = title.icon.bindprops({
+ // stylesheet: 'sideBar'
+ // });
} else if (typeof title.icon === 'string' || !title.icon) {
// add some classes to help with displaying css background imgs
- title.iconClass = classes(title.iconClass, 'jp-Icon', 'jp-Icon-20');
+ // title.iconClass = classes(title.iconClass, 'jp-Icon', 'jp-Icon-20');
}
this._refreshVisibility();
diff --git a/packages/application/style/base.css b/packages/application/style/base.css
index 25daa9c913..3c937aa43a 100644
--- a/packages/application/style/base.css
+++ b/packages/application/style/base.css
@@ -13,7 +13,7 @@
body {
font-family: var(--jp-ui-font-family);
- background: var(--jp-layout-color3);
+ background: #f0f2f5;
margin: 0;
padding: 0;
overflow: hidden;
@@ -31,8 +31,13 @@ body {
border-top: 4px solid red;
}
+#jp-main-vsplit-panel,
+#jp-main-split-panel {
+ overflow: visible;
+}
+
#jp-main-dock-panel {
- padding: 5px;
+ padding: 10px;
}
#jp-main-dock-panel[data-mode='single-document'] {
@@ -44,8 +49,7 @@ body {
}
#jp-top-panel {
- border-bottom: var(--jp-border-width) solid var(--jp-border-color0);
- background: var(--jp-layout-color1);
+ background-color: #222222;
display: flex;
min-height: var(--jp-private-menubar-height);
overflow: visible;
@@ -53,7 +57,23 @@ body {
#jp-menu-panel {
min-height: var(--jp-private-menu-panel-height);
- background: var(--jp-layout-color1);
+ align-self: center;
+}
+
+#jp-MainMenu {
+ background-color: #222222;
+ color: #afafaf;
+}
+
+#jp-MainMenu .lm-MenuBar-item {
+ padding: 0 20px;
+ border: none;
+}
+
+#jp-MainMenu .lm-MenuBar-item.lm-mod-active {
+ background-color: #333333;
+ border: none;
+ box-shadow: none;
}
#jp-down-stack {
diff --git a/packages/application/style/buttons.css b/packages/application/style/buttons.css
index 0c25eb4b3e..2e90a454e5 100644
--- a/packages/application/style/buttons.css
+++ b/packages/application/style/buttons.css
@@ -13,52 +13,32 @@
|----------------------------------------------------------------------------*/
button {
- border-radius: var(--jp-border-radius);
-}
-
-button:focus-visible {
- border: 1px solid var(--md-blue-900);
+ border-radius: 2px;
}
button.jp-mod-styled.jp-mod-accept {
- background: var(--md-blue-700);
- border: 0;
+ background: #4883fb;
+ border: 1px solid #4883fb;
color: white;
}
button.jp-mod-styled.jp-mod-accept:hover {
- background: var(--md-blue-800);
-}
-
-button.jp-mod-styled.jp-mod-accept:active {
- background: var(--md-blue-900);
-}
-
-button.jp-mod-styled.jp-mod-accept:focus-visible {
- border: 1px solid var(--md-blue-900);
+ background: #276fff;
}
button.jp-mod-styled.jp-mod-reject {
- background: var(--md-grey-600);
- border: 0;
- color: white;
+ background-color: white;
+ border: 1px solid #dddddd;
+ color: #7d7d7d;
}
button.jp-mod-styled.jp-mod-reject:hover {
- background: var(--md-grey-700);
-}
-
-button.jp-mod-styled.jp-mod-reject:active {
- background: var(--md-grey-800);
-}
-
-button.jp-mod-styled.jp-mod-reject:focus-visible {
- border: 1px solid var(--md-grey-800);
+ background: #eeeeee;
}
button.jp-mod-styled.jp-mod-warn {
background: var(--md-red-700);
- border: 0;
+ border: 1px solid var(--md-red-700);
color: white;
}
@@ -66,14 +46,6 @@ button.jp-mod-styled.jp-mod-warn:hover {
background: var(--md-red-800);
}
-button.jp-mod-styled.jp-mod-warn:active {
- background: var(--md-red-900);
-}
-
-button.jp-mod-styled.jp-mod-warn:focus-visible {
- border: 1px solid var(--md-red-900);
-}
-
.jp-Button-flat {
text-decoration: none;
padding: var(--jp-flat-button-padding);
diff --git a/packages/application/style/dockpanel.css b/packages/application/style/dockpanel.css
index 827eccb72c..a189fb6727 100644
--- a/packages/application/style/dockpanel.css
+++ b/packages/application/style/dockpanel.css
@@ -14,9 +14,7 @@
.lm-DockPanel-widget,
.lm-TabPanel-stackedPanel {
background: var(--jp-layout-color0);
- border-left: var(--jp-border-width) solid var(--jp-border-color1);
- border-right: var(--jp-border-width) solid var(--jp-border-color1);
- border-bottom: var(--jp-border-width) solid var(--jp-border-color1);
+ box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.1);
}
.lm-DockPanel-overlay {
@@ -34,3 +32,11 @@
.lm-DockPanel-overlay.lm-mod-root-center {
border-width: 2px;
}
+
+#jp-main-dock-panel .lm-DockPanel-widget {
+ z-index: 2;
+}
+
+#jp-main-dock-panel .lm-DockPanel-tabBar {
+ z-index: unset;
+}
diff --git a/packages/application/style/menus.css b/packages/application/style/menus.css
index 36535b8571..97241b8730 100644
--- a/packages/application/style/menus.css
+++ b/packages/application/style/menus.css
@@ -26,10 +26,6 @@
overflow-x: auto;
}
-.lm-MenuBar-menu {
- transform: translateY(calc(-2 * var(--jp-border-width)));
-}
-
.lm-MenuBar-item {
padding: 0px 8px;
border-left: var(--jp-border-width) solid transparent;
diff --git a/packages/application/style/sidepanel.css b/packages/application/style/sidepanel.css
index d19f2d2841..ed7ff3b8bf 100644
--- a/packages/application/style/sidepanel.css
+++ b/packages/application/style/sidepanel.css
@@ -21,18 +21,14 @@
font-size: var(--jp-ui-font-size1);
}
-.jp-SideBar.lm-TabBar,
-#jp-down-stack .lm-TabBar {
- color: var(--jp-ui-font-color1);
- background: var(--jp-layout-color2);
- font-size: var(--jp-ui-font-size1);
- overflow: visible;
-}
-
.jp-SideBar.lm-TabBar {
- min-width: calc(var(--jp-private-sidebar-tab-width) + var(--jp-border-width));
- max-width: calc(var(--jp-private-sidebar-tab-width) + var(--jp-border-width));
+ color: #4a4a4a;
+ background-color: white;
+ font-size: var(--jp-ui-font-size1);
+ min-width: 180px;
+ max-width: 180px;
display: block;
+ height: 100%;
}
.jp-SideBar .lm-TabBar-content {
@@ -41,103 +37,44 @@
display: flex;
align-items: stretch;
list-style-type: none;
- height: var(--jp-private-sidebar-tab-width);
- transform-origin: 0 0 0;
}
.jp-SideBar .lm-TabBar-tab {
- padding: 0 16px;
+ display: flex;
+ align-items: center;
+ height: 50px;
+ padding: 0 25px;
border: none;
- overflow: visible;
+ color: #4a4a4a;
}
.jp-SideBar .lm-TabBar-tab.lm-mod-current {
- min-height: calc(
- var(--jp-private-sidebar-tab-width) + var(--jp-border-width)
- );
- max-height: calc(
- var(--jp-private-sidebar-tab-width) + var(--jp-border-width)
- );
- /* transform: translateY(var(--jp-border-width)); */
-}
-
-.jp-SideBar .lm-TabBar-tab:not(.lm-mod-current),
-#jp-down-stack .lm-TabBar-tab:not(.lm-mod-current) {
- background: var(--jp-layout-color2);
-}
-
-.jp-SideBar .lm-TabBar-tabIcon.jp-SideBar-tabIcon {
- min-width: 20px;
- min-height: 20px;
- background-size: 20px;
- display: inline-block;
- vertical-align: middle;
- background-repeat: no-repeat;
- background-position: center;
-}
-
-.jp-SideBar .lm-TabBar-tabLabel {
- line-height: var(--jp-private-sidebar-tab-width);
-}
-
-.jp-SideBar .lm-TabBar-tab:hover:not(.lm-mod-current),
-#jp-down-stack .lm-TabBar-tab:hover:not(.lm-mod-current) {
- background: var(--jp-layout-color1);
-}
-
-/* Left */
-
-/* Borders */
-
-.jp-SideBar.lm-TabBar.jp-mod-left {
- border-right: var(--jp-border-width) solid var(--jp-border-color0);
-}
-
-.jp-SideBar.lm-TabBar.jp-mod-left .lm-TabBar-tab + .lm-TabBar-tab {
- border-right: var(--jp-border-width) solid var(--jp-layout-color2);
+ background-color: #147bd1;
+ color: white;
}
-.jp-SideBar.lm-TabBar.jp-mod-left
- .lm-TabBar-tab.lm-mod-current
- + .lm-TabBar-tab {
- border-right: var(--jp-border-width) solid var(--jp-border-color0);
+.jp-SideBar .lm-TabBar-tab .jp-icon3[fill] {
+ fill: #4a4a4a;
}
-.jp-SideBar.lm-TabBar.jp-mod-left
- .lm-TabBar-tab
- + .lm-TabBar-tab.lm-mod-current {
- border-right: var(--jp-border-width) solid var(--jp-border-color0);
+.jp-SideBar .lm-TabBar-tab.lm-mod-current .jp-icon3[fill] {
+ fill: white;
}
-.jp-SideBar.lm-TabBar.jp-mod-left .lm-TabBar-tab.lm-mod-current:last-child {
- border-left: var(--jp-border-width) solid var(--jp-border-color0);
-}
-
-/* Transforms */
-
-.jp-SideBar.lm-TabBar.jp-mod-left .lm-TabBar-content {
- flex-direction: row-reverse;
- transform: rotate(-90deg) translateX(-100%);
+.jp-SideBar .lm-TabBar-tabIcon svg {
+ width: 16px;
+ height: 16px;
+ display: block;
}
-.jp-SideBar.lm-TabBar.jp-mod-left
- .lm-TabBar-tab:not(.lm-mod-current)
- .lm-TabBar-tabIcon {
- transform: rotate(90deg);
+.jp-SideBar .lm-TabBar-tabIcon {
+ margin-right: 16px;
}
-.jp-SideBar.lm-TabBar.jp-mod-left
- .lm-TabBar-tab.lm-mod-current
- .lm-TabBar-tabIcon {
- transform: rotate(90deg)
- translate(
- calc(-0.5 * var(--jp-border-width)),
- calc(-0.5 * var(--jp-border-width))
- );
+.jp-SideBar .lm-TabBar-tab:hover:not(.lm-mod-current) {
+ background-color: #eeeeee;
}
-/* Right */
-
/* Borders */
.jp-SideBar.lm-TabBar.jp-mod-right {
@@ -217,6 +154,7 @@
#jp-left-stack > .lm-Widget,
#jp-right-stack > .lm-Widget {
min-width: var(--jp-sidebar-min-width);
+ background-color: #f8f8f9;
}
#jp-right-stack {
@@ -224,7 +162,7 @@
}
#jp-left-stack {
- border-right: var(--jp-border-width) solid var(--jp-border-color1);
+ box-shadow: 1px 0px 6px 0px rgba(0, 0, 0, 0.12);
}
#jp-down-stack > .lm-TabPanel-stackedPanel {
diff --git a/packages/application/style/tabs.css b/packages/application/style/tabs.css
index bb23cb958f..171e3d34ef 100644
--- a/packages/application/style/tabs.css
+++ b/packages/application/style/tabs.css
@@ -20,7 +20,6 @@
.lm-DockPanel-tabBar,
.lm-TabPanel-tabBar {
- border-bottom: var(--jp-border-width) solid var(--jp-border-color1);
overflow: visible;
color: var(--jp-ui-font-color1);
font-size: var(--jp-ui-font-size1);
@@ -52,18 +51,38 @@
var(--jp-private-horizontal-tab-height) + var(--jp-border-width)
);
min-width: 0px;
- margin-left: calc(-1 * var(--jp-border-width));
+ margin-left: -10px;
+ margin-right: 25px;
line-height: var(--jp-private-horizontal-tab-height);
padding: 0px 8px;
- background: var(--jp-layout-color2);
- border: var(--jp-border-width) solid var(--jp-border-color1);
- border-bottom: none;
+ background: #eeeeee;
+ border: none;
position: relative;
+ overflow: visible;
+ color: #4a4a4a;
+ box-shadow: -2px -2px 4px -2px rgba(0, 0, 0, 0.1);
+}
+
+.lm-DockPanel-tabBar .lm-TabBar-tab::after {
+ content: ' ';
+ position: absolute;
+ top: 0;
+ height: 100%;
+ background-color: inherit;
+ z-index: 1;
+ width: 22px;
+ right: -12px;
+ transform: skew(40deg);
+ box-shadow: 4px 0px 4px -4px rgba(0, 0, 0, 0.1);
+}
+
+.lm-DockPanel-tabBar .lm-TabBar-tab .lm-TabBar-tabCloseIcon {
+ z-index: 2;
}
.lm-DockPanel-tabBar .lm-TabBar-tab:hover:not(.lm-mod-current),
.lm-TabPanel-tabBar .lm-TabBar-tab:hover:not(.lm-mod-current) {
- background: var(--jp-layout-color1);
+ background-color: #f5f5f5;
}
.lm-DockPanel-tabBar .lm-TabBar-tab:first-child,
@@ -74,11 +93,10 @@
/* This is a current tab of a tab bar in the dock panel: each tab bar has 1. */
.lm-DockPanel-tabBar .lm-TabBar-tab.lm-mod-current {
background: var(--jp-layout-color1);
- color: var(--jp-ui-font-color0);
+ color: #4a4a4a;
min-height: calc(
var(--jp-private-horizontal-tab-height) + 2 * var(--jp-border-width)
);
- transform: translateY(var(--jp-border-width));
}
.lm-TabPanel-tabBar .lm-TabBar-tab.lm-mod-current {
@@ -86,17 +104,6 @@
color: var(--jp-ui-font-color0);
}
-/* This is the main application level current tab: only 1 exists. */
-.lm-DockPanel-tabBar .lm-TabBar-tab.jp-mod-current:before {
- position: absolute;
- top: calc(-1 * var(--jp-border-width) + 1px);
- left: calc(-1 * var(--jp-border-width));
- content: '';
- height: var(--jp-private-horizontal-tab-active-top-border);
- width: calc(100% + 2 * var(--jp-border-width));
- background: var(--jp-brand-color1);
-}
-
/* This is the left tab bar current tab: only 1 exists. */
.lm-TabBar-tab.lm-mod-current {
color: var(--jp-ui-font-color0);
diff --git a/packages/apputils-extension/src/index.ts b/packages/apputils-extension/src/index.ts
index fe5cee38f2..cdf726aa6e 100644
--- a/packages/apputils-extension/src/index.ts
+++ b/packages/apputils-extension/src/index.ts
@@ -22,7 +22,7 @@ import {
ISplashScreen,
IWindowResolver,
MainAreaWidget,
- Printing,
+ // Printing,
sessionContextDialogs,
WindowResolver
} from '@jupyterlab/apputils';
@@ -268,28 +268,28 @@ Would you like to clear the workspace or keep waiting?`),
}
};
-const print: JupyterFrontEndPlugin<void> = {
- id: '@jupyterlab/apputils-extension:print',
- autoStart: true,
- requires: [ITranslator],
- activate: (app: JupyterFrontEnd, translator: ITranslator) => {
- const trans = translator.load('jupyterlab');
- app.commands.addCommand(CommandIDs.print, {
- label: trans.__('Print…'),
- isEnabled: () => {
- const widget = app.shell.currentWidget;
- return Printing.getPrintFunction(widget) !== null;
- },
- execute: async () => {
- const widget = app.shell.currentWidget;
- const printFunction = Printing.getPrintFunction(widget);
- if (printFunction) {
- await printFunction();
- }
- }
- });
- }
-};
+// const print: JupyterFrontEndPlugin<void> = {
+// id: '@jupyterlab/apputils-extension:print',
+// autoStart: true,
+// requires: [ITranslator],
+// activate: (app: JupyterFrontEnd, translator: ITranslator) => {
+// const trans = translator.load('jupyterlab');
+// app.commands.addCommand(CommandIDs.print, {
+// label: trans.__('Print…'),
+// isEnabled: () => {
+// const widget = app.shell.currentWidget;
+// return Printing.getPrintFunction(widget) !== null;
+// },
+// execute: async () => {
+// const widget = app.shell.currentWidget;
+// const printFunction = Printing.getPrintFunction(widget);
+// if (printFunction) {
+// await printFunction();
+// }
+// }
+// });
+// }
+// };
export const toggleHeader: JupyterFrontEndPlugin<void> = {
id: '@jupyterlab/apputils-extension:toggle-header',
@@ -620,7 +620,7 @@ const sanitizer: JupyterFrontEndPlugin<ISanitizer> = {
const plugins: JupyterFrontEndPlugin<any>[] = [
palette,
paletteRestorer,
- print,
+ // print,
resolver,
sanitizer,
settingsPlugin,
diff --git a/packages/apputils-extension/src/workspacesplugin.ts b/packages/apputils-extension/src/workspacesplugin.ts
index ffcefb6ded..bf8b93a806 100644
--- a/packages/apputils-extension/src/workspacesplugin.ts
+++ b/packages/apputils-extension/src/workspacesplugin.ts
@@ -24,11 +24,11 @@ import { IStateDB } from '@jupyterlab/statedb';
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
import { Widget } from '@lumino/widgets';
-namespace CommandIDs {
- export const saveWorkspace = 'workspace-ui:save';
+// namespace CommandIDs {
+// export const saveWorkspace = 'workspace-ui:save';
- export const saveWorkspaceAs = 'workspace-ui:save-as';
-}
+// export const saveWorkspaceAs = 'workspace-ui:save-as';
+// }
const WORKSPACE_NAME = 'jupyterlab-workspace';
const WORKSPACE_EXT = '.' + WORKSPACE_NAME;
@@ -78,39 +78,39 @@ export const workspacesPlugin: JupyterFrontEndPlugin<void> = {
iconClass: ICON_NAME
});
app.docRegistry.addWidgetFactory(factory);
- app.commands.addCommand(CommandIDs.saveWorkspaceAs, {
- label: trans.__('Save Current Workspace As…'),
- execute: async () => {
- const data = app.serviceManager.workspaces.fetch(resolver.name);
- await Private.saveAs(
- fbf.defaultBrowser,
- app.serviceManager.contents,
- data,
- state,
- translator
- );
- }
- });
+ // app.commands.addCommand(CommandIDs.saveWorkspaceAs, {
+ // label: trans.__('Save Current Workspace As…'),
+ // execute: async () => {
+ // const data = app.serviceManager.workspaces.fetch(resolver.name);
+ // await Private.saveAs(
+ // fbf.defaultBrowser,
+ // app.serviceManager.contents,
+ // data,
+ // state,
+ // translator
+ // );
+ // }
+ // });
- app.commands.addCommand(CommandIDs.saveWorkspace, {
- label: trans.__('Save Current Workspace'),
- execute: async () => {
- const { contents } = app.serviceManager;
- const data = app.serviceManager.workspaces.fetch(resolver.name);
- const lastSave = (await state.fetch(LAST_SAVE_ID)) as string;
- if (lastSave === undefined) {
- await Private.saveAs(
- fbf.defaultBrowser,
- contents,
- data,
- state,
- translator
- );
- } else {
- await Private.save(lastSave, contents, data, state);
- }
- }
- });
+ // app.commands.addCommand(CommandIDs.saveWorkspace, {
+ // label: trans.__('Save Current Workspace'),
+ // execute: async () => {
+ // const { contents } = app.serviceManager;
+ // const data = app.serviceManager.workspaces.fetch(resolver.name);
+ // const lastSave = (await state.fetch(LAST_SAVE_ID)) as string;
+ // if (lastSave === undefined) {
+ // await Private.saveAs(
+ // fbf.defaultBrowser,
+ // contents,
+ // data,
+ // state,
+ // translator
+ // );
+ // } else {
+ // await Private.save(lastSave, contents, data, state);
+ // }
+ // }
+ // });
}
};
diff --git a/packages/apputils/src/dialog.tsx b/packages/apputils/src/dialog.tsx
index 2003f99c5a..9f3854c394 100644
--- a/packages/apputils/src/dialog.tsx
+++ b/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' })
]
@@ -415,8 +415,6 @@ export class Dialog<T> extends Widget {
this.dispose();
return;
}
- this._promise = null;
- ArrayExt.removeFirstOf(Private.launchQueue, promise.promise);
const body = this._body;
let value: T | null = null;
if (
@@ -426,6 +424,8 @@ export class Dialog<T> extends Widget {
) {
value = body.getValue();
}
+ this._promise = null;
+ ArrayExt.removeFirstOf(Private.launchQueue, promise.promise);
this.dispose();
promise.resolve({ button, value });
}
@@ -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.
*
diff --git a/packages/apputils/src/mainareawidget.ts b/packages/apputils/src/mainareawidget.ts
index baa4eaa21f..f01dbd18f1 100644
--- a/packages/apputils/src/mainareawidget.ts
+++ b/packages/apputils/src/mainareawidget.ts
@@ -60,8 +60,8 @@ export class MainAreaWidget<T extends Widget = Widget>
BoxLayout.setStretch(toolbar, 0);
BoxLayout.setStretch(contentHeader, 0);
BoxLayout.setStretch(content, 1);
- layout.addWidget(toolbar);
layout.addWidget(contentHeader);
+ layout.addWidget(toolbar);
layout.addWidget(content);
if (!content.id) {
diff --git a/packages/apputils/style/dialog.css b/packages/apputils/style/dialog.css
index 7994fb4b59..17dfd7307f 100644
--- a/packages/apputils/style/dialog.css
+++ b/packages/apputils/style/dialog.css
@@ -6,7 +6,7 @@
.jp-Dialog {
position: absolute;
- z-index: 10000;
+ z-index: 1000;
display: flex;
flex-direction: column;
align-items: center;
@@ -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,17 @@
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 {
@@ -50,50 +47,32 @@
overflow: visible;
}
-button.jp-Dialog-button:focus {
- outline: 1px solid var(--jp-brand-color1);
- outline-offset: 4px;
- -moz-outline-radius: 0px;
-}
-
button.jp-Dialog-button:focus::-moz-focus-inner {
border: 0;
}
-button.jp-Dialog-button.jp-mod-styled.jp-mod-accept:focus,
-button.jp-Dialog-button.jp-mod-styled.jp-mod-warn:focus,
-button.jp-Dialog-button.jp-mod-styled.jp-mod-reject:focus {
- outline-offset: 4px;
- -moz-outline-radius: 0px;
-}
-
-button.jp-Dialog-button.jp-mod-styled.jp-mod-accept:focus {
- outline: 1px solid var(--md-blue-700);
-}
-
-button.jp-Dialog-button.jp-mod-styled.jp-mod-warn:focus {
- outline: 1px solid var(--md-red-600);
-}
-
-button.jp-Dialog-button.jp-mod-styled.jp-mod-reject:focus {
- outline: 1px solid var(--md-grey-700);
-}
-
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 {
@@ -103,16 +82,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 {
@@ -130,10 +108,10 @@ button.jp-Dialog-close-button {
}
.jp-Dialog-body > label {
- line-height: 1.4;
- color: var(--jp-ui-font-color0);
+ color: #4a4a4a;
+ margin-bottom: 5px;
}
.jp-Dialog-button.jp-mod-styled:not(:last-child) {
- margin-right: 12px;
+ margin-right: 50px;
}
diff --git a/packages/apputils/style/styling.css b/packages/apputils/style/styling.css
index de5146bb28..1b21b48370 100644
--- a/packages/apputils/style/styling.css
+++ b/packages/apputils/style/styling.css
@@ -10,9 +10,8 @@ button.jp-mod-styled {
border: none;
box-sizing: border-box;
text-align: center;
- line-height: 32px;
height: 32px;
- padding: 0px 12px;
+ width: 80px;
letter-spacing: 0.8px;
outline: none;
appearance: none;
@@ -21,18 +20,19 @@ button.jp-mod-styled {
}
input.jp-mod-styled {
- background: var(--jp-input-background);
- height: 28px;
+ height: 32px;
box-sizing: border-box;
- border: var(--jp-border-width) solid var(--jp-border-color1);
- padding-left: 7px;
- padding-right: 7px;
- font-size: var(--jp-ui-font-size2);
+ border: 1px solid #c8d3e9;
+ border-radius: 2px;
+ padding: 0 15px;
+ font-size: 12px;
color: var(--jp-ui-font-color0);
outline: none;
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
+ transition: all 100ms;
+ outline: 1px solid transparent;
}
input[type='checkbox'].jp-mod-styled {
@@ -43,8 +43,7 @@ input[type='checkbox'].jp-mod-styled {
}
input.jp-mod-styled:focus {
- border: var(--jp-border-width) solid var(--md-blue-500);
- box-shadow: inset 0 0 4px var(--md-blue-300);
+ outline-color: #147bd1;
}
.jp-FileDialog-Checkbox {
diff --git a/packages/cells/style/inputarea.css b/packages/cells/style/inputarea.css
index ec6f1620c0..5831ab644d 100644
--- a/packages/cells/style/inputarea.css
+++ b/packages/cells/style/inputarea.css
@@ -36,7 +36,7 @@ body[data-format='mobile'] .jp-InputArea-editor {
.jp-InputPrompt {
flex: 0 0 var(--jp-cell-prompt-width);
- color: var(--jp-cell-inprompt-font-color);
+ color: #147bd1;
font-family: var(--jp-cell-prompt-font-family);
padding: var(--jp-code-padding);
letter-spacing: var(--jp-cell-prompt-letter-spacing);
diff --git a/packages/console-extension/src/index.ts b/packages/console-extension/src/index.ts
index fe4c7d1d05..16cdb587e8 100644
--- a/packages/console-extension/src/index.ts
+++ b/packages/console-extension/src/index.ts
@@ -25,12 +25,12 @@ import { ConsolePanel, IConsoleTracker } from '@jupyterlab/console';
import { IFileBrowserFactory } from '@jupyterlab/filebrowser';
import { ILauncher } from '@jupyterlab/launcher';
import {
- IEditMenu,
- IFileMenu,
- IHelpMenu,
- IKernelMenu,
- IMainMenu,
- IRunMenu
+ // IEditMenu,
+ // IFileMenu,
+ // IHelpMenu,
+ // IKernelMenu,
+ IMainMenu
+ // IRunMenu
} from '@jupyterlab/mainmenu';
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
import { ISettingRegistry } from '@jupyterlab/settingregistry';
@@ -673,79 +673,79 @@ async function activateConsole(
});
}
- if (mainMenu) {
- // Add a close and shutdown command to the file menu.
- mainMenu.fileMenu.closeAndCleaners.add({
- tracker,
- closeAndCleanupLabel: (n: number) => trans.__('Shutdown Console'),
- closeAndCleanup: (current: ConsolePanel) => {
- return showDialog({
- title: trans.__('Shut down the Console?'),
- body: trans.__(
- 'Are you sure you want to close "%1"?',
- current.title.label
- ),
- buttons: [Dialog.cancelButton(), Dialog.warnButton()]
- }).then(result => {
- if (result.button.accept) {
- return current.console.sessionContext.shutdown().then(() => {
- current.dispose();
- });
- } else {
- return void 0;
- }
- });
- }
- } as IFileMenu.ICloseAndCleaner<ConsolePanel>);
-
- // Add a kernel user to the Kernel menu
- mainMenu.kernelMenu.kernelUsers.add({
- tracker,
- restartKernelAndClearLabel: n =>
- trans.__('Restart Kernel and Clear Console'),
- interruptKernel: current => {
- const kernel = current.console.sessionContext.session?.kernel;
- if (kernel) {
- return kernel.interrupt();
- }
- return Promise.resolve(void 0);
- },
- restartKernel: current =>
- sessionDialogs!.restart(current.console.sessionContext, translator),
- restartKernelAndClear: current => {
- return sessionDialogs!
- .restart(current.console.sessionContext)
- .then(restarted => {
- if (restarted) {
- current.console.clear();
- }
- return restarted;
- });
- },
- changeKernel: current =>
- sessionDialogs!.selectKernel(
- current.console.sessionContext,
- translator
- ),
- shutdownKernel: current => current.console.sessionContext.shutdown()
- } as IKernelMenu.IKernelUser<ConsolePanel>);
-
- // Add a code runner to the Run menu.
- mainMenu.runMenu.codeRunners.add({
- tracker,
- runLabel: (n: number) => trans.__('Run Cell'),
- run: current => current.console.execute(true)
- } as IRunMenu.ICodeRunner<ConsolePanel>);
-
- // Add a clearer to the edit menu
- mainMenu.editMenu.clearers.add({
- tracker,
- clearCurrentLabel: (n: number) => trans.__('Clear Console Cell'),
- clearCurrent: (current: ConsolePanel) => {
- return current.console.clear();
- }
- } as IEditMenu.IClearer<ConsolePanel>);
- }
+ // if (mainMenu) {
+ // // Add a close and shutdown command to the file menu.
+ // mainMenu.fileMenu.closeAndCleaners.add({
+ // tracker,
+ // closeAndCleanupLabel: (n: number) => trans.__('Shutdown Console'),
+ // closeAndCleanup: (current: ConsolePanel) => {
+ // return showDialog({
+ // title: trans.__('Shut down the Console?'),
+ // body: trans.__(
+ // 'Are you sure you want to close "%1"?',
+ // current.title.label
+ // ),
+ // buttons: [Dialog.cancelButton(), Dialog.warnButton()]
+ // }).then(result => {
+ // if (result.button.accept) {
+ // return current.console.sessionContext.shutdown().then(() => {
+ // current.dispose();
+ // });
+ // } else {
+ // return void 0;
+ // }
+ // });
+ // }
+ // } as IFileMenu.ICloseAndCleaner<ConsolePanel>);
+
+ // // Add a kernel user to the Kernel menu
+ // mainMenu.kernelMenu.kernelUsers.add({
+ // tracker,
+ // restartKernelAndClearLabel: n =>
+ // trans.__('Restart Kernel and Clear Console'),
+ // interruptKernel: current => {
+ // const kernel = current.console.sessionContext.session?.kernel;
+ // if (kernel) {
+ // return kernel.interrupt();
+ // }
+ // return Promise.resolve(void 0);
+ // },
+ // restartKernel: current =>
+ // sessionDialogs!.restart(current.console.sessionContext, translator),
+ // restartKernelAndClear: current => {
+ // return sessionDialogs!
+ // .restart(current.console.sessionContext)
+ // .then(restarted => {
+ // if (restarted) {
+ // current.console.clear();
+ // }
+ // return restarted;
+ // });
+ // },
+ // changeKernel: current =>
+ // sessionDialogs!.selectKernel(
+ // current.console.sessionContext,
+ // translator
+ // ),
+ // shutdownKernel: current => current.console.sessionContext.shutdown()
+ // } as IKernelMenu.IKernelUser<ConsolePanel>);
+
+ // // Add a code runner to the Run menu.
+ // mainMenu.runMenu.codeRunners.add({
+ // tracker,
+ // runLabel: (n: number) => trans.__('Run Cell'),
+ // run: current => current.console.execute(true)
+ // } as IRunMenu.ICodeRunner<ConsolePanel>);
+
+ // // Add a clearer to the edit menu
+ // mainMenu.editMenu.clearers.add({
+ // tracker,
+ // clearCurrentLabel: (n: number) => trans.__('Clear Console Cell'),
+ // clearCurrent: (current: ConsolePanel) => {
+ // return current.console.clear();
+ // }
+ // } as IEditMenu.IClearer<ConsolePanel>);
+ // }
// For backwards compatibility and clarity, we explicitly label the run
// keystroke with the actual effected change, rather than the generic
@@ -775,13 +775,13 @@ async function activateConsole(
isToggled: args => args['interactionMode'] === interactionMode
});
- if (mainMenu) {
- // Add kernel information to the application help menu.
- mainMenu.helpMenu.kernelUsers.add({
- tracker,
- getKernel: current => current.sessionContext.session?.kernel
- } as IHelpMenu.IKernelUser<ConsolePanel>);
- }
+ // if (mainMenu) {
+ // // Add kernel information to the application help menu.
+ // mainMenu.helpMenu.kernelUsers.add({
+ // tracker,
+ // getKernel: current => current.sessionContext.session?.kernel
+ // } as IHelpMenu.IKernelUser<ConsolePanel>);
+ // }
return tracker;
}
diff --git a/packages/debugger-extension/src/index.ts b/packages/debugger-extension/src/index.ts
index fe710a9d2a..659f5c0692 100644
--- a/packages/debugger-extension/src/index.ts
+++ b/packages/debugger-extension/src/index.ts
@@ -15,7 +15,7 @@ import {
ICommandPalette,
IThemeManager,
MainAreaWidget,
- sessionContextDialogs,
+ // sessionContextDialogs,
WidgetTracker
} from '@jupyterlab/apputils';
import { IEditorServices } from '@jupyterlab/codeeditor';
@@ -35,7 +35,7 @@ import { FileEditor, IEditorTracker } from '@jupyterlab/fileeditor';
import { ILoggerRegistry } from '@jupyterlab/logconsole';
import {
INotebookTracker,
- NotebookActions,
+ // NotebookActions,
NotebookPanel
} from '@jupyterlab/notebook';
import {
@@ -167,88 +167,88 @@ const files: JupyterFrontEndPlugin<void> = {
/**
* A plugin that provides visual debugging support for notebooks.
*/
-const notebooks: JupyterFrontEndPlugin<IDebugger.IHandler> = {
- id: '@jupyterlab/debugger-extension:notebooks',
- autoStart: true,
- requires: [IDebugger, INotebookTracker, ITranslator],
- optional: [ILabShell, ICommandPalette],
- provides: IDebuggerHandler,
- activate: (
- app: JupyterFrontEnd,
- service: IDebugger,
- notebookTracker: INotebookTracker,
- translator: ITranslator,
- labShell: ILabShell | null,
- palette: ICommandPalette | null
- ): Debugger.Handler => {
- const handler = new Debugger.Handler({
- type: 'notebook',
- shell: app.shell,
- service
- });
-
- const trans = translator.load('jupyterlab');
- app.commands.addCommand(Debugger.CommandIDs.restartDebug, {
- label: trans.__('Restart Kernel and Debug…'),
- caption: trans.__('Restart Kernel and Debug…'),
- isEnabled: () => service.isStarted,
- execute: async () => {
- const state = service.getDebuggerState();
- await service.stop();
-
- const widget = notebookTracker.currentWidget;
- if (!widget) {
- return;
- }
-
- const { content, sessionContext } = widget;
- const restarted = await sessionContextDialogs.restart(sessionContext);
- if (!restarted) {
- return;
- }
-
- await service.restoreDebuggerState(state);
- await handler.updateWidget(widget, sessionContext.session);
- await NotebookActions.runAll(content, sessionContext);
- }
- });
-
- const updateHandlerAndCommands = async (
- widget: NotebookPanel
- ): Promise<void> => {
- if (widget) {
- const { sessionContext } = widget;
- await sessionContext.ready;
- await handler.updateContext(widget, sessionContext);
- }
- app.commands.notifyCommandChanged();
- };
-
- if (labShell) {
- labShell.currentChanged.connect((_, update) => {
- const widget = update.newValue;
- if (widget instanceof NotebookPanel) {
- void updateHandlerAndCommands(widget);
- }
- });
- } else {
- notebookTracker.currentChanged.connect((_, notebookPanel) => {
- if (notebookPanel) {
- void updateHandlerAndCommands(notebookPanel);
- }
- });
- }
-
- if (palette) {
- palette.addItem({
- category: 'Notebook Operations',
- command: Debugger.CommandIDs.restartDebug
- });
- }
-
- return handler;
- }
-};
+// const notebooks: JupyterFrontEndPlugin<IDebugger.IHandler> = {
+// id: '@jupyterlab/debugger-extension:notebooks',
+// autoStart: true,
+// requires: [IDebugger, INotebookTracker, ITranslator],
+// optional: [ILabShell, ICommandPalette],
+// provides: IDebuggerHandler,
+// activate: (
+// app: JupyterFrontEnd,
+// service: IDebugger,
+// notebookTracker: INotebookTracker,
+// translator: ITranslator,
+// labShell: ILabShell | null,
+// palette: ICommandPalette | null
+// ): Debugger.Handler => {
+// const handler = new Debugger.Handler({
+// type: 'notebook',
+// shell: app.shell,
+// service
+// });
+
+// const trans = translator.load('jupyterlab');
+// app.commands.addCommand(Debugger.CommandIDs.restartDebug, {
+// label: trans.__('Restart Kernel and Debug…'),
+// caption: trans.__('Restart Kernel and Debug…'),
+// isEnabled: () => service.isStarted,
+// execute: async () => {
+// const state = service.getDebuggerState();
+// await service.stop();
+
+// const widget = notebookTracker.currentWidget;
+// if (!widget) {
+// return;
+// }
+
+// const { content, sessionContext } = widget;
+// const restarted = await sessionContextDialogs.restart(sessionContext);
+// if (!restarted) {
+// return;
+// }
+
+// await service.restoreDebuggerState(state);
+// await handler.updateWidget(widget, sessionContext.session);
+// await NotebookActions.runAll(content, sessionContext);
+// }
+// });
+
+// const updateHandlerAndCommands = async (
+// widget: NotebookPanel
+// ): Promise<void> => {
+// if (widget) {
+// const { sessionContext } = widget;
+// await sessionContext.ready;
+// await handler.updateContext(widget, sessionContext);
+// }
+// app.commands.notifyCommandChanged();
+// };
+
+// if (labShell) {
+// labShell.currentChanged.connect((_, update) => {
+// const widget = update.newValue;
+// if (widget instanceof NotebookPanel) {
+// void updateHandlerAndCommands(widget);
+// }
+// });
+// } else {
+// notebookTracker.currentChanged.connect((_, notebookPanel) => {
+// if (notebookPanel) {
+// void updateHandlerAndCommands(notebookPanel);
+// }
+// });
+// }
+
+// if (palette) {
+// palette.addItem({
+// category: 'Notebook Operations',
+// command: Debugger.CommandIDs.restartDebug
+// });
+// }
+
+// return handler;
+// }
+// };
/**
* A plugin that provides a debugger service.
@@ -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: (
@@ -868,7 +868,7 @@ const plugins: JupyterFrontEndPlugin<any>[] = [
service,
consoles,
files,
- notebooks,
+ // notebooks,
variables,
sidebar,
main,
diff --git a/packages/docmanager-extension/src/index.tsx b/packages/docmanager-extension/src/index.tsx
index fac8aadb2b..4a0a90ae55 100644
--- a/packages/docmanager-extension/src/index.tsx
+++ b/packages/docmanager-extension/src/index.tsx
@@ -342,49 +342,49 @@ export const pathStatusPlugin: JupyterFrontEndPlugin<void> = {
/**
* A plugin providing download commands in the file menu and command palette.
*/
-export const downloadPlugin: JupyterFrontEndPlugin<void> = {
- id: '@jupyterlab/docmanager-extension:download',
- autoStart: true,
- requires: [ITranslator, IDocumentManager],
- optional: [ICommandPalette],
- activate: (
- app: JupyterFrontEnd,
- translator: ITranslator,
- docManager: IDocumentManager,
- palette: ICommandPalette | null
- ) => {
- const trans = translator.load('jupyterlab');
- const { commands, shell } = app;
- const isEnabled = () => {
- const { currentWidget } = shell;
- return !!(currentWidget && docManager.contextForWidget(currentWidget));
- };
- commands.addCommand(CommandIDs.download, {
- label: trans.__('Download'),
- caption: trans.__('Download the file to your computer'),
- isEnabled,
- execute: () => {
- // Checks that shell.currentWidget is valid:
- if (isEnabled()) {
- const context = docManager.contextForWidget(shell.currentWidget!);
- if (!context) {
- return showDialog({
- title: trans.__('Cannot Download'),
- body: trans.__('No context found for current widget!'),
- buttons: [Dialog.okButton({ label: trans.__('OK') })]
- });
- }
- return context.download();
- }
- }
- });
-
- const category = trans.__('File Operations');
- if (palette) {
- palette.addItem({ command: CommandIDs.download, category });
- }
- }
-};
+// export const downloadPlugin: JupyterFrontEndPlugin<void> = {
+// id: '@jupyterlab/docmanager-extension:download',
+// autoStart: true,
+// requires: [ITranslator, IDocumentManager],
+// optional: [ICommandPalette],
+// activate: (
+// app: JupyterFrontEnd,
+// translator: ITranslator,
+// docManager: IDocumentManager,
+// palette: ICommandPalette | null
+// ) => {
+// const trans = translator.load('jupyterlab');
+// const { commands, shell } = app;
+// const isEnabled = () => {
+// const { currentWidget } = shell;
+// return !!(currentWidget && docManager.contextForWidget(currentWidget));
+// };
+// commands.addCommand(CommandIDs.download, {
+// label: trans.__('Download'),
+// caption: trans.__('Download the file to your computer'),
+// isEnabled,
+// execute: () => {
+// // Checks that shell.currentWidget is valid:
+// if (isEnabled()) {
+// const context = docManager.contextForWidget(shell.currentWidget!);
+// if (!context) {
+// return showDialog({
+// title: trans.__('Cannot Download'),
+// body: trans.__('No context found for current widget!'),
+// buttons: [Dialog.okButton({ label: trans.__('OK') })]
+// });
+// }
+// return context.download();
+// }
+// }
+// });
+
+// const category = trans.__('File Operations');
+// if (palette) {
+// palette.addItem({ command: CommandIDs.download, category });
+// }
+// }
+// };
/**
* A plugin providing open-browser-tab commands.
@@ -438,7 +438,7 @@ const plugins: JupyterFrontEndPlugin<any>[] = [
docManagerPlugin,
pathStatusPlugin,
savingStatusPlugin,
- downloadPlugin,
+ // downloadPlugin,
openBrowserTabPlugin
];
export default plugins;
diff --git a/packages/docregistry/src/context.ts b/packages/docregistry/src/context.ts
index 966dadf146..f9bb12ed26 100644
--- a/packages/docregistry/src/context.ts
+++ b/packages/docregistry/src/context.ts
@@ -1047,6 +1047,8 @@ namespace Private {
function createSaveNode(path: string): HTMLElement {
const input = document.createElement('input');
input.value = path;
- return input;
+ const container = document.createElement('div');
+ container.appendChild(input);
+ return container;
}
}
diff --git a/packages/extensionmanager-extension/examples/listings/index.js b/packages/extensionmanager-extension/examples/listings/index.js
index 9d05d78fa7..19776fc525 100644
--- a/packages/extensionmanager-extension/examples/listings/index.js
+++ b/packages/extensionmanager-extension/examples/listings/index.js
@@ -37,7 +37,6 @@ window.addEventListener('load', async function () {
require('@jupyterlab/shortcuts-extension'),
require('@jupyterlab/statusbar-extension'),
require('@jupyterlab/terminal-extension'),
- require('@jupyterlab/theme-dark-extension'),
require('@jupyterlab/theme-light-extension'),
require('@jupyterlab/tooltip-extension'),
require('@jupyterlab/ui-components-extension')
diff --git a/packages/extensionmanager-extension/examples/listings/package.json b/packages/extensionmanager-extension/examples/listings/package.json
index c7e3b09207..6dca5df7b2 100644
--- a/packages/extensionmanager-extension/examples/listings/package.json
+++ b/packages/extensionmanager-extension/examples/listings/package.json
@@ -34,7 +34,6 @@
"@jupyterlab/shortcuts-extension": "^2.0.2",
"@jupyterlab/statusbar-extension": "^2.0.2",
"@jupyterlab/terminal-extension": "^2.0.2",
- "@jupyterlab/theme-dark-extension": "^2.0.2",
"@jupyterlab/theme-light-extension": "^2.0.2",
"@jupyterlab/tooltip-extension": "^2.0.2",
"@jupyterlab/ui-components-extension": "^2.0.2",
diff --git a/packages/extensionmanager-extension/schema/plugin.json b/packages/extensionmanager-extension/schema/plugin.json
index dda72c020d..3f2c190d75 100644
--- a/packages/extensionmanager-extension/schema/plugin.json
+++ b/packages/extensionmanager-extension/schema/plugin.json
@@ -28,7 +28,7 @@
"enabled": {
"title": "Enabled Status",
"description": "Enables extension manager (requires Node.js/npm).\nWARNING: installing untrusted extensions may be unsafe.",
- "default": true,
+ "default": false,
"type": "boolean"
},
"disclaimed": {
diff --git a/packages/filebrowser-extension/src/index.ts b/packages/filebrowser-extension/src/index.ts
index b6c810262b..18d20e6bb7 100644
--- a/packages/filebrowser-extension/src/index.ts
+++ b/packages/filebrowser-extension/src/index.ts
@@ -29,7 +29,7 @@ import { IDocumentManager } from '@jupyterlab/docmanager';
import { DocumentRegistry } from '@jupyterlab/docregistry';
import {
FileBrowser,
- FileUploadStatus,
+ // FileUploadStatus,
FilterFileBrowserModel,
IFileBrowserCommands,
IFileBrowserFactory,
@@ -39,18 +39,19 @@ import { Launcher } from '@jupyterlab/launcher';
import { Contents } from '@jupyterlab/services';
import { ISettingRegistry } from '@jupyterlab/settingregistry';
import { IStateDB } from '@jupyterlab/statedb';
-import { IStatusBar } from '@jupyterlab/statusbar';
+// import { IStatusBar } from '@jupyterlab/statusbar';
import { ITranslator } from '@jupyterlab/translation';
import {
addIcon,
closeIcon,
copyIcon,
cutIcon,
- downloadIcon,
+ // downloadIcon,
editIcon,
fileIcon,
folderIcon,
- linkIcon,
+ LabIcon,
+ // linkIcon,
markdownIcon,
newFolderIcon,
pasteIcon,
@@ -60,8 +61,14 @@ import {
} from '@jupyterlab/ui-components';
import { find, IIterator, map, reduce, toArray } from '@lumino/algorithm';
import { CommandRegistry } from '@lumino/commands';
-import { ContextMenu } from '@lumino/widgets';
+// import { ContextMenu } from '@lumino/widgets';
import { JSONObject } from '@lumino/coreutils';
+import analysisSvgStr from '../style/icons/analysis.svg';
+
+const analysisIcon = new LabIcon({
+ name: 'analysis',
+ svgstr: analysisSvgStr
+});
const FILE_BROWSER_FACTORY = 'FileBrowser';
@@ -176,10 +183,10 @@ const browser: JupyterFrontEndPlugin<void> = {
}
// Navigate to preferred-dir trait if found
- const preferredPath = PageConfig.getOption('preferredPath');
- if (preferredPath) {
- await browser.model.cd(preferredPath);
- }
+ // const preferredPath = PageConfig.getOption('preferredPath');
+ // if (preferredPath) {
+ // await browser.model.cd(preferredPath);
+ // }
addCommands(app, factory, translator, settingRegistry, commandPalette);
@@ -322,50 +329,50 @@ const factory: JupyterFrontEndPlugin<IFileBrowserFactory> = {
* Users will still be able to retrieve files from the file download URLs the
* server provides.
*/
-const downloadPlugin: JupyterFrontEndPlugin<void> = {
- id: '@jupyterlab/filebrowser-extension:download',
- requires: [IFileBrowserFactory, ITranslator],
- autoStart: true,
- activate: (
- app: JupyterFrontEnd,
- factory: IFileBrowserFactory,
- translator: ITranslator
- ): void => {
- const trans = translator.load('jupyterlab');
- const { commands } = app;
- const { tracker } = factory;
-
- commands.addCommand(CommandIDs.download, {
- execute: () => {
- const widget = tracker.currentWidget;
-
- if (widget) {
- return widget.download();
- }
- },
- icon: downloadIcon.bindprops({ stylesheet: 'menuItem' }),
- label: trans.__('Download')
- });
-
- commands.addCommand(CommandIDs.copyDownloadLink, {
- execute: () => {
- const widget = tracker.currentWidget;
- if (!widget) {
- return;
- }
-
- return widget.model.manager.services.contents
- .getDownloadUrl(widget.selectedItems().next()!.path)
- .then(url => {
- Clipboard.copyToSystem(url);
- });
- },
- icon: copyIcon.bindprops({ stylesheet: 'menuItem' }),
- label: trans.__('Copy Download Link'),
- mnemonic: 0
- });
- }
-};
+// const downloadPlugin: JupyterFrontEndPlugin<void> = {
+// id: '@jupyterlab/filebrowser-extension:download',
+// requires: [IFileBrowserFactory, ITranslator],
+// autoStart: true,
+// activate: (
+// app: JupyterFrontEnd,
+// factory: IFileBrowserFactory,
+// translator: ITranslator
+// ): void => {
+// const trans = translator.load('jupyterlab');
+// const { commands } = app;
+// const { tracker } = factory;
+
+// commands.addCommand(CommandIDs.download, {
+// execute: () => {
+// const widget = tracker.currentWidget;
+
+// if (widget) {
+// return widget.download();
+// }
+// },
+// icon: downloadIcon.bindprops({ stylesheet: 'menuItem' }),
+// label: trans.__('Download')
+// });
+
+// commands.addCommand(CommandIDs.copyDownloadLink, {
+// execute: () => {
+// const widget = tracker.currentWidget;
+// if (!widget) {
+// return;
+// }
+
+// return widget.model.manager.services.contents
+// .getDownloadUrl(widget.selectedItems().next()!.path)
+// .then(url => {
+// Clipboard.copyToSystem(url);
+// });
+// },
+// icon: copyIcon.bindprops({ stylesheet: 'menuItem' }),
+// label: trans.__('Copy Download Link'),
+// mnemonic: 0
+// });
+// }
+// };
/**
* A plugin to add the file browser widget to an ILabShell
@@ -398,7 +405,8 @@ const browserWidget: JupyterFrontEndPlugin<void> = {
// Set attributes when adding the browser to the UI
browser.node.setAttribute('role', 'region');
browser.node.setAttribute('aria-label', trans.__('File Browser Section'));
- browser.title.icon = folderIcon;
+ browser.title.icon = analysisIcon;
+ browser.title.label = '可视化编程';
// Toolbar
toolbarRegistry.registerFactory(
@@ -519,43 +527,43 @@ const browserWidget: JupyterFrontEndPlugin<void> = {
* /user-redirect URL for JupyterHub), disable this plugin and replace it
* with another implementation.
*/
-const shareFile: JupyterFrontEndPlugin<void> = {
- id: '@jupyterlab/filebrowser-extension:share-file',
- requires: [IFileBrowserFactory, ITranslator],
- autoStart: true,
- activate: (
- app: JupyterFrontEnd,
- factory: IFileBrowserFactory,
- translator: ITranslator
- ): void => {
- const trans = translator.load('jupyterlab');
- const { commands } = app;
- const { tracker } = factory;
-
- commands.addCommand(CommandIDs.copyShareableLink, {
- execute: () => {
- const widget = tracker.currentWidget;
- const model = widget?.selectedItems().next();
- if (!model) {
- return;
- }
-
- Clipboard.copyToSystem(
- PageConfig.getUrl({
- workspace: PageConfig.defaultWorkspace,
- treePath: model.path,
- toShare: true
- })
- );
- },
- isVisible: () =>
- !!tracker.currentWidget &&
- toArray(tracker.currentWidget.selectedItems()).length === 1,
- icon: linkIcon.bindprops({ stylesheet: 'menuItem' }),
- label: trans.__('Copy Shareable Link')
- });
- }
-};
+// const shareFile: JupyterFrontEndPlugin<void> = {
+// id: '@jupyterlab/filebrowser-extension:share-file',
+// requires: [IFileBrowserFactory, ITranslator],
+// autoStart: true,
+// activate: (
+// app: JupyterFrontEnd,
+// factory: IFileBrowserFactory,
+// translator: ITranslator
+// ): void => {
+// const trans = translator.load('jupyterlab');
+// const { commands } = app;
+// const { tracker } = factory;
+
+// commands.addCommand(CommandIDs.copyShareableLink, {
+// execute: () => {
+// const widget = tracker.currentWidget;
+// const model = widget?.selectedItems().next();
+// if (!model) {
+// return;
+// }
+
+// Clipboard.copyToSystem(
+// PageConfig.getUrl({
+// workspace: PageConfig.defaultWorkspace,
+// treePath: model.path,
+// toShare: true
+// })
+// );
+// },
+// isVisible: () =>
+// !!tracker.currentWidget &&
+// toArray(tracker.currentWidget.selectedItems()).length === 1,
+// icon: linkIcon.bindprops({ stylesheet: 'menuItem' }),
+// label: trans.__('Copy Shareable Link')
+// });
+// }
+// };
/**
* The "Open With" context menu.
@@ -563,51 +571,51 @@ const shareFile: JupyterFrontEndPlugin<void> = {
* This is its own plugin in case you would like to disable this feature.
* e.g. jupyter labextension disable @jupyterlab/filebrowser-extension:open-with
*/
-const openWithPlugin: JupyterFrontEndPlugin<void> = {
- id: '@jupyterlab/filebrowser-extension:open-with',
- requires: [IFileBrowserFactory],
- autoStart: true,
- activate: (app: JupyterFrontEnd, factory: IFileBrowserFactory): void => {
- const { docRegistry } = app;
- const { tracker } = factory;
-
- function updateOpenWithMenu(contextMenu: ContextMenu) {
- const openWith =
- contextMenu.menu.items.find(
- item =>
- item.type === 'submenu' &&
- item.submenu?.id === 'jp-contextmenu-open-with'
- )?.submenu ?? null;
-
- if (!openWith) {
- return; // Bail early if the open with menu is not displayed
- }
-
- // clear the current menu items
- openWith.clearItems();
-
- // get the widget factories that could be used to open all of the items
- // in the current filebrowser selection
- const factories = tracker.currentWidget
- ? Private.OpenWith.intersection<string>(
- map(tracker.currentWidget.selectedItems(), i => {
- return Private.OpenWith.getFactories(docRegistry, i);
- })
- )
- : new Set<string>();
-
- // make new menu items from the widget factories
- factories.forEach(factory => {
- openWith.addItem({
- args: { factory: factory },
- command: CommandIDs.open
- });
- });
- }
-
- app.contextMenu.opened.connect(updateOpenWithMenu);
- }
-};
+// const openWithPlugin: JupyterFrontEndPlugin<void> = {
+// id: '@jupyterlab/filebrowser-extension:open-with',
+// requires: [IFileBrowserFactory],
+// autoStart: true,
+// activate: (app: JupyterFrontEnd, factory: IFileBrowserFactory): void => {
+// const { docRegistry } = app;
+// const { tracker } = factory;
+
+// function updateOpenWithMenu(contextMenu: ContextMenu) {
+// const openWith =
+// contextMenu.menu.items.find(
+// item =>
+// item.type === 'submenu' &&
+// item.submenu?.id === 'jp-contextmenu-open-with'
+// )?.submenu ?? null;
+
+// if (!openWith) {
+// return; // Bail early if the open with menu is not displayed
+// }
+
+// // clear the current menu items
+// openWith.clearItems();
+
+// // get the widget factories that could be used to open all of the items
+// // in the current filebrowser selection
+// const factories = tracker.currentWidget
+// ? Private.OpenWith.intersection<string>(
+// map(tracker.currentWidget.selectedItems(), i => {
+// return Private.OpenWith.getFactories(docRegistry, i);
+// })
+// )
+// : new Set<string>();
+
+// // make new menu items from the widget factories
+// factories.forEach(factory => {
+// openWith.addItem({
+// args: { factory: factory },
+// command: CommandIDs.open
+// });
+// });
+// }
+
+// app.contextMenu.opened.connect(updateOpenWithMenu);
+// }
+// };
/**
* The "Open in New Browser Tab" context menu.
@@ -618,181 +626,181 @@ const openWithPlugin: JupyterFrontEndPlugin<void> = {
* Note: If disabling this, you may also want to disable:
* @jupyterlab/docmanager-extension:open-browser-tab
*/
-const openBrowserTabPlugin: JupyterFrontEndPlugin<void> = {
- id: '@jupyterlab/filebrowser-extension:open-browser-tab',
- requires: [IFileBrowserFactory, ITranslator],
- autoStart: true,
- activate: (
- app: JupyterFrontEnd,
- factory: IFileBrowserFactory,
- translator: ITranslator
- ): void => {
- const { commands } = app;
- const trans = translator.load('jupyterlab');
- const { tracker } = factory;
-
- commands.addCommand(CommandIDs.openBrowserTab, {
- execute: args => {
- const widget = tracker.currentWidget;
-
- if (!widget) {
- return;
- }
-
- const mode = args['mode'] as string | undefined;
-
- return Promise.all(
- toArray(
- map(widget.selectedItems(), item => {
- if (mode === 'single-document') {
- const url = PageConfig.getUrl({
- mode: 'single-document',
- treePath: item.path
- });
- const opened = window.open();
- if (opened) {
- opened.opener = null;
- opened.location.href = url;
- } else {
- throw new Error('Failed to open new browser tab.');
- }
- } else {
- return commands.execute('docmanager:open-browser-tab', {
- path: item.path
- });
- }
- })
- )
- );
- },
- icon: addIcon.bindprops({ stylesheet: 'menuItem' }),
- label: args =>
- args['mode'] === 'single-document'
- ? trans.__('Open in Simple Mode')
- : trans.__('Open in New Browser Tab'),
- mnemonic: 0
- });
- }
-};
+// const openBrowserTabPlugin: JupyterFrontEndPlugin<void> = {
+// id: '@jupyterlab/filebrowser-extension:open-browser-tab',
+// requires: [IFileBrowserFactory, ITranslator],
+// autoStart: true,
+// activate: (
+// app: JupyterFrontEnd,
+// factory: IFileBrowserFactory,
+// translator: ITranslator
+// ): void => {
+// const { commands } = app;
+// const trans = translator.load('jupyterlab');
+// const { tracker } = factory;
+
+// commands.addCommand(CommandIDs.openBrowserTab, {
+// execute: args => {
+// const widget = tracker.currentWidget;
+
+// if (!widget) {
+// return;
+// }
+
+// const mode = args['mode'] as string | undefined;
+
+// return Promise.all(
+// toArray(
+// map(widget.selectedItems(), item => {
+// if (mode === 'single-document') {
+// const url = PageConfig.getUrl({
+// mode: 'single-document',
+// treePath: item.path
+// });
+// const opened = window.open();
+// if (opened) {
+// opened.opener = null;
+// opened.location.href = url;
+// } else {
+// throw new Error('Failed to open new browser tab.');
+// }
+// } else {
+// return commands.execute('docmanager:open-browser-tab', {
+// path: item.path
+// });
+// }
+// })
+// )
+// );
+// },
+// icon: addIcon.bindprops({ stylesheet: 'menuItem' }),
+// label: args =>
+// args['mode'] === 'single-document'
+// ? trans.__('Open in Simple Mode')
+// : trans.__('Open in New Browser Tab'),
+// mnemonic: 0
+// });
+// }
+// };
/**
* A plugin providing file upload status.
*/
-export const fileUploadStatus: JupyterFrontEndPlugin<void> = {
- id: '@jupyterlab/filebrowser-extension:file-upload-status',
- autoStart: true,
- requires: [IFileBrowserFactory, ITranslator],
- optional: [IStatusBar],
- activate: (
- app: JupyterFrontEnd,
- browser: IFileBrowserFactory,
- translator: ITranslator,
- statusBar: IStatusBar | null
- ) => {
- if (!statusBar) {
- // Automatically disable if statusbar missing
- return;
- }
- const item = new FileUploadStatus({
- tracker: browser.tracker,
- translator
- });
-
- statusBar.registerStatusItem(
- '@jupyterlab/filebrowser-extension:file-upload-status',
- {
- item,
- align: 'middle',
- isActive: () => {
- return !!item.model && item.model.items.length > 0;
- },
- activeStateChanged: item.model.stateChanged
- }
- );
- }
-};
+// export const fileUploadStatus: JupyterFrontEndPlugin<void> = {
+// id: '@jupyterlab/filebrowser-extension:file-upload-status',
+// autoStart: true,
+// requires: [IFileBrowserFactory, ITranslator],
+// optional: [IStatusBar],
+// activate: (
+// app: JupyterFrontEnd,
+// browser: IFileBrowserFactory,
+// translator: ITranslator,
+// statusBar: IStatusBar | null
+// ) => {
+// if (!statusBar) {
+// // Automatically disable if statusbar missing
+// return;
+// }
+// const item = new FileUploadStatus({
+// tracker: browser.tracker,
+// translator
+// });
+
+// statusBar.registerStatusItem(
+// '@jupyterlab/filebrowser-extension:file-upload-status',
+// {
+// item,
+// align: 'middle',
+// isActive: () => {
+// return !!item.model && item.model.items.length > 0;
+// },
+// activeStateChanged: item.model.stateChanged
+// }
+// );
+// }
+// };
/**
* A plugin to open files from remote URLs
*/
-const openUrlPlugin: JupyterFrontEndPlugin<void> = {
- id: '@jupyterlab/filebrowser-extension:open-url',
- autoStart: true,
- requires: [IFileBrowserFactory, ITranslator],
- optional: [ICommandPalette],
- activate: (
- app: JupyterFrontEnd,
- factory: IFileBrowserFactory,
- translator: ITranslator,
- palette: ICommandPalette | null
- ) => {
- const { commands } = app;
- const trans = translator.load('jupyterlab');
- const { defaultBrowser: browser } = factory;
- const command = CommandIDs.openUrl;
-
- commands.addCommand(command, {
- label: args =>
- args.url ? trans.__('Open %1', args.url) : trans.__('Open from URL…'),
- caption: args =>
- args.url ? trans.__('Open %1', args.url) : trans.__('Open from URL'),
- execute: async args => {
- let url: string | undefined = (args?.url as string) ?? '';
- if (!url) {
- url =
- (
- await InputDialog.getText({
- label: trans.__('URL'),
- placeholder: 'https://example.com/path/to/file',
- title: trans.__('Open URL'),
- okLabel: trans.__('Open')
- })
- ).value ?? undefined;
- }
- if (!url) {
- return;
- }
-
- let type = '';
- let blob;
-
- // fetch the file from the URL
- try {
- const req = await fetch(url);
- blob = await req.blob();
- type = req.headers.get('Content-Type') ?? '';
- } catch (reason) {
- if (reason.response && reason.response.status !== 200) {
- reason.message = trans.__('Could not open URL: %1', url);
- }
- return showErrorMessage(trans.__('Cannot fetch'), reason);
- }
-
- // upload the content of the file to the server
- try {
- const name = PathExt.basename(url);
- const file = new File([blob], name, { type });
- const model = await browser.model.upload(file);
- return commands.execute('docmanager:open', {
- path: model.path
- });
- } catch (error) {
- return showErrorMessage(
- trans._p('showErrorMessage', 'Upload Error'),
- error
- );
- }
- }
- });
-
- if (palette) {
- palette.addItem({
- command,
- category: trans.__('File Operations')
- });
- }
- }
-};
+// const openUrlPlugin: JupyterFrontEndPlugin<void> = {
+// id: '@jupyterlab/filebrowser-extension:open-url',
+// autoStart: true,
+// requires: [IFileBrowserFactory, ITranslator],
+// optional: [ICommandPalette],
+// activate: (
+// app: JupyterFrontEnd,
+// factory: IFileBrowserFactory,
+// translator: ITranslator,
+// palette: ICommandPalette | null
+// ) => {
+// const { commands } = app;
+// const trans = translator.load('jupyterlab');
+// const { defaultBrowser: browser } = factory;
+// const command = CommandIDs.openUrl;
+
+// commands.addCommand(command, {
+// label: args =>
+// args.url ? trans.__('Open %1', args.url) : trans.__('Open from URL…'),
+// caption: args =>
+// args.url ? trans.__('Open %1', args.url) : trans.__('Open from URL'),
+// execute: async args => {
+// let url: string | undefined = (args?.url as string) ?? '';
+// if (!url) {
+// url =
+// (
+// await InputDialog.getText({
+// label: trans.__('URL'),
+// placeholder: 'https://example.com/path/to/file',
+// title: trans.__('Open URL'),
+// okLabel: trans.__('Open')
+// })
+// ).value ?? undefined;
+// }
+// if (!url) {
+// return;
+// }
+
+// let type = '';
+// let blob;
+
+// // fetch the file from the URL
+// try {
+// const req = await fetch(url);
+// blob = await req.blob();
+// type = req.headers.get('Content-Type') ?? '';
+// } catch (reason) {
+// if (reason.response && reason.response.status !== 200) {
+// reason.message = trans.__('Could not open URL: %1', url);
+// }
+// return showErrorMessage(trans.__('Cannot fetch'), reason);
+// }
+
+// // upload the content of the file to the server
+// try {
+// const name = PathExt.basename(url);
+// const file = new File([blob], name, { type });
+// const model = await browser.model.upload(file);
+// return commands.execute('docmanager:open', {
+// path: model.path
+// });
+// } catch (error) {
+// return showErrorMessage(
+// trans._p('showErrorMessage', 'Upload Error'),
+// error
+// );
+// }
+// }
+// });
+
+// if (palette) {
+// palette.addItem({
+// command,
+// category: trans.__('File Operations')
+// });
+// }
+// }
+// };
/**
* Add the main file browser commands to the application's command registry.
@@ -1342,13 +1350,13 @@ namespace Private {
const plugins: JupyterFrontEndPlugin<any>[] = [
factory,
browser,
- shareFile,
- fileUploadStatus,
- downloadPlugin,
- browserWidget,
- openWithPlugin,
- openBrowserTabPlugin,
- openUrlPlugin
+ // shareFile,
+ // fileUploadStatus,
+ // downloadPlugin,
+ browserWidget
+ // openWithPlugin,
+ // openBrowserTabPlugin,
+ // openUrlPlugin
];
export default plugins;
diff --git a/packages/filebrowser-extension/src/svg.d.ts b/packages/filebrowser-extension/src/svg.d.ts
new file mode 100644
index 0000000000..0ca27598c5
--- /dev/null
+++ b/packages/filebrowser-extension/src/svg.d.ts
@@ -0,0 +1,4 @@
+declare module "*.svg" {
+ const value: string;
+ export default value;
+}
diff --git a/packages/filebrowser-extension/style/icons/analysis.svg b/packages/filebrowser-extension/style/icons/analysis.svg
new file mode 100644
index 0000000000..780413c090
--- /dev/null
+++ b/packages/filebrowser-extension/style/icons/analysis.svg
@@ -0,0 +1,5 @@
+<svg width="4.2214mm" height="4.2302mm" version="1.1" viewBox="0 0 4.2214 4.2302" xmlns="http://www.w3.org/2000/svg">
+ <path fill="#000000" class="jp-icon3 jp-icon-selectable"
+ d="m3.6685 2.0479a0.13229 0.13229 0 0 0-0.074931 0.026355 0.13229 0.13229 0 0 0-0.027388 0.18552l0.44752 0.60151a0.13229 0.13229 0 0 0 0.18552 0.027389 0.13229 0.13229 0 0 0 0.02222-0.021188v-0.17105l-0.4439-0.5948a0.13229 0.13229 0 0 0-0.0863-0.05271 0.13229 0.13229 0 0 0-0.022738-0.00103zm-0.648-1.9296a1.066 1.066 0 0 0-1.0661 1.0661 1.066 1.066 0 0 0 1.0661 1.0661 1.066 1.066 0 0 0 1.0661-1.0661 1.066 1.066 0 0 0-1.0661-1.0661zm0 0.051676a1.0142 1.0142 0 0 1 1.0139 1.0144 1.0142 1.0142 0 0 1-1.0139 1.0144 1.0142 1.0142 0 0 1-1.0144-1.0144 1.0142 1.0142 0 0 1 1.0144-1.0144zm-1.4834 3.2988v0.60938h0.26562v-0.60938zm-0.68944 0.4978a0.1325 0.1325 0 0 0-0.13281 0.13281 0.1325 0.1325 0 0 0 0.13281 0.13086h1.707a0.1325 0.1325 0 0 0 0.13281-0.13086 0.1325 0.1325 0 0 0-0.13281-0.13281zm-0.66576-3.6286c-0.098598 0-0.17777 0.079169-0.17777 0.17777v2.8448c0 0.098598 0.079169 0.17828 0.17777 0.17828h3.0949c0.098598 0 0.17777-0.079685 0.17777-0.17828v-0.86868h-0.22996v0.67903c0 0.085436-0.069077 0.154-0.15451 0.154h-2.6815c-0.085436 0-0.154-0.06856-0.154-0.154v-2.465c0-0.085436 0.06856-0.15451 0.154-0.15451h1.3715v-0.21342zm2.8309-0.33796c-0.65642-1.4612e-8 -1.1885 0.53212-1.1885 1.1885 1.188e-4 0.24219 0.074223 0.47857 0.21239 0.67746 0.00764 0.018057 0.019516 0.034009 0.034623 0.046508 0.22473 0.2926 0.5726 0.46423 0.94153 0.46458 0.20986-6e-5 0.41597-0.055689 0.59737-0.16123 0.00235 0.00547 0.0053 0.010668 0.00878 0.015503l0.45114 0.62115c0.026992 0.036636 0.078554 0.044497 0.11524 0.017571 0.036636-0.026992 0.044497-0.078554 0.017571-0.11524l-0.45114-0.61906c-0.00249-0.00348-0.00526-0.00677-0.00827-0.00982 0.28892-0.22521 0.45786-0.57107 0.45786-0.93741 0-0.65642-0.53212-1.1885-1.1885-1.1885zm0 0.16795c0.56366 1e-8 1.0206 0.45693 1.0206 1.0206 0 0.56366-0.45693 1.0206-1.0206 1.0206-0.28641-4.41e-5 -0.55961-0.12043-0.75292-0.33176l0.57567-0.75344c0.041476-0.053839 0.031025-0.13118-0.023254-0.17208-0.053488-0.040071-0.12925-0.029707-0.17001 0.023254l-0.53072 0.69193c-0.07831-0.14735-0.1193-0.31165-0.11937-0.47852 0-0.56366 0.45693-1.0206 1.0206-1.0206zm-2.8707 0.17001c-0.078728 0-0.14211 0.060602-0.14211 0.13539v2.9337c0 0.074799 0.06338 0.13487 0.14211 0.13487h1.4454v0.52347h-0.75807c-0.044899 4.497e-4 -0.081186 0.036747-0.081647 0.081647 1.8045e-4 0.045103 0.036546 0.0817 0.081647 0.082165h1.7446c0.0451-4.762e-4 0.081467-0.037062 0.081647-0.082165-4.498e-4 -0.044899-0.036748-0.081186-0.081647-0.081647h-0.82268v-0.52347h1.5689c0.078728 0 0.14211-0.060094 0.14211-0.13487l-0.0077522-0.91518-0.15141 0.018086v0.76223c0 0.067899-0.0577 0.12247-0.12919 0.12247h-2.8855c-0.07149 0-0.12919-0.054503-0.12919-0.12247v-0.7028c8.7629e-4 -6.694e-4 0.001738-0.00136 0.002584-0.00207l0.9591-1.1131 0.5059 1.0583c0.024655 0.053403 0.098384 0.05894 0.13074 0.00982l0.27233-0.3948c-0.035803-0.037507-0.069447-0.077016-0.10077-0.11834l-0.2222 0.32194-0.50021-1.0449c-0.022933-0.049186-0.088894-0.058491-0.12454-0.01757l-0.92293 1.0723v-1.7327c0-0.067899 0.0577-0.12299 0.12919-0.12299h1.4684l0.00332-0.14728z"
+ style="-inkscape-stroke:none" />
+</svg>
\ No newline at end of file
diff --git a/packages/filebrowser/src/browser.ts b/packages/filebrowser/src/browser.ts
index d7fde430e2..fbe49b2562 100644
--- a/packages/filebrowser/src/browser.ts
+++ b/packages/filebrowser/src/browser.ts
@@ -106,10 +106,15 @@ export class FileBrowser extends Widget {
this._filenameSearcher.addClass(FILTERBOX_CLASS);
this.listing.addClass(LISTING_CLASS);
+ const header = new Widget();
+ header.node.textContent = '编程列表';
+ header.addClass('jp-FileBrowser-header');
+
this.layout = new PanelLayout();
- this.layout.addWidget(this.toolbar);
- this.layout.addWidget(this._filenameSearcher);
- this.layout.addWidget(this.crumbs);
+ this.layout.addWidget(header);
+ // this.layout.addWidget(this.toolbar);
+ // this.layout.addWidget(this._filenameSearcher);
+ // this.layout.addWidget(this.crumbs);
this.layout.addWidget(this.listing);
if (options.restore !== false) {
@@ -180,12 +185,12 @@ export class FileBrowser extends Widget {
});
this._filenameSearcher.addClass(FILTERBOX_CLASS);
- this.layout.removeWidget(this._filenameSearcher);
- this.layout.removeWidget(this.crumbs);
+ // this.layout.removeWidget(this._filenameSearcher);
+ // this.layout.removeWidget(this.crumbs);
this.layout.removeWidget(this.listing);
- this.layout.addWidget(this._filenameSearcher);
- this.layout.addWidget(this.crumbs);
+ // this.layout.addWidget(this._filenameSearcher);
+ // this.layout.addWidget(this.crumbs);
this.layout.addWidget(this.listing);
}
diff --git a/packages/filebrowser/src/crumbs.ts b/packages/filebrowser/src/crumbs.ts
index b67e132a31..cd098f37fb 100644
--- a/packages/filebrowser/src/crumbs.ts
+++ b/packages/filebrowser/src/crumbs.ts
@@ -73,8 +73,9 @@ export class BreadCrumbs extends Widget {
this.addClass(BREADCRUMB_CLASS);
this._crumbs = Private.createCrumbs();
this._crumbSeps = Private.createCrumbSeparators();
- const hasPreferred = PageConfig.getOption('preferredPath');
- this._hasPreferred = hasPreferred && hasPreferred !== '/' ? true : false;
+ // const hasPreferred = PageConfig.getOption('preferredPath');
+ // this._hasPreferred = hasPreferred && hasPreferred !== '/' ? true : false;
+ this._hasPreferred = false;
if (this._hasPreferred) {
this.node.appendChild(this._crumbs[Private.Crumb.Preferred]);
}
diff --git a/packages/filebrowser/src/directoryswitcher.ts b/packages/filebrowser/src/directoryswitcher.ts
new file mode 100644
index 0000000000..2a96059486
--- /dev/null
+++ b/packages/filebrowser/src/directoryswitcher.ts
@@ -0,0 +1,19 @@
+import { Widget } from '@lumino/widgets';
+
+export default class DirectorySwitcher extends Widget {
+ constructor(options: Widget.IOptions) {
+ super(options);
+ this._createButtons();
+ }
+
+ private _createButtons() {
+ const btn1 = document.createElement('button');
+ btn1.textContent = '开发目录';
+ btn1.classList.add('jldbq-btn', 'jldbq-btn-current');
+ this.node.appendChild(btn1);
+ const btn2 = document.createElement('button');
+ btn2.textContent = '通用算子库';
+ btn2.classList.add('jldbq-btn');
+ this.node.appendChild(btn2);
+ }
+}
diff --git a/packages/filebrowser/style/base.css b/packages/filebrowser/style/base.css
index 940da54f23..1973c3f35a 100644
--- a/packages/filebrowser/style/base.css
+++ b/packages/filebrowser/style/base.css
@@ -36,6 +36,13 @@
justify-content: flex-start;
}
+.jp-FileBrowser-header {
+ margin: 5px;
+ padding: 15px;
+ font-weight: bold;
+ border-bottom: 1px solid #dbe3ea;
+}
+
.jp-BreadCrumbs {
flex: 0 0 auto;
margin: 8px 12px 8px 12px;
@@ -127,13 +134,9 @@
outline: 0;
}
-.jp-DirListing:focus-visible {
- border: 1px solid var(--jp-brand-color1);
-}
-
.jp-DirListing-header {
flex: 0 0 auto;
- display: flex;
+ display: none;
flex-direction: row;
overflow: hidden;
border-top: var(--jp-border-width) solid var(--jp-border-color2);
@@ -190,7 +193,6 @@
padding: 0;
list-style-type: none;
overflow: auto;
- background-color: var(--jp-layout-color1);
}
.jp-DirListing-content mark {
@@ -251,6 +253,7 @@
}
.jp-DirListing-itemModified {
+ display: none;
flex: 0 0 125px;
text-align: right;
}
diff --git a/packages/jldbq-extenison/package.json b/packages/jldbq-extenison/package.json
new file mode 100644
index 0000000000..02e5c0f464
--- /dev/null
+++ b/packages/jldbq-extenison/package.json
@@ -0,0 +1,61 @@
+{
+ "name": "@jupyterlab/jldbq-extension",
+ "version": "1.0.0",
+ "description": "JLDBQ Extension",
+ "homepage": "",
+ "license": "MIT",
+ "author": "yili",
+ "sideEffects": [
+ "style/**/*.css",
+ "style/index.js"
+ ],
+ "main": "lib/index.js",
+ "types": "lib/index.d.ts",
+ "style": "style/index.css",
+ "directories": {
+ "lib": "lib/"
+ },
+ "files": [
+ "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
+ "style/**/*.{css,js,eot,gif,html,jpg,json,png,svg,woff2,ttf}",
+ "schema/*.json"
+ ],
+ "scripts": {
+ "build": "tsc -b",
+ "clean": "rimraf lib && rimraf tsconfig.tsbuildinfo",
+ "docs": "typedoc src",
+ "watch": "tsc -b --watch"
+ },
+ "dependencies": {
+ "@emotion/react": "^11.9.0",
+ "@emotion/styled": "^11.8.1",
+ "@jupyterlab/application": "^3.4.3",
+ "@jupyterlab/apputils": "^3.4.3",
+ "@jupyterlab/settingregistry": "^3.4.3",
+ "@jupyterlab/ui-components": "^3.4.3",
+ "@lumino/signaling": "^1.10.0",
+ "@lumino/widgets": "^1.30.0",
+ "@mui/icons-material": "^5.8.0",
+ "@mui/lab": "^5.0.0-alpha.83",
+ "@mui/material": "^5.8.1",
+ "@silevis/reactgrid": "^4.0.3",
+ "antd": "^4.22.3",
+ "moment": "^2.29.4",
+ "react": "^17.0.1",
+ "react-select": "^5.4.0",
+ "swr": "^1.3.0"
+ },
+ "devDependencies": {
+ "rimraf": "~3.0.0",
+ "typedoc": "~0.21.2",
+ "typescript": "~4.1.3"
+ },
+ "publishConfig": {
+ "access": "public"
+ },
+ "jupyterlab": {
+ "extension": true,
+ "schemaDir": "schema"
+ },
+ "styleModule": "style/index.js"
+}
diff --git a/packages/jldbq-extenison/schema/plugin.json b/packages/jldbq-extenison/schema/plugin.json
new file mode 100644
index 0000000000..8a5b32c902
--- /dev/null
+++ b/packages/jldbq-extenison/schema/plugin.json
@@ -0,0 +1,14 @@
+{
+ "title": "JLDBQ",
+ "description": "JLDBQ settings.",
+ "type": "object",
+ "properties": {
+ "flaskBackend": {
+ "title": "Flask Backend address.",
+ "description": "Flask Backend address.",
+ "type": "string",
+ "default": "http://127.0.0.1:5000"
+ }
+ },
+ "additionalProperties": false
+}
diff --git a/packages/jldbq-extenison/src/DataTable.tsx b/packages/jldbq-extenison/src/DataTable.tsx
new file mode 100644
index 0000000000..2f797b7356
--- /dev/null
+++ b/packages/jldbq-extenison/src/DataTable.tsx
@@ -0,0 +1,77 @@
+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;
+}
+
+const getText = (value: any): string => {
+ if (value === null || value === undefined) {
+ return '';
+ } else if (typeof value === 'object') {
+ return JSON.stringify(value);
+ } else {
+ return value.toString();
+ }
+};
+
+const DataTable = ({ data }: IProps): JSX.Element => {
+ const [cols, setCols] = useState<Column[]>(() =>
+ Object.keys(data).map(columnId => {
+ return { columnId, width: 100, resizable: true };
+ })
+ );
+
+ const rows = useMemo((): Row<Cell>[] => {
+ const colNames = Object.keys(data);
+ const header = {
+ rowId: 'header',
+ cells: colNames.map(text => {
+ return {
+ text,
+ type: 'header'
+ };
+ })
+ };
+ const dataRows = Object.keys(data[colNames[0]]).map(rowId => {
+ return {
+ rowId,
+ cells: colNames.map(c => {
+ return {
+ type: 'text',
+ text: getText(data[c][rowId]),
+ nonEditable: true
+ };
+ })
+ };
+ });
+ return [header, ...dataRows];
+ }, [data]);
+
+ const handleColumnResize = (ci: Id, width: number) => {
+ setCols(prevColumns => {
+ const columnIndex = prevColumns.findIndex(el => el.columnId === ci);
+ const resizedColumn = prevColumns[columnIndex];
+ const updatedColumn = { ...resizedColumn, width };
+ prevColumns[columnIndex] = updatedColumn;
+ return [...prevColumns];
+ });
+ };
+
+ return (
+ <div style={{ width: '100%', height: '100%', overflow: 'scroll' }}>
+ <ReactGrid
+ enableRangeSelection
+ stickyTopRows={1}
+ rows={rows}
+ columns={cols}
+ onColumnResized={handleColumnResize}
+ />
+ </div>
+ );
+};
+
+export default DataTable;
diff --git a/packages/jldbq-extenison/src/DataTableWidget.tsx b/packages/jldbq-extenison/src/DataTableWidget.tsx
new file mode 100644
index 0000000000..ff8ed85207
--- /dev/null
+++ b/packages/jldbq-extenison/src/DataTableWidget.tsx
@@ -0,0 +1,41 @@
+import React from 'react';
+import { ReactWidget } from '@jupyterlab/apputils';
+import { Widget } from '@lumino/widgets';
+import DataTable from './DataTable';
+import { fetchTableContent, IDatasource, ITableData } from './api/datasource';
+
+class DataTableWidget extends ReactWidget {
+ constructor(
+ datasource: IDatasource,
+ tableName: string,
+ options?: Widget.IOptions
+ ) {
+ super(options);
+ void this._requestData(datasource, tableName);
+ }
+
+ private _requestData = async (datasource: IDatasource, tableName: string) => {
+ const res = await fetchTableContent(datasource, tableName);
+ if (res === 'error') {
+ this._err = res;
+ } else {
+ this._data = res;
+ }
+ this.update();
+ };
+
+ render(): JSX.Element {
+ if (this._err) {
+ return <div>Error</div>;
+ } else if (!this._data) {
+ return <div>Loading ...</div>;
+ } else {
+ return <DataTable data={this._data} />;
+ }
+ }
+
+ private _data: ITableData | null = null;
+ private _err: any;
+}
+
+export default DataTableWidget;
diff --git a/packages/jldbq-extenison/src/DataView.tsx b/packages/jldbq-extenison/src/DataView.tsx
new file mode 100644
index 0000000000..b2af5d4cf8
--- /dev/null
+++ b/packages/jldbq-extenison/src/DataView.tsx
@@ -0,0 +1,73 @@
+import React from 'react';
+import { useState } from 'react';
+
+interface IProps {
+ dataSourceElement: JSX.Element;
+ dataSyncElement: JSX.Element;
+}
+
+type ViewType = 'datasource' | 'datasync';
+
+const SwitchButton: React.FunctionComponent<{
+ viewType: ViewType;
+ current: ViewType;
+ label: string;
+ onClick: (t: ViewType) => void;
+}> = props => {
+ return (
+ <button
+ type="button"
+ className={
+ 'jldbq-btn ' +
+ (props.viewType === props.current ? 'jldbq-btn-current' : '')
+ }
+ onClick={() => props.onClick(props.viewType)}
+ >
+ {props.label}
+ </button>
+ );
+};
+
+const DataView: React.FunctionComponent<IProps> = props => {
+ const [view, setView] = useState('datasource' as ViewType);
+
+ const el =
+ view === 'datasource' ? props.dataSourceElement : props.dataSyncElement;
+
+ return (
+ <div
+ style={{
+ height: '100%',
+ display: 'flex',
+ flexDirection: 'column',
+ padding: '5px'
+ }}
+ >
+ <div
+ style={{
+ padding: '5px 5px 10px',
+ borderBottom: '1px solid #DBE3EA',
+ display: 'flex',
+ justifyContent: 'space-around',
+ alignItems: 'center'
+ }}
+ >
+ <SwitchButton
+ viewType="datasource"
+ current={view}
+ label="数据源管理"
+ onClick={setView}
+ />
+ <SwitchButton
+ viewType="datasync"
+ current={view}
+ label="同步配置"
+ onClick={setView}
+ />
+ </div>
+ {el}
+ </div>
+ );
+};
+
+export default DataView;
diff --git a/packages/jldbq-extenison/src/DataViewWidget.tsx b/packages/jldbq-extenison/src/DataViewWidget.tsx
new file mode 100644
index 0000000000..0ab84b92f9
--- /dev/null
+++ b/packages/jldbq-extenison/src/DataViewWidget.tsx
@@ -0,0 +1,57 @@
+import React from 'react';
+import { ReactWidget } from '@jupyterlab/apputils';
+import { ISignal, Signal } from '@lumino/signaling';
+import DatasourceView from './DatasourceView';
+import DatasyncView from './DatasyncView';
+import DataView from './DataView';
+import { IDatasource } from './api/datasource';
+import { Widget } from '@lumino/widgets';
+
+interface ITableOpenSignalData {
+ datasource: IDatasource;
+ tableName: string;
+}
+
+class DataViewWidget extends ReactWidget {
+ constructor(manager: string, options?: Widget.IOptions) {
+ super(options);
+ this._manager = manager;
+ }
+
+ public get tableOpened(): ISignal<DataViewWidget, ITableOpenSignalData> {
+ return this._tableOpened;
+ }
+
+ render(): JSX.Element {
+ const datasourceView = (
+ <DatasourceView
+ manager={this._manager}
+ onOpenTable={(datasource, tableName) =>
+ this._tableOpened.emit({ datasource, tableName })
+ }
+ />
+ );
+
+ const datasyncView = <DatasyncView />;
+
+ return (
+ <div
+ style={{
+ height: '100%',
+ display: 'flex',
+ flexDirection: 'column'
+ }}
+ >
+ <DataView
+ dataSourceElement={datasourceView}
+ dataSyncElement={datasyncView}
+ />
+ </div>
+ );
+ }
+
+ private _manager: string;
+ private _tableOpened = new Signal<DataViewWidget, ITableOpenSignalData>(this);
+}
+
+export default DataViewWidget;
diff --git a/packages/jldbq-extenison/src/DatasourceForm.tsx b/packages/jldbq-extenison/src/DatasourceForm.tsx
new file mode 100644
index 0000000000..e4a470440d
--- /dev/null
+++ b/packages/jldbq-extenison/src/DatasourceForm.tsx
@@ -0,0 +1,185 @@
+import React from 'react';
+import { Dialog, ReactWidget } from '@jupyterlab/apputils';
+import { IDatasource } from './api/datasource';
+import { Widget } from '@lumino/widgets';
+
+interface IDatasourceItem {
+ address: string;
+ username: string;
+ password: string;
+ databasename: string;
+ type: 'mysql' | 'hive';
+}
+
+interface IProps {
+ value: Partial<IDatasourceItem>;
+ error: keyof IDatasourceItem | null;
+ onChange: (v: Partial<IDatasourceItem>) => void;
+}
+
+const DatasourceForm: React.FunctionComponent<IProps> = ({
+ value,
+ error,
+ onChange
+}) => {
+ return (
+ <form className="jldbq-form">
+ <label className={error === 'type' ? 'jldbq-form-error' : ''}>
+ <span className="jldbq-form-label">数据源类型:</span>
+ <div className="jldbq-form-switcher">
+ <button
+ type="button"
+ className={
+ 'jldbq-btn ' + (value.type === 'mysql' ? 'jldbq-btn-current' : '')
+ }
+ onClick={() => onChange({ type: 'mysql' })}
+ >
+ MySQL
+ </button>
+ <button
+ type="button"
+ className={
+ 'jldbq-btn ' + (value.type === 'hive' ? 'jldbq-btn-current' : '')
+ }
+ onClick={() => onChange({ type: 'hive' })}
+ >
+ Hive
+ </button>
+ </div>
+ </label>
+ <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 })}
+ />
+ </label>
+ <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 })}
+ />
+ </label>
+ <label className={error === 'password' ? 'jldbq-form-error' : ''}>
+ <span className="jldbq-form-label">密码:</span>
+ <input
+ className="jldbq-form-input"
+ type="password"
+ placeholder="请输入密码"
+ value={value.password || ''}
+ onChange={evt => onChange({ password: evt.target.value })}
+ />
+ </label>
+ <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 })}
+ />
+ </label>
+ </form>
+ );
+};
+
+export class DatasourceFormDialogBody
+ extends ReactWidget
+ implements Dialog.IBodyWidget<IDatasource> {
+ constructor(manager: string, options?: Widget.IOptions) {
+ super(options);
+ this._manager = manager;
+ }
+ render(): JSX.Element {
+ return (
+ <DatasourceForm
+ value={this._datasourceItem}
+ error={this._error}
+ onChange={v => {
+ this._datasourceItem = { ...this._datasourceItem, ...v };
+ this._error = null;
+ this.update();
+ }}
+ />
+ );
+ }
+
+ getValue(): IDatasource {
+ const {
+ address,
+ username: user,
+ password,
+ databasename,
+ type: source
+ } = this._datasourceItem;
+ if (!source) {
+ this._setError('type');
+ }
+ if (!address || !validateIpAndPort(address)) {
+ this._setError('address');
+ }
+ const [host, portStr] = address.split(':');
+ const port = portStr ? +portStr : 3306;
+ if (!user) {
+ this._setError('username');
+ }
+ if (!password) {
+ this._setError('password');
+ }
+ if (!databasename) {
+ this._setError('databasename');
+ }
+ return {
+ host,
+ user,
+ port,
+ password,
+ charset: 'utf8',
+ source,
+ databasename,
+ sourcename: databasename,
+ manager: this._manager
+ };
+ }
+
+ private _setError(error: keyof IDatasourceItem): never {
+ this._error = error;
+ this.update();
+ throw new Error(error);
+ }
+
+ private _datasourceItem: Partial<IDatasourceItem> = {};
+ private _error: IProps['error'] = null;
+ private _manager: string;
+}
+
+function validateIpAndPort(input: string): boolean {
+ const parts = input.split(':');
+ if (parts.length > 2) {
+ return false;
+ }
+ const ip = parts[0].split('.');
+ if (
+ ip.length !== 4 ||
+ !ip.every(function (segment) {
+ return validateNum(segment, 0, 255);
+ })
+ ) {
+ return false;
+ }
+ const port = parts[1];
+ if (port && !validateNum(port, 1, 65535)) {
+ return false;
+ }
+ return true;
+}
+
+function validateNum(input: string, min: number, max: number): boolean {
+ const num = +input;
+ return num >= min && num <= max && input === num.toString();
+}
diff --git a/packages/jldbq-extenison/src/DatasourceView.tsx b/packages/jldbq-extenison/src/DatasourceView.tsx
new file mode 100644
index 0000000000..f7e97e0702
--- /dev/null
+++ b/packages/jldbq-extenison/src/DatasourceView.tsx
@@ -0,0 +1,182 @@
+import React from 'react';
+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 './DatasourceForm';
+
+const dragImg = new Image();
+dragImg.src = 'data:image/svg+xml;base64,' + btoa(databaseSvgStr);
+
+interface IProps {
+ manager: string;
+ onOpenTable: (datasource: IDatasource, tableName: string) => void;
+}
+
+const DatasourceView: React.FunctionComponent<IProps> = ({
+ manager,
+ onOpenTable
+}) => {
+ const { datasources, loading, error, refresh } = useDatasourceList(manager);
+ const [tables, setTables] = useState<
+ Partial<{
+ [key: string]: string[] | 'error';
+ }>
+ >({});
+
+ const handleNodeToggle = async (ds: IDatasource) => {
+ if (!tables[ds.sourcename]) {
+ const tables = await fetchTables(ds);
+ setTables(prev => {
+ return { [ds.sourcename]: tables, ...prev };
+ });
+ }
+ };
+
+ let tree: JSX.Element[] | JSX.Element;
+ if (error) {
+ tree = <div style={{ padding: '0px 12px' }}>Error</div>;
+ } else if (loading) {
+ tree = <div style={{ padding: '0px 12px' }}>Loading ...</div>;
+ } else {
+ tree = datasources!.map(ds => {
+ const table = tables[ds.sourcename];
+ let tableItems;
+ if (!table) {
+ tableItems = (
+ <TreeItem nodeId={`${ds.sourcename}-loading`} label="Loading ..." />
+ );
+ } else if (table === 'error') {
+ tableItems = (
+ <TreeItem nodeId={`${ds.sourcename}-error`} label="Error" />
+ );
+ } else if (table.length === 0) {
+ tableItems = (
+ <TreeItem nodeId={`${ds.sourcename}-error`} label="Empty" />
+ );
+ } else {
+ tableItems = table.map(t => {
+ return (
+ <TreeItem
+ title={t}
+ key={`${ds.sourcename}-${t}`}
+ nodeId={`${ds.sourcename}-${t}`}
+ label={t}
+ onDoubleClick={() => onOpenTable(ds, t)}
+ draggable="true"
+ onDragStart={evt => {
+ const data = {
+ operation: 'addToCanvas',
+ data: {
+ editType: 'createNode',
+ finalized: true,
+ nodeTemplate: {
+ id: `${ds.manager}-${ds.sourcename}-${t}`,
+ op: `database-${ds.source}-input`,
+ description: t,
+ type: 'execution_node',
+ label: t,
+ inputs: [],
+ parameters: {},
+ outputs: [
+ {
+ id: 'outPort',
+ app_data: {
+ ui_data: {
+ cardinality: {
+ min: 0,
+ max: -1
+ },
+ label: 'Output Port'
+ }
+ }
+ }
+ ],
+ app_data: {
+ ui_data: {
+ description: t,
+ image: '',
+ label: t
+ }
+ }
+ }
+ }
+ };
+ evt.dataTransfer.setData('text/plain', JSON.stringify(data));
+ evt.dataTransfer.setDragImage(dragImg, 10, 10);
+ }}
+ onFocusCapture={e => e.stopPropagation()}
+ />
+ );
+ });
+ }
+ return (
+ <TreeItem
+ key={ds.sourcename}
+ nodeId={ds.sourcename}
+ label={ds.databasename}
+ onClick={() => handleNodeToggle(ds)}
+ >
+ {tableItems}
+ </TreeItem>
+ );
+ });
+ }
+
+ const handleAddDatasource = async () => {
+ const { value } = await showDialog({
+ title: '添加数据源',
+ body: new DatasourceFormDialogBody(manager),
+ hasClose: true,
+ 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={handleAddDatasource}>
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ width="20"
+ height="20"
+ fill="currentColor"
+ viewBox="0 0 16 16"
+ >
+ <path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z" />
+ </svg>
+ 添加数据源
+ </button>
+ </div>
+ <TreeView
+ aria-label="file system navigator"
+ defaultCollapseIcon={<ExpandMoreIcon />}
+ defaultExpandIcon={<ChevronRightIcon />}
+ sx={{ overflow: 'auto', flexGrow: 1 }}
+ >
+ {tree}
+ </TreeView>
+ </div>
+ );
+};
+
+export default DatasourceView;
diff --git a/packages/jldbq-extenison/src/DatasyncForm.tsx b/packages/jldbq-extenison/src/DatasyncForm.tsx
new file mode 100644
index 0000000000..d638ff736e
--- /dev/null
+++ b/packages/jldbq-extenison/src/DatasyncForm.tsx
@@ -0,0 +1,322 @@
+import React, { useState } from 'react';
+import {
+ Button,
+ DatePicker,
+ Form,
+ InputNumber,
+ Radio,
+ RadioChangeEvent,
+ Select,
+ Space
+} from 'antd';
+import { IDatasource } from './api/datasource';
+import arrowImgUrl from '../style/img/arrow.png';
+import deleteImgUrl from '../style/img/delete.png';
+
+type FreqUnit = 'day' | 'week' | 'month';
+
+interface ISyncMeta {
+ startTime: Date;
+ frequency: number;
+ freqUnit: FreqUnit;
+}
+
+interface ISyncMapping {
+ srcDatasource: IDatasource;
+ srcTableName: string;
+ dstDatasource: IDatasource;
+ dstTableName: string;
+}
+
+export interface ISyncData {
+ mapping: ISyncMapping;
+ meta: ISyncMeta;
+}
+
+interface IProps {
+ datasourceList: IDatasource[];
+ tableListFetcher: (ds: IDatasource) => Promise<string[]>;
+ onConfirm: (data: ISyncData[]) => void;
+ onCancel: () => void;
+}
+
+const DatasyncForm: React.FunctionComponent<IProps> = props => {
+ const [srcDatasource, setSrcDatasource] = useState<IDatasource | null>(null);
+ const [srcTableName, setSrcTableName] = useState<string | null>(null);
+ const [srcTableList, setSrcTableList] = useState<string[]>([]);
+ const [dstDatasource, setDstDatasource] = useState<IDatasource | null>(null);
+ const [dstTableName, setDstTableName] = useState<string | null>(null);
+ const [dstTableList, setDstTableList] = useState<string[]>([]);
+ const [mappingList, setMappingList] = useState<ISyncMapping[]>([]);
+ const [form] = Form.useForm();
+
+ const onFinish = (meta: any) => {
+ // startTime = moment(startTime).toDate();
+ const results = mappingList.map(mapping => {
+ return {
+ mapping,
+ meta: {
+ startTime: meta.startTime.toDate(),
+ frequency: Math.max(parseInt(meta.frequency), 0),
+ freqUnit: meta.freqUnit as FreqUnit
+ }
+ };
+ });
+ props.onConfirm(results);
+ };
+
+ const sourceDatasourceChange = (sourcename: string) => {
+ const ds = props.datasourceList.find(
+ item => item.sourcename === sourcename
+ )!;
+ setSrcDatasource(ds);
+ setSrcTableName(null);
+ setSrcTableList([]);
+ void props.tableListFetcher(ds).then(lst => {
+ setSrcTableList(lst);
+ });
+ };
+
+ const destDatasourceChange = (sourcename: string) => {
+ const ds = props.datasourceList.find(
+ item => item.sourcename === sourcename
+ )!;
+ setDstDatasource(ds);
+ setDstTableName(null);
+ setDstTableList([]);
+ void props.tableListFetcher(ds).then(lst => {
+ setDstTableList(lst);
+ });
+ };
+
+ const sourceTableChange = (e: RadioChangeEvent) => {
+ setSrcTableName(e.target.value as string);
+ };
+
+ const destTableChange = (e: RadioChangeEvent) => {
+ setDstTableName(e.target.value as string);
+ };
+
+ const addMapping = () => {
+ if (!srcDatasource || !srcTableName || !dstDatasource || !dstTableName) {
+ return;
+ }
+ if (
+ mappingList.find(
+ item =>
+ item.srcDatasource.sourcename === srcDatasource.sourcename &&
+ item.srcTableName === srcTableName &&
+ item.dstDatasource.sourcename === dstDatasource.sourcename &&
+ item.dstTableName === dstTableName
+ )
+ ) {
+ return;
+ }
+ setMappingList([
+ ...mappingList,
+ {
+ srcDatasource,
+ srcTableName,
+ dstDatasource,
+ dstTableName
+ }
+ ]);
+ };
+
+ const deleteMapping = (mapping: ISyncMapping) => {
+ setMappingList(mappingList.filter(item => item !== mapping));
+ };
+
+ const freqUnitSelector = (
+ <Form.Item
+ name="freqUnit"
+ rules={[{ required: true, message: '请输入同步频次单位' }]}
+ noStyle
+ >
+ <Select style={{ width: 100 }}>
+ <Select.Option value="day">天</Select.Option>
+ <Select.Option value="week">周</Select.Option>
+ <Select.Option value="month">月</Select.Option>
+ </Select>
+ </Form.Item>
+ );
+
+ return (
+ <div>
+ <Form
+ form={form}
+ name="datasyncForm"
+ onFinish={onFinish}
+ style={{ width: '800px' }}
+ >
+ <div style={{ display: 'flex' }}>
+ <Form.Item style={{ width: '25%' }}>
+ <Form.Item
+ name="srcDatasource"
+ noStyle
+ // rules={[{ required: true, message: '请选择数据源' }]}
+ >
+ <Select
+ placeholder="选择数据源"
+ onChange={sourceDatasourceChange}
+ >
+ {props.datasourceList.map(item => {
+ return (
+ <Select.Option
+ value={item.sourcename}
+ key={item.sourcename}
+ >
+ {item.databasename}
+ </Select.Option>
+ );
+ })}
+ </Select>
+ </Form.Item>
+
+ <Form.Item
+ name="srcTableName"
+ // rules={[{ required: true, message: '请选择源数据表' }]}
+ noStyle
+ >
+ <div className="plane">
+ <Radio.Group value={srcTableName} onChange={sourceTableChange}>
+ <Space direction="vertical">
+ {srcTableList.map(item => {
+ return (
+ <Radio value={item} key={item}>
+ {item}
+ </Radio>
+ );
+ })}
+ </Space>
+ </Radio.Group>
+ </div>
+ </Form.Item>
+ </Form.Item>
+ <div className="arrow">
+ <img
+ src={arrowImgUrl}
+ alt=""
+ onClick={addMapping}
+ style={{ width: '20px', height: '20px', cursor: 'pointer' }}
+ />
+ </div>
+ <Form.Item style={{ width: '25%' }}>
+ <Form.Item
+ name="dstDatasource"
+ // rules={[{ required: true, message: '请选择同步目标' }]}
+ noStyle
+ >
+ <Select
+ placeholder="选择同步目标"
+ onChange={destDatasourceChange}
+ >
+ {props.datasourceList.map(item => {
+ return (
+ <Select.Option
+ value={item.sourcename}
+ key={item.sourcename}
+ >
+ {item.databasename}
+ </Select.Option>
+ );
+ })}
+ </Select>
+ </Form.Item>
+ <Form.Item
+ name="dstTableName"
+ // rules={[{ required: true, message: '请选择目标数据表' }]}
+ noStyle
+ >
+ <div className="plane">
+ <Radio.Group value={dstTableName} onChange={destTableChange}>
+ <Space direction="vertical">
+ {dstTableList.map(item => {
+ return (
+ <Radio value={item} key={item}>
+ {item}
+ </Radio>
+ );
+ })}
+ </Space>
+ </Radio.Group>
+ </div>
+ </Form.Item>
+ </Form.Item>
+ <div className="line"></div>
+ <div className="mappings">
+ <p className="mappings__title">同步映射</p>
+ <div className="mappings__content">
+ {mappingList.map(item => {
+ const key = `${item.dstDatasource.sourcename}-${item.dstTableName}-${item.srcDatasource.sourcename}-${item.srcTableName}`;
+ return (
+ <p key={key}>
+ <span>{item.srcTableName}</span>
+ <img
+ src={arrowImgUrl}
+ alt=""
+ style={{
+ width: '10px',
+ height: '10px',
+ margin: '0 50px'
+ }}
+ />
+ <span>{item.dstTableName}</span>
+ <img
+ src={deleteImgUrl}
+ alt=""
+ onClick={() => {
+ deleteMapping(item);
+ }}
+ style={{
+ width: '10px',
+ height: '10px',
+ marginLeft: '30px',
+ cursor: 'pointer'
+ }}
+ />
+ </p>
+ );
+ })}
+ </div>
+ </div>
+ </div>
+ <Form.Item
+ label="开始时间"
+ name="startTime"
+ rules={[{ required: true, message: '请选择开始时间' }]}
+ >
+ <DatePicker placeholder="请选择日期" style={{ width: '50%' }} />
+ </Form.Item>
+ <Form.Item label="同步频次" required>
+ <span style={{ lineHeight: '32px' }}>每</span>
+ <Form.Item
+ name="frequency"
+ rules={[{ required: true, message: '请输入同步频次' }]}
+ noStyle
+ >
+ <InputNumber
+ addonAfter={freqUnitSelector}
+ style={{ width: '47%', margin: '0 1%' }}
+ />
+ </Form.Item>
+ <span style={{ lineHeight: '32px' }}>/次</span>
+ </Form.Item>
+ <Form.Item style={{ display: 'flex', justifyContent: 'center' }}>
+ <Button
+ type="primary"
+ htmlType="submit"
+ style={{ marginRight: '40px' }}
+ >
+ 确定
+ </Button>
+ <Button htmlType="button" onClick={props.onCancel}>
+ 取消
+ </Button>
+ </Form.Item>
+ </Form>
+ </div>
+ );
+};
+
+export default DatasyncForm;
diff --git a/packages/jldbq-extenison/src/DatasyncView.tsx b/packages/jldbq-extenison/src/DatasyncView.tsx
new file mode 100644
index 0000000000..910eef1ed6
--- /dev/null
+++ b/packages/jldbq-extenison/src/DatasyncView.tsx
@@ -0,0 +1,99 @@
+import React from 'react';
+import { Dialog, ReactWidget } from '@jupyterlab/apputils';
+import { Widget } from '@lumino/widgets';
+import { Signal } from '@lumino/signaling';
+import DatasyncForm, { ISyncData } from './DatasyncForm';
+
+interface IProps {}
+
+const DatasyncView: React.FunctionComponent<IProps> = props => {
+ 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 () => {
+ const body = new DatasyncFormDialogBody();
+ const dialog = new Dialog({
+ title: '添加同步任务',
+ body,
+ renderer: new DatasyncFormDialogRenderer()
+ });
+ body.confirm.connect((_sender, data) => {
+ console.log(data);
+ dialog.reject();
+ });
+ body.cancel.connect(() => {
+ dialog.reject();
+ });
+ await dialog.launch();
+ }}
+ >
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ width="20"
+ height="20"
+ fill="currentColor"
+ viewBox="0 0 16 16"
+ >
+ <path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z" />
+ </svg>
+ 添加同步任务
+ </button>
+ </div>
+ </div>
+ );
+};
+
+export default DatasyncView;
+
+class DatasyncFormDialogBody extends ReactWidget {
+ constructor(options?: Widget.IOptions) {
+ super(options);
+ }
+
+ render(): JSX.Element {
+ Signal;
+ return (
+ <DatasyncForm
+ datasourceList={[
+ {
+ host: '1.1.1.1',
+ user: 'user',
+ port: 3306,
+ password: '',
+ charset: 'utf8',
+ manager: 'manager',
+ source: 'mysql',
+ databasename: 'default',
+ sourcename: 'default'
+ }
+ ]}
+ tableListFetcher={async () => {
+ return ['1', '2', '3'];
+ }}
+ onConfirm={v => this._confirm.emit(v)}
+ onCancel={() => this._cancel.emit()}
+ />
+ );
+ }
+
+ get confirm() {
+ return this._confirm;
+ }
+
+ get cancel() {
+ return this._cancel;
+ }
+
+ private _confirm = new Signal<DatasyncFormDialogBody, ISyncData[]>(this);
+ private _cancel = new Signal<DatasyncFormDialogBody, void>(this);
+}
+
+class DatasyncFormDialogRenderer extends Dialog.Renderer {
+ createFooter(_buttons: ReadonlyArray<HTMLElement>): Widget {
+ return new Widget();
+ }
+}
diff --git a/packages/jldbq-extenison/src/MonitorViewWidget.tsx b/packages/jldbq-extenison/src/MonitorViewWidget.tsx
new file mode 100644
index 0000000000..02baa7af47
--- /dev/null
+++ b/packages/jldbq-extenison/src/MonitorViewWidget.tsx
@@ -0,0 +1,8 @@
+import React from 'react';
+import { ReactWidget } from '@jupyterlab/apputils';
+
+export default class MonitorWidget extends ReactWidget {
+ render(): JSX.Element {
+ return <div style={{ height: '100%' }} />;
+ }
+}
diff --git a/packages/jldbq-extenison/src/TaskViewWidget.tsx b/packages/jldbq-extenison/src/TaskViewWidget.tsx
new file mode 100644
index 0000000000..9497654443
--- /dev/null
+++ b/packages/jldbq-extenison/src/TaskViewWidget.tsx
@@ -0,0 +1,8 @@
+import React from 'react';
+import { ReactWidget } from '@jupyterlab/apputils';
+
+export default class TaskViewWidget extends ReactWidget {
+ render(): JSX.Element {
+ return <div style={{ height: '100%' }} />;
+ }
+}
diff --git a/packages/jldbq-extenison/src/api/config.ts b/packages/jldbq-extenison/src/api/config.ts
new file mode 100644
index 0000000000..78b468134b
--- /dev/null
+++ b/packages/jldbq-extenison/src/api/config.ts
@@ -0,0 +1,5 @@
+const config = {
+ endpoint: 'http://192.168.51.19:5000'
+};
+
+export default config;
diff --git a/packages/jldbq-extenison/src/api/datasource.ts b/packages/jldbq-extenison/src/api/datasource.ts
new file mode 100644
index 0000000000..8927b678bb
--- /dev/null
+++ b/packages/jldbq-extenison/src/api/datasource.ts
@@ -0,0 +1,106 @@
+import useSWR from 'swr';
+import config from './config';
+
+type DbEnc = 'utf8';
+type DbType = 'mysql' | 'hive';
+
+export interface IDatasource {
+ host: string;
+ user: string;
+ port: number;
+ password: string;
+ charset: DbEnc;
+ manager: string;
+ source: DbType;
+ databasename: string;
+ sourcename: string;
+}
+
+interface IDatasourceResponse {
+ datasources?: IDatasource[];
+ loading: boolean;
+ error?: any;
+ refresh: () => void;
+}
+
+export type ITableData = Record<string, Record<string, any>>;
+
+export const useDatasourceList = (manager: string): IDatasourceResponse => {
+ const endpoint = config.endpoint;
+ const item = encodeURIComponent(manager);
+ const url = `${endpoint}/managelist/item=${item}`;
+ const { data, error, mutate } = useSWR(url, (...args) =>
+ fetch(...args).then(res => res.json())
+ );
+ return {
+ datasources: data,
+ loading: !error && !data,
+ error,
+ refresh: mutate
+ };
+};
+
+export const setDatasource = async (
+ datasource: IDatasource
+): Promise<string> => {
+ const endpoint = config.endpoint;
+ const url = `${endpoint}/manage`;
+ try {
+ const resp = await fetch(url, {
+ method: 'post',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(datasource)
+ });
+ if (!resp.ok) {
+ return 'error';
+ }
+ const data = await resp.text();
+ return data;
+ } catch (e) {
+ console.error(e);
+ return 'error';
+ }
+};
+
+export const fetchTables = async (
+ ds: IDatasource
+): Promise<'error' | string[]> => {
+ const endpoint = config.endpoint;
+ const item = encodeURIComponent(
+ `${ds.manager};${ds.sourcename};${ds.databasename}`
+ );
+ const url = `${endpoint}/show/${ds.source}/tables/item=${item}`;
+ try {
+ const resp = await fetch(url);
+ if (!resp.ok) {
+ return 'error';
+ }
+ const data = (await resp.json()) as string[];
+ return data;
+ } catch (e) {
+ console.error(e);
+ return 'error';
+ }
+};
+
+export const fetchTableContent = async (
+ ds: IDatasource,
+ t: string
+): Promise<ITableData | 'error'> => {
+ const endpoint = config.endpoint;
+ const item = encodeURIComponent(
+ `${ds.manager};${ds.sourcename};${ds.databasename};${t}`
+ );
+ const url = `${endpoint}/show/${ds.source}/results/item=${item}`;
+ try {
+ const resp = await fetch(url);
+ if (!resp.ok) {
+ return 'error';
+ }
+ const data = (await resp.json()) as ITableData;
+ return data;
+ } catch (e) {
+ console.error(e);
+ return 'error';
+ }
+};
diff --git a/packages/jldbq-extenison/src/api/index.ts b/packages/jldbq-extenison/src/api/index.ts
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/jldbq-extenison/src/icons.ts b/packages/jldbq-extenison/src/icons.ts
new file mode 100644
index 0000000000..9e2b76f812
--- /dev/null
+++ b/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
+});
diff --git a/packages/jldbq-extenison/src/index.ts b/packages/jldbq-extenison/src/index.ts
new file mode 100644
index 0000000000..28da880058
--- /dev/null
+++ b/packages/jldbq-extenison/src/index.ts
@@ -0,0 +1,71 @@
+/**
+ * @packageDocumentation
+ * @module jldbq-extension
+ */
+
+import {
+ JupyterFrontEnd,
+ JupyterFrontEndPlugin
+} from '@jupyterlab/application';
+import { MainAreaWidget } from '@jupyterlab/apputils';
+import { ISettingRegistry } from '@jupyterlab/settingregistry';
+import DataViewWidget from './DataViewWidget';
+import DataTableWidget from './DataTableWidget';
+import TaskViewWidget from './TaskViewWidget';
+import MonitorViewWidget from './MonitorViewWidget';
+import { cliIcon, monitorIcon, timerIcon } from './icons';
+import config from './api/config';
+
+const PLUGIN_ID = '@jupyterlab/jldbq-extension:plugin';
+
+const plugin: JupyterFrontEndPlugin<void> = {
+ id: PLUGIN_ID,
+ autoStart: true,
+ requires: [ISettingRegistry],
+ activate: async (app: JupyterFrontEnd, registry: ISettingRegistry) => {
+ registry.pluginChanged.connect(async (_sender, plugin) => {
+ if (plugin === PLUGIN_ID) {
+ await updateConfig(registry);
+ }
+ });
+ await updateConfig(registry);
+
+ const manager = 'test1'; // TODO: 读取当前用户
+
+ const dataViewWidget = new DataViewWidget(manager);
+ dataViewWidget.id = 'jldbq-data';
+ dataViewWidget.title.icon = cliIcon;
+ dataViewWidget.title.caption = '数据开发';
+ dataViewWidget.title.label = '数据开发';
+ dataViewWidget.tableOpened.connect((_sender, { datasource, tableName }) => {
+ const content = new DataTableWidget(datasource, tableName);
+ const widget = new MainAreaWidget({ content });
+ widget.title.label = tableName;
+ widget.title.icon = cliIcon;
+ app.shell.add(widget, 'main');
+ });
+ app.shell.add(dataViewWidget, 'left', { rank: 100 });
+
+ const taskViewWidget = new TaskViewWidget();
+ taskViewWidget.id = 'jldbq-sync';
+ taskViewWidget.title.icon = timerIcon;
+ taskViewWidget.title.caption = '定时任务';
+ taskViewWidget.title.label = '定时任务';
+ app.shell.add(taskViewWidget, 'left', { rank: 1000 });
+
+ const monitorViewWidget = new MonitorViewWidget();
+ monitorViewWidget.id = 'jldbq-monitor';
+ monitorViewWidget.title.icon = monitorIcon;
+ monitorViewWidget.title.caption = '调度监控';
+ monitorViewWidget.title.label = '调度监控';
+ app.shell.add(monitorViewWidget, 'left', { rank: 1100 });
+ }
+};
+
+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;
+}
diff --git a/packages/jldbq-extenison/src/png.d.ts b/packages/jldbq-extenison/src/png.d.ts
new file mode 100644
index 0000000000..1c5923252c
--- /dev/null
+++ b/packages/jldbq-extenison/src/png.d.ts
@@ -0,0 +1,4 @@
+declare module '*.png' {
+ const value: string;
+ export default value;
+}
diff --git a/packages/jldbq-extenison/src/svg.d.ts b/packages/jldbq-extenison/src/svg.d.ts
new file mode 100644
index 0000000000..0ca27598c5
--- /dev/null
+++ b/packages/jldbq-extenison/src/svg.d.ts
@@ -0,0 +1,4 @@
+declare module "*.svg" {
+ const value: string;
+ export default value;
+}
diff --git a/packages/jldbq-extenison/style/base.css b/packages/jldbq-extenison/style/base.css
new file mode 100644
index 0000000000..e2026de0cb
--- /dev/null
+++ b/packages/jldbq-extenison/style/base.css
@@ -0,0 +1,9 @@
+/*
+ See the JupyterLab Developer Guide for useful CSS Patterns:
+
+ https://jupyterlab.readthedocs.io/en/stable/developer/css.html
+*/
+
+@import './syncform.css';
+@import './button.css';
+@import './dsform.css';
diff --git a/packages/jldbq-extenison/style/button.css b/packages/jldbq-extenison/style/button.css
new file mode 100644
index 0000000000..ea9c093f0b
--- /dev/null
+++ b/packages/jldbq-extenison/style/button.css
@@ -0,0 +1,31 @@
+.jldbq-btn {
+ width: 95px;
+ height: 33px;
+ padding: 0;
+ border: none;
+ background-color: #edf0f6;
+ color: #4a4a4a;
+ border-radius: 0;
+}
+
+.jldbq-btn.jldbq-btn-current {
+ background-color: #d1e4f6;
+}
+
+.jldbq-btn:hover:not(.jldbq-btn-current) {
+ opacity: 0.8;
+}
+
+.jldbq-btn-add {
+ display: flex;
+ align-items: center;
+ padding: 0;
+ background: none;
+ border: none;
+ color: #147bd1;
+ cursor: pointer;
+}
+
+.jldbq-btn-add:hover {
+ opacity: 0.8;
+}
diff --git a/packages/jldbq-extenison/style/dsform.css b/packages/jldbq-extenison/style/dsform.css
new file mode 100644
index 0000000000..f952bc34f4
--- /dev/null
+++ b/packages/jldbq-extenison/style/dsform.css
@@ -0,0 +1,105 @@
+.jldbq-form {
+ display: flex;
+ flex-direction: column;
+}
+
+.jldbq-form label {
+ margin-bottom: 30px;
+ display: flex;
+ align-items: center;
+}
+
+.jldbq-form label:last-child {
+ margin-bottom: 0;
+}
+
+.jldbq-form label.jldbq-form-error:last-child {
+ border: 1px solid #ed5555;
+}
+
+.jldbq-form .jldbq-form-label {
+ color: #4a4a4a;
+ width: 75px;
+ 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;
+ width: 320px;
+ height: 32px;
+ border-radius: 2px;
+ border: 1px solid #c8d3e9;
+ margin-left: 15px;
+ padding: 0 15px;
+ font-size: 12px;
+ transition: all 100ms;
+ outline: 1px solid transparent;
+}
+
+.jldbq-form .jldbq-form-input:focus {
+ outline-color: #147bd1;
+}
+
+.jldbq-form .react-select-container {
+ width: 320px;
+ margin-left: 15px;
+}
+
+.jldbq-form .react-select__control {
+ border-radius: 2px;
+ border: 1px solid #c8d3e9;
+ min-height: 32px;
+}
+
+.jldbq-form .react-select__control:hover {
+ border-color: #c8d3e9;
+}
+
+.jldbq-form .react-select__indicator-separator {
+ background-color: #c8d3e9;
+ margin: 4px 0;
+}
+
+.jldbq-form .react-select__indicator {
+ color: #4883fb;
+ padding: 0 8px;
+}
+
+.jldbq-form .react-select__value-container {
+ padding: 0 15px;
+ font-size: 12px;
+}
+
+.jldbq-form .react-select__single-value {
+ padding: 0;
+ margin: 0;
+}
+
+.jldbq-form .react-select__placeholder {
+ padding: 0;
+ margin: 0;
+}
+
+.jldbq-form .react-select__input-container {
+ padding: 0;
+ margin: 0;
+}
+
+.jldbq-form .react-select__menu-notice {
+ font-size: 12px;
+}
+
+.jldbq-form .react-select__option {
+ font-size: 12px;
+ padding-left: 16px;
+ padding-right: 16px;
+}
diff --git a/packages/jldbq-extenison/style/icons/cli.svg b/packages/jldbq-extenison/style/icons/cli.svg
new file mode 100644
index 0000000000..d712aada18
--- /dev/null
+++ b/packages/jldbq-extenison/style/icons/cli.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="4.2333331mm" height="4.2333331mm" viewBox="0 0 4.2333331 4.2333332" version="1.1"
+ xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
+ <g transform="translate(-20.017746,-119.34786)">
+ <path fill="#000000" class="jp-icon3 jp-icon-selectable"
+ style="stroke-width:1.00157;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 0 0 L 0 16 L 16 16 L 16 12.998047 L 15.240234 12.998047 L 15.240234 15.240234 L 0.75976562 15.240234 L 0.75976562 3.7871094 L 15.240234 3.7871094 L 15.240234 5.8144531 L 16 5.8144531 L 16 0 L 0 0 z M 0.75976562 0.75976562 L 15.240234 0.75976562 L 15.240234 3.1660156 L 0.75976562 3.1660156 L 0.75976562 0.75976562 z M 11.039062 6.0175781 A 0.49999937 0.49999937 0 0 0 10.574219 6.3476562 L 8.640625 11.839844 A 0.49999937 0.49999937 0 0 0 8.9433594 12.474609 A 0.49999937 0.49999937 0 0 0 9.5859375 12.171875 L 11.519531 6.6796875 A 0.49999937 0.49999937 0 0 0 11.210938 6.0449219 L 11.208984 6.0449219 A 0.49999937 0.49999937 0 0 0 11.039062 6.0175781 z M 13.609375 6.3925781 A 0.49999937 0.49999937 0 0 0 13.3125 6.4882812 A 0.49999937 0.49999937 0 0 0 13.208984 7.1894531 L 14.832031 9.4179688 L 13.134766 11.285156 A 0.49999937 0.49999937 0 0 0 13.171875 11.994141 A 0.49999937 0.49999937 0 0 0 13.880859 11.957031 L 15.84375 9.7871094 A 0.50004934 0.50004934 0 0 0 15.880859 9.1523438 L 14.013672 6.5976562 A 0.49999937 0.49999937 0 0 0 13.689453 6.3984375 L 13.6875 6.3984375 A 0.49999937 0.49999937 0 0 0 13.609375 6.3925781 z M 6.5507812 6.3945312 A 0.49999937 0.49999937 0 0 0 6.4726562 6.4003906 L 6.4726562 6.3984375 A 0.49999937 0.49999937 0 0 0 6.1484375 6.5976562 L 4.28125 9.1523438 A 0.50004934 0.50004934 0 0 0 4.3105469 9.7871094 L 6.28125 11.957031 A 0.49999937 0.49999937 0 0 0 6.9902344 11.996094 A 0.49999937 0.49999937 0 0 0 7.0273438 11.287109 L 5.3300781 9.4199219 L 6.953125 7.1894531 A 0.49999937 0.49999937 0 0 0 6.8417969 6.4882812 A 0.49999937 0.49999937 0 0 0 6.5507812 6.3945312 z "
+ transform="matrix(0.26458333,0,0,0.26458333,20.017746,119.34786)" />
+ </g>
+</svg>
\ No newline at end of file
diff --git a/packages/jldbq-extenison/style/icons/clock-fill.svg b/packages/jldbq-extenison/style/icons/clock-fill.svg
new file mode 100644
index 0000000000..7cece1ee7b
--- /dev/null
+++ b/packages/jldbq-extenison/style/icons/clock-fill.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#616161" class="jp-icon3 jp-icon-selectable"
+ viewBox="0 0 16 16">
+ <path
+ d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71V3.5z" />
+</svg>
\ No newline at end of file
diff --git a/packages/jldbq-extenison/style/icons/database-solid-ghost.svg b/packages/jldbq-extenison/style/icons/database-solid-ghost.svg
new file mode 100644
index 0000000000..8edad9815c
--- /dev/null
+++ b/packages/jldbq-extenison/style/icons/database-solid-ghost.svg
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ viewBox="0 0 43 49.14286"
+ version="1.1"
+ id="svg19"
+ sodipodi:docname="database-solid-ghost.svg"
+ width="43"
+ height="49.14286"
+ inkscape:version="1.1.2 (b8e25be833, 2022-02-05)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ id="defs23" />
+ <sodipodi:namedview
+ id="namedview21"
+ pagecolor="#ffffff"
+ bordercolor="#999999"
+ borderopacity="1"
+ inkscape:pageshadow="0"
+ inkscape:pageopacity="0"
+ inkscape:pagecheckerboard="0"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:zoom="1"
+ inkscape:cx="71.5"
+ inkscape:cy="316"
+ inkscape:window-width="1920"
+ inkscape:window-height="1017"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg19" />
+ <!--! Font Awesome Pro 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
+ <path
+ d="m 43,7.678571 v 4.607143 c 0,4.242411 -9.627009,7.678572 -21.5,7.678572 C 9.627009,19.964286 0,16.528125 0,12.285714 V 7.678571 C 0,3.43808 9.627009,0 21.5,0 33.372991,0 43,3.43808 43,7.678571 Z M 37.740179,20.607366 C 39.650223,19.897098 41.569866,18.985268 43,17.862277 v 9.78058 c 0,4.242411 -9.627009,7.678572 -21.5,7.678572 -11.872991,0 -21.5,-3.436161 -21.5,-7.678572 v -9.78058 c 1.433013,1.122991 3.265312,2.034821 5.264621,2.745089 4.300959,1.535714 10.044531,2.428348 16.235379,2.428348 6.190848,0 11.93058,-0.892634 16.240179,-2.428348 z M 5.264621,35.964509 C 9.56558,37.500223 15.309152,38.392857 21.5,38.392857 c 6.190848,0 11.93058,-0.892634 16.240179,-2.428348 C 39.650223,35.254241 41.569866,34.342411 43,33.21942 v 8.244866 C 43,45.7067 33.372991,49.14286 21.5,49.14286 9.627009,49.14286 0,45.7067 0,41.464286 V 33.21942 c 1.433013,1.122991 3.265312,2.034821 5.264621,2.745089 z"
+ id="path17"
+ style="fill:#616161;fill-opacity:1;stroke-width:0.0959821" />
+</svg>
diff --git a/packages/jldbq-extenison/style/icons/database-solid.svg b/packages/jldbq-extenison/style/icons/database-solid.svg
new file mode 100644
index 0000000000..e867c2bf34
--- /dev/null
+++ b/packages/jldbq-extenison/style/icons/database-solid.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg viewBox="0 0 548 626" version="1.1" width="548" height="626" xmlns="http://www.w3.org/2000/svg">
+ <path fill="#616161" class="jp-icon3 jp-icon-selectable"
+ d="m 498,137 v 48 c 0,44.2 -100.3,80 -224,80 C 150.3,265 50,229.2 50,185 v -48 c 0,-44.18 100.3,-80 224,-80 123.7,0 224,35.82 224,80 z m -54.8,134.7 c 19.9,-7.4 39.9,-16.9 54.8,-28.6 V 345 c 0,44.2 -100.3,80 -224,80 C 150.3,425 50,389.2 50,345 V 243.1 c 14.93,11.7 34.02,21.2 54.85,28.6 44.81,16 104.65,25.3 169.15,25.3 64.5,0 124.3,-9.3 169.2,-25.3 z m -338.35,160 c 44.81,16 104.65,25.3 169.15,25.3 64.5,0 124.3,-9.3 169.2,-25.3 19.9,-7.4 39.9,-16.9 54.8,-28.6 V 489 c 0,44.2 -100.3,80 -224,80 C 150.3,569 50,533.2 50,489 v -85.9 c 14.93,11.7 34.02,21.2 54.85,28.6 z" />
+</svg>
\ No newline at end of file
diff --git a/packages/jldbq-extenison/style/icons/monitor.svg b/packages/jldbq-extenison/style/icons/monitor.svg
new file mode 100644
index 0000000000..5cd7ad7c83
--- /dev/null
+++ b/packages/jldbq-extenison/style/icons/monitor.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="4.2333341mm" height="3.9620304mm" viewBox="0 0 4.2333341 3.9620305" version="1.1"
+ xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
+ <g transform="translate(-24.619015,-119.41814)">
+ <path fill="#000000" class="jp-icon3 jp-icon-selectable"
+ style="stroke-width:0.171832;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
+ d="m 24.825721,119.41814 c -0.114651,0 -0.206706,0.0921 -0.206706,0.2067 v 2.75642 c 0,0.11466 0.09205,0.20671 0.206706,0.20671 h 1.110527 v 0.52658 h -0.644406 a 0.13249998,0.13249998 0 0 0 -0.132808,0.13281 0.13249998,0.13249998 0 0 0 0.132808,0.13281 h 2.886646 a 0.13249998,0.13249998 0 0 0 0.132808,-0.13281 0.13249998,0.13249998 0 0 0 -0.132808,-0.13281 h -0.652157 v -0.52658 h 1.118795 c 0.114651,0 0.207223,-0.0921 0.207223,-0.20671 v -2.75642 c 0,-0.11465 -0.09257,-0.2067 -0.207223,-0.2067 z m 0.23151,0.19172 h 3.356901 c 0.100775,0 0.181901,0.0811 0.181901,0.1819 v 2.42259 c 0,0.10077 -0.08113,0.1819 -0.181901,0.1819 h -3.356901 c -0.100774,0 -0.181901,-0.0811 -0.181901,-0.1819 v -2.42259 c 0,-0.10078 0.08113,-0.1819 0.181901,-0.1819 z m 2.596224,0.60461 a 0.08250825,0.08250825 0 0 0 -0.06873,0.0289 l -0.933277,1.1312 -0.519865,-0.61133 a 0.08250825,0.08250825 0 0 0 -0.128674,0.004 l -0.666109,0.88625 a 0.0825,0.0825 0 0 0 0.0155,0.11524 0.0825,0.0825 0 0 0 0.115238,-0.0155 l 0.605648,-0.80461 0.517798,0.60772 a 0.08250825,0.08250825 0 0 0 0.126607,0 l 0.923975,-1.12345 0.505912,0.74259 a 0.0825,0.0825 0 0 0 0.115238,0.0212 0.0825,0.0825 0 0 0 0.02119,-0.11524 l -0.566374,-0.83199 a 0.08250825,0.08250825 0 0 0 -0.06408,-0.0351 z m -1.453141,2.3735 h 1.0604 v 0.52658 h -1.0604 z" />
+ </g>
+</svg>
\ No newline at end of file
diff --git a/packages/jldbq-extenison/style/icons/timer.svg b/packages/jldbq-extenison/style/icons/timer.svg
new file mode 100644
index 0000000000..94d2d8509f
--- /dev/null
+++ b/packages/jldbq-extenison/style/icons/timer.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="4.2782922mm" height="4.26331mm" viewBox="0 0 4.2782922 4.26331" version="1.1"
+ xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
+ <g transform="translate(-24.62537,-119.25549)">
+ <path fill="#000000" class="jp-icon3 jp-icon-selectable"
+ style="stroke-width:0.200096;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
+ d="m 24.826392,119.25549 c -0.11134,0 -0.201022,0.0897 -0.201022,0.20102 v 3.83129 c 0,0.11134 0.08968,0.20102 0.201022,0.20102 h 2.345076 a 1.2378182,1.2378182 0 0 1 -0.238745,-0.19172 h -1.944584 c -0.101249,0 -0.182418,-0.0817 -0.182418,-0.18293 v -2.5647 h 3.614767 v 0.80357 a 1.2378182,1.2378182 0 0 1 0.18035,0.12247 v -2.019 c 0,-0.11134 -0.08968,-0.20102 -0.201021,-0.20102 z m 0.161747,0.19172 h 3.249931 c 0.101248,0 0.182418,0.0817 0.182418,0.18293 v 0.75551 h -3.614767 v -0.75551 c 0,-0.10124 0.08117,-0.18293 0.182418,-0.18293 z m 1.805058,0.33951 a 0.14616301,0.14616301 0 0 0 -0.146245,0.14625 0.14616301,0.14616301 0 0 0 0.146245,0.14624 0.14616301,0.14616301 0 0 0 0.146244,-0.14624 0.14616301,0.14616301 0 0 0 -0.146244,-0.14625 z m 0.538985,0 a 0.14616301,0.14616301 0 0 0 -0.146244,0.14625 0.14616301,0.14616301 0 0 0 0.146244,0.14624 0.14616301,0.14616301 0 0 0 0.146244,-0.14624 0.14616301,0.14616301 0 0 0 -0.146244,-0.14625 z m 0.538985,0 a 0.14616301,0.14616301 0 0 0 -0.146244,0.14625 0.14616301,0.14616301 0 0 0 0.146244,0.14624 0.14616301,0.14616301 0 0 0 0.146244,-0.14624 0.14616301,0.14616301 0 0 0 -0.146244,-0.14625 z m -1.506368,1.07332 a 0.0825,0.0825 0 0 0 -0.05839,0.0238 l -0.592212,0.56638 -0.363285,-0.33021 a 0.0825,0.0825 0 0 0 -0.116789,0.004 0.0825,0.0825 0 0 0 0.0057,0.11731 l 0.42013,0.3824 a 0.08250825,0.08250825 0 0 0 0.113171,0 l 0.648539,-0.62115 a 0.0825,0.0825 0 0 0 0.0021,-0.11679 0.0825,0.0825 0 0 0 -0.05891,-0.0253 z m 1.456242,0.49351 a 1.0825199,1.0825199 0 0 0 -1.082621,1.08262 1.0825199,1.0825199 0 0 0 1.082621,1.08263 1.0825199,1.0825199 0 0 0 1.082621,-1.08263 1.0825199,1.0825199 0 0 0 -1.082621,-1.08262 z m -0.0047,0.17829 a 0.89981608,0.89981608 0 0 1 0.899687,0.89968 0.89981608,0.89981608 0 0 1 -0.899687,0.89969 0.89981608,0.89981608 0 0 1 -0.899687,-0.89969 0.89981608,0.89981608 0 0 1 0.899687,-0.89968 z m -0.0217,0.27388 a 0.0825,0.0825 0 0 0 -0.08423,0.0817 v 0.62115 a 0.08250825,0.08250825 0 0 0 0.08423,0.0842 h 0.546737 a 0.0825,0.0825 0 0 0 0.08216,-0.0842 0.0825,0.0825 0 0 0 -0.08216,-0.0817 H 27.87629 v -0.5395 a 0.0825,0.0825 0 0 0 -0.08165,-0.0817 z m -1.424203,0.0956 a 0.0825,0.0825 0 0 0 -0.05839,0.0233 l -0.593762,0.56844 -0.363285,-0.33228 a 0.0825,0.0825 0 0 0 -0.117306,0.004 0.0825,0.0825 0 0 0 0.0062,0.11731 l 0.419613,0.38499 a 0.08250825,0.08250825 0 0 0 0.113171,-0.002 l 0.64854,-0.62115 a 0.0825,0.0825 0 0 0 0.0021,-0.1173 0.0825,0.0825 0 0 0 -0.05684,-0.0253 z" />
+ </g>
+</svg>
\ No newline at end of file
diff --git a/packages/jldbq-extenison/style/img/arrow.png b/packages/jldbq-extenison/style/img/arrow.png
new file mode 100644
index 0000000000..50c9571f4e
Binary files /dev/null and b/packages/jldbq-extenison/style/img/arrow.png differ
diff --git a/packages/jldbq-extenison/style/img/delete.png b/packages/jldbq-extenison/style/img/delete.png
new file mode 100644
index 0000000000..a64b86a722
Binary files /dev/null and b/packages/jldbq-extenison/style/img/delete.png differ
diff --git a/packages/jldbq-extenison/style/index.css b/packages/jldbq-extenison/style/index.css
new file mode 100644
index 0000000000..2257bf1a6e
--- /dev/null
+++ b/packages/jldbq-extenison/style/index.css
@@ -0,0 +1,12 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) Jupyter Development Team.
+| Distributed under the terms of the Modified BSD License.
+|----------------------------------------------------------------------------*/
+
+/* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */
+@import url('~@lumino/widgets/style/index.css');
+@import url('~@jupyterlab/ui-components/style/index.css');
+@import url('~@jupyterlab/apputils/style/index.css');
+@import url('~@jupyterlab/application/style/index.css');
+
+@import url('./base.css');
diff --git a/packages/jldbq-extenison/style/index.js b/packages/jldbq-extenison/style/index.js
new file mode 100644
index 0000000000..6f57f28e14
--- /dev/null
+++ b/packages/jldbq-extenison/style/index.js
@@ -0,0 +1,12 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) Jupyter Development Team.
+| Distributed under the terms of the Modified BSD License.
+|----------------------------------------------------------------------------*/
+
+/* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */
+import '@lumino/widgets/style/index.js';
+import '@jupyterlab/ui-components/style/index.js';
+import '@jupyterlab/apputils/style/index.js';
+import '@jupyterlab/application/style/index.js';
+
+import './base.css';
diff --git a/packages/jldbq-extenison/style/syncform.css b/packages/jldbq-extenison/style/syncform.css
new file mode 100644
index 0000000000..701d4a2e25
--- /dev/null
+++ b/packages/jldbq-extenison/style/syncform.css
@@ -0,0 +1,45 @@
+@import '~antd/dist/antd.css';
+
+.arrow {
+ display: inline-flex;
+ width: 10%;
+ height: 300px;
+ justify-content: center;
+ align-items: center;
+}
+
+.plane {
+ height: 265px;
+ border: 1px solid #d9d9d9;
+ margin-top: 10px;
+ padding: 10px 0 0 10px;
+ overflow-y: scroll;
+}
+
+.line {
+ height: 307px;
+ border-left: 1px solid #d9d9d9;
+ margin: 0 5%;
+}
+
+.mappings {
+ width: 30%;
+ height: 307px;
+ border: 1px solid #d9d9d9;
+ padding-left: 15px;
+}
+
+.mappings__title {
+ height: 32px;
+ line-height: 32px;
+ font-weight: 500;
+}
+
+.mappings__content {
+ height: 260px;
+ overflow-y: scroll;
+}
+
+#datasyncForm > .ant-form-item:last-child {
+ margin-bottom: 0;
+}
diff --git a/packages/launcher-extension/src/index.ts b/packages/launcher-extension/src/index.ts
index 94dd0d7538..da8d738526 100644
--- a/packages/launcher-extension/src/index.ts
+++ b/packages/launcher-extension/src/index.ts
@@ -32,9 +32,9 @@ const plugin: JupyterFrontEndPlugin<ILauncher> = {
activate,
id: '@jupyterlab/launcher-extension:plugin',
requires: [ITranslator],
- optional: [ILabShell, ICommandPalette],
- provides: ILauncher,
- autoStart: true
+ optional: [ILabShell, ICommandPalette]
+ // provides: ILauncher,
+ // autoStart: true
};
/**
diff --git a/packages/metapackage/package.json b/packages/metapackage/package.json
index 2832703b72..921f346507 100644
--- a/packages/metapackage/package.json
+++ b/packages/metapackage/package.json
@@ -15,13 +15,16 @@
"sideEffects": false,
"main": "lib/index.js",
"types": "lib/index.d.ts",
+ "style": "style/index.css",
"directories": {
"lib": "lib/"
},
"files": [
"lib/*.d.ts",
"lib/*.js.map",
- "lib/*.js"
+ "lib/*.js",
+ "style/index.css",
+ "style/index.js"
],
"scripts": {
"build": "tsc -b",
@@ -75,6 +78,7 @@
"@jupyterlab/inspector": "^3.4.3",
"@jupyterlab/inspector-extension": "^3.4.3",
"@jupyterlab/javascript-extension": "^3.4.3",
+ "@jupyterlab/jldbq-extension": "^1.0.0",
"@jupyterlab/json-extension": "^3.4.3",
"@jupyterlab/launcher": "^3.4.3",
"@jupyterlab/launcher-extension": "^3.4.3",
@@ -86,6 +90,7 @@
"@jupyterlab/markdownviewer-extension": "^3.4.3",
"@jupyterlab/mathjax2": "^3.4.3",
"@jupyterlab/mathjax2-extension": "^3.4.3",
+ "@jupyterlab/mytest-extension": "^1.0.0",
"@jupyterlab/nbconvert-css": "^3.4.3",
"@jupyterlab/nbformat": "^3.4.3",
"@jupyterlab/notebook": "^3.4.3",
@@ -110,7 +115,6 @@
"@jupyterlab/statusbar-extension": "^3.4.3",
"@jupyterlab/terminal": "^3.4.3",
"@jupyterlab/terminal-extension": "^3.4.3",
- "@jupyterlab/theme-dark-extension": "^3.4.3",
"@jupyterlab/theme-light-extension": "^3.4.3",
"@jupyterlab/toc": "^5.4.3",
"@jupyterlab/toc-extension": "^5.4.3",
@@ -132,5 +136,6 @@
},
"publishConfig": {
"access": "public"
- }
+ },
+ "styleModule": "style/index.js"
}
diff --git a/packages/theme-dark-extension/style/theme.css b/packages/metapackage/style/index.css
similarity index 52%
rename from packages/theme-dark-extension/style/theme.css
rename to packages/metapackage/style/index.css
index 4761c94d2b..b2f19abe63 100644
--- a/packages/theme-dark-extension/style/theme.css
+++ b/packages/metapackage/style/index.css
@@ -3,15 +3,6 @@
| Distributed under the terms of the Modified BSD License.
|----------------------------------------------------------------------------*/
-@import './variables.css';
-
-/* Set the default typography for monospace elements */
-tt,
-code,
-kbd,
-samp,
-pre {
- font-family: var(--jp-code-font-family);
- font-size: var(--jp-code-font-size);
- line-height: var(--jp-code-line-height);
-}
+/* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */
+@import url('~@jupyterlab/jldbq-extension/style/index.css');
+@import url('~@jupyterlab/mytest-extension/style/index.css');
diff --git a/packages/metapackage/style/index.js b/packages/metapackage/style/index.js
new file mode 100644
index 0000000000..cae86f17db
--- /dev/null
+++ b/packages/metapackage/style/index.js
@@ -0,0 +1,8 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) Jupyter Development Team.
+| Distributed under the terms of the Modified BSD License.
+|----------------------------------------------------------------------------*/
+
+/* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */
+import '@jupyterlab/jldbq-extension/style/index.js';
+import '@jupyterlab/mytest-extension/style/index.js';
diff --git a/packages/notebook-extension/src/index.ts b/packages/notebook-extension/src/index.ts
index 39a8057b24..c1524b80ad 100644
--- a/packages/notebook-extension/src/index.ts
+++ b/packages/notebook-extension/src/index.ts
@@ -21,7 +21,6 @@ import {
MainAreaWidget,
sessionContextDialogs,
showDialog,
- Toolbar,
WidgetTracker
} from '@jupyterlab/apputils';
import { Cell, CodeCell, ICellModel, MarkdownCell } from '@jupyterlab/cells';
@@ -94,7 +93,8 @@ import {
} from '@lumino/coreutils';
import { DisposableSet, IDisposable } from '@lumino/disposable';
import { Message, MessageLoop } from '@lumino/messaging';
-import { Menu, Panel } from '@lumino/widgets';
+// import { Menu, Panel } from '@lumino/widgets';
+import { Panel } from '@lumino/widgets';
import { logNotebookOutput } from './nboutput';
/**
@@ -270,7 +270,7 @@ const FACTORY = 'Notebook';
* The excluded Export To ...
* (returned from nbconvert's export list)
*/
-const FORMAT_EXCLUDE = ['notebook', 'python', 'custom'];
+// const FORMAT_EXCLUDE = ['notebook', 'python', 'custom'];
/**
* Setting Id storing the customized toolbar definition.
@@ -477,111 +477,111 @@ export const executionIndicator: JupyterFrontEndPlugin<void> = {
/**
* A plugin providing export commands in the main menu and command palette
*/
-export const exportPlugin: JupyterFrontEndPlugin<void> = {
- id: '@jupyterlab/notebook-extension:export',
- autoStart: true,
- requires: [ITranslator, INotebookTracker],
- optional: [IMainMenu, ICommandPalette],
- activate: (
- app: JupyterFrontEnd,
- translator: ITranslator,
- tracker: INotebookTracker,
- mainMenu: IMainMenu | null,
- palette: ICommandPalette | null
- ) => {
- const trans = translator.load('jupyterlab');
- const { commands, shell } = app;
- const services = app.serviceManager;
-
- const isEnabled = (): boolean => {
- return Private.isEnabled(shell, tracker);
- };
-
- commands.addCommand(CommandIDs.exportToFormat, {
- label: args => {
- const formatLabel = args['label'] as string;
- return args['isPalette']
- ? trans.__('Save and Export Notebook: %1', formatLabel)
- : formatLabel;
- },
- execute: args => {
- const current = getCurrent(tracker, shell, args);
-
- if (!current) {
- return;
- }
-
- const url = PageConfig.getNBConvertURL({
- format: args['format'] as string,
- download: true,
- path: current.context.path
- });
- const { context } = current;
-
- if (context.model.dirty && !context.model.readOnly) {
- return context.save().then(() => {
- window.open(url, '_blank', 'noopener');
- });
- }
-
- return new Promise<void>(resolve => {
- window.open(url, '_blank', 'noopener');
- resolve(undefined);
- });
- },
- isEnabled
- });
-
- // Add a notebook group to the File menu.
- let exportTo: Menu | null | undefined;
- if (mainMenu) {
- exportTo = mainMenu.fileMenu.items.find(
- item =>
- item.type === 'submenu' &&
- item.submenu?.id === 'jp-mainmenu-file-notebookexport'
- )?.submenu;
- }
-
- void services.nbconvert.getExportFormats().then(response => {
- if (response) {
- const formatLabels: any = Private.getFormatLabels(translator);
-
- // Convert export list to palette and menu items.
- const formatList = Object.keys(response);
- formatList.forEach(function (key) {
- const capCaseKey = trans.__(key[0].toUpperCase() + key.substr(1));
- const labelStr = formatLabels[key] ? formatLabels[key] : capCaseKey;
- let args = {
- format: key,
- label: labelStr,
- isPalette: false
- };
- if (FORMAT_EXCLUDE.indexOf(key) === -1) {
- if (exportTo) {
- exportTo.addItem({
- command: CommandIDs.exportToFormat,
- args: args
- });
- }
- if (palette) {
- args = {
- format: key,
- label: labelStr,
- isPalette: true
- };
- const category = trans.__('Notebook Operations');
- palette.addItem({
- command: CommandIDs.exportToFormat,
- category,
- args
- });
- }
- }
- });
- }
- });
- }
-};
+// export const exportPlugin: JupyterFrontEndPlugin<void> = {
+// id: '@jupyterlab/notebook-extension:export',
+// autoStart: true,
+// requires: [ITranslator, INotebookTracker],
+// optional: [IMainMenu, ICommandPalette],
+// activate: (
+// app: JupyterFrontEnd,
+// translator: ITranslator,
+// tracker: INotebookTracker,
+// mainMenu: IMainMenu | null,
+// palette: ICommandPalette | null
+// ) => {
+// const trans = translator.load('jupyterlab');
+// const { commands, shell } = app;
+// const services = app.serviceManager;
+
+// const isEnabled = (): boolean => {
+// return Private.isEnabled(shell, tracker);
+// };
+
+// commands.addCommand(CommandIDs.exportToFormat, {
+// label: args => {
+// const formatLabel = args['label'] as string;
+// return args['isPalette']
+// ? trans.__('Save and Export Notebook: %1', formatLabel)
+// : formatLabel;
+// },
+// execute: args => {
+// const current = getCurrent(tracker, shell, args);
+
+// if (!current) {
+// return;
+// }
+
+// const url = PageConfig.getNBConvertURL({
+// format: args['format'] as string,
+// download: true,
+// path: current.context.path
+// });
+// const { context } = current;
+
+// if (context.model.dirty && !context.model.readOnly) {
+// return context.save().then(() => {
+// window.open(url, '_blank', 'noopener');
+// });
+// }
+
+// return new Promise<void>(resolve => {
+// window.open(url, '_blank', 'noopener');
+// resolve(undefined);
+// });
+// },
+// isEnabled
+// });
+
+// // Add a notebook group to the File menu.
+// let exportTo: Menu | null | undefined;
+// if (mainMenu) {
+// exportTo = mainMenu.fileMenu.items.find(
+// item =>
+// item.type === 'submenu' &&
+// item.submenu?.id === 'jp-mainmenu-file-notebookexport'
+// )?.submenu;
+// }
+
+// void services.nbconvert.getExportFormats().then(response => {
+// if (response) {
+// const formatLabels: any = Private.getFormatLabels(translator);
+
+// // Convert export list to palette and menu items.
+// const formatList = Object.keys(response);
+// formatList.forEach(function (key) {
+// const capCaseKey = trans.__(key[0].toUpperCase() + key.substr(1));
+// const labelStr = formatLabels[key] ? formatLabels[key] : capCaseKey;
+// let args = {
+// format: key,
+// label: labelStr,
+// isPalette: false
+// };
+// if (FORMAT_EXCLUDE.indexOf(key) === -1) {
+// if (exportTo) {
+// exportTo.addItem({
+// command: CommandIDs.exportToFormat,
+// args: args
+// });
+// }
+// if (palette) {
+// args = {
+// format: key,
+// label: labelStr,
+// isPalette: true
+// };
+// const category = trans.__('Notebook Operations');
+// palette.addItem({
+// command: CommandIDs.exportToFormat,
+// category,
+// args
+// });
+// }
+// }
+// });
+// }
+// });
+// }
+// };
/**
* A plugin that adds a notebook trust status item to the status bar.
@@ -682,7 +682,7 @@ const plugins: JupyterFrontEndPlugin<any>[] = [
factory,
trackerPlugin,
executionIndicator,
- exportPlugin,
+ // exportPlugin,
tools,
commandEditItem,
notebookTrustItem,
@@ -844,13 +844,6 @@ function activateWidgetFactory(
toolbarRegistry.registerFactory<NotebookPanel>(FACTORY, 'cellType', panel =>
ToolbarItems.createCellTypeItem(panel, translator)
);
- toolbarRegistry.registerFactory<NotebookPanel>(FACTORY, 'kernelName', panel =>
- Toolbar.createKernelNameItem(
- panel.sessionContext,
- sessionContextDialogs,
- translator
- )
- );
toolbarRegistry.registerFactory<NotebookPanel>(
FACTORY,
diff --git a/packages/notebook/src/default-toolbar.tsx b/packages/notebook/src/default-toolbar.tsx
index bf94760cc6..5e931bb525 100644
--- a/packages/notebook/src/default-toolbar.tsx
+++ b/packages/notebook/src/default-toolbar.tsx
@@ -278,15 +278,7 @@ export namespace ToolbarItems {
widget: createRestartRunAllButton(panel, sessionDialogs, translator)
},
{ name: 'cellType', widget: createCellTypeItem(panel, translator) },
- { name: 'spacer', widget: Toolbar.createSpacerItem() },
- {
- name: 'kernelName',
- widget: Toolbar.createKernelNameItem(
- panel.sessionContext,
- sessionDialogs,
- translator
- )
- }
+ { name: 'spacer', widget: Toolbar.createSpacerItem() }
];
}
}
diff --git a/packages/notebook/src/panel.ts b/packages/notebook/src/panel.ts
index e1f70352f4..a30e01bd00 100644
--- a/packages/notebook/src/panel.ts
+++ b/packages/notebook/src/panel.ts
@@ -17,6 +17,7 @@ import {
TranslationBundle
} from '@jupyterlab/translation';
import { each } from '@lumino/algorithm';
+import { BoxLayout } from '@lumino/widgets';
import { Token } from '@lumino/coreutils';
import { INotebookModel } from './model';
import { Notebook, StaticNotebook } from './widget';
@@ -54,6 +55,8 @@ export class NotebookPanel extends DocumentWidget<Notebook, INotebookModel> {
// Set up CSS classes
this.addClass(NOTEBOOK_PANEL_CLASS);
this.toolbar.addClass(NOTEBOOK_PANEL_TOOLBAR_CLASS);
+ BoxLayout.setSizeBasis(this.toolbar, 42);
+ (this.layout as BoxLayout).spacing = 10;
this.content.addClass(NOTEBOOK_PANEL_NOTEBOOK_CLASS);
// Set up things related to the context
@@ -136,7 +139,7 @@ export class NotebookPanel extends DocumentWidget<Notebook, INotebookModel> {
/**
* Set URI fragment identifier.
*/
- setFragment(fragment: string) {
+ setFragment(fragment: string): void {
void this.context.ready.then(() => {
this.content.setFragment(fragment);
});
@@ -154,7 +157,7 @@ export class NotebookPanel extends DocumentWidget<Notebook, INotebookModel> {
* Prints the notebook by converting to HTML with nbconvert.
*/
[Printing.symbol]() {
- return async () => {
+ return async (): Promise<void> => {
// Save before generating HTML
if (this.context.model.dirty && !this.context.model.readOnly) {
await this.context.save();
diff --git a/packages/notebook/style/base.css b/packages/notebook/style/base.css
index 4d90131c53..11b23e5da2 100644
--- a/packages/notebook/style/base.css
+++ b/packages/notebook/style/base.css
@@ -28,6 +28,7 @@
.jp-NotebookPanel {
display: block;
height: 100%;
+ padding: 20px;
}
.jp-NotebookPanel.jp-Document {
@@ -36,7 +37,7 @@
}
.jp-Notebook {
- padding: var(--jp-notebook-padding);
+ padding-right: var(--jp-notebook-padding);
outline: none;
overflow: auto;
background: var(--jp-layout-color0);
@@ -95,7 +96,7 @@
/* cell is active */
.jp-Notebook .jp-Cell.jp-mod-active .jp-Collapser {
- background: var(--jp-brand-color1);
+ background: #147bd1;
}
/* cell is dirty */
diff --git a/packages/notebook/style/toolbar.css b/packages/notebook/style/toolbar.css
index c1a3259af0..28a4859c59 100644
--- a/packages/notebook/style/toolbar.css
+++ b/packages/notebook/style/toolbar.css
@@ -17,8 +17,16 @@
| Styles
|----------------------------------------------------------------------------*/
-.jp-NotebookPanel-toolbar {
- padding: var(--jp-notebook-toolbar-padding);
+.jp-Toolbar.jp-NotebookPanel-toolbar {
+ align-items: center;
+ background-color: #f7f9fd;
+ border: none;
+ box-shadow: none;
+ padding: 0 24px;
+}
+
+.jp-Toolbar.jp-NotebookPanel-toolbar > .jp-Toolbar-item {
+ height: auto;
}
.jp-Toolbar-item.jp-Notebook-toolbarCellType .jp-select-wrapper.jp-mod-focused {
diff --git a/packages/running-extension/src/index.ts b/packages/running-extension/src/index.ts
index fa4e785803..5a8efd480b 100644
--- a/packages/running-extension/src/index.ts
+++ b/packages/running-extension/src/index.ts
@@ -68,7 +68,7 @@ function activate(
addKernelRunningSessionManager(runningSessionManagers, translator, app);
// Rank has been chosen somewhat arbitrarily to give priority to the running
// sessions widget in the sidebar.
- app.shell.add(running, 'left', { rank: 200 });
+ // app.shell.add(running, 'left', { rank: 200 });
return runningSessionManagers;
}
diff --git a/packages/statusbar/src/statusbar.ts b/packages/statusbar/src/statusbar.ts
index 58da932baa..dadfbfcdc1 100644
--- a/packages/statusbar/src/statusbar.ts
+++ b/packages/statusbar/src/statusbar.ts
@@ -116,7 +116,7 @@ export class StatusBar extends Widget implements IStatusBar {
/**
* Dispose of the status bar.
*/
- dispose() {
+ dispose(): void {
this._leftRankItems.length = 0;
this._rightRankItems.length = 0;
this._disposables.dispose();
@@ -126,7 +126,7 @@ export class StatusBar extends Widget implements IStatusBar {
/**
* Handle an 'update-request' message to the status bar.
*/
- protected onUpdateRequest(msg: Message) {
+ protected onUpdateRequest(msg: Message): void {
this._refreshAll();
super.onUpdateRequest(msg);
}
diff --git a/packages/terminal-extension/src/index.ts b/packages/terminal-extension/src/index.ts
index 6aca46fbd2..5a18f9f165 100644
--- a/packages/terminal-extension/src/index.ts
+++ b/packages/terminal-extension/src/index.ts
@@ -17,7 +17,8 @@ import {
WidgetTracker
} from '@jupyterlab/apputils';
import { ILauncher } from '@jupyterlab/launcher';
-import { IFileMenu, IMainMenu } from '@jupyterlab/mainmenu';
+// import { IFileMenu, IMainMenu } from '@jupyterlab/mainmenu';
+import { IMainMenu } from '@jupyterlab/mainmenu';
import { IRunningSessionManagers, IRunningSessions } from '@jupyterlab/running';
import { Terminal, TerminalAPI } from '@jupyterlab/services';
import { ISettingRegistry } from '@jupyterlab/settingregistry';
@@ -27,7 +28,7 @@ import * as WidgetModuleType from '@jupyterlab/terminal/lib/widget';
import { ITranslator } from '@jupyterlab/translation';
import { terminalIcon } from '@jupyterlab/ui-components';
import { toArray } from '@lumino/algorithm';
-import { Menu } from '@lumino/widgets';
+// import { Menu } from '@lumino/widgets';
/**
* The command IDs used by the terminal plugin.
@@ -85,7 +86,8 @@ function activate(
runningSessionManagers: IRunningSessionManagers | null
): ITerminalTracker {
const trans = translator.load('jupyterlab');
- const { serviceManager, commands } = app;
+ // const { serviceManager, commands } = app;
+ const { serviceManager } = app;
const category = trans.__('Terminal');
const namespace = 'terminal';
const tracker = new WidgetTracker<MainAreaWidget<ITerminal.ITerminal>>({
@@ -171,57 +173,57 @@ function activate(
addCommands(app, tracker, settingRegistry, translator, options);
- if (mainMenu) {
- // Add "Terminal Theme" menu below "Theme" menu.
- const themeMenu = new Menu({ commands });
- themeMenu.title.label = trans._p('menu', 'Terminal Theme');
- themeMenu.addItem({
- command: CommandIDs.setTheme,
- args: {
- theme: 'inherit',
- displayName: trans.__('Inherit'),
- isPalette: false
- }
- });
- themeMenu.addItem({
- command: CommandIDs.setTheme,
- args: {
- theme: 'light',
- displayName: trans.__('Light'),
- isPalette: false
- }
- });
- themeMenu.addItem({
- command: CommandIDs.setTheme,
- args: { theme: 'dark', displayName: trans.__('Dark'), isPalette: false }
- });
-
- // Add some commands to the "View" menu.
- mainMenu.settingsMenu.addGroup(
- [
- { command: CommandIDs.increaseFont },
- { command: CommandIDs.decreaseFont },
- { type: 'submenu', submenu: themeMenu }
- ],
- 40
- );
-
- // Add terminal creation to the file menu.
- mainMenu.fileMenu.newMenu.addItem({
- command: CommandIDs.createNew,
- rank: 20
- });
-
- // Add terminal close-and-shutdown to the file menu.
- mainMenu.fileMenu.closeAndCleaners.add({
- tracker,
- closeAndCleanupLabel: (n: number) => trans.__('Shutdown Terminal'),
- closeAndCleanup: (current: MainAreaWidget<ITerminal.ITerminal>) => {
- // The widget is automatically disposed upon session shutdown.
- return current.content.session.shutdown();
- }
- } as IFileMenu.ICloseAndCleaner<MainAreaWidget<ITerminal.ITerminal>>);
- }
+ // if (mainMenu) {
+ // // Add "Terminal Theme" menu below "Theme" menu.
+ // const themeMenu = new Menu({ commands });
+ // themeMenu.title.label = trans._p('menu', 'Terminal Theme');
+ // themeMenu.addItem({
+ // command: CommandIDs.setTheme,
+ // args: {
+ // theme: 'inherit',
+ // displayName: trans.__('Inherit'),
+ // isPalette: false
+ // }
+ // });
+ // themeMenu.addItem({
+ // command: CommandIDs.setTheme,
+ // args: {
+ // theme: 'light',
+ // displayName: trans.__('Light'),
+ // isPalette: false
+ // }
+ // });
+ // themeMenu.addItem({
+ // command: CommandIDs.setTheme,
+ // args: { theme: 'dark', displayName: trans.__('Dark'), isPalette: false }
+ // });
+
+ // // Add some commands to the "View" menu.
+ // mainMenu.settingsMenu.addGroup(
+ // [
+ // { command: CommandIDs.increaseFont },
+ // { command: CommandIDs.decreaseFont },
+ // { type: 'submenu', submenu: themeMenu }
+ // ],
+ // 40
+ // );
+
+ // // Add terminal creation to the file menu.
+ // mainMenu.fileMenu.newMenu.addItem({
+ // command: CommandIDs.createNew,
+ // rank: 20
+ // });
+
+ // // Add terminal close-and-shutdown to the file menu.
+ // mainMenu.fileMenu.closeAndCleaners.add({
+ // tracker,
+ // closeAndCleanupLabel: (n: number) => trans.__('Shutdown Terminal'),
+ // closeAndCleanup: (current: MainAreaWidget<ITerminal.ITerminal>) => {
+ // // The widget is automatically disposed upon session shutdown.
+ // return current.content.session.shutdown();
+ // }
+ // } as IFileMenu.ICloseAndCleaner<MainAreaWidget<ITerminal.ITerminal>>);
+ // }
if (palette) {
// Add command palette items.
diff --git a/packages/theme-dark-extension/README.md b/packages/theme-dark-extension/README.md
deleted file mode 100644
index 6c19ca27cd..0000000000
--- a/packages/theme-dark-extension/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# @jupyterlab/theme-dark-extension
-
-A JupyterLab theme extension which provides the default dark-colored theme.
diff --git a/packages/theme-dark-extension/package.json b/packages/theme-dark-extension/package.json
deleted file mode 100644
index eaded8c880..0000000000
--- a/packages/theme-dark-extension/package.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
- "name": "@jupyterlab/theme-dark-extension",
- "version": "3.4.3",
- "description": "JupyterLab - Default Dark Theme",
- "homepage": "https://github.com/jupyterlab/jupyterlab",
- "bugs": {
- "url": "https://github.com/jupyterlab/jupyterlab/issues"
- },
- "repository": {
- "type": "git",
- "url": "https://github.com/jupyterlab/jupyterlab.git"
- },
- "license": "BSD-3-Clause",
- "author": "Project Jupyter",
- "sideEffects": true,
- "main": "lib/index.js",
- "types": "lib/index.d.ts",
- "directories": {
- "lib": "lib/"
- },
- "files": [
- "lib/*.d.ts",
- "lib/*.js.map",
- "lib/*.js",
- "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}",
- "style/index.js"
- ],
- "scripts": {
- "build": "tsc -b",
- "clean": "rimraf lib && rimraf tsconfig.tsbuildinfo",
- "watch": "tsc -b --watch"
- },
- "dependencies": {
- "@jupyterlab/application": "^3.4.3",
- "@jupyterlab/apputils": "^3.4.3",
- "@jupyterlab/translation": "^3.4.3"
- },
- "devDependencies": {
- "rimraf": "~3.0.0",
- "typedoc": "~0.21.2",
- "typescript": "~4.1.3"
- },
- "publishConfig": {
- "access": "public"
- },
- "jupyterlab": {
- "extension": true,
- "themePath": "style/theme.css"
- }
-}
diff --git a/packages/theme-dark-extension/src/index.ts b/packages/theme-dark-extension/src/index.ts
deleted file mode 100644
index 6f20ea8e9a..0000000000
--- a/packages/theme-dark-extension/src/index.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) Jupyter Development Team.
-// Distributed under the terms of the Modified BSD License.
-/**
- * @packageDocumentation
- * @module theme-dark-extension
- */
-
-import {
- JupyterFrontEnd,
- JupyterFrontEndPlugin
-} from '@jupyterlab/application';
-import { IThemeManager } from '@jupyterlab/apputils';
-import { ITranslator } from '@jupyterlab/translation';
-
-/**
- * A plugin for the Jupyter Dark Theme.
- */
-const plugin: JupyterFrontEndPlugin<void> = {
- id: '@jupyterlab/theme-dark-extension:plugin',
- requires: [IThemeManager, ITranslator],
- activate: (
- app: JupyterFrontEnd,
- manager: IThemeManager,
- translator: ITranslator
- ) => {
- const trans = translator.load('jupyterlab');
- const style = '@jupyterlab/theme-dark-extension/index.css';
- manager.register({
- name: 'JupyterLab Dark',
- displayName: trans.__('JupyterLab Dark'),
- isLight: false,
- themeScrollbars: true,
- load: () => manager.loadCSS(style),
- unload: () => Promise.resolve(undefined)
- });
- },
- autoStart: true
-};
-
-export default plugin;
diff --git a/packages/theme-dark-extension/style/variables.css b/packages/theme-dark-extension/style/variables.css
deleted file mode 100644
index ff87a764c3..0000000000
--- a/packages/theme-dark-extension/style/variables.css
+++ /dev/null
@@ -1,410 +0,0 @@
-/*-----------------------------------------------------------------------------
-| Copyright (c) Jupyter Development Team.
-| Distributed under the terms of the Modified BSD License.
-|----------------------------------------------------------------------------*/
-
-/*
-The following CSS variables define the main, public API for styling JupyterLab.
-These variables should be used by all plugins wherever possible. In other
-words, plugins should not define custom colors, sizes, etc unless absolutely
-necessary. This enables users to change the visual theme of JupyterLab
-by changing these variables.
-
-Many variables appear in an ordered sequence (0,1,2,3). These sequences
-are designed to work well together, so for example, `--jp-border-color1` should
-be used with `--jp-layout-color1`. The numbers have the following meanings:
-
-* 0: super-primary, reserved for special emphasis
-* 1: primary, most important under normal situations
-* 2: secondary, next most important under normal situations
-* 3: tertiary, next most important under normal situations
-
-Throughout JupyterLab, we are mostly following principles from Google's
-Material Design when selecting colors. We are not, however, following
-all of MD as it is not optimized for dense, information rich UIs.
-*/
-
-:root {
- /* Elevation
- *
- * We style box-shadows using Material Design's idea of elevation. These particular numbers are taken from here:
- *
- * https://github.com/material-components/material-components-web
- * https://material-components-web.appspot.com/elevation.html
- */
-
- /* The dark theme shadows need a bit of work, but this will probably also require work on the core layout
- * colors used in the theme as well. */
- --jp-shadow-base-lightness: 32;
- --jp-shadow-umbra-color: rgba(
- var(--jp-shadow-base-lightness),
- var(--jp-shadow-base-lightness),
- var(--jp-shadow-base-lightness),
- 0.2
- );
- --jp-shadow-penumbra-color: rgba(
- var(--jp-shadow-base-lightness),
- var(--jp-shadow-base-lightness),
- var(--jp-shadow-base-lightness),
- 0.14
- );
- --jp-shadow-ambient-color: rgba(
- var(--jp-shadow-base-lightness),
- var(--jp-shadow-base-lightness),
- var(--jp-shadow-base-lightness),
- 0.12
- );
- --jp-elevation-z0: none;
- --jp-elevation-z1: 0px 2px 1px -1px var(--jp-shadow-umbra-color),
- 0px 1px 1px 0px var(--jp-shadow-penumbra-color),
- 0px 1px 3px 0px var(--jp-shadow-ambient-color);
- --jp-elevation-z2: 0px 3px 1px -2px var(--jp-shadow-umbra-color),
- 0px 2px 2px 0px var(--jp-shadow-penumbra-color),
- 0px 1px 5px 0px var(--jp-shadow-ambient-color);
- --jp-elevation-z4: 0px 2px 4px -1px var(--jp-shadow-umbra-color),
- 0px 4px 5px 0px var(--jp-shadow-penumbra-color),
- 0px 1px 10px 0px var(--jp-shadow-ambient-color);
- --jp-elevation-z6: 0px 3px 5px -1px var(--jp-shadow-umbra-color),
- 0px 6px 10px 0px var(--jp-shadow-penumbra-color),
- 0px 1px 18px 0px var(--jp-shadow-ambient-color);
- --jp-elevation-z8: 0px 5px 5px -3px var(--jp-shadow-umbra-color),
- 0px 8px 10px 1px var(--jp-shadow-penumbra-color),
- 0px 3px 14px 2px var(--jp-shadow-ambient-color);
- --jp-elevation-z12: 0px 7px 8px -4px var(--jp-shadow-umbra-color),
- 0px 12px 17px 2px var(--jp-shadow-penumbra-color),
- 0px 5px 22px 4px var(--jp-shadow-ambient-color);
- --jp-elevation-z16: 0px 8px 10px -5px var(--jp-shadow-umbra-color),
- 0px 16px 24px 2px var(--jp-shadow-penumbra-color),
- 0px 6px 30px 5px var(--jp-shadow-ambient-color);
- --jp-elevation-z20: 0px 10px 13px -6px var(--jp-shadow-umbra-color),
- 0px 20px 31px 3px var(--jp-shadow-penumbra-color),
- 0px 8px 38px 7px var(--jp-shadow-ambient-color);
- --jp-elevation-z24: 0px 11px 15px -7px var(--jp-shadow-umbra-color),
- 0px 24px 38px 3px var(--jp-shadow-penumbra-color),
- 0px 9px 46px 8px var(--jp-shadow-ambient-color);
-
- /* Borders
- *
- * The following variables, specify the visual styling of borders in JupyterLab.
- */
-
- --jp-border-width: 1px;
- --jp-border-color0: var(--md-grey-700);
- --jp-border-color1: var(--md-grey-700);
- --jp-border-color2: var(--md-grey-800);
- --jp-border-color3: var(--md-grey-900);
- --jp-inverse-border-color: var(--md-grey-600);
- --jp-border-radius: 2px;
-
- /* UI Fonts
- *
- * The UI font CSS variables are used for the typography all of the JupyterLab
- * user interface elements that are not directly user generated content.
- *
- * The font sizing here is done assuming that the body font size of --jp-ui-font-size1
- * is applied to a parent element. When children elements, such as headings, are sized
- * in em all things will be computed relative to that body size.
- */
-
- --jp-ui-font-scale-factor: 1.2;
- --jp-ui-font-size0: 0.83333em;
- --jp-ui-font-size1: 13px; /* Base font size */
- --jp-ui-font-size2: 1.2em;
- --jp-ui-font-size3: 1.44em;
-
- --jp-ui-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica,
- Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
-
- /*
- * Use these font colors against the corresponding main layout colors.
- * In a light theme, these go from dark to light.
- */
-
- /* Defaults use Material Design specification */
- --jp-ui-font-color0: rgba(255, 255, 255, 1);
- --jp-ui-font-color1: rgba(255, 255, 255, 0.87);
- --jp-ui-font-color2: rgba(255, 255, 255, 0.54);
- --jp-ui-font-color3: rgba(255, 255, 255, 0.38);
-
- /*
- * Use these against the brand/accent/warn/error colors.
- * These will typically go from light to darker, in both a dark and light theme.
- */
-
- --jp-ui-inverse-font-color0: rgba(0, 0, 0, 1);
- --jp-ui-inverse-font-color1: rgba(0, 0, 0, 0.8);
- --jp-ui-inverse-font-color2: rgba(0, 0, 0, 0.5);
- --jp-ui-inverse-font-color3: rgba(0, 0, 0, 0.3);
-
- /* Content Fonts
- *
- * Content font variables are used for typography of user generated content.
- *
- * The font sizing here is done assuming that the body font size of --jp-content-font-size1
- * is applied to a parent element. When children elements, such as headings, are sized
- * in em all things will be computed relative to that body size.
- */
-
- --jp-content-line-height: 1.6;
- --jp-content-font-scale-factor: 1.2;
- --jp-content-font-size0: 0.83333em;
- --jp-content-font-size1: 14px; /* Base font size */
- --jp-content-font-size2: 1.2em;
- --jp-content-font-size3: 1.44em;
- --jp-content-font-size4: 1.728em;
- --jp-content-font-size5: 2.0736em;
-
- /* This gives a magnification of about 125% in presentation mode over normal. */
- --jp-content-presentation-font-size1: 17px;
-
- --jp-content-heading-line-height: 1;
- --jp-content-heading-margin-top: 1.2em;
- --jp-content-heading-margin-bottom: 0.8em;
- --jp-content-heading-font-weight: 500;
-
- /* Defaults use Material Design specification */
- --jp-content-font-color0: rgba(255, 255, 255, 1);
- --jp-content-font-color1: rgba(255, 255, 255, 1);
- --jp-content-font-color2: rgba(255, 255, 255, 0.7);
- --jp-content-font-color3: rgba(255, 255, 255, 0.5);
-
- --jp-content-link-color: var(--md-blue-300);
-
- --jp-content-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI',
- Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
- 'Segoe UI Symbol';
-
- /*
- * Code Fonts
- *
- * Code font variables are used for typography of code and other monospaces content.
- */
-
- --jp-code-font-size: 13px;
- --jp-code-line-height: 1.3077; /* 17px for 13px base */
- --jp-code-padding: 5px; /* 5px for 13px base, codemirror highlighting needs integer px value */
- --jp-code-font-family-default: Menlo, Consolas, 'DejaVu Sans Mono', monospace;
- --jp-code-font-family: var(--jp-code-font-family-default);
-
- /* This gives a magnification of about 125% in presentation mode over normal. */
- --jp-code-presentation-font-size: 16px;
-
- /* may need to tweak cursor width if you change font size */
- --jp-code-cursor-width0: 1.4px;
- --jp-code-cursor-width1: 2px;
- --jp-code-cursor-width2: 4px;
-
- /* Layout
- *
- * The following are the main layout colors use in JupyterLab. In a light
- * theme these would go from light to dark.
- */
-
- --jp-layout-color0: #111111;
- --jp-layout-color1: var(--md-grey-900);
- --jp-layout-color2: var(--md-grey-800);
- --jp-layout-color3: var(--md-grey-700);
- --jp-layout-color4: var(--md-grey-600);
-
- /* Inverse Layout
- *
- * The following are the inverse layout colors use in JupyterLab. In a light
- * theme these would go from dark to light.
- */
-
- --jp-inverse-layout-color0: white;
- --jp-inverse-layout-color1: white;
- --jp-inverse-layout-color2: var(--md-grey-200);
- --jp-inverse-layout-color3: var(--md-grey-400);
- --jp-inverse-layout-color4: var(--md-grey-600);
-
- /* Brand/accent */
-
- --jp-brand-color0: var(--md-blue-700);
- --jp-brand-color1: var(--md-blue-500);
- --jp-brand-color2: var(--md-blue-300);
- --jp-brand-color3: var(--md-blue-100);
- --jp-brand-color4: var(--md-blue-50);
-
- --jp-accent-color0: var(--md-green-700);
- --jp-accent-color1: var(--md-green-500);
- --jp-accent-color2: var(--md-green-300);
- --jp-accent-color3: var(--md-green-100);
-
- /* State colors (warn, error, success, info) */
-
- --jp-warn-color0: var(--md-orange-700);
- --jp-warn-color1: var(--md-orange-500);
- --jp-warn-color2: var(--md-orange-300);
- --jp-warn-color3: var(--md-orange-100);
-
- --jp-error-color0: var(--md-red-700);
- --jp-error-color1: var(--md-red-500);
- --jp-error-color2: var(--md-red-300);
- --jp-error-color3: var(--md-red-100);
-
- --jp-success-color0: var(--md-green-700);
- --jp-success-color1: var(--md-green-500);
- --jp-success-color2: var(--md-green-300);
- --jp-success-color3: var(--md-green-100);
-
- --jp-info-color0: var(--md-cyan-700);
- --jp-info-color1: var(--md-cyan-500);
- --jp-info-color2: var(--md-cyan-300);
- --jp-info-color3: var(--md-cyan-100);
-
- /* Cell specific styles */
-
- --jp-cell-padding: 5px;
-
- --jp-cell-collapser-width: 8px;
- --jp-cell-collapser-min-height: 20px;
- --jp-cell-collapser-not-active-hover-opacity: 0.6;
-
- --jp-cell-editor-background: var(--jp-layout-color1);
- --jp-cell-editor-border-color: var(--md-grey-700);
- --jp-cell-editor-box-shadow: inset 0 0 2px var(--md-blue-300);
- --jp-cell-editor-active-background: var(--jp-layout-color0);
- --jp-cell-editor-active-border-color: var(--jp-brand-color1);
-
- --jp-cell-prompt-width: 64px;
- --jp-cell-prompt-font-family: var(--jp-code-font-family-default);
- --jp-cell-prompt-letter-spacing: 0px;
- --jp-cell-prompt-opacity: 1;
- --jp-cell-prompt-not-active-opacity: 1;
- --jp-cell-prompt-not-active-font-color: var(--md-grey-300);
-
- /* A custom blend of MD grey and blue 600
- * See https://meyerweb.com/eric/tools/color-blend/#546E7A:1E88E5:5:hex */
- --jp-cell-inprompt-font-color: #307fc1;
- /* A custom blend of MD grey and orange 600
- * https://meyerweb.com/eric/tools/color-blend/#546E7A:F4511E:5:hex */
- --jp-cell-outprompt-font-color: #bf5b3d;
-
- /* Notebook specific styles */
-
- --jp-notebook-padding: 10px;
- --jp-notebook-select-background: var(--jp-layout-color1);
- --jp-notebook-multiselected-color: rgba(33, 150, 243, 0.24);
-
- /* The scroll padding is calculated to fill enough space at the bottom of the
- notebook to show one single-line cell (with appropriate padding) at the top
- when the notebook is scrolled all the way to the bottom. We also subtract one
- pixel so that no scrollbar appears if we have just one single-line cell in the
- notebook. This padding is to enable a 'scroll past end' feature in a notebook.
- */
- --jp-notebook-scroll-padding: calc(
- 100% - var(--jp-code-font-size) * var(--jp-code-line-height) -
- var(--jp-code-padding) - var(--jp-cell-padding) - 1px
- );
-
- /* Rendermime styles */
-
- --jp-rendermime-error-background: rgba(244, 67, 54, 0.28);
- --jp-rendermime-table-row-background: var(--md-grey-900);
- --jp-rendermime-table-row-hover-background: rgba(3, 169, 244, 0.2);
-
- /* Dialog specific styles */
-
- --jp-dialog-background: rgba(0, 0, 0, 0.6);
-
- /* Console specific styles */
-
- --jp-console-padding: 10px;
-
- /* Toolbar specific styles */
-
- --jp-toolbar-border-color: var(--jp-border-color2);
- --jp-toolbar-micro-height: 8px;
- --jp-toolbar-background: var(--jp-layout-color1);
- --jp-toolbar-box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.8);
- --jp-toolbar-header-margin: 4px 4px 0px 4px;
- --jp-toolbar-active-background: var(--jp-layout-color0);
-
- /* Statusbar specific styles */
-
- --jp-statusbar-height: 24px;
-
- /* Input field styles */
-
- --jp-input-box-shadow: inset 0 0 2px var(--md-blue-300);
- --jp-input-active-background: var(--jp-layout-color0);
- --jp-input-hover-background: var(--jp-layout-color2);
- --jp-input-background: var(--md-grey-800);
- --jp-input-border-color: var(--jp-inverse-border-color);
- --jp-input-active-border-color: var(--jp-brand-color1);
- --jp-input-active-box-shadow-color: rgba(19, 124, 189, 0.3);
-
- /* General editor styles */
-
- --jp-editor-selected-background: var(--jp-layout-color2);
- --jp-editor-selected-focused-background: rgba(33, 150, 243, 0.24);
- --jp-editor-cursor-color: var(--jp-ui-font-color0);
-
- /* Code mirror specific styles */
-
- --jp-mirror-editor-keyword-color: var(--md-green-500);
- --jp-mirror-editor-atom-color: var(--md-blue-300);
- --jp-mirror-editor-number-color: var(--md-green-400);
- --jp-mirror-editor-def-color: var(--md-blue-600);
- --jp-mirror-editor-variable-color: var(--md-grey-300);
- --jp-mirror-editor-variable-2-color: var(--md-blue-400);
- --jp-mirror-editor-variable-3-color: var(--md-green-600);
- --jp-mirror-editor-punctuation-color: var(--md-blue-400);
- --jp-mirror-editor-property-color: var(--md-blue-400);
- --jp-mirror-editor-operator-color: #aa22ff;
- --jp-mirror-editor-comment-color: #408080;
- --jp-mirror-editor-string-color: #ff7070;
- --jp-mirror-editor-string-2-color: var(--md-purple-300);
- --jp-mirror-editor-meta-color: #aa22ff;
- --jp-mirror-editor-qualifier-color: #555;
- --jp-mirror-editor-builtin-color: var(--md-green-600);
- --jp-mirror-editor-bracket-color: #997;
- --jp-mirror-editor-tag-color: var(--md-green-700);
- --jp-mirror-editor-attribute-color: var(--md-blue-700);
- --jp-mirror-editor-header-color: var(--md-blue-500);
- --jp-mirror-editor-quote-color: var(--md-green-300);
- --jp-mirror-editor-link-color: var(--md-blue-700);
- --jp-mirror-editor-error-color: #f00;
- --jp-mirror-editor-hr-color: #999;
-
- /* Vega extension styles */
-
- --jp-vega-background: var(--md-grey-400);
-
- /* Sidebar-related styles */
-
- --jp-sidebar-min-width: 250px;
-
- /* Search-related styles */
-
- --jp-search-toggle-off-opacity: 0.6;
- --jp-search-toggle-hover-opacity: 0.8;
- --jp-search-toggle-on-opacity: 1;
- --jp-search-selected-match-background-color: rgb(255, 225, 0);
- --jp-search-selected-match-color: black;
- --jp-search-unselected-match-background-color: var(
- --jp-inverse-layout-color0
- );
- --jp-search-unselected-match-color: var(--jp-ui-inverse-font-color0);
-
- /* scrollbar related styles. Supports every browser except Edge. */
-
- /* colors based on JetBrain's Darcula theme */
-
- --jp-scrollbar-background-color: #3f4244;
- --jp-scrollbar-thumb-color: 88, 96, 97; /* need to specify thumb color as an RGB triplet */
-
- --jp-scrollbar-endpad: 3px; /* the minimum gap between the thumb and the ends of a scrollbar */
-
- /* hacks for setting the thumb shape. These do nothing in Firefox */
-
- --jp-scrollbar-thumb-margin: 3.5px; /* the space in between the sides of the thumb and the track */
- --jp-scrollbar-thumb-radius: 9px; /* set to a large-ish value for rounded endcaps on the thumb */
-
- /* Icon colors that work well with light or dark backgrounds */
- --jp-icon-contrast-color0: var(--md-purple-600);
- --jp-icon-contrast-color1: var(--md-green-600);
- --jp-icon-contrast-color2: var(--md-pink-600);
- --jp-icon-contrast-color3: var(--md-blue-600);
-}
diff --git a/packages/theme-dark-extension/typedoc.json b/packages/theme-dark-extension/typedoc.json
deleted file mode 100644
index 7ddb378afe..0000000000
--- a/packages/theme-dark-extension/typedoc.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "out": "../../docs/api/theme-dark-extension",
- "theme": "../../typedoc-theme"
-}
diff --git a/packages/toc-extension/src/index.ts b/packages/toc-extension/src/index.ts
index 334a5a2a2d..94ac4441ed 100644
--- a/packages/toc-extension/src/index.ts
+++ b/packages/toc-extension/src/index.ts
@@ -85,7 +85,7 @@ async function activateTOC(
toc.node.setAttribute('role', 'region');
toc.node.setAttribute('aria-label', trans.__('Table of Contents section'));
- app.shell.add(toc, 'left', { rank: 400 });
+ // app.shell.add(toc, 'left', { rank: 400 });
app.commands.addCommand(CommandIDs.runCells, {
execute: args => {
diff --git a/packages/translation-extension/schema/plugin.json b/packages/translation-extension/schema/plugin.json
index 2ef8ed8bb7..b6cf3f74e9 100644
--- a/packages/translation-extension/schema/plugin.json
+++ b/packages/translation-extension/schema/plugin.json
@@ -34,7 +34,7 @@
"type": "string",
"title": "Language locale",
"description": "Set the interface display language. Examples: 'es_CO', 'fr'.",
- "default": "en"
+ "default": "zh_CN"
},
"stringsPrefix": {
"type": "string",
diff --git a/packages/ui-components/package.json b/packages/ui-components/package.json
index beb11f76d7..78abe9a098 100644
--- a/packages/ui-components/package.json
+++ b/packages/ui-components/package.json
@@ -50,6 +50,7 @@
"@lumino/commands": "^1.19.0",
"@lumino/coreutils": "^1.11.0",
"@lumino/disposable": "^1.10.0",
+ "@lumino/messaging": "^1.10.0",
"@lumino/signaling": "^1.10.0",
"@lumino/virtualdom": "^1.14.0",
"@lumino/widgets": "^1.30.0",
diff --git a/packages/ui-components/src/icon/widgets/tabbarsvg.ts b/packages/ui-components/src/icon/widgets/tabbarsvg.ts
index fbcae09f57..330b751260 100644
--- a/packages/ui-components/src/icon/widgets/tabbarsvg.ts
+++ b/packages/ui-components/src/icon/widgets/tabbarsvg.ts
@@ -7,6 +7,8 @@ import { LabIconStyle } from '../../style';
import { classes } from '../../utils';
import { addIcon, closeIcon } from '../iconimports';
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
+import { Message } from '@lumino/messaging';
+import { ElementInlineStyle, VirtualDOM } from '@lumino/virtualdom';
/**
* a widget which displays titles as a single row or column of tabs.
@@ -29,6 +31,20 @@ export class TabBarSvg<T> extends TabBar<T> {
title: trans.__('New Launcher')
});
}
+
+ protected onUpdateRequest(msg: Message): void {
+ let titles = this.titles;
+ let renderer = this.renderer;
+ let currentTitle = this.currentTitle;
+ let content = new Array<VirtualElement>(titles.length);
+ for (let i = 0, n = titles.length; i < n; ++i) {
+ let title = titles[i];
+ let current = title === currentTitle;
+ let zIndex = current ? 3 : 0;
+ content[i] = renderer.renderTab({ title, current, zIndex });
+ }
+ VirtualDOM.render(content, this.contentNode);
+ }
}
export namespace TabBarSvg {
@@ -59,6 +75,13 @@ export namespace TabBarSvg {
closeIcon
) as unknown) as VirtualElement;
}
+
+ createTabStyle(data: TabBar.IRenderData<any>): ElementInlineStyle {
+ if (data.zIndex === 0) {
+ return {};
+ }
+ return { zIndex: `${data.zIndex}` };
+ }
}
export const defaultRenderer = new Renderer();