mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-19 08:03:16 +00:00
fix(drafts): land /add redirects on the real workspace username, not "me"
The `/add` → `/edit/u/{username}/draft_{uuid}` redirects ran during
SvelteKit's load phase, BEFORE the (logged) layout's async `getUserExt`
populated `userStore`. `get(userStore)?.username` returned undefined and
fell back to the `'me'` placeholder on every fresh nav, producing
`u/me/draft_{uuid}` paths instead of the user's real namespace — broke
ownership checks against `authed.username` and silently scoped autosaves
under the wrong path.
Layout now persists `username` to localStorage on every successful
`getUserExt`, and `getUsernameForNamespace` (new shared helper, used by
all four `/add/+page.ts` files) reads the live store first, falls back
to the cached value, and only then to `'me'` for true first-ever loads.
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
import { get } from 'svelte/store'
|
||||
import { userStore } from '$lib/stores'
|
||||
|
||||
/**
|
||||
* Workspace username for the authed user, suitable as the `u/{X}/...`
|
||||
* namespace in editor draft paths.
|
||||
*
|
||||
* The `/add` → `/edit/u/{username}/draft_{uuid}` redirects in each
|
||||
* editor's `+page.ts` run during SvelteKit's load phase — BEFORE the
|
||||
* (logged) layout's async `getUserExt` populates `userStore`. Reading
|
||||
* `get(userStore)?.username` from there returns `undefined` on every
|
||||
* fresh nav, falling back to the `'me'` placeholder and producing
|
||||
* `u/me/draft_{uuid}` paths instead of the real namespace.
|
||||
*
|
||||
* The layout writes `username` to `localStorage` on every successful
|
||||
* `getUserExt`, so this helper:
|
||||
* 1. Reads `userStore` first (live value when it IS populated, e.g.
|
||||
* same-tab re-navs after the first load).
|
||||
* 2. Falls back to `localStorage` (warm-cache from the previous
|
||||
* session — covers the load-phase race on cold reload).
|
||||
* 3. Falls back to `'me'` (true first-ever load with no session yet).
|
||||
*/
|
||||
export function getUsernameForNamespace(): string {
|
||||
const live = get(userStore)?.username
|
||||
if (live) return live
|
||||
try {
|
||||
const cached = localStorage.getItem('username')
|
||||
if (cached) return cached
|
||||
} catch {}
|
||||
return 'me'
|
||||
}
|
||||
@@ -136,6 +136,16 @@
|
||||
if (!deepEqual(user, $userStore)) {
|
||||
userStore.set(user)
|
||||
}
|
||||
// Persist the workspace username so the synchronous `/add` →
|
||||
// `/edit/u/{user}/draft_{uuid}` redirects (in each editor's
|
||||
// `+page.ts`) can land on the right namespace without waiting
|
||||
// for this async layout fetch. Without this they fall back to
|
||||
// the `'me'` placeholder on every fresh nav.
|
||||
try {
|
||||
if (user?.username) localStorage.setItem('username', user.username)
|
||||
} catch (e) {
|
||||
console.error('Could not persist username to local storage', e)
|
||||
}
|
||||
if (isCloudHosted() && user?.is_admin) {
|
||||
isPremiumStore.set(await WorkspaceService.getIsPremium({ workspace }))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { redirect } from '@sveltejs/kit'
|
||||
import { base } from '$app/paths'
|
||||
import { get } from 'svelte/store'
|
||||
import { userStore } from '$lib/stores'
|
||||
import { getUsernameForNamespace } from '$lib/userNamespace'
|
||||
import type { PageLoad } from './$types'
|
||||
|
||||
// See /scripts/add/+page.ts for the rationale — redirect at load time
|
||||
@@ -10,7 +9,7 @@ import type { PageLoad } from './$types'
|
||||
export const prerender = false
|
||||
|
||||
export const load: PageLoad = ({ url }) => {
|
||||
const username = get(userStore)?.username ?? 'me'
|
||||
const username = getUsernameForNamespace()
|
||||
const uuid = crypto.randomUUID()
|
||||
const params = new URLSearchParams(url.searchParams)
|
||||
params.set('new_draft', 'true')
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { redirect } from '@sveltejs/kit'
|
||||
import { base } from '$app/paths'
|
||||
import { get } from 'svelte/store'
|
||||
import { userStore } from '$lib/stores'
|
||||
import { getUsernameForNamespace } from '$lib/userNamespace'
|
||||
import type { PageLoad } from './$types'
|
||||
|
||||
// See /scripts/add/+page.ts for the rationale — redirect at load time
|
||||
@@ -10,7 +9,7 @@ import type { PageLoad } from './$types'
|
||||
export const prerender = false
|
||||
|
||||
export const load: PageLoad = ({ url }) => {
|
||||
const username = get(userStore)?.username ?? 'me'
|
||||
const username = getUsernameForNamespace()
|
||||
const uuid = crypto.randomUUID()
|
||||
const params = new URLSearchParams(url.searchParams)
|
||||
params.set('new_draft', 'true')
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { redirect } from '@sveltejs/kit'
|
||||
import { base } from '$app/paths'
|
||||
import { get } from 'svelte/store'
|
||||
import { userStore } from '$lib/stores'
|
||||
import { getUsernameForNamespace } from '$lib/userNamespace'
|
||||
import type { PageLoad } from './$types'
|
||||
|
||||
// See /scripts/add/+page.ts for the rationale — redirect at load time
|
||||
@@ -10,7 +9,7 @@ import type { PageLoad } from './$types'
|
||||
export const prerender = false
|
||||
|
||||
export const load: PageLoad = ({ url }) => {
|
||||
const username = get(userStore)?.username ?? 'me'
|
||||
const username = getUsernameForNamespace()
|
||||
const uuid = crypto.randomUUID()
|
||||
const params = new URLSearchParams(url.searchParams)
|
||||
params.set('new_draft', 'true')
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { redirect } from '@sveltejs/kit'
|
||||
import { base } from '$app/paths'
|
||||
import { get } from 'svelte/store'
|
||||
import { userStore } from '$lib/stores'
|
||||
import { getUsernameForNamespace } from '$lib/userNamespace'
|
||||
import type { PageLoad } from './$types'
|
||||
|
||||
// Redirect at the load phase, before the +page.svelte ever mounts. The
|
||||
@@ -9,17 +8,11 @@ import type { PageLoad } from './$types'
|
||||
// one frame before navigating, hence the white flash; doing the work in
|
||||
// `load` lets SvelteKit cancel the route transition and head straight
|
||||
// for the edit page.
|
||||
//
|
||||
// `userStore` is populated client-side by the (logged) layout, so by
|
||||
// the time this load runs (always after layout setup) it usually has
|
||||
// the real username. The `'me'` fallback is the same one the original
|
||||
// onMount used — keeps behavior identical for the rare race where the
|
||||
// store hasn't filled yet.
|
||||
|
||||
export const prerender = false
|
||||
|
||||
export const load: PageLoad = ({ url }) => {
|
||||
const username = get(userStore)?.username ?? 'me'
|
||||
const username = getUsernameForNamespace()
|
||||
const uuid = crypto.randomUUID()
|
||||
const params = new URLSearchParams(url.searchParams)
|
||||
params.set('new_draft', 'true')
|
||||
|
||||
Reference in New Issue
Block a user