From cc2fcb9b9d2e69981091e40f07d8b9acf17f5a5a Mon Sep 17 00:00:00 2001 From: mobyw Date: Sun, 22 Sep 2024 00:02:07 +0800 Subject: [PATCH] :sparkles: Add export config --- packages/app/src/App.vue | 4 + packages/app/src/components/ButtonPanel.vue | 27 +-- packages/app/src/components/ConfigTab.vue | 102 ++++++++++++ packages/app/src/components/ContentCard.vue | 9 + packages/app/src/workspace.ts | 172 +++++++++++++++++++- 5 files changed, 287 insertions(+), 27 deletions(-) create mode 100644 packages/app/src/components/ConfigTab.vue diff --git a/packages/app/src/App.vue b/packages/app/src/App.vue index 6fa6990..8625df4 100644 --- a/packages/app/src/App.vue +++ b/packages/app/src/App.vue @@ -5,6 +5,7 @@ import ContentCard from "@/components/ContentCard.vue"; import BlocklyTab from "@/components/BlocklyTab.vue"; import TutorialTab from "@/components/TutorialTab.vue"; import CodeTab from "@/components/CodeTab.vue"; +import ConfigTab from "@/components/ConfigTab.vue"; import ButtonPanel from "@/components/ButtonPanel.vue"; // Workspace import { loadJson, generateCode } from "@/workspace"; @@ -61,6 +62,9 @@ onMounted(() => { + diff --git a/packages/app/src/components/ButtonPanel.vue b/packages/app/src/components/ButtonPanel.vue index 3409d1c..1a6e104 100644 --- a/packages/app/src/components/ButtonPanel.vue +++ b/packages/app/src/components/ButtonPanel.vue @@ -1,10 +1,10 @@ + + diff --git a/packages/app/src/components/ContentCard.vue b/packages/app/src/components/ContentCard.vue index 21e5faf..74e1fd7 100644 --- a/packages/app/src/components/ContentCard.vue +++ b/packages/app/src/components/ContentCard.vue @@ -10,6 +10,7 @@ 编程 教程 代码 + 配置 @@ -37,6 +38,14 @@ + + + +
+ +
+
+
diff --git a/packages/app/src/workspace.ts b/packages/app/src/workspace.ts index 107f006..2734897 100644 --- a/packages/app/src/workspace.ts +++ b/packages/app/src/workspace.ts @@ -54,6 +54,12 @@ export const outputsStore = reactive({ snackbarMsg: "" as string, snackbarTimeout: 2500 as number, snackbarColor: "green" as string, + export: { + name: "app" as string, + preset: { name: "console", description: "控制台机器人" }, + port: 8080 as number, + platform: ["windows", "linux"] as string[], + }, }); export function setWorkspaceTheme(theme: string) { @@ -111,15 +117,175 @@ export function generateCode() { outputsStore.code = pythonGenerator.workspaceToCode(workspace); } +export function exportPress() { + outputsStore.activeTab = "tab-3"; +} + +function generatePyproject(code: string, preset: string) { + const dependencies = new Set([ + "nonebot2[fastapi,httpx,websockets]>=2.3.3", + "nb-cli>=1.4.2", + ]); + const importLines = code.split("\n\n")[0].split("\n"); + importLines.forEach((line) => { + if (line.startsWith("from nonebot_plugin_alconna")) { + dependencies.add("nonebot-plugin-alconna>=0.52.3"); + } else if (line.startsWith("from nonebot_plugin_apscheduler")) { + dependencies.add("nonebot-plugin-apscheduler>=0.5.0"); + } else if (line.startsWith("import nonebot_plugin_localstore")) { + dependencies.add("nonebot-plugin-localstore>=0.7.1"); + } + }); + let adapters = ""; + if (preset === "console") { + adapters = '{ name = "Console", module_name = "nonebot.adapters.console" }'; + dependencies.add("nonebot-adapter-console>=0.6.0"); + } else if (preset === "onebot") { + adapters = + '{ name = "OneBot V11", module_name = "nonebot.adapters.onebot.v11" }'; + adapters += + ', { name = "OneBot V12", module_name = "nonebot.adapters.onebot.v12" }'; + dependencies.add("nonebot-adapter-onebot>=2.4.5"); + } + return `\ + [project] + name = "noneblockly-app" + version = "0.1.0" + description = "NoneBot project generated by NoneBlockly" + authors = [{name = "name", email = "name@example.com"}] + dependencies = [ + ${Array.from(dependencies) + .map((dep) => `"${dep}"`) + .join(", \n")} + ] + requires-python = ">=3.9" + license = {text = "MIT"} + + [tool.nonebot] + adapters = [ + { name = "Console", module_name = "nonebot.adapters.console" } + ] + plugin_dirs = ["plugins"]`; +} + +function generateEnv(port: number) { + return `\ + DRIVER=~fastapi+~httpx+~websockets + PORT=${port}`; +} + +const windowsScripts = { + install: `\ + # Step 1: Check if 'uv' is installed + $uvVersion = try { + uv --version + } catch { + $null + } + + if ($uvVersion) { + Write-Host "UV is installed. Version: " + Write-Host $uvVersion + } else { + # Step 2: If 'uv' is not installed, ask user for confirmation to install + Write-Host "UV is not installed on this system." + $confirmation = Read-Host "Do you want to install UV? (Press Enter to confirm or type 'n' to cancel)" + + if ($confirmation -eq '') { + Write-Host "Installing UV..." + Invoke-RestMethod https://astral.sh/uv/install.ps1 | Invoke-Expression + Write-Host "UV has been installed successfully." + } else { + Write-Host "Installation canceled." + exit + } + } + + # Step 3: Create a Python virtual environment + Write-Host "Creating a Python virtual environment with Python 3.12..." + uv venv --python 3.12 + + Write-Host "Python virtual environment created successfully." + + # Step 4: Install dependencies + uv pip install -r pyproject.toml`, + run: `\ + $uvVersion = try { + uv --version + } catch { + $null + } + + if ($null -eq $uvVersion) { + Write-Host "Please run 'install.ps1' first." + exit + } + + uv run nb run`, +}; + +const linuxScripts = { + install: `\ + #!/bin/bash + + # Step 1: Check if 'uv' is installed + if command -v uv &> /dev/null + then + echo "UV is installed. Version info:" + uv --version + else + # Step 2: If 'uv' is not installed, ask user for confirmation to install + echo "UV is not installed on this system." + read -p "Do you want to install UV? (Press Enter to confirm or type 'n' to cancel): " confirmation + + if [ "$confirmation" == "" ]; then + echo "Installing UV..." + curl -LsSf https://astral.sh/uv/install.sh | sh + echo "UV has been installed successfully." + else + echo "Installation canceled." + exit 1 + fi + fi + + # Step 3: Create a Python virtual environment + echo "Creating a Python virtual environment with Python 3.12..." + uv venv --python 3.12 + + echo "Python virtual environment created successfully."`, + run: `\ + if ! command -v uv &> /dev/null + then + echo "Please run 'install.sh' first" + exit + fi + + uv run nb run`, +}; + export function exportZip() { - let workspace = Blockly.getMainWorkspace(); let zip = new JSZip(); + let workspace = Blockly.getMainWorkspace(); let code = pythonGenerator.workspaceToCode(workspace); - zip.file("plugins/plugin_example.py", code); + zip.file("plugins/plugin_exported.py", code); + zip.file( + "pyproject.toml", + generatePyproject(code, outputsStore.export.preset.name), + ); + zip.file(".env.prod", generateEnv(outputsStore.export.port)); + outputsStore.export.platform.forEach((platform) => { + if (platform === "windows") { + zip.file("install.ps1", windowsScripts.install); + zip.file("run.ps1", windowsScripts.run); + } else if (platform === "linux") { + zip.file("install.sh", linuxScripts.install); + zip.file("run.sh", linuxScripts.run); + } + }); outputsStore.snackbarColor = "green"; outputsStore.snackbarMsg = "😎 已导出 Python 项目"; outputsStore.snackbar = true; zip.generateAsync({ type: "blob" }).then(function (content) { - saveAs(content, "noneblockly.zip"); + saveAs(content, `${outputsStore.export.name}.zip`); }); }