mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-30 08:16:49 +00:00
fix: show not deployed yet for undeployed apps in session preview tabs (#12076)
* fix: show not deployed yet for undeployed apps in session preview tabs * fix: say what an embed-token 404 means in the app viewer comment * fix: name the protection rule only when the rules were actually read
This commit is contained in:
@@ -117,6 +117,9 @@
|
||||
headers
|
||||
})
|
||||
if (!res.ok) {
|
||||
// Minted for the deployed app under the caller's RLS: a 404 is "nothing deployed here" or
|
||||
// "not visible to this member", the same reading as `getAppLiteByPath`'s 404 below.
|
||||
if (res.status == 404) onLoadState?.('not_found')
|
||||
const err: any = new Error('Failed to fetch embed token')
|
||||
err.status = res.status
|
||||
throw err
|
||||
|
||||
@@ -21,8 +21,11 @@
|
||||
previewLocationLabel,
|
||||
barePath
|
||||
} from './previewRouter'
|
||||
import { useSessionPermissions } from './sessionPermissions.svelte'
|
||||
import { useSessionPermissions, useSessionReadOnly } from './sessionPermissions.svelte'
|
||||
import { agentWriteCount } from '$lib/components/flows/agentEditorStore.svelte'
|
||||
import { userWorkspaces } from '$lib/stores'
|
||||
import { findCanonicalDevWorkspace } from '$lib/utils/workspaceHierarchy'
|
||||
import { devLabelNoun } from '$lib/utils/devWorkspaceLabel'
|
||||
|
||||
let {
|
||||
runtime,
|
||||
@@ -70,6 +73,8 @@
|
||||
() => runtime.manager
|
||||
)
|
||||
const canEdit = $derived(permissions.canOpenEditor(kind))
|
||||
const protectedWorkspace = useSessionReadOnly(() => workspaceId)
|
||||
const devWorkspace = $derived(findCanonicalDevWorkspace(workspaceId, $userWorkspaces))
|
||||
|
||||
// This reads the deployed version over the API rather than from the editor cell the
|
||||
// chat mutates, so it is the one preview kind that does not self-sync (the invariant
|
||||
@@ -259,7 +264,11 @@
|
||||
<div class="text-xs text-tertiary max-w-sm">
|
||||
Nothing is deployed at <span class="font-mono">{path}</span>, so there is no deployed
|
||||
version to view.{#if canEdit}{' '}
|
||||
Deploy it from the editor to see it here.{/if}
|
||||
Deploy it from the editor to see it here.{:else if protectedWorkspace.confirmed}{' '}
|
||||
Direct deployment is disabled in this workspace, so this session can read and run deployed
|
||||
items, but not edit. Pick {devWorkspace
|
||||
? `its ${devLabelNoun(devWorkspace.dev_workspace_label)}`
|
||||
: 'a fork'} to make changes.{/if}
|
||||
</div>
|
||||
{#if canEdit}
|
||||
<Button unifiedSize="sm" variant="default" startIcon={{ icon: Pen }} on:click={toEditSide}>
|
||||
|
||||
@@ -16,9 +16,12 @@ import { previewPageAllowed, type PreviewPage } from './previewRouter'
|
||||
/** Whether a session in `workspace` is read-only because the workspace is protected: the verdict
|
||||
* `resolveSessionAccess` gives the chat, so the UI and the toolset agree. */
|
||||
export function useSessionReadOnly(workspace: () => string | undefined) {
|
||||
const verdict = resource(workspace, async (ws) =>
|
||||
ws ? { workspace: ws, readOnly: await isReadOnlySessionWorkspace(ws) } : undefined
|
||||
)
|
||||
const verdict = resource(workspace, async (ws) => {
|
||||
if (!ws) return undefined
|
||||
const readOnly = await isReadOnlySessionWorkspace(ws)
|
||||
// Only a successful read settles a verdict; a failed one is read-only to fail closed.
|
||||
return { workspace: ws, readOnly, rulesRead: settledReadOnlyVerdict(ws) !== undefined }
|
||||
})
|
||||
// `resource` keeps the previous workspace's verdict while it asks about the next one.
|
||||
const verdictFor = (ws: string): boolean | undefined => {
|
||||
const landed = verdict.current
|
||||
@@ -38,6 +41,16 @@ export function useSessionReadOnly(workspace: () => string | undefined) {
|
||||
const ws = workspace()
|
||||
return !!ws && (verdictFor(ws) ?? false)
|
||||
},
|
||||
/** Protected by a rule that was actually read: false when the read failed, where the session
|
||||
* is still read-only. For text that names the rule as the reason. */
|
||||
get confirmed() {
|
||||
const ws = workspace()
|
||||
if (!ws) return false
|
||||
const landed = verdict.current
|
||||
return landed?.workspace === ws
|
||||
? landed.readOnly && landed.rulesRead
|
||||
: (settledReadOnlyVerdict(ws) ?? false)
|
||||
},
|
||||
/** Whether the rules were read, a failed read included, which settles as read-only. */
|
||||
get settled() {
|
||||
const ws = workspace()
|
||||
|
||||
Reference in New Issue
Block a user