Files
coder/site/index.html
T
Kyle Carberry 47846c0ee4 fix(site): inject permissions and organizations metadata to eliminate loading spinners (#22741)
## Problem

Two network requests were blocking the initial page render with
fullscreen `<Loader fullscreen />` spinners:

1. **`POST /api/v2/authcheck`** (permissions) — blocked in `RequireAuth`
via `AuthProvider.isLoading`
2. **`GET /api/v2/organizations`** — blocked in `DashboardProvider`

All other bootstrap queries (`user`, `entitlements`, `appearance`,
`experiments`, `build-info`, `regions`) already used server-side
metadata injection via `index.html` meta tags and resolved instantly.
These two did not.

## Solution

Follow the existing `cachedQuery` + `<meta>` tag pattern to inject both
datasets server-side:

### Server-side (`site/site.go`)
- Add `Permissions` and `Organizations` fields to `htmlState`
- Fetch organizations via `GetOrganizationsByUserID` in parallel with
existing queries
- Evaluate all `permissionChecks` using the RBAC authorizer directly
- Inject results as HTML-escaped JSON into `<meta>` tags

### Frontend
- Register `permissions` and `organizations` in `useEmbeddedMetadata`
- Update `checkAuthorization()` to accept optional metadata and use
`disabledRefetchOptions` when available
- Update `organizations()` to accept optional metadata and use
`cachedQuery` when available
- Wire metadata through `AuthProvider` and `DashboardProvider`

### Note
The Go `permissionChecks` map in `site/site.go` mirrors
`site/src/modules/permissions/index.ts` and must be kept in sync.
2026-03-09 16:12:04 +00:00

64 lines
2.4 KiB
HTML

<!doctype html>
<!--
-####### +######- ########+ ########## ########+. ###########
+#####--###### +#####--#####+ ############ ########## ####+++#####- ###########
####- -#### ####- ##### #### ####+ #### #### .#### ###########
.#### #### #### #### #### ######### ####...+##+ ###########
####. .#### #### +#### #### +#### #### ####+####### ###########
#####- -##### ######..###### ############- ########## #### ##### ###########
.########+ -########. #########+ ########## #### .#### ###########
-->
<head>
<meta charset="utf-8" />
<title>Coder</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#17172E" />
<meta name="application-name" content="{{ .ApplicationName }}" />
<meta property="og:type" content="website" />
<meta property="csrf-token" content="{{ .CSRF.Token }}" />
<meta property="build-info" content="{{ .BuildInfo }}" />
<meta property="user" content="{{ .User }}" />
<meta property="entitlements" content="{{ .Entitlements }}" />
<meta property="appearance" content="{{ .Appearance }}" />
<meta property="userAppearance" content="{{ .UserAppearance }}" />
<meta property="experiments" content="{{ .Experiments }}" />
<meta property="regions" content="{{ .Regions }}" />
<meta property="docs-url" content="{{ .DocsURL }}" />
<meta property="logo-url" content="{{ .LogoURL }}" />
<meta property="tasks-tab-visible" content="{{ .TasksTabVisible }}" />
<meta property="agents-tab-visible" content="{{ .AgentsTabVisible }}" />
<meta property="permissions" content="{{ .Permissions }}" />
<meta property="organizations" content="{{ .Organizations }}" />
<link
rel="alternate icon"
type="image/png"
href="/favicons/favicon-light.png"
media="(prefers-color-scheme: dark)"
/>
<link
rel="icon"
type="image/svg+xml"
href="/favicons/favicon-light.svg"
media="(prefers-color-scheme: dark)"
/>
<link
rel="alternate icon"
type="image/png"
href="/favicons/favicon-dark.png"
media="(prefers-color-scheme: light)"
/>
<link
rel="icon"
type="image/svg+xml"
href="/favicons/favicon-dark.svg"
media="(prefers-color-scheme: light)"
/>
</head>
<body>
<div id="root"></div>
<script type="module" src="./src/index.tsx"></script>
</body>