diff --git a/Dockerfile b/Dockerfile index 9d74397..69b407d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,12 +25,12 @@ COPY --from=builder /app/package.json ./package.json COPY --from=builder /app/dist ./dist COPY --from=builder /app/index.html ./index.html -RUN mkdir -p /home/node/.gh-issues-dashboard \ - && chown -R node:node /home/node/.gh-issues-dashboard /app +RUN mkdir -p /home/node/.gitdeck \ + && chown -R node:node /home/node/.gitdeck /app USER node EXPOSE 8765 -VOLUME ["/home/node/.gh-issues-dashboard"] +VOLUME ["/home/node/.gitdeck"] CMD ["node", "dist/server.js"] diff --git a/README.md b/README.md index b600928..c0cd092 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ -# gh-dashboard - -> `gh-dashboard` is a working name. The final project name will be picked together with the community — share your suggestion in the [naming discussion](https://github.com/debba/gh-dashboard/discussions/1) or on Discord. +# Gitdeck > The initial scaffolding of this repository was produced in an AI-assisted session with [Claude Code](https://claude.com/claude-code). From here on, code is reviewed and maintained by humans, and contributions are welcome. @@ -12,12 +10,12 @@ RepoStars

-An open-source dashboard to explore your GitHub repositories, issues, pull requests, traffic, and CI activity from a single interface. +An open-source, local dashboard to explore repositories, issues, pull requests, traffic, and CI activity across multiple accounts on GitHub and Forgejo-compatible forges (Codeberg, self-hosted) — from a single interface. ## Demo
- gh-dashboard demo + Gitdeck demo
## What it does @@ -49,7 +47,7 @@ Open any repository to see: The app is a single repository with two cooperating processes: -- **Backend** — a Node HTTP server (`src/server.ts` + `src/server/*`) that handles GitHub OAuth (Device Flow), proxies all REST/GraphQL calls, caches responses on disk, and exposes a small JSON API under `/api/*`. The GitHub token is stored locally under `~/.gh-issues-dashboard/` and **never exposed to the browser**. +- **Backend** — a Node HTTP server (`src/server.ts` + `src/server/*`) that handles GitHub OAuth (Device Flow), proxies all REST/GraphQL calls, caches responses on disk, and exposes a small JSON API under `/api/*`. The GitHub token is stored locally under `~/.gitdeck/` and **never exposed to the browser**. - **Frontend** — a React 19 + Vite SPA (`src/main.tsx`, `src/App.tsx`, `src/components/*`, `src/api/*`) that consumes the backend's `/api/*` endpoints. In production both are served by the Node process: Vite builds the SPA into `dist/client/` and the server falls back to `index.html` for non-API routes. @@ -83,7 +81,7 @@ The dashboard talks to GitHub using a personal **OAuth App** with the **Device A 1. Go to → **OAuth Apps** → **New OAuth App**. (For an org-owned app, use **Settings → Developer settings → OAuth Apps** on the organization instead.) 2. Fill in the form: - - **Application name** — anything, e.g. `gh-dashboard (local)`. + - **Application name** — anything, e.g. `Gitdeck (local)`. - **Homepage URL** — `http://127.0.0.1:8765` (or any URL you control; this is informational). - **Authorization callback URL** — `http://127.0.0.1:8765` will do. Device Flow does not actually use a redirect, but GitHub requires the field. 3. Click **Register application**. @@ -111,9 +109,9 @@ When you open the dashboard for the first time, it will: 1. call the backend, which asks GitHub for a **device code**; 2. show you a short **user code** and a verification URL (typically ); 3. you paste the code on GitHub and approve the requested scopes; -4. the backend exchanges the device code for an access token and stores it in `~/.gh-issues-dashboard/` — **the token never reaches the browser**. +4. the backend exchanges the device code for an access token and stores it in `~/.gitdeck/` — **the token never reaches the browser**. -Granted scopes default to `repo read:org project read:user user:email`. To narrow them, set `GITHUB_OAUTH_SCOPES` (see [Configuration](#configuration)). If you ever want to revoke access, remove the app from and delete the local token file under `~/.gh-issues-dashboard/`. +Granted scopes default to `repo read:org project read:user user:email`. To narrow them, set `GITHUB_OAUTH_SCOPES` (see [Configuration](#configuration)). If you ever want to revoke access, remove the app from and delete the local token file under `~/.gitdeck/`. ## Configuration @@ -134,13 +132,13 @@ The server reads its configuration from environment variables: The dashboard can obtain a GitHub token in three different ways. Pick the one that fits your setup: -- **`device` (default)** — OAuth App + Device Flow, as described above. The token is stored under `~/.gh-issues-dashboard/` and refreshed via the in-app sign-in screen. Requires `GITHUB_CLIENT_ID`. +- **`device` (default)** — OAuth App + Device Flow, as described above. The token is stored under `~/.gitdeck/` and refreshed via the in-app sign-in screen. Requires `GITHUB_CLIENT_ID`. - **`gh-cli`** — if you already use the [GitHub CLI](https://cli.github.com/), set `GH_AUTH_MODE=gh-cli` and the server will read the token by running `gh auth token` on each request (cached in-process for 60s). No OAuth App is needed; the scopes are whatever your `gh` session already has. Run `gh auth refresh -h github.com -s repo,read:org,project` if you need extra scopes. - **`token`** — bring-your-own personal access token. Set `GH_AUTH_MODE=token` and export `GITHUB_TOKEN=`. Useful for headless / CI-style deployments. In `gh-cli` and `token` modes the device-flow sign-in screen is hidden; the server treats the configured source as authoritative. -Tokens and snapshots are persisted under `~/.gh-issues-dashboard/`. +Tokens and snapshots are persisted under `~/.gitdeck/`. If you previously ran an older build that stored data in `~/.gh-issues-dashboard/`, the server migrates it automatically on first start. ### Quick env setup @@ -196,7 +194,7 @@ Then open . ## Run with Docker -A multi-stage `Dockerfile` and a `docker-compose.yml` are provided. The image builds the server + SPA bundle and runs as a non-root user; tokens and snapshots are persisted to a named volume mounted at `/home/node/.gh-issues-dashboard`. +A multi-stage `Dockerfile` and a `docker-compose.yml` are provided. The image builds the server + SPA bundle and runs as a non-root user; tokens and snapshots are persisted to a named volume mounted at `/home/node/.gitdeck`. With Docker Compose (recommended): @@ -216,16 +214,16 @@ docker compose up -d --build With plain Docker: ```bash -docker build -t gh-dashboard . -docker run -d --name gh-dashboard \ +docker build -t gitdeck . +docker run -d --name gitdeck \ -p 8765:8765 \ -e GITHUB_CLIENT_ID=Iv1.xxxxxxxxxxxxxxxx \ -e OPENAI_API_KEY=sk-... \ - -v gh-dashboard-data:/home/node/.gh-issues-dashboard \ - gh-dashboard + -v gitdeck-data:/home/node/.gitdeck \ + gitdeck ``` -The container forwards `GITHUB_CLIENT_ID`, `GITHUB_OAUTH_SCOPES`, `OPENAI_API_KEY` and `OPENAI_DIGEST_MODEL` from the host environment (or `.env` with Compose) — see [Configuration](#configuration) for the full list. It sets `HOST=0.0.0.0` so the server is reachable from outside. To wipe the stored token (full logout) remove the volume: `docker volume rm gh-dashboard-data`. +The container forwards `GITHUB_CLIENT_ID`, `GITHUB_OAUTH_SCOPES`, `OPENAI_API_KEY` and `OPENAI_DIGEST_MODEL` from the host environment (or `.env` with Compose) — see [Configuration](#configuration) for the full list. It sets `HOST=0.0.0.0` so the server is reachable from outside. To wipe the stored token (full logout) remove the volume: `docker volume rm gitdeck-data`. ## Test & type-check @@ -266,7 +264,6 @@ Early scaffolding. APIs, modules, and the UI are still being shaped — expect r ## Community - [Discord server](https://discord.gg/YrZPHAwMSG) — suggest features, report issues, or just say hi. -- [Help name the project](https://github.com/debba/gh-dashboard/discussions/1) — open discussion for naming suggestions. ## Contributing diff --git a/docker-compose.yml b/docker-compose.yml index 58cb145..4185829 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,8 @@ services: - gh-dashboard: + gitdeck: build: . - image: gh-dashboard:latest - container_name: gh-dashboard + image: gitdeck:latest + container_name: gitdeck restart: unless-stopped ports: - "8765:8765" @@ -12,7 +12,7 @@ services: OPENAI_API_KEY: ${OPENAI_API_KEY:-} OPENAI_DIGEST_MODEL: ${OPENAI_DIGEST_MODEL:-} volumes: - - gh-dashboard-data:/home/node/.gh-issues-dashboard + - gitdeck-data:/home/node/.gitdeck volumes: - gh-dashboard-data: + gitdeck-data: diff --git a/docs/translations.md b/docs/translations.md index d9a3a9e..a2d69fd 100644 --- a/docs/translations.md +++ b/docs/translations.md @@ -73,7 +73,7 @@ Use a lowercase language code as the file name. For example, Portuguese would us import type { en } from "./en"; export const pt: Record = { - "app.title": "GitHub Dashboard", + "app.title": "Gitdeck", // ... }; ``` diff --git a/index.html b/index.html index cecac5a..1da5dfa 100644 --- a/index.html +++ b/index.html @@ -5,7 +5,7 @@ - GitHub Dashboard + Gitdeck
diff --git a/package.json b/package.json index 127003a..bdfd427 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { - "name": "gh-issues-dashboard", + "name": "gitdeck", "version": "1.0.2", "private": true, "type": "module", - "description": "Local dashboard showing open issues across your GitHub repositories using GitHub OAuth.", + "description": "Local multi-account dashboard for GitHub and Forgejo-compatible forges (Codeberg, self-hosted).", "scripts": { "api": "tsx watch src/server.ts", "dev": "concurrently \"npm:api\" \"vite --host 127.0.0.1\"", diff --git a/src/App.tsx b/src/App.tsx index 98920d8..0fcb352 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -71,6 +71,7 @@ import { formatNumber } from "./utils/format"; import { clearStatsCache, readStatsCache, writeStatsCache } from "./utils/statsCache"; import { clearFiltersCache, hydrateFilters, readFiltersCache, writeFiltersCache } from "./utils/filtersCache"; import { useI18n } from "./i18n/I18nProvider"; +import { useCapability } from "./contexts/AccountContext"; type Tab = "inbox" | "repos" | "issues" | "prs" | "kanban" | "insights" | "ci" | "digests"; type Theme = "dark" | "light" | "auto"; @@ -159,6 +160,7 @@ type AuthState = "checking" | "anonymous" | "authenticated"; export function App() { const { t } = useI18n(); + const projectsEnabled = useCapability("projects"); const location = useLocation(); const navigate = useNavigate(); const [searchParams, setSearchParams] = useSearchParams(); @@ -657,7 +659,9 @@ export function App() { { key: "insights" as const, label: t("tabs.insights"), count: filteredInsights.length, icon: }, { key: "ci" as const, label: t("tabs.ci"), count: ciHealth.length, icon: }, { key: "digests" as const, label: t("tabs.digest"), count: dailyDigests.length, icon: }, - { key: "kanban" as const, label: t("tabs.board"), count: "—", icon: }, + ...(projectsEnabled + ? [{ key: "kanban" as const, label: t("tabs.board"), count: "—", icon: }] + : []), ]; return ( @@ -885,7 +889,7 @@ export function App() { ) : null} - {tab === "kanban" ? : null} + {tab === "kanban" && projectsEnabled ? : null}