Multi-account support, Forgejo provider, rename to Gitdeck#14
Merged
Conversation
Carve the GitHub-specific code (oauth device flow, identity fetch, gh-cli loader) out into a Provider plugin and move single-account token persistence to a new accountStore that supports N accounts plus ephemeral env-derived ones. On boot the store migrates a legacy auth.json into accounts.json (atomic write + .legacy.bak) so existing users see no change. The public surface of authProvider/oauth stays stable; tokenStore is marked deprecated. Behaviour for users with a single account is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Expose GET /api/accounts, POST /api/accounts/activate and DELETE /api/accounts so the client can list, switch and remove stored accounts. Activate/remove invalidate the data, notifications and CI caches. The frontend wraps the app in an AccountProvider and renders an AccountSwitcher in the TopBar. The switcher stays hidden until at least two accounts exist, so users on a single account see no UI change yet — this lays the wiring for the multi-account flow that lands in the next step. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The TopBar switcher is now always visible. From its dropdown the user can kick off a fresh device flow to add another GitHub account (modal reusing /api/auth/start + /api/auth/poll), and remove any inactive non-ephemeral account with a confirm prompt. Adding an account triggers a context refresh; removing one invalidates the server-side caches via DELETE /api/accounts. Switching between accounts uses the wiring landed in the previous commit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a useCapability hook that reads the active account's capabilities exposed by /api/accounts and use it in App.tsx to hide the Projects (kanban) tab when the provider doesn't support it. Today every account is GitHub with full capabilities so nothing changes visibly — this just lays the wiring so the Forgejo provider can opt out of Projects, Dependents and Code Search without touching App.tsx again. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add the Forgejo provider (Codeberg config baked in) that authenticates via personal access token: fetchIdentity hits /api/v1/user with a "token …" header, capabilities declare GraphQL/Projects/Dependents unavailable so the UI can hide what doesn't apply. Expose POST /api/accounts/add-token and GET /api/provider-configs. The Add account modal becomes a two-step flow: pick a provider, then either run the existing GitHub device flow or paste a token for Codeberg. The new account lands in accounts.json next to any GitHub one already configured. Data fetching for a Forgejo-active account still falls back to the GitHub code path (next commit re-routes it through the provider). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Move the GitHub-specific fetchers (owners, repos, issues, pull requests, notifications, mark-read mutations) out of dashboardData and notifications and onto GitHubProvider. ForgejoProvider implements the same operations against /api/v1 endpoints, mapping Gitea-style payloads into GhRepo/GhIssue/GhPullRequest/GhNotification. The core now resolves the active account, asks the registry for its provider, and calls provider.listOwners/listRepos/etc with no branches on providerKind. Adding a new backend means writing a Provider implementation and a registry entry — no edits to dashboardData or notifications. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AuthGate used to start the GitHub device flow immediately. Now it loads the provider configs and shows the same picker the Add account modal uses, so a brand-new install can land directly on Codeberg via a personal access token without ever touching GitHub. External auth modes (gh-cli, GITHUB_TOKEN) keep their existing diagnostic panel. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Update AuthGate markup and styles; update app.title i18n and index.html title
Migrate legacy ~/.gh-issues-dashboard to ~/.gitdeck and update Docker, README, i18n, tests
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is the chunk of work that turns the app from a single-account GitHub dashboard into something that can hold a few accounts at once and talk to more than just github.com. Along the way I renamed the project to Gitdeck since "GitHub Dashboard" stopped being accurate.
Heads up: it kind of works end-to-end but I'm still hitting some errors here and there — opening it now so the diff is visible and we can iron the rough edges out in follow-ups instead of in one giant branch.
What's in here
dashboardDataandnotifications. They now sit behind aProviderinterface insrc/server/providers/. The core resolves the active account, asks the registry for its provider, and callsprovider.listOwners/listRepos/ etc. No moreif (providerKind === 'github')branches in the domain layer.auth.jsonis replaced by anaccountStorethat supports N accounts plus ephemeral env-derived ones. First boot migrates the legacy file toaccounts.json(atomic write +.legacy.bak) so existing setups keep working with zero action./api/accountsendpoints (list / activate / delete) and anAccountSwitcherin the TopBar. From the dropdown you can add another GitHub account via device flow or remove an inactive one. Switching invalidates the data / notifications / CI caches./api/v1. Maps Gitea-style payloads into the sameGhRepo/GhIssue/GhPullRequest/GhNotificationshapes the rest of the app already speaks.useCapabilityhook reads the active account's capabilities and hides features the provider doesn't support — e.g. the Projects (kanban) tab disappears for Forgejo since it has no Projects API. Right now every GitHub account declares full capabilities so nothing changes visibly there.gh-cli,GITHUB_TOKEN) keep their diagnostic panel.~/.gh-issues-dashboardto~/.gitdeckon first run.Why it's structured this way
The provider interface is the load-bearing piece. Adding a third backend (Gitea proper, GitLab, whatever) should mean writing one
Providerimplementation and a registry entry — no edits todashboardData,notifications, or the React side. The capability flags are the escape hatch for "this backend doesn't have feature X" so the UI degrades gracefully instead of erroring.The rename was deliberately bundled in: once Forgejo lands, calling the app "GitHub Dashboard" is misleading, and doing the rename separately would mean churning the same files twice.
Tests / sanity checks
tests/server/accountStore.test.tscovers the migration + multi-account read/write paths.Migration notes
auth.json→accounts.jsonhappens automatically on first boot; the old file is kept asauth.json.legacy.bak.~/.gh-issues-dashboard→~/.gitdecklikewise migrated on first boot.