From 8e8358a748b7ff210306be5a987a856bf56ad570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A2=96=E9=80=B8?= <49649786+Zuoqiu-Yingyi@users.noreply.github.com> Date: Tue, 31 Oct 2023 13:20:35 +0800 Subject: [PATCH] hore(jupyter-client): release v0.2.1 --- .github/workflows/release-please.yml | 2 +- package.json | 10 +- public/i18n/en_US.json | 17 ++- public/i18n/zh_CHT.json | 17 ++- public/i18n/zh_CN.json | 17 ++- public/plugin.json | 22 +++- src/index.ts | 165 ++++++++++++++++++++++++--- 7 files changed, 217 insertions(+), 33 deletions(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 7e4626e..e681e96 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -14,7 +14,7 @@ permissions: env: PACKAGE_NAME: jupyter-client - PACKAGE_VERSION: 0.2.0 + PACKAGE_VERSION: 0.2.1 jobs: release-please: diff --git a/package.json b/package.json index 2e8d76a..2079bf5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "jupyter-client", "private": true, - "version": "0.2.0", + "version": "0.2.1", "type": "module", "scripts": { "dev": "vite", @@ -14,18 +14,18 @@ }, "devDependencies": { "@jupyter-lsp/theme-vscode": "3.0.0-rc.0", - "@jupyterlab/services": "^7.0.6", - "@jupyterlab/ui-components": "^4.0.6", + "@jupyterlab/services": "^7.0.7", + "@jupyterlab/ui-components": "^4.0.7", "@sveltejs/vite-plugin-svelte": "^2.4.6", "@tsconfig/svelte": "^5.0.2", "less": "^4.2.0", "strip-ansi": "^7.1.0", - "svelte": "^4.2.0", + "svelte": "^4.2.2", "svelte-check": "^2.10.3", "svelte-preprocess-less": "^0.4.0", "tslib": "^2.6.2", "typescript": "^5.2.2", - "vite": "^4.4.9", + "vite": "^4.5.0", "xterm": "^5.3.0", "xterm-addon-fit": "^0.7.0" }, diff --git a/public/i18n/en_US.json b/public/i18n/en_US.json index 939ff87..fc83d9e 100644 --- a/public/i18n/en_US.json +++ b/public/i18n/en_US.json @@ -1,5 +1,14 @@ { "commands": { + "openJupyterBrowser": { + "text": "Open Jupyter in Browser" + }, + "openJupyterTab": { + "text": "Open Jupyter in New Tab" + }, + "openJupyterWindow": { + "text": "Open Jupyter in New Window" + }, "runSelectedCells": { "text": "Run selected cells" }, @@ -197,14 +206,14 @@ "title": "Code execution" }, "globalTab": { - "enable": { - "description": "Enable to attempt to establish connection with Jupyter service", - "title": "Enable Jupyter client" - }, "delay": { "description": "The delay time when calling the Jupyter kernel language service to get context help and code suggestions.
Unit: milliseconds", "title": "Language service call delay" }, + "enable": { + "description": "Enable to attempt to establish connection with Jupyter service", + "title": "Enable Jupyter client" + }, "title": "Global" }, "importTab": { diff --git a/public/i18n/zh_CHT.json b/public/i18n/zh_CHT.json index 45327b3..80e414b 100644 --- a/public/i18n/zh_CHT.json +++ b/public/i18n/zh_CHT.json @@ -1,5 +1,14 @@ { "commands": { + "openJupyterBrowser": { + "text": "在瀏覽器中打開 Jupyter" + }, + "openJupyterTab": { + "text": "在新頁籤中打開 Jupyter" + }, + "openJupyterWindow": { + "text": "在新窗口中打開 Jupyter" + }, "runSelectedCells": { "text": "運行所選代碼塊" }, @@ -197,14 +206,14 @@ "title": "代碼運行" }, "globalTab": { - "enable": { - "description": "開啟後將嘗試與 Jupyter 服務建立連接", - "title": "啟用 Jupyter 客戶端" - }, "delay": { "description": "調用 Jupyter 內核語言服務獲取上下文幫助與代碼建議時的延時時間
單位:毫秒", "title": "語言服務調用延時" }, + "enable": { + "description": "開啟後將嘗試與 Jupyter 服務建立連接", + "title": "啟用 Jupyter 客戶端" + }, "title": "全局" }, "importTab": { diff --git a/public/i18n/zh_CN.json b/public/i18n/zh_CN.json index 217f45c..08dc67d 100644 --- a/public/i18n/zh_CN.json +++ b/public/i18n/zh_CN.json @@ -1,5 +1,14 @@ { "commands": { + "openJupyterBrowser": { + "text": "在浏览器中打开 Jupyter" + }, + "openJupyterTab": { + "text": "在新页签中打开 Jupyter" + }, + "openJupyterWindow": { + "text": "在新窗口中打开 Jupyter" + }, "runSelectedCells": { "text": "运行所选代码块" }, @@ -197,14 +206,14 @@ "title": "代码运行" }, "globalTab": { - "enable": { - "description": "开启后将尝试与 Jupyter 服务建立连接", - "title": "启用 Jupyter 客户端" - }, "delay": { "description": "调用 Jupyter 内核语言服务获取上下文帮助与代码建议时的延时时间
单位:毫秒", "title": "语言服务调用延时" }, + "enable": { + "description": "开启后将尝试与 Jupyter 服务建立连接", + "title": "启用 Jupyter 客户端" + }, "title": "全局" }, "importTab": { diff --git a/public/plugin.json b/public/plugin.json index 5972800..9b5d3e9 100644 --- a/public/plugin.json +++ b/public/plugin.json @@ -2,8 +2,26 @@ "name": "jupyter-client", "author": "Zuoqiu Yingyi", "url": "https://github.com/Zuoqiu-Yingyi/siyuan-plugin-jupyter-client", - "version": "0.2.0", - "minAppVersion": "2.10.3", + "version": "0.2.1", + "minAppVersion": "2.10.13", + "keywords": [ + "代码", + "程式碼", + "执行代码", + "執行程式碼", + "code", + "execute", + "jupyter", + "notebook", + "lab", + "hub" + ], + "backends": [ + "all" + ], + "frontends": [ + "all" + ], "displayName": { "default": "Jupyter Client", "zh_CN": "Jupyter 客户端", diff --git a/src/index.ts b/src/index.ts index ca6b6ab..a7c2d7a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -47,6 +47,7 @@ import icon_jupyter_client_session_notebook from "./assets/symbols/icon-jupyter- import * as sdk from "@siyuan-community/siyuan-sdk"; import Item from "@workspace/components/siyuan/menu/Item.svelte" +import JupyterTab from "@workspace/components/siyuan/tab/IframeTab.svelte"; import Settings from "./components/Settings.svelte"; import JupyterDock from "./components/JupyterDock.svelte"; import JupyterInspectDock from "./components/JupyterInspectDock.svelte"; @@ -80,6 +81,7 @@ import { toUint8Array } from "@workspace/utils/misc/base64"; import { encode } from "@workspace/utils/misc/base64"; import { select } from "@workspace/utils/dom/selection"; import { replaceRangeWithText } from "@workspace/utils/dom/range"; +import { openWindow } from "@workspace/utils/window/open"; import uuid from "@workspace/utils/misc/uuid"; import CONSTANTS from "./constants"; @@ -114,7 +116,8 @@ import type { IClickEditorContentEvent, IClickEditorTitleIconEvent, IDestroyProtyleEvent, - ILoadedProtyleEvent, + ILoadedProtyleStaticEvent, + ISwitchProtyleEvent, } from "@workspace/types/siyuan/events"; import type { THandlersWrapper } from "@workspace/utils/worker/bridge"; import type { WorkerHandlers } from "./workers/jupyter"; @@ -134,9 +137,14 @@ export type TMenuContext = IBlockMenuContext | { isMultiBlock: false, id: BlockID, }; +export interface IJupyterTab extends siyuan.ITabModel { + component?: InstanceType; +} export default class JupyterClientPlugin extends siyuan.Plugin { static readonly GLOBAL_CONFIG_NAME = "global-config"; + public static readonly CUSTOM_TAB_TYPE_JUPYTER = "-jupyter-tab"; + static readonly EDIT_KEYBOARD_EVENT_STATUS_INSPECT: IKeyboardStatus = { type: "keyup", altKey: false, @@ -160,7 +168,12 @@ export default class JupyterClientPlugin extends siyuan.Plugin { public readonly logger: InstanceType; public readonly client: InstanceType; + protected readonly TOP_BAR_MENU_ID: string; protected readonly SETTINGS_DIALOG_ID: string; + protected readonly CUSTOM_TAB_ID_JUPYTER: string; + + protected readonly jupyterTab: ReturnType; + protected topBarButton?: HTMLElement; // 顶部菜单栏按钮 public config: IConfig = DEFAULT_CONFIG; protected worker?: InstanceType; // worker @@ -207,7 +220,10 @@ export default class JupyterClientPlugin extends siyuan.Plugin { this.logger = new Logger(this.name); this.client = new sdk.Client(undefined, "fetch"); + this.TOP_BAR_MENU_ID = `${this.name}-top-bar-menu`; this.SETTINGS_DIALOG_ID = `${this.name}-settings-dialog`; + this.CUSTOM_TAB_ID_JUPYTER = `${this.name}${JupyterClientPlugin.CUSTOM_TAB_TYPE_JUPYTER}`; + this.handlers = { gotoBlock: { this: this, @@ -238,6 +254,29 @@ export default class JupyterClientPlugin extends siyuan.Plugin { }, } as const; + /* 注册页签 */ + this.jupyterTab = this.addTab({ + type: JupyterClientPlugin.CUSTOM_TAB_TYPE_JUPYTER, + init() { + // plugin.logger.debug("tab-init"); + // plugin.logger.debug(this); + + const tab: IJupyterTab = this; + tab.component = new JupyterTab({ + target: tab.element, + props: { + ...tab.data, + }, + }); + }, + destroy() { + // plugin.logger.debug("tab-destroy"); + + const tab: IJupyterTab = this; + tab.component?.$destroy(); + }, + }); + /** * 注册自定义 HTMLElement 组件 * REF: https://developer.mozilla.org/zh-CN/docs/Web/API/CustomElementRegistry @@ -426,6 +465,28 @@ export default class JupyterClientPlugin extends siyuan.Plugin { }, }); + this.addCommand({ // 在新页签中打开 Jupyter + langKey: "open-jupyter-tab", + langText: this.i18n.commands.openJupyterTab.text, + hotkey: "", // 默认快捷键 + customHotkey: "", // 自定义快捷键 + callback: this.openJupyterTab, + }); + this.addCommand({ // 在浏览器中打开 Jupyter + langKey: "open-jupyter-browser", + langText: this.i18n.commands.openJupyterBrowser.text, + hotkey: "", // 默认快捷键 + customHotkey: "", // 自定义快捷键 + callback: this.openJupyterBrowser, + }); + this.addCommand({ // 在新窗口中打开 Jupyter + langKey: "open-jupyter-window", + langText: this.i18n.commands.openJupyterWindow.text, + hotkey: "", // 默认快捷键 + customHotkey: "", // 自定义快捷键 + callback: this.openJupyterWindow, + }); + /* 加载数据 */ this.loadData(JupyterClientPlugin.GLOBAL_CONFIG_NAME) .then(config => { @@ -461,19 +522,55 @@ export default class JupyterClientPlugin extends siyuan.Plugin { this.eventBus.on("click-editortitleicon", this.blockMenuEventListener); this.eventBus.on("click-blockicon", this.blockMenuEventListener); this.eventBus.on("click-editorcontent", this.clickEditorContentEventListener); - this.eventBus.on("loaded-protyle", this.loadedProtyleEventListener); + this.eventBus.on("loaded-protyle-static", this.loadedProtyleEventListener); + this.eventBus.on("switch-protyle", this.loadedProtyleEventListener); this.eventBus.off("destroy-protyle", this.destroyProtyleEventListener); }); } onLayoutReady(): void { + /* 添加菜单项 */ + this.topBarButton = this.addTopBar({ + icon: "icon-jupyter-client", + title: this.displayName, + position: "right", + callback: e => { + const menu = new siyuan.Menu(this.TOP_BAR_MENU_ID); + menu.addItem({ + icon: "iconLayout", + label: this.i18n.commands.openJupyterTab.text, + click: this.openJupyterTab, + }); + menu.addItem({ + icon: "iconOpen", + label: this.i18n.commands.openJupyterBrowser.text, + click: this.openJupyterBrowser, + }); + menu.addItem({ + icon: "iconOpenWindow", + label: this.i18n.commands.openJupyterWindow.text, + click: this.openJupyterWindow, + }); + if (FLAG_MOBILE) { + menu.fullscreen(); + } + else { + menu.open({ + x: globalThis.siyuan?.coordinates?.pageX ?? 0, + y: globalThis.siyuan?.coordinates?.pageY ?? 0, + isLeft: true, + }); + } + }, + }); } onunload(): void { this.eventBus.off("click-editortitleicon", this.blockMenuEventListener); this.eventBus.off("click-blockicon", this.blockMenuEventListener); this.eventBus.off("click-editorcontent", this.clickEditorContentEventListener); - this.eventBus.off("loaded-protyle", this.loadedProtyleEventListener); + this.eventBus.off("loaded-protyle-static", this.loadedProtyleEventListener); + this.eventBus.off("switch-protyle", this.loadedProtyleEventListener); this.eventBus.off("destroy-protyle", this.destroyProtyleEventListener); for (const objectURL of this.kernelName2logoObjectURL.values()) { @@ -787,12 +884,12 @@ export default class JupyterClientPlugin extends siyuan.Plugin { const pathname = (() => { switch (true) { - case "logo-svg" in spec.resources: - return spec.resources["logo-svg"]; - case "logo-32x32" in spec.resources: - return spec.resources["logo-32x32"]; case "logo-64x64" in spec.resources: return spec.resources["logo-64x64"]; + case "logo-32x32" in spec.resources: + return spec.resources["logo-32x32"]; + case "logo-svg" in spec.resources: + return spec.resources["logo-svg"]; default: if (Object.keys(spec.resources).length > 0) { return Object.values(spec.resources)[0]; @@ -1592,8 +1689,8 @@ export default class JupyterClientPlugin extends siyuan.Plugin { const menu = new siyuan.Menu(message.header.msg_id, () => { this.complating = false; - if (menu.menu.element.lastElementChild instanceof HTMLElement) { - menu.menu.element.lastElementChild.style.maxHeight = ""; + if (menu.element.lastElementChild instanceof HTMLElement) { + menu.element.lastElementChild.style.maxHeight = ""; } }); @@ -1605,9 +1702,9 @@ export default class JupyterClientPlugin extends siyuan.Plugin { menu.open(options); /* 调整菜单位置 */ - const menu_rect = menu.menu.element.getBoundingClientRect(); + const menu_rect = menu.element.getBoundingClientRect(); if (menu_rect.y !== options.y) { - const items_element = menu.menu.element.lastElementChild; + const items_element = menu.element.lastElementChild; if (items_element instanceof HTMLElement) { const max_height = globalThis.innerHeight - options.y - 32; @@ -2072,9 +2169,9 @@ export default class JupyterClientPlugin extends siyuan.Plugin { } /* 编辑器加载事件监听器 */ - protected readonly loadedProtyleEventListener = async (e: ILoadedProtyleEvent) => { + protected readonly loadedProtyleEventListener = async (e: ILoadedProtyleStaticEvent | ISwitchProtyleEvent) => { // this.logger.debug(e); - const protyle = e.detail; + const protyle = e.detail.protyle; /* 更新内核状态 */ if (!this.doc2session.has(protyle.block.rootID!)) { // 当前文档未连接会话 @@ -2256,4 +2353,46 @@ export default class JupyterClientPlugin extends siyuan.Plugin { sessions, }); } + + /** + * 在新页签中打开 Jupyter + */ + protected readonly openJupyterTab = async () => { + siyuan.openTab({ + app: this.app, + custom: { + icon: "icon-jupyter-client", + title: "Jupyter", + id: this.CUSTOM_TAB_ID_JUPYTER, + data: { + src: this.baseUrl, + title: "Jupyter", + }, + }, + keepCursor: false, + removeCurrentTab: false, + }); + }; + + /** + * 在浏览器中打开 Jupyter + */ + protected readonly openJupyterBrowser = async () => { + globalThis.open(this.baseUrl); + }; + + /** + * 在新窗口中打开 Jupyter + */ + protected readonly openJupyterWindow = async () => { + openWindow({ + url: this.baseUrl, + base: { + center: true, + }, + extra: { + enableMenuBar: true, + }, + }); + }; };