mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-15 16:03:02 +00:00
feat: show operators a disabled fork entry explaining the ruleset
When no ruleset allows operators to fork, the workspace picker keeps a greyed-out "Workspace fork" entry whose tooltip says an admin can turn on "Allow operators to fork". It stays hidden when forking is disabled for everyone, as it is for developers. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
cd3efb86ed
commit
d39d134222
@@ -36,7 +36,11 @@
|
||||
findWorkspaceAncestors,
|
||||
isForkOwner
|
||||
} from '$lib/utils/workspaceHierarchy'
|
||||
import { canCreateFork } from '$lib/utils/editInFork'
|
||||
import {
|
||||
canCreateFork,
|
||||
OPERATOR_FORK_BLOCKED_REASON,
|
||||
operatorForkBlocked
|
||||
} from '$lib/utils/editInFork'
|
||||
import { workspaceRootId } from '$lib/components/sessions/sessionScope.svelte'
|
||||
import DevWorkspaceBadge from '$lib/components/DevWorkspaceBadge.svelte'
|
||||
|
||||
@@ -156,6 +160,11 @@
|
||||
const canForkHere = $derived(
|
||||
(!isCloudHosted() || $maybePremium) && $workspaceStore !== 'admins' && canCreateFork($userStore)
|
||||
)
|
||||
const forkBlockedHere = $derived(
|
||||
(!isCloudHosted() || $maybePremium) &&
|
||||
$workspaceStore !== 'admins' &&
|
||||
operatorForkBlocked($userStore)
|
||||
)
|
||||
// The row mechanics below — which family to expand, which collapsed row carries the tick — key on
|
||||
// a depth-0 row of the list, which `buildWorkspaceHierarchy` puts at the highest workspace the
|
||||
// caller can see: parentless, or with a parent absent from their list. `findWorkspaceAncestors`
|
||||
@@ -363,7 +372,7 @@
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{#if (isCloudHosted() || $superadmin || canForkHere) && !strictWorkspaceSelect}
|
||||
{#if (isCloudHosted() || $superadmin || canForkHere || forkBlockedHere) && !strictWorkspaceSelect}
|
||||
<div class="py-1" role="none">
|
||||
{#if isCloudHosted() || $superadmin}
|
||||
<MenuItem href="/user/create_workspace" class={itemClass} {item}>
|
||||
@@ -376,16 +385,25 @@
|
||||
<Plus size={16} />
|
||||
Workspace fork
|
||||
</MenuItem>
|
||||
{:else if forkBlockedHere}
|
||||
<Tooltip class="block w-full" placement="right" openDelay={200}>
|
||||
<div
|
||||
class="{itemClass} opacity-60 cursor-not-allowed hover:bg-transparent"
|
||||
aria-disabled="true"
|
||||
>
|
||||
<Plus size={16} />
|
||||
Workspace fork
|
||||
</div>
|
||||
{#snippet text()}
|
||||
<span class="block max-w-64 text-xs">{OPERATOR_FORK_BLOCKED_REASON}</span>
|
||||
{/snippet}
|
||||
</Tooltip>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{#if canManageWorkspace && !strictWorkspaceSelect}
|
||||
<div class="py-1" role="none">
|
||||
<MenuItem
|
||||
href="/workspace_settings?workspace={$workspaceStore}"
|
||||
class={itemClass}
|
||||
{item}
|
||||
>
|
||||
<MenuItem href="/workspace_settings?workspace={$workspaceStore}" class={itemClass} {item}>
|
||||
<Settings size={16} />
|
||||
{(activeWorkspace && ambiguousNames.has(activeWorkspace.name)
|
||||
? activeWorkspace.id
|
||||
|
||||
@@ -76,6 +76,18 @@ export function canCreateFork(user: UserExt | undefined): boolean {
|
||||
)
|
||||
}
|
||||
|
||||
export const OPERATOR_FORK_BLOCKED_REASON =
|
||||
'Operators cannot fork this workspace. A workspace admin can allow it by turning on "Allow operators to fork" in a ruleset, under Workspace settings > Rulesets.'
|
||||
|
||||
/**
|
||||
* Whether the only thing refusing this user a fork is the missing `AllowOperatorForking`. The fork
|
||||
* entries then stay visible, disabled, so the operator learns an admin can turn it on; when forking
|
||||
* is disabled for everyone they stay hidden, as they are for developers.
|
||||
*/
|
||||
export function operatorForkBlocked(user: UserExt | undefined): boolean {
|
||||
return !!user?.operator && !canCreateFork(user) && !isRuleActive('DisableWorkspaceForking')
|
||||
}
|
||||
|
||||
function editPathFor(itemType: ItemType, itemPath: string): string {
|
||||
switch (itemType) {
|
||||
case 'script':
|
||||
|
||||
Reference in New Issue
Block a user