mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-09 16:05:42 +00:00
fix: answer the round-33 nits on the hub route and the empty state
- `empty_state_view` is no longer logged for an archived-only workspace, which is not the state the counter measures. - `detail`'s fetcher keeps its last answer in a local instead of reading `detail.current`, a self-reference that typed the resource `any`. - `list_projects`' comment, including its authorization contract, is back on the handler rather than on the predicate inserted above it. - `listHubProjects` documents the 400 an instance with the hub disabled returns. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
This commit is contained in:
co-authored by
Claude Opus 5
parent
1745573ec6
commit
d30bb8a82c
@@ -25624,7 +25624,8 @@ paths:
|
||||
Forwards to the configured Hub's public project catalogue and returns its
|
||||
status code and raw response body. Readable by any workspace member: the
|
||||
listing is not workspace-scoped, and it is proxied only because the Hub's
|
||||
listing endpoint sends no CORS header.
|
||||
listing endpoint sends no CORS header. Refused with 400 when the instance
|
||||
has the Hub disabled, in which case no outbound request is made.
|
||||
operationId: listHubProjects
|
||||
tags:
|
||||
- hubPublish
|
||||
@@ -25637,6 +25638,8 @@ paths:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
"400":
|
||||
description: the Hub is disabled on this instance
|
||||
|
||||
/w/{workspace}/hub/project:
|
||||
get:
|
||||
|
||||
@@ -550,16 +550,6 @@ async fn get_project_by_source(ctx: HubPublishCtx) -> Result<impl IntoResponse,
|
||||
ctx.get("/projects/by_source").await
|
||||
}
|
||||
|
||||
// The hub's project catalogue. Read by any workspace member rather than through
|
||||
// `HubPublishCtx`, which requires an admin: nothing here is workspace-scoped or
|
||||
// publishing-related. It exists at all because the hub's listing endpoint sends no
|
||||
// CORS header, so the browser cannot read it directly the way it reads a single
|
||||
// project. `accept: application/json` is what makes the hub answer with JSON.
|
||||
//
|
||||
// The caller's token is sent only to a hub this instance was pointed at deliberately.
|
||||
// Every other route here is admin-only; this one is not, so forwarding a member's
|
||||
// bearer token to `hub.windmill.dev` would put a credential replayable against this
|
||||
// instance on a host outside it — for a listing that needs no credential at all.
|
||||
/// Whether this instance points at the public hub. Compared by parsed host rather than by the
|
||||
/// string: `hub_base_url` is stored as the operator typed it, so `http://`, a port, a trailing
|
||||
/// slash, a mixed-case scheme or host, userinfo and a trailing dot all name the same public
|
||||
@@ -589,6 +579,16 @@ fn is_public_hub(hub: &str) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
// The hub's project catalogue. Read by any workspace member rather than through
|
||||
// `HubPublishCtx`, which requires an admin: nothing here is workspace-scoped or
|
||||
// publishing-related. It exists at all because the hub's listing endpoint sends no
|
||||
// CORS header, so the browser cannot read it directly the way it reads a single
|
||||
// project. `accept: application/json` is what makes the hub answer with JSON.
|
||||
//
|
||||
// The caller's token is sent only to a hub this instance was pointed at deliberately.
|
||||
// Every other route here is admin-only; this one is not, so forwarding a member's
|
||||
// bearer token to `hub.windmill.dev` would put a credential replayable against this
|
||||
// instance on a host outside it — for a listing that needs no credential at all.
|
||||
async fn list_projects(
|
||||
_authed: ApiAuthed,
|
||||
Extension(db): Extension<DB>,
|
||||
|
||||
@@ -145,12 +145,16 @@
|
||||
// previous controller but `fetchHubProject` takes no signal, and nothing orders the
|
||||
// responses — so picking A, dismissing, then picking B can land A's name, author and
|
||||
// counts over an import that writes B.
|
||||
// Kept in a local rather than read back off `detail.current` inside `detail`'s own fetcher,
|
||||
// which makes the resource's type circular and resolves it to `any`.
|
||||
let lastDetail = $state<ImportProjectSummary | undefined>(undefined)
|
||||
const detail = resource(
|
||||
() => slug,
|
||||
async (s) => {
|
||||
if (!s) return undefined
|
||||
const fetched = await fetchHubProject(s)
|
||||
return s === slug ? fetched : detail.current
|
||||
if (s === slug) lastDetail = fetched
|
||||
return lastDetail
|
||||
}
|
||||
)
|
||||
let project = $derived<ImportProjectSummary | undefined>(
|
||||
|
||||
@@ -40,7 +40,9 @@
|
||||
let newLinkEl: HTMLButtonElement | undefined = $state(undefined)
|
||||
|
||||
onMount(() => {
|
||||
logFeatureUsage('home', 'empty_state_view')
|
||||
// Only the empty case: the counter answers how many workspaces sit empty and what
|
||||
// their owners do next, and a workspace whose items are all archived is neither.
|
||||
if (!archivedOnly) logFeatureUsage('home', 'empty_state_view')
|
||||
})
|
||||
|
||||
// The catalogue is fetched when the picker opens, never on render: `disable_hub` says an
|
||||
|
||||
Reference in New Issue
Block a user