diff --git a/frontend/src/lib/components/workspaceSettings/DeployToHub.svelte b/frontend/src/lib/components/workspaceSettings/DeployToHub.svelte index feef41c19a..41b241aa09 100644 --- a/frontend/src/lib/components/workspaceSettings/DeployToHub.svelte +++ b/frontend/src/lib/components/workspaceSettings/DeployToHub.svelte @@ -5,7 +5,6 @@ import SchemaForm from '$lib/components/SchemaForm.svelte' import Tooltip from '$lib/components/Tooltip.svelte' import TextInput from '$lib/components/text_input/TextInput.svelte' - import Select from '$lib/components/select/Select.svelte' import { sendUserToast } from '$lib/toast' import { AppService, @@ -137,6 +136,9 @@ return typeof v === 'string' && v !== '' ? v : undefined } + // Folder name (no `f/`) this project is scoped to; provided by the /folders launcher. + let { folder: folderProp }: { folder: string } = $props() + let phase = $state('predeploy') let workspaceItems = $state([]) let draftItems = $state([]) @@ -150,16 +152,11 @@ timeStyle: 'short' }) - let selectedFolder = $state(undefined) - let availableFolders = $derived( - Array.from( - new Set( - workspaceItems - .map((i) => i.path.split('/').slice(0, 2).join('/')) - .filter((p) => p.startsWith('f/')) - ) - ).sort() - ) + // Project is always scoped to folderProp; selectedFolder is its `f/`-prefixed path. + let selectedFolder = $derived(`f/${folderProp}`) + function folderQs(folder: string = folderProp): string { + return `?folder=${encodeURIComponent(folder)}` + } let filteredWorkspaceItems = $derived( selectedFolder ? workspaceItems.filter((i) => i.path.startsWith(selectedFolder + '/')) : [] ) @@ -399,14 +396,14 @@ } } - async function rehydrateFromHub(workspace: string, seq: number) { + async function rehydrateFromHub(workspace: string, folder: string, seq: number) { try { - const res = await fetch(`/api/w/${workspace}/hub/project`, { + const res = await fetch(`/api/w/${workspace}/hub/project${folderQs(folder)}`, { credentials: 'include', headers: { accept: 'application/json' } }) if (seq !== workspaceLoadSeq) return - if (!res.ok) return // 404 = no project published for this workspace yet + if (!res.ok) return // 404 = no project published for this folder yet const p = JSON.parse(await res.text()) if (seq !== workspaceLoadSeq || !p?.slug) return effectiveSlug = p.slug @@ -438,7 +435,6 @@ workspaceItems = [] workspaceTriggers = [] schedulePreviews = {} - selectedFolder = undefined manualDeselected = new Set() phase = 'predeploy' draftItems = [] @@ -454,7 +450,8 @@ bundleReadme = '' loadWorkspace($workspaceStore, seq) loadTriggers($workspaceStore, seq) - rehydrateFromHub($workspaceStore, seq) + // Resume the folder's project if one exists. + rehydrateFromHub($workspaceStore, folderProp, seq) } }) @@ -637,7 +634,7 @@ const workspace = $workspaceStore if (!workspace) return try { - const res = await fetch(`/api/w/${workspace}/hub/publish_draft`, { + const res = await fetch(`/api/w/${workspace}/hub/publish_draft${folderQs()}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', @@ -898,7 +895,7 @@ path: string, body: unknown ): Promise | undefined> { - const res = await fetch(`/api/w/${workspace}${path}`, { + const res = await fetch(`/api/w/${workspace}${path}${folderQs()}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', @@ -1185,7 +1182,7 @@ submitting = true try { const res = await fetch( - `/api/w/${workspace}/hub/projects/${encodeURIComponent(slug)}/submit`, + `/api/w/${workspace}/hub/projects/${encodeURIComponent(slug)}/submit${folderQs()}`, { method: 'POST', credentials: 'include', @@ -1219,7 +1216,7 @@ // under_review / live: re-fetch the Hub project to pick up an // admin status change (under_review -> live). const before = phase - await rehydrateFromHub(workspace, workspaceLoadSeq) + await rehydrateFromHub(workspace, folderProp, workspaceLoadSeq) sendUserToast( phase === before ? 'Still waiting for review.' @@ -1235,12 +1232,6 @@ } } function startNewDraft() { - const folders = new Set( - draftItems - .map((i) => i.path.split('/').slice(0, 2).join('/')) - .filter((p) => p.startsWith('f/')) - ) - selectedFolder = folders.size === 1 ? [...folders][0] : undefined draftItems = [] recordings = {} phase = 'predeploy' @@ -1547,8 +1538,8 @@
  • 1 ? 'opacity-60' : ''}> {stepNum > 1 ? '✓' : '1.'} - Bundle your project — pack every script, - flow, app and resource into a single draft. + Bundle your project — creates a draft on + the Hub with every selected script, flow, app and resource from this folder.
  • 2 ? 'opacity-60' : 'opacity-40'}> {stepNum > 2 ? '✓' : '2.'} @@ -1589,32 +1580,20 @@ {/if} {#if phase === 'predeploy'} -
    - Folder (required) - {#if availableFolders.length === 0} - - This workspace has no f/<folder>/ items. - Personal paths (u/<user>/) cannot be bundled — - move the items you want to publish into a shared folder first. - - {:else} -