|
| 1 | +# Git Graph Demo MiniApp / Git Graph 示例 MiniApp |
| 2 | + |
| 3 | +[English](#english) | [中文](#中文) |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## English |
| 8 | + |
| 9 | +This demo showcases BitFun MiniApp's full-stack collaboration capability — specifically, using a third-party npm package (`simple-git`) inside a Node.js/Bun Worker to read a local Git repository and render an interactive commit graph. |
| 10 | + |
| 11 | +### Features |
| 12 | + |
| 13 | +- **Pick a repository** — opens a native directory picker via `app.dialog.open({ directory: true })` |
| 14 | +- **Commit graph** — Worker fetches `git.graphData` (log + refs + stashes + uncommitted in one call); UI renders commit nodes and branch lines as SVG |
| 15 | +- **Branches & status** — shows current branch, full branch list, and workspace status (modified / staged / untracked) |
| 16 | +- **Commit detail** — click any commit to view author, timestamp, diff stat, and per-file diff |
| 17 | +- **Branch management** — create, delete, rename, checkout local/remote branches |
| 18 | +- **Merge / Rebase** — merge a branch into HEAD, rebase HEAD onto a branch |
| 19 | +- **Cherry-pick / Revert / Reset** — cherry-pick a commit, revert with a new commit, or hard/mixed/soft reset |
| 20 | +- **Push / Fetch** — push to remote, fetch with prune, fetch a remote branch into a local branch |
| 21 | +- **Remote management** — add, remove, update remote URLs via the Remotes panel |
| 22 | +- **Stash** — push, apply, pop, drop, and branch-from-stash operations |
| 23 | +- **Search commits** — filter commit list by message, hash, or author |
| 24 | +- **Tag management** — add lightweight or annotated tags, delete tags, push tags |
| 25 | + |
| 26 | +### Data Flow |
| 27 | + |
| 28 | +1. **UI → Bridge**: `app.call('git.log', { cwd, maxCount })` etc. via `window.app` (JSON-RPC) |
| 29 | +2. **Bridge → Tauri**: postMessage intercepted by the host `useMiniAppBridge`, which calls `miniapp_worker_call` |
| 30 | +3. **Tauri → Worker**: Rust writes the request to Worker stdin (JSON-RPC) |
| 31 | +4. **Worker**: `worker_host.js` loads `source/worker.js`; exported handlers are invoked — primarily `git.graphData` (returns commits + refs + stashes + uncommitted in one response), plus `git.show`, `git.checkout`, `git.merge`, `git.push`, `git.stashPush`, and 20+ other methods — all backed by the `simple-git` npm package |
| 32 | +5. **Worker → Tauri → Bridge → UI**: response travels back via stderr → Rust → postMessage to iframe → UI refreshes graph and detail panel |
| 33 | + |
| 34 | +### Directory Structure |
| 35 | + |
| 36 | +``` |
| 37 | +miniapps/git-graph/ |
| 38 | +├── README.md # this file |
| 39 | +├── meta.json # metadata & permissions (fs/shell/node) |
| 40 | +├── package.json # npm deps (simple-git) + build script |
| 41 | +├── storage.json # app KV (e.g. last opened repo path) |
| 42 | +└── source/ |
| 43 | + ├── index.html # UI skeleton |
| 44 | + ├── build.js # build script: concat ui/*.js → ui.js, styles/*.css → style.css |
| 45 | + ├── ui.js # frontend entry (generated by build, do not edit directly) |
| 46 | + ├── style.css # style entry (generated by build, do not edit directly) |
| 47 | + ├── ui/ # frontend modules (run `npm run build` after editing) |
| 48 | + │ ├── state.js, theme.js, main.js, bootstrap.js |
| 49 | + │ ├── graph/layout.js, graph/renderRowSvg.js |
| 50 | + │ ├── components/contextMenu.js, modal.js, findWidget.js |
| 51 | + │ ├── panels/detailPanel.js, remotePanel.js |
| 52 | + │ └── services/gitClient.js |
| 53 | + ├── styles/ # style modules (run `npm run build` after editing) |
| 54 | + │ ├── tokens.css, layout.css, graph.css |
| 55 | + │ ├── detail-panel.css, overlay.css |
| 56 | + │ └── (merge order defined in build.js) |
| 57 | + ├── worker.js # backend CJS (simple-git wrapper) |
| 58 | + └── esm_dependencies.json # ESM deps (empty for this demo) |
| 59 | +``` |
| 60 | + |
| 61 | +**During development**: after editing `source/ui/*.js` or `source/styles/*.css`, run `npm run build` inside the `miniapps/git-graph` directory to regenerate `source/ui.js` and `source/style.css`. BitFun will pick up the latest build on next load. |
| 62 | + |
| 63 | +### Running in BitFun |
| 64 | + |
| 65 | +1. **Install to user data directory**: copy this folder into BitFun's MiniApp data directory under an `app_id` subdirectory, e.g.: |
| 66 | + - The data directory is typically `{user_data}/miniapps/` |
| 67 | + - Create a subdirectory like `git-graph-sample` and place all files from this folder inside it (i.e. `meta.json`, `package.json`, `source/` etc. at the root of that subdirectory) |
| 68 | + |
| 69 | +2. **Or import via API**: if BitFun supports path-based import, use `create_miniapp` or equivalent, pointing to this directory as the source; make sure the `id` in `meta.json` matches the directory name. |
| 70 | + |
| 71 | +3. **Install dependencies**: inside the MiniApp's app directory, run: |
| 72 | + - `bun install` or `npm install` (matching the runtime BitFun detected) |
| 73 | + - Or use the "Install Dependencies" action in Toolbox (calls `miniapp_install_deps`) |
| 74 | + |
| 75 | +4. **Compile**: to regenerate `compiled.html`, call `miniapp_recompile` or let BitFun compile automatically when the MiniApp is opened. |
| 76 | + |
| 77 | +5. Open the MiniApp in the Toolbox scene, pick a repository, and the Git Graph will appear. |
| 78 | + |
| 79 | +### Permissions |
| 80 | + |
| 81 | +| Permission | Value | Purpose | |
| 82 | +|---|---|---| |
| 83 | +| `fs.read` | `{appdata}`, `{workspace}`, `{user-selected}` | Read app data, workspace, and user-selected repo | |
| 84 | +| `fs.write` | `{appdata}` | Write app-own data only (e.g. storage) | |
| 85 | +| `shell.allow` | `["git"]` | `simple-git` needs to invoke the system `git` binary | |
| 86 | +| `node.enabled` | `true` | Enable JS Worker to execute `simple-git` logic in `worker.js` | |
| 87 | + |
| 88 | +### Technical Highlights |
| 89 | + |
| 90 | +- **Client-side third-party library**: `require('simple-git')` in `worker.js` runs inside a Bun or Node.js Worker process — no need to reimplement Git in Rust |
| 91 | +- **Zero custom dialect**: UI is plain concatenated JavaScript (IIFE modules sharing `window.__GG`), Worker is standard CJS — no custom framework or transpiler required; `window.app` is the unified Bridge API |
| 92 | +- **ESM dependencies**: this demo uses plain vanilla JS; `esm_dependencies.json` is empty — add React, D3, etc. there to have them served via Import Map from esm.sh |
| 93 | + |
| 94 | +--- |
| 95 | + |
| 96 | +## 中文 |
| 97 | + |
| 98 | +本示例展示 BitFun MiniApp 的前后端协同能力,尤其是通过 Node.js/Bun 在端侧使用三方 npm 库(`simple-git`)读取 Git 仓库并渲染交互式提交图谱。 |
| 99 | + |
| 100 | +### 功能 |
| 101 | + |
| 102 | +- **选择仓库**:通过 `app.dialog.open({ directory: true })` 打开原生目录选择器,选择本地 Git 仓库 |
| 103 | +- **提交图谱**:Worker 端通过 `git.graphData`(一次调用返回提交列表 + refs + stash + 未提交变更),UI 端用 SVG 绘制提交节点与分支线 |
| 104 | +- **分支与状态**:展示当前分支、所有分支列表及工作区状态(modified/staged/untracked) |
| 105 | +- **提交详情**:点击某个 commit 可查看作者、时间、diff stat 及逐文件 diff |
| 106 | +- **分支管理**:创建、删除、重命名、checkout 本地/远程分支 |
| 107 | +- **Merge / Rebase**:将分支合并到 HEAD,或将 HEAD rebase 到目标分支 |
| 108 | +- **Cherry-pick / Revert / Reset**:cherry-pick 指定 commit,revert 生成新提交,或 hard/mixed/soft reset |
| 109 | +- **Push / Fetch**:推送到远程,带 prune 的 fetch,将远程分支 fetch 到本地分支 |
| 110 | +- **远程管理**:通过远程面板添加、删除、修改远程 URL |
| 111 | +- **Stash**:push、apply、pop、drop 及从 stash 创建分支 |
| 112 | +- **搜索提交**:按消息、hash 或作者过滤提交列表 |
| 113 | +- **Tag 管理**:添加轻量/注解 tag,删除 tag,推送 tag |
| 114 | + |
| 115 | +### 前后端协同流程 |
| 116 | + |
| 117 | +1. **UI → Bridge**:`app.call('git.log', { cwd, maxCount })` 等通过 `window.app` 发起 RPC |
| 118 | +2. **Bridge → Tauri**:postMessage 被宿主 `useMiniAppBridge` 接收,调用 `miniapp_worker_call` |
| 119 | +3. **Tauri → Worker**:Rust 将请求写入 Worker 进程 stdin(JSON-RPC) |
| 120 | +4. **Worker**:`worker_host.js` 加载本目录 `source/worker.js`,其导出的处理函数被调用 — 主要是 `git.graphData`(一次返回提交 + refs + stash + 未提交变更),以及 `git.show`、`git.checkout`、`git.merge`、`git.push`、`git.stashPush` 等 20+ 个方法 — 均基于 `simple-git` npm 包 |
| 121 | +5. **Worker → Tauri → Bridge → UI**:响应经 stderr 回传 Rust,再 postMessage 回 iframe,UI 更新图谱与详情 |
| 122 | + |
| 123 | +### 目录结构 |
| 124 | + |
| 125 | +``` |
| 126 | +miniapps/git-graph/ |
| 127 | +├── README.md # 本说明 |
| 128 | +├── meta.json # 元数据与权限(fs/shell/node) |
| 129 | +├── package.json # npm 依赖(simple-git)及 build 脚本 |
| 130 | +├── storage.json # 应用 KV(如最近打开的仓库路径) |
| 131 | +└── source/ |
| 132 | + ├── index.html # UI 骨架 |
| 133 | + ├── build.js # 构建脚本:合并 ui/*.js → ui.js,styles/*.css → style.css |
| 134 | + ├── ui.js # 前端入口(由 build 生成,勿直接编辑) |
| 135 | + ├── style.css # 样式入口(由 build 生成,勿直接编辑) |
| 136 | + ├── ui/ # 前端模块(编辑后需运行 npm run build) |
| 137 | + │ ├── state.js, theme.js, main.js, bootstrap.js |
| 138 | + │ ├── graph/layout.js, graph/renderRowSvg.js |
| 139 | + │ ├── components/contextMenu.js, modal.js, findWidget.js |
| 140 | + │ ├── panels/detailPanel.js, remotePanel.js |
| 141 | + │ └── services/gitClient.js |
| 142 | + ├── styles/ # 样式模块(编辑后需运行 npm run build) |
| 143 | + │ ├── tokens.css, layout.css, graph.css |
| 144 | + │ ├── detail-panel.css, overlay.css |
| 145 | + │ └── (合并顺序见 build.js) |
| 146 | + ├── worker.js # 后端 CJS(simple-git 封装) |
| 147 | + └── esm_dependencies.json # ESM 依赖(本示例为空) |
| 148 | +``` |
| 149 | + |
| 150 | +**开发时**:修改 `source/ui/*.js` 或 `source/styles/*.css` 后,在 `miniapps/git-graph` 目录执行 `npm run build` 生成 `source/ui.js` 与 `source/style.css`,BitFun 加载时会使用最新构建结果。 |
| 151 | + |
| 152 | +### 在 BitFun 中运行 |
| 153 | + |
| 154 | +1. **安装到用户数据目录**:将本目录复制到 BitFun 的 MiniApp 数据目录下,并赋予一个 app_id 子目录,例如: |
| 155 | + - 数据目录一般为 `{user_data}/miniapps/` |
| 156 | + - 新建子目录如 `git-graph-sample`,将本目录中所有文件按相同结构放入其中(即 `meta.json`、`package.json`、`source/` 等在该子目录下) |
| 157 | + |
| 158 | +2. **或通过 API 创建**:若 BitFun 支持从路径导入,可使用 `create_miniapp` 或等价方式,将本目录作为 source 路径导入,并确保 `meta.json` 中的 `id` 与目录名一致。 |
| 159 | + |
| 160 | +3. **安装依赖**:在 MiniApp 的 app 目录下执行: |
| 161 | + - `bun install` 或 `npm install`(与 BitFun 检测到的运行时一致) |
| 162 | + - 或在 Toolbox 中对该 MiniApp 执行「安装依赖」操作(调用 `miniapp_install_deps`) |
| 163 | + |
| 164 | +4. **编译**:若需重新生成 `compiled.html`,可调用 `miniapp_recompile` 或由 BitFun 在打开该 MiniApp 时自动编译。 |
| 165 | + |
| 166 | +5. 在 Toolbox 场景中打开该 MiniApp,选择仓库后即可查看 Git Graph。 |
| 167 | + |
| 168 | +### 权限说明 |
| 169 | + |
| 170 | +| 权限 | 值 | 用途 | |
| 171 | +|---|---|---| |
| 172 | +| `fs.read` | `{appdata}`、`{workspace}`、`{user-selected}` | 读取应用数据、工作区及用户选择的仓库目录 | |
| 173 | +| `fs.write` | `{appdata}` | 仅写入应用自身数据(如 storage) | |
| 174 | +| `shell.allow` | `["git"]` | `simple-git` 需调用系统 `git` 命令 | |
| 175 | +| `node.enabled` | `true` | 启用 JS Worker,以便执行 `worker.js` 中的 `simple-git` 逻辑 | |
| 176 | + |
| 177 | +### 技术要点 |
| 178 | + |
| 179 | +- **端侧三方库**:`worker.js` 中 `require('simple-git')`,在 Bun 或 Node.js Worker 进程中运行,无需在 Rust 中重新实现 Git 能力 |
| 180 | +- **无自定义方言**:UI 为普通拼接脚本(IIFE 模块通过 `window.__GG` 共享状态),Worker 为标准 CJS,无需自定义框架或转译器;`window.app` 为统一 Bridge API |
| 181 | +- **ESM 依赖**:本示例 UI 使用纯 vanilla JS,`esm_dependencies.json` 为空;若需 React/D3 等,可在其中声明并由 Import Map 从 esm.sh 加载 |
0 commit comments