mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-21 00:02:30 +00:00
fix: bring back Publish to Hub for scripts (#11097)
* fix: bring back Publish to Hub for scripts Publishing to the Hub moved to the folder-level flow, which publishes a whole project and needs a workspace admin. That left no way to share a single script, which is what private hubs mostly use the Hub for. Restore the "Publish to Hub" item on the script detail page and in the script list row menu. Both open the Hub's script submission form prefilled with the script, on whichever Hub the instance is configured to use, and are hidden when the instance disables the Hub. Flows and apps still reach the Hub only inside a project. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: open the Hub tab before fetching, and hide Publish to Hub from operators The script list row has to fetch the script before it can build the Hub URL, and Safari refuses window.open after an await, so the tab never opened there. Claim it inside the click with claimTab(), point it at the Hub once the script loads, and close it with a toast if the fetch fails. A blocked popup falls back to a late window.open, and says so if that is blocked too. Operators can't write scripts, so the row menu now hides the item from them, as the script page's menu already does. The script page opens the Hub with noopener, and scriptToHubUrl takes the script instead of eight positional arguments. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
670628b300
commit
864e5f02ec
@@ -9,7 +9,14 @@
|
||||
import type ShareModal from '$lib/components/ShareModal.svelte'
|
||||
|
||||
import { ScriptService, type Script } from '$lib/gen'
|
||||
import { userStore, userWorkspaces, workspaceStore } from '$lib/stores'
|
||||
import {
|
||||
disableHubStore,
|
||||
hubBaseUrlStore,
|
||||
userStore,
|
||||
userWorkspaces,
|
||||
workspaceStore
|
||||
} from '$lib/stores'
|
||||
import { scriptToHubUrl } from '$lib/hub'
|
||||
import { UserDraftDbSyncer } from '$lib/userDraftDbSyncer.svelte'
|
||||
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
@@ -32,6 +39,7 @@
|
||||
FolderOpen,
|
||||
ChevronUpSquare,
|
||||
GitFork,
|
||||
Globe2,
|
||||
List,
|
||||
Pen,
|
||||
Shield,
|
||||
@@ -47,7 +55,12 @@
|
||||
import Popover from '$lib/components/Popover.svelte'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
import { getDeployUiSettings } from '$lib/components/home/deploy_ui'
|
||||
import { editInForkAllowed, editInForkLabel, onEditInForkClick } from '$lib/utils/editInFork'
|
||||
import {
|
||||
claimTab,
|
||||
editInForkAllowed,
|
||||
editInForkLabel,
|
||||
onEditInForkClick
|
||||
} from '$lib/utils/editInFork'
|
||||
import EditInForkButton from './EditInForkButton.svelte'
|
||||
import { isCloudHosted } from '$lib/cloud'
|
||||
|
||||
@@ -403,6 +416,32 @@
|
||||
copyToClipboard(script.path)
|
||||
}
|
||||
},
|
||||
{
|
||||
displayName: 'Publish to Hub',
|
||||
icon: Globe2,
|
||||
action: async () => {
|
||||
// The row only carries metadata, so the code has to be fetched first; the tab is
|
||||
// claimed before that, since Safari won't open one after an await.
|
||||
const tab = claimTab()
|
||||
try {
|
||||
const fullScript = await ScriptService.getScriptByPath({
|
||||
workspace: $workspaceStore!,
|
||||
path: script.path
|
||||
})
|
||||
const url = scriptToHubUrl(fullScript, $hubBaseUrlStore).toString()
|
||||
if (tab) {
|
||||
tab.show(url)
|
||||
} else if (!window.open(url)) {
|
||||
sendUserToast('Allow popups to publish this script to the Hub', true)
|
||||
}
|
||||
} catch (e: any) {
|
||||
tab?.discard()
|
||||
sendUserToast(`Could not load ${script.path}: ${e?.body ?? e?.message ?? e}`, true)
|
||||
}
|
||||
},
|
||||
// Operators can't write scripts, so they have nothing to publish.
|
||||
hide: $disableHubStore || $userStore?.operator
|
||||
},
|
||||
{
|
||||
displayName: script.archived ? 'Unarchive' : 'Archive',
|
||||
icon: Archive,
|
||||
|
||||
+28
-1
@@ -1,5 +1,6 @@
|
||||
import { AppService, FlowService } from './gen'
|
||||
import { AppService, FlowService, type Script } from './gen'
|
||||
import hubPathsData from './hubPaths.json'
|
||||
import { encodeState } from './utils'
|
||||
import {
|
||||
replacePlaceholderForSignatureScriptTemplate,
|
||||
SIGNATURE_TEMPLATE_FLOW_HUB_ID,
|
||||
@@ -17,6 +18,32 @@ export const HubFlow = {
|
||||
SIGNATURE_TEMPLATE: SIGNATURE_TEMPLATE_FLOW_HUB_ID
|
||||
} as const
|
||||
|
||||
/**
|
||||
* The Hub's script submission form, prefilled with this script. The Hub decodes the
|
||||
* hash, so the code never reaches its server until the user submits. Flows and apps
|
||||
* reach the Hub inside a project, published from a folder, so only scripts have this.
|
||||
*/
|
||||
export function scriptToHubUrl(
|
||||
script: Pick<
|
||||
Script,
|
||||
'content' | 'summary' | 'description' | 'kind' | 'language' | 'schema' | 'lock'
|
||||
>,
|
||||
hubBaseUrl: string
|
||||
): URL {
|
||||
const { content, summary, kind, language, schema } = script
|
||||
const url = new URL(hubBaseUrl + '/scripts/add')
|
||||
url.hash = encodeState({
|
||||
content,
|
||||
summary,
|
||||
description: script.description ?? '',
|
||||
kind,
|
||||
language,
|
||||
schema,
|
||||
lock: script.lock ?? ''
|
||||
})
|
||||
return url
|
||||
}
|
||||
|
||||
export function replaceScriptPlaceholderWithItsValues(id: string, content: string) {
|
||||
switch (id) {
|
||||
case HubScript.SIGNATURE_TEMPLATE:
|
||||
|
||||
@@ -22,7 +22,14 @@
|
||||
} from '$lib/utils'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
import ShareModal from '$lib/components/ShareModal.svelte'
|
||||
import { enterpriseLicense, userStore, userWorkspaces, workspaceStore } from '$lib/stores'
|
||||
import {
|
||||
disableHubStore,
|
||||
enterpriseLicense,
|
||||
hubBaseUrlStore,
|
||||
userStore,
|
||||
userWorkspaces,
|
||||
workspaceStore
|
||||
} from '$lib/stores'
|
||||
import { isDeployable, ALL_DEPLOYABLE } from '$lib/utils_deployable'
|
||||
import AIFormAssistant from '$lib/components/copilot/AIFormAssistant.svelte'
|
||||
|
||||
@@ -59,6 +66,7 @@
|
||||
Eye,
|
||||
FolderOpen,
|
||||
GitFork,
|
||||
Globe2,
|
||||
History,
|
||||
Loader2,
|
||||
Pen,
|
||||
@@ -71,6 +79,7 @@
|
||||
ChevronDown,
|
||||
ChevronRight
|
||||
} from 'lucide-svelte'
|
||||
import { scriptToHubUrl } from '$lib/hub'
|
||||
import SharedBadge from '$lib/components/SharedBadge.svelte'
|
||||
import Popover from '$lib/components/Popover.svelte'
|
||||
import ScriptVersionHistory from '$lib/components/ScriptVersionHistory.svelte'
|
||||
@@ -619,6 +628,17 @@
|
||||
})
|
||||
}
|
||||
|
||||
if (!$disableHubStore) {
|
||||
menuItems.push({
|
||||
label: 'Publish to Hub',
|
||||
Icon: Globe2,
|
||||
onclick: () => {
|
||||
if (!script) return
|
||||
window.open(scriptToHubUrl(script, $hubBaseUrlStore).toString(), '_blank', 'noopener')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (showEditButtons) {
|
||||
if (script.archived) {
|
||||
menuItems.push({
|
||||
|
||||
Reference in New Issue
Block a user