{"id":51278137,"url":"https://github.com/abhi-singhs/ghcp-ulb-ui","last_synced_at":"2026-06-29T23:02:29.433Z","repository":{"id":366977566,"uuid":"1278690933","full_name":"abhi-singhs/ghcp-ulb-ui","owner":"abhi-singhs","description":"User-level budgets UI for GitHub Copilot AI credits — manage universal budgets, per-user overrides, and bulk CSV/XLSX import. Built with React, TypeScript, Vite, and Primer.","archived":false,"fork":false,"pushed_at":"2026-06-24T04:03:04.000Z","size":147,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-24T05:25:59.667Z","etag":null,"topics":["ai-credits","budget-management","copilot","dashboard","github-copilot","primer","react","react-query","typescript","vite"],"latest_commit_sha":null,"homepage":"https://abhisingh.in/ghcp-ulb-ui/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/abhi-singhs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-24T02:53:53.000Z","updated_at":"2026-06-24T04:02:58.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/abhi-singhs/ghcp-ulb-ui","commit_stats":null,"previous_names":["abhi-singhs/ghcp-ulb-ui"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/abhi-singhs/ghcp-ulb-ui","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abhi-singhs%2Fghcp-ulb-ui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abhi-singhs%2Fghcp-ulb-ui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abhi-singhs%2Fghcp-ulb-ui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abhi-singhs%2Fghcp-ulb-ui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/abhi-singhs","download_url":"https://codeload.github.com/abhi-singhs/ghcp-ulb-ui/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abhi-singhs%2Fghcp-ulb-ui/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34945707,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-29T02:00:05.398Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-credits","budget-management","copilot","dashboard","github-copilot","primer","react","react-query","typescript","vite"],"created_at":"2026-06-29T23:02:28.851Z","updated_at":"2026-06-29T23:02:29.405Z","avatar_url":"https://github.com/abhi-singhs.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Copilot AI Credits · User‑Level Budgets\n\n\u003e [!IMPORTANT]\n\u003e **Unofficial:** This is an unofficial solution and is not affiliated with,\n\u003e endorsed by, or supported by GitHub.\n\nA fully **client‑side** single‑page app for managing GitHub Copilot **AI Credits**\nuser‑level budgets (ULB) across an enterprise. It talks **directly** to the\n[GitHub Budgets REST API](https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets?apiVersion=2026-03-10)\nfrom the browser — there is no backend.\n\nBuilt with Vite + React + TypeScript and GitHub's own [Primer](https://primer.style) design system.\n\n## What it does\n\n- **Universal ULB** — view, create, and edit the `multi_user_customer`‑scope AI Credits\n  budget that applies to every user by default (monthly cap, usage, alerting).\n- **Override budgets** — manage per‑user (`user`‑scope) caps that take precedence over the\n  universal budget: searchable, paginated table with usage bars and alert status.\n- **Add / edit overrides** — single‑user create and edit dialog with validation.\n- **Bulk delete** — multi‑select rows (or select‑all on the page) and delete with a\n  confirmation step and progress.\n- **Bulk upload** — import a **CSV or Excel** file to create/update many overrides at once\n  (upsert), with a classified preview (create vs. update vs. error) before applying.\n- **Bulk download** — export every override budget to a `username,budget_amount` CSV with one click.\n- **Demo mode \u0026 Live mode** — explore with seeded mock data, or connect to a real enterprise.\n- **Light / dark / system** theme, persisted locally.\n\n## Demo vs. Live\n\nThe mode toggle lives in the top‑right of the header.\n\n- **Demo** — Seeded sample data (1 universal budget + 50 overrides) lives entirely in your\n  browser's `localStorage`. No network requests are made. Use **Reset demo data** to restore\n  the original seed. Great for trying every flow, including bulk upload.\n- **Live** — Enter your **enterprise slug** and a **personal access token**, then\n  **Test connection**. All calls go straight from your browser to `api.github.com`\n  (GitHub's REST API supports CORS). You'll need a **classic PAT** with the\n  `manage_billing:enterprise` scope — see\n  [Authentication \u0026 security](#authentication--security-read-this-for-live-mode).\n\n## Authentication \u0026 security (read this for Live mode)\n\n\u003e [!CAUTION]\n\u003e **Use at your own risk.** This is an unofficial, community‑built tool. You use it\n\u003e **entirely at your own risk**, and GitHub is **not responsible or liable** for any\n\u003e loss, damage, token compromise, unexpected billing changes, or other liability\n\u003e arising from your use of it. Review the source before connecting a real enterprise,\n\u003e and connect only with a token that grants the **least privilege** necessary.\n\n### Which token you need\n\nThe enterprise [Budgets REST API](https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets?apiVersion=2026-03-10)\nthat this app calls is only accessible to an **enterprise admin or billing manager**,\nauthenticating with a **classic personal access token** that has the\n**`manage_billing:enterprise`** scope. **Fine‑grained personal access tokens are not\nsupported** for these endpoints.\n\n`manage_billing:enterprise` is a **narrow** scope — it grants billing management only — but\nbecause this app runs **entirely in your browser** and holds your token there, still treat it\ncarefully: grant **only** that one scope, set the **shortest expiration**, and **revoke** the\ntoken as soon as you're done.\n\n### Create the token\n\n1. Go to **GitHub → Settings → Developer settings → Personal access tokens →\n   Tokens (classic) → Generate new token (classic)**.\n2. Choose the **shortest expiration** that fits your task.\n3. Select **only** the **`manage_billing:enterprise`** scope. Leave **every other scope\n   unchecked**.\n4. Generate the token, copy it, and paste it into the **Personal access token** field. Do\n   **not** reuse this token for any other purpose.\n5. **Revoke the token** as soon as you no longer need it.\n\n### Where your token lives\n\n- **Your token is held in your browser only.** By default it is kept in memory for the\n  session and discarded when you close the tab.\n- If you tick **“Remember token”**, it is saved to `localStorage` on your machine — only do\n  this on a **trusted, private device**.\n- No token or budget data is ever sent anywhere except `api.github.com`. There is no server,\n  analytics, or third‑party call.\n- All requests send `X‑GitHub‑Api‑Version: 2026-03-10`.\n\n### Keeping your credentials secure\n\nTreat your token like a password. Per GitHub's\n[Keeping your API credentials secure](https://docs.github.com/en/enterprise-cloud@latest/rest/authentication/keeping-your-api-credentials-secure)\nguide:\n\n- **Limit permissions and lifetime** — grant only the `manage_billing:enterprise` scope and\n  set the shortest expiration you need.\n- **Store it securely** — never commit a token to a repository (even a private one), and never\n  send it over unencrypted chat or email. If a team needs it, keep it in a secrets manager\n  such as [1Password](https://1password.com/),\n  [Azure Key Vault](https://azure.microsoft.com/products/key-vault), or\n  [HashiCorp Vault](https://www.hashicorp.com/products/vault).\n- **Don't share your token** — a token carries the owner's own access; grant people the\n  billing‑manager role instead of handing out a token.\n- **Don't persist it unnecessarily** — leave **“Remember token”** unticked so the token is\n  never written to `localStorage`.\n- **Have a remediation plan** — if a token is ever leaked, generate a replacement, update it\n  everywhere you use it, then delete the compromised one from **Settings → Developer settings →\n  Personal access tokens**.\n\n## Bulk upload format\n\nAccepted file types: `.csv`, `.xlsx`, `.xls`. Columns (header row required):\n\n| Column | Required | Notes |\n| --- | --- | --- |\n| `username` | yes | GitHub login (a leading `@` is stripped). |\n| `budget_amount` | yes | Whole US dollars. `$` and thousands separators are tolerated. |\n\n**Upsert behavior:** if a user already has an override it is updated (`PATCH`), otherwise a new\none is created (`POST`). Use **Download sample CSV** in the dialog for a ready‑made template.\n\n\u003e AI Credits budgets always block spending when exceeded — `prevent_further_usage` is forced\n\u003e `true` for both universal and override budgets, as required by the API.\n\n## Getting started\n\n```bash\nnpm install\nnpm run dev        # start the dev server (Vite)\n```\n\nThen open the printed local URL. The app starts in **Demo** mode, so no token is needed.\n\n### Scripts\n\n| Command | Description |\n| --- | --- |\n| `npm run dev` | Start the Vite dev server with HMR. |\n| `npm run build` | Type‑check (`tsc -b`) and produce a production build in `dist/`. |\n| `npm run preview` | Preview the production build locally. |\n| `npm run lint` | Run ESLint. |\n\n### Deploying\n\n`npm run build` emits a static `dist/` folder. Host it on any static host (GitHub Pages,\nNetlify, S3, etc.) — there is nothing server‑side to run.\n\n#### GitHub Pages (automated)\n\nThis repo ships a [GitHub Actions workflow](./.github/workflows/deploy-pages.yml) that builds\nthe app and publishes it to GitHub Pages on every push to `main` (and on demand via the\nActions tab → **Deploy to GitHub Pages** → **Run workflow**).\n\nTo enable it once: open **Settings → Pages** and set **Source** to **GitHub Actions**. The\nsite is then served from `https://\u003cowner\u003e.github.io/ghcp-ulb-ui/`.\n\n\u003e The Vite [`base`](./vite.config.ts) is set to `/ghcp-ulb-ui/` so asset URLs resolve under\n\u003e that project‑pages subpath. If you deploy under a different repo name or to a custom domain,\n\u003e update `base` accordingly.\n\n## How it maps to the API\n\n| UI concept | Scope | Key fields |\n| --- | --- | --- |\n| Universal ULB | `multi_user_customer` | `budget_type: \"BundlePricing\"`, `budget_product_sku: \"ai_credits\"`, `prevent_further_usage: true` |\n| Override budget | `user` | same as above plus a required `user` (login) |\n\nBase endpoint:\n`https://api.github.com/enterprises/{enterprise}/settings/billing/budgets`\n\n## Project structure\n\n```\nsrc/\n  api/        BudgetClient interface + live GitHub client + localStorage mock client\n  components/ Header, universal card, overrides table/panel, dialogs, theme toggle\n  context/    Color mode, connection (demo/live + token), toast providers\n  hooks/      TanStack Query hooks for budgets\n  types/      Budget types, payloads, AI Credits constants\n  utils/      CSV/Excel parsing, bulk import, formatting, concurrency pool\n```\n\n## Tech stack\n\nVite · React 19 · TypeScript · Primer React + Octicons · TanStack Query ·\npapaparse (CSV) · SheetJS/xlsx (Excel).\n\n\u003e Note: this project pins the patched SheetJS CDN build of `xlsx` (the npm package has\n\u003e unaddressed security advisories).\n\n## License\n\nReleased under the [MIT License](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabhi-singhs%2Fghcp-ulb-ui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fabhi-singhs%2Fghcp-ulb-ui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabhi-singhs%2Fghcp-ulb-ui/lists"}