From dd416cf519932fd777d15f4e26dc2634860b680b Mon Sep 17 00:00:00 2001 From: tristantr Date: Mon, 25 May 2026 12:03:13 +0200 Subject: [PATCH] Add publish-app drawer with per-app rate limit mock - Publish drawer on raw_apps/apps exposes public URL, copy-iframe, unpublish - Inline per-app rate limit config (req/min, burst, per-IP toggle) - Rename workspace settings "Default app" tab header to "Apps" to cover both default app and public rate limiting Co-Authored-By: Claude Opus 4.7 (1M context) --- .../components/WorkspaceDeployLayout.svelte | 36 +- .../workspaceSettings/DeployToHub.svelte | 736 ++++++++++-------- .../(logged)/workspace_settings/+page.svelte | 12 +- 3 files changed, 444 insertions(+), 340 deletions(-) diff --git a/frontend/src/lib/components/WorkspaceDeployLayout.svelte b/frontend/src/lib/components/WorkspaceDeployLayout.svelte index b6c45b01d0..690b8ef326 100644 --- a/frontend/src/lib/components/WorkspaceDeployLayout.svelte +++ b/frontend/src/lib/components/WorkspaceDeployLayout.svelte @@ -21,6 +21,7 @@ deploymentStatus: Record allSelected?: boolean emptyMessage?: string + hideSelection?: boolean children?: Snippet // Snippets for customization @@ -43,6 +44,7 @@ deploymentStatus, allSelected = false, emptyMessage = 'No items to deploy', + hideSelection = false, header, alerts, itemSummary, @@ -72,20 +74,22 @@ {#if items.length > 0} -
-
- Select all + {#if !hideSelection} +
+
+ Select all +
-
+ {/if}
@@ -97,9 +101,9 @@ {@const isDeployed = status?.status === 'deployed'} onToggleItem?.(item)} path={item.kind !== 'resource' && diff --git a/frontend/src/lib/components/workspaceSettings/DeployToHub.svelte b/frontend/src/lib/components/workspaceSettings/DeployToHub.svelte index 93dbeee670..77e2ec0f42 100644 --- a/frontend/src/lib/components/workspaceSettings/DeployToHub.svelte +++ b/frontend/src/lib/components/workspaceSettings/DeployToHub.svelte @@ -1,377 +1,384 @@ -
- {#if loadingItems} -
- Loading items… -
- {:else if items.length === 0} -

No deployable items found in this workspace.

- {:else} -
-
- Files - - {doneCount}/{actionable.length} ready - -
-
- {#each grouped as { bucket, list } (bucket)} - {@const Icon = BUCKET_ICON[bucket]} - {@const open = !collapsed[bucket]} - - {#if open} -
    - {#each list as it (it.kind + ':' + it.path)} - {@const artifact = artifactOf(it.kind)} - {@const st = statusOf(it)} -
  • - {#if it.kind === 'resource'} - {#if it.resourceType} - - {it.resourceType.charAt(0).toUpperCase() + it.resourceType.slice(1)} - {:else} - {it.path} - {/if} - - Referenced - - {:else} - {it.summary?.trim() || it.path} - {#if artifact} -
    - {#if st.status === 'done'} - - - {artifact === 'recording' ? 'Recorded' : 'Built'} - {#if st.durationMs} - ({(st.durationMs / 1000).toFixed(1)}s) - {/if} - - - {:else} - - {/if} -
    - {/if} - {/if} -
  • - {/each} -
+
+ + {#snippet header()} +
+
+ {#if phase === 'predeploy'} + Not on the Hub yet + {:else} + + + on Hub: + {hubSlug} + + v{hubVersion} + + Open in Hub + {/if} - {/each} +
-
+ {/snippet} -
- {#if !allDone} - - Record all scripts/flows and build all apps before submitting. - + {#snippet itemSummary(item)} + {@const it = item as DeployItem} + + {it.kind === 'resource' ? (it.resourceType ?? it.path) : it.summary?.trim() || it.path} + + {/snippet} + + {#snippet itemActions(item)} + {@const it = item as DeployItem} + {#if phase === 'live' && canRecord(it.kind)} + {#if it.rec === 'recorded'} + + Recorded v{hubVersion} + + + {:else} + + {/if} {/if} - -
- {/if} + {#if phase === 'live' && canPublishApp(it.kind)} + {#if it.published && it.publicUrl} + + Public + + + Open + + + + {:else} + + {/if} + {/if} + {/snippet} + + {#snippet footer()} +
+ {#if phase === 'predeploy'} + + Bundles the whole workspace and publishes it to the Hub as v1. + + + {:else} + + Republishes the current workspace state as v{hubVersion + 1}, overriding the Hub copy. + + + {/if} +
+ {/snippet} +
- + recordDrawer?.closeDrawer()} >

Provide the inputs to run this {recordTarget?.kind} once. The run is captured as a recording - and shipped with the workspace to the Hub. + and attached to the item's current version on the Hub.

- {#if loadingSchema} -
- Loading inputs… -
- {:else if recordSchema} - - {:else} -

This item has no inputs.

- {/if} +
{#snippet actions()} - + + + {/snippet} +
+
diff --git a/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte b/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte index da258d6945..a7dc24465f 100644 --- a/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte @@ -1103,9 +1103,9 @@ }, { id: 'hub', - label: 'Submit to Hub', + label: 'Deploy to Hub', aiId: 'workspace-settings-hub', - aiDescription: 'Submit workspace folders to the Hub for review' + aiDescription: 'Publish this workspace to the Hub' } ] }, @@ -1874,8 +1874,8 @@ export async function main( {:else if tab == 'default_app'} {#if !$enterpriseLicense} @@ -1964,8 +1964,8 @@ export async function main( /> {:else if tab == 'hub'}