Skip to content

Fix GitHub tree deletion and migrate to React + MUI with Vite build#15

Open
Copilot wants to merge 15 commits intomainfrom
copilot/fix-delete-file-function
Open

Fix GitHub tree deletion and migrate to React + MUI with Vite build#15
Copilot wants to merge 15 commits intomainfrom
copilot/fix-delete-file-function

Conversation

Copy link
Contributor

Copilot AI commented Feb 20, 2026

Fixes GitHub API 404 error when deleting files. Replaces static HTML with React + Material-UI components. Adds Vite build pipeline for optimized bundle delivery.

Delete Fix

GitHub's tree API doesn't support sha: null for deletion. Changed to fetch full tree recursively, filter out target paths, and create new tree:

const fullTree = await github.git.getTree({ owner, repo, tree_sha: treeSha, recursive: true });
const newTree = fullTree.data.tree
  .filter((item) => !item.path?.startsWith(`${fileId}/`))
  .map(({ path, mode, type, sha }) => ({ path, mode, type, sha }));

Frontend Migration

  • React 19 + MUI 7: All UI components (Cards, Tables, Dialogs, Progress, Snackbars)
  • Vite 7: Build to public/ directory, tree-shaking enabled
  • Bundle: 447KB → 139KB gzipped
  • Features: Auto dark mode, Chinese i18n, responsive layout, confirmation dialogs

Build Pipeline

npm run build   # Vite compiles frontend
npm run deploy  # Build + Wrangler deploy

Structure

frontend/src/     # React components, MUI imports
public/           # Build output (gitignored)
vite.config.js    # Builds to public/, emptyOutDir: true

Built assets served via Cloudflare Workers + edge network. Single JS bundle eliminates CDN latency for China region.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • sparrow.cloudflare.com
    • Triggering command: /opt/hostedtoolcache/node/24.13.0/x64/bin/node /opt/hostedtoolcache/node/24.13.0/x64/bin/node --no-warnings --experimental-vm-modules /home/REDACTED/work/FileShare/FileShare/node_modules/wrangler/wrangler-dist/cli.js deploy --dry-run (dns block)
    • Triggering command: /opt/hostedtoolcache/node/24.13.0/x64/bin/node /opt/hostedtoolcache/node/24.13.0/x64/bin/node --no-warnings --experimental-vm-modules /home/REDACTED/work/FileShare/FileShare/node_modules/wrangler/wrangler-dist/cli.js deploy --dry-run --local tnet/tools/sh credential.helpegit (dns block)

If you need me to access, download, or install something from one of these locations, you can either:


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Co-authored-by: langningchen <81672884+langningchen@users.noreply.github.com>
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Feb 20, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
file-share 9f69ffa Commit Preview URL

Branch Preview URL
Feb 20 2026, 06:17 AM

Copilot AI and others added 9 commits February 20, 2026 05:34
Co-authored-by: langningchen <81672884+langningchen@users.noreply.github.com>
Co-authored-by: langningchen <81672884+langningchen@users.noreply.github.com>
Co-authored-by: langningchen <81672884+langningchen@users.noreply.github.com>
…ty and validation

Co-authored-by: langningchen <81672884+langningchen@users.noreply.github.com>
Co-authored-by: langningchen <81672884+langningchen@users.noreply.github.com>
Co-authored-by: langningchen <81672884+langningchen@users.noreply.github.com>
Co-authored-by: langningchen <81672884+langningchen@users.noreply.github.com>
Co-authored-by: langningchen <81672884+langningchen@users.noreply.github.com>
Co-authored-by: langningchen <81672884+langningchen@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix delete file function and handling Not Found error Fix GitHub tree deletion and migrate to React + MUI with Vite build Feb 20, 2026
Copilot AI requested a review from langningchen February 20, 2026 05:46
@langningchen langningchen marked this pull request as ready for review February 20, 2026 06:04
Copilot AI review requested due to automatic review settings February 20, 2026 06:04
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes GitHub-backed file deletion in the Worker and replaces the legacy static Bootstrap UI with a React + MUI frontend built via Vite and served as Worker static assets.

Changes:

  • Reworked /delete to rebuild a GitHub tree from a recursive listing rather than using sha: null.
  • Added a React + MUI frontend under frontend/, with Vite building output to public/.
  • Updated Wrangler assets configuration and npm scripts to build before deploy.

Reviewed changes

Copilot reviewed 10 out of 12 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
wrangler.toml Switches to [assets] binding (ASSETS) and updates compatibility date.
src/index.ts Serves static assets on GET and rewrites GitHub tree deletion logic.
vite.config.js Adds Vite build config targeting public/ and sets frontend as root.
package.json Adds React/MUI/Vite deps and build/dev/preview/deploy scripts.
pnpm-lock.yaml Locks newly added frontend/build dependencies.
frontend/index.html Vite HTML entry template for the React app.
frontend/src/main.jsx React entry wiring MUI theme + dark mode.
frontend/src/App.jsx New MUI-based UI implementing upload/list/download/delete flows.
public/index.html Replaces old static page with a built (hashed) Vite output HTML.
README.md Updates docs for the new build/deploy workflow and features.
IMPROVEMENTS.md Adds a Chinese/English summary of the migration and deletion fix.
.gitignore Ignores build outputs (public/, dist) and backups.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

export default defineConfig({
plugins: [react()],
build: {
outDir: path.resolve(__dirname, 'public'),
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

outDir: path.resolve(__dirname, ...) relies on __dirname, which is not available in native ESM. Since this config file uses ESM import syntax, builds can break depending on how the config is loaded. Consider resolving from process.cwd() / import.meta.url, or using a relative outDir like ../public (given root: 'frontend').

Suggested change
outDir: path.resolve(__dirname, 'public'),
outDir: '../public',

Copilot uses AI. Check for mistakes.
Comment on lines 23 to +27
"@cloudflare/workers-types": "^4.20260219.0",
"@types/node": "^25.3.0",
"@vitejs/plugin-react": "^5.1.4",
"typescript": "^5.9.3",
"vite": "^7.3.1",
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vite 7 / @vitejs/plugin-react require Node ^20.19.0 || >=22.12.0 (per their engines). Without declaring this in package.json (or README), installs/builds on older Node versions will fail unexpectedly. Consider adding an explicit engines.node constraint.

Copilot uses AI. Check for mistakes.
Comment on lines +172 to +176
const { done, value } = await reader.read();
if (done) break;
readLength += value.length;
setDownloadProgress(((chunk + readLength / length) / file.chunks) * 100);
fileData = new Blob([fileData, value]);
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating the download blob via fileData = new Blob([fileData, value]) inside the read loop is O(n²) in time/memory for large files. Accumulate chunks into an array (or stream to disk) and construct a single Blob once at the end.

Copilot uses AI. Check for mistakes.
Comment on lines 55 to +59
if (!env.GithubPAT || !env.GithubOwner || !env.GithubRepo || !env.GithubBranch) {
return new ResJson(false, 'Please set the environment variables', {});
}
if (req.method === 'GET') { return env.ASSETS.fetch(req); }
if (req.method !== 'POST') { return new ResJson(false, 'Method not allowed', {}); }
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GET static asset handling is placed after the GitHub env-var check. As a result, a missing GithubPAT/Owner/Repo/Branch will prevent serving the UI (and any other GET asset) even though those secrets are only needed for API POST routes. Consider handling GET requests (or at least / and /assets/*) before validating GitHub env vars.

Suggested change
if (!env.GithubPAT || !env.GithubOwner || !env.GithubRepo || !env.GithubBranch) {
return new ResJson(false, 'Please set the environment variables', {});
}
if (req.method === 'GET') { return env.ASSETS.fetch(req); }
if (req.method !== 'POST') { return new ResJson(false, 'Method not allowed', {}); }
if (req.method === 'GET') { return env.ASSETS.fetch(req); }
if (req.method !== 'POST') { return new ResJson(false, 'Method not allowed', {}); }
if (!env.GithubPAT || !env.GithubOwner || !env.GithubRepo || !env.GithubBranch) {
return new ResJson(false, 'Please set the environment variables', {});
}

Copilot uses AI. Check for mistakes.
Comment on lines +58 to +59
if (req.method === 'GET') { return env.ASSETS.fetch(req); }
if (req.method !== 'POST') { return new ResJson(false, 'Method not allowed', {}); }
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

env.ASSETS is used here, but the Env interface in this file does not declare an ASSETS binding. This causes a TypeScript type error and makes the binding contract unclear. Add the ASSETS binding to Env (e.g., Fetcher) to match wrangler.toml.

Copilot uses AI. Check for mistakes.
}
return json.Data;
}
return { reader: res.body.getReader(), length: parseInt(res.headers.get('Content-Length')) };
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Content-Length may be missing for streamed responses, so parseInt(res.headers.get('Content-Length')) can yield NaN. Downstream progress calculations then become NaN as well. Add a fallback when the header is absent/invalid (e.g., only use received-bytes progress).

Suggested change
return { reader: res.body.getReader(), length: parseInt(res.headers.get('Content-Length')) };
const contentLengthHeader = res.headers.get('Content-Length');
const parsedLength = contentLengthHeader != null ? parseInt(contentLengthHeader, 10) : null;
const length = Number.isFinite(parsedLength) ? parsedLength : null;
return { reader: res.body.getReader(), length };

Copilot uses AI. Check for mistakes.
const oldTree = (await github.git.getTree({ owner, repo, tree_sha: folderSha, })).data.tree;
const newTree = oldTree.map(({ path, mode, type }) => ({ path: `${fileId}/${path}`, sha: null, mode, type }));
const newTreeSha = (await github.git.createTree({ owner, repo, base_tree: treeSha, tree: newTree as any, })).data.sha;
const fullTree = (await github.git.getTree({ owner, repo, tree_sha: treeSha, recursive: true })).data.tree;
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

git.getTree(..., recursive: true) responses can be truncated. Since you build a brand-new tree (no base_tree) from the returned entries, a truncated response would silently drop unrelated files from the repo in the new commit. Check fullTreeResponse.data.truncated and fail/handle pagination (or use a safer strategy) before calling createTree.

Suggested change
const fullTree = (await github.git.getTree({ owner, repo, tree_sha: treeSha, recursive: true })).data.tree;
const fullTreeResponse = await github.git.getTree({ owner, repo, tree_sha: treeSha, recursive: true });
if (fullTreeResponse.data.truncated) {
return new ResJson(false, 'Repository tree is too large to process delete operation safely', {});
}
const fullTree = fullTreeResponse.data.tree;

Copilot uses AI. Check for mistakes.
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Share</title>
<script type="module" crossorigin src="/assets/index-CvnL0yOX.js"></script>
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This public/index.html looks like a Vite build output (hashed /assets/index-*.js). Committing it will likely become stale on the next build and may reference an asset file that isn’t present in the repo (especially since public/ is gitignored). Prefer not tracking build outputs in git; let vite build generate public/index.html during deploy.

Suggested change
<script type="module" crossorigin src="/assets/index-CvnL0yOX.js"></script>
<script type="module" crossorigin src="/src/main.tsx"></script>

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants