Files
windmill/frontend/src/lib/components/operatingWorkspace.svelte.ts
T
6186a0645d feat: edit variables, resources and triggers in their own session tab (#11206)
* feat: edit variables, resources and triggers in their own session tab

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: take a trigger's flow kind from its config and name the written trigger

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* refactor: one operating-workspace context for editors acting on a session's workspace

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: reload page item tabs only in sessions acting on the tool's workspace

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: resolve open in workspace for every preview tab kind in one place

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: guard every component under a session editor against the navigation workspace

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: show a page item tab whose item is gone instead of mounting its editor

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: follow a saved page item in the tab's own workspace and restore in-frame rows

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat: close a page item tab from its editor header

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: judge trigger permissions by the user acting in the session workspace

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: judge every session-editor permission by the user acting in that workspace

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: keep session permissions reactive to the acting role and restore tabs as last seen

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: default Path's owner controls to the user acting in its workspace

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2026-09-19 23:29:14 +02:00

49 lines
2.7 KiB
TypeScript

import { getContext, setContext } from 'svelte'
import { fromStore, toStore, type Readable } from 'svelte/store'
import { workspaceStore } from '$lib/stores'
import { withWorkspaceParam } from './sessions/sessionMode.svelte'
import { useActingUser } from '$lib/actingUser.svelte'
// The workspace a subtree acts on. An AI session edits its (possibly forked) workspace while
// `workspaceStore` stays on the navigation workspace, and a component that reads the navigation
// store directly writes to the parent from inside a fork's editor. So the hosts that embed an
// editor for another workspace set it once, and every component under them reads
// `useOperatingWorkspace()` instead of `$workspaceStore` — nothing has to thread it through props.
// Outside such a host it is the navigation store itself.
const KEY = Symbol('operatingWorkspace')
const navigation = fromStore(workspaceStore)
/** Declare the workspace this subtree acts on. A getter, read wherever the workspace is used;
* resolving to nothing defers to the enclosing host. Reads context: call during component
* initialisation. */
export function setOperatingWorkspace(resolve: () => string | undefined): void {
const outer = getContext<(() => string | undefined) | undefined>(KEY)
setContext(KEY, outer ? () => resolve() ?? outer() : resolve)
}
/** The workspace this component acts on, as a store. Reads context: call during component
* initialisation. Falls back to the navigation workspace where no host set one, or where the
* host's resolves to nothing. */
export function useOperatingWorkspace(): Readable<string | undefined> {
const resolve = getContext<(() => string | undefined) | undefined>(KEY)
return resolve ? toStore(() => resolve() ?? navigation.current) : workspaceStore
}
/** The user acting in this subtree's operating workspace: `$userStore` describes the navigation
* workspace, so a permission check reading it inside a fork's editor answers about the parent —
* enabling or disabling controls by the wrong roles. Unresolved reads as unknown, which
* `canWrite`/`isOwner` refuse; ask `resolved` before rendering that as a denial. Reads context
* and registers an effect: call during component initialisation. */
export function useOperatingUser(): ReturnType<typeof useActingUser> {
const operating = fromStore(useOperatingWorkspace())
return useActingUser(() => operating.current)
}
/** Stamps this component's operating workspace onto an in-app link, which otherwise opens in
* the navigation workspace. Reads context: call during component initialisation. */
export function useOperatingWorkspaceHref(): (href: string) => string {
const operating = fromStore(useOperatingWorkspace())
return (href) => withWorkspaceParam(href, operating.current)
}