From 3ed86816fbafa616e0787eb4caa203157e2e9130 Mon Sep 17 00:00:00 2001 From: Guilhem Date: Tue, 17 Feb 2026 12:48:58 +0000 Subject: [PATCH] fix flow rename (#7978) * fix(frontend): preserve flow settings when updating summary/path from detail page Co-Authored-By: Claude Opus 4.5 * refactor(frontend): type builders prop with ReturnType Co-Authored-By: Claude Opus 4.5 * refactor(frontend): extract shared updateItemPathAndSummary utility to deduplicate move/rename logic Co-Authored-By: Claude Opus 4.6 * feat(frontend): enable inline summary/path editing on script detail page Co-Authored-By: Claude Opus 4.6 * improve layout * feat(frontend): add dirty tracking to MoveDrawer Co-Authored-By: Claude Opus 4.6 * nit move drawer * fix(frontend): drop on_behalf_of_email from move/rename and warn user about redeployment Co-Authored-By: Claude Opus 4.6 * fix(frontend): hide on_behalf_of warning in MoveDrawer when user is not owner Co-Authored-By: Claude Opus 4.6 * fix(frontend): only reload script when path unchanged in onSaved callback Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.5 --- .../lib/components/DropdownSubmenuItem.svelte | 4 +- .../src/lib/components/DropdownV2Inner.svelte | 4 +- frontend/src/lib/components/MoveDrawer.svelte | 112 ++++++++---------- .../lib/components/SummaryPathDisplay.svelte | 103 ++++++++++------ .../details/DetailPageHeader.svelte | 6 +- .../src/lib/components/moveRenameManager.ts | 73 ++++++++++++ .../(logged)/flows/get/[...path]/+page.svelte | 29 +---- .../scripts/get/[...hash]/+page.svelte | 9 ++ 8 files changed, 213 insertions(+), 127 deletions(-) create mode 100644 frontend/src/lib/components/moveRenameManager.ts diff --git a/frontend/src/lib/components/DropdownSubmenuItem.svelte b/frontend/src/lib/components/DropdownSubmenuItem.svelte index b9204b7ae9..45346aaa3c 100644 --- a/frontend/src/lib/components/DropdownSubmenuItem.svelte +++ b/frontend/src/lib/components/DropdownSubmenuItem.svelte @@ -4,12 +4,12 @@ import { twMerge } from 'tailwind-merge' import { ChevronRight } from 'lucide-svelte' import type { Item } from '$lib/utils' - import type { MenubarMenuElements } from '@melt-ui/svelte' + import type { MenubarMenuElements, createDropdownMenu } from '@melt-ui/svelte' import { Tooltip } from './meltComponents' interface Props { item: Item - builders: any + builders: ReturnType['builders'] meltItem: MenubarMenuElements['item'] } diff --git a/frontend/src/lib/components/DropdownV2Inner.svelte b/frontend/src/lib/components/DropdownV2Inner.svelte index 35fedd660e..21157bd6b2 100644 --- a/frontend/src/lib/components/DropdownV2Inner.svelte +++ b/frontend/src/lib/components/DropdownV2Inner.svelte @@ -3,7 +3,7 @@ import DropdownSubmenuItem from '$lib/components/DropdownSubmenuItem.svelte' import { Loader2 } from 'lucide-svelte' import { twMerge } from 'tailwind-merge' - import type { MenubarMenuElements } from '@melt-ui/svelte' + import type { MenubarMenuElements, createDropdownMenu } from '@melt-ui/svelte' import type { Item } from '$lib/utils' import { Tooltip } from './meltComponents' @@ -11,7 +11,7 @@ aiId?: string items?: Item[] | (() => Item[]) | (() => Promise) meltItem: MenubarMenuElements['item'] - builders?: any + builders?: ReturnType['builders'] } let { aiId, items = [], meltItem, builders }: Props = $props() diff --git a/frontend/src/lib/components/MoveDrawer.svelte b/frontend/src/lib/components/MoveDrawer.svelte index 493cab3cc3..f661ae4817 100644 --- a/frontend/src/lib/components/MoveDrawer.svelte +++ b/frontend/src/lib/components/MoveDrawer.svelte @@ -4,21 +4,28 @@ import { Alert, Button, Drawer } from './common' import DrawerContent from './common/drawer/DrawerContent.svelte' import Path from './Path.svelte' - import { AppService, FlowService, ScriptService } from '$lib/gen' import { isOwner } from '$lib/utils' + import { updateItemPathAndSummary, checkFlowOnBehalfOf } from './moveRenameManager' + import Label from './Label.svelte' + import TextInput from './text_input/TextInput.svelte' const dispatch = createEventDispatcher() type Kind = 'script' | 'resource' | 'schedule' | 'variable' | 'flow' | 'app' - let kind: Kind - let initialPath: string = '' - let path: string | undefined = undefined - let summary: undefined | string = undefined + let kind = $state('flow') + let initialPath = $state('') + let initialSummary = $state('') + let path = $state(undefined) + let summary = $state(undefined) + let dirtyPath = $state(false) - let drawer: Drawer + let drawer = $state() as Drawer + + let own = $state(false) + let onBehalfOfEmail = $state(undefined) + let hasChanges = $derived((summary ?? '') !== initialSummary || dirtyPath) - let own = false export async function openDrawer( initialPath_l: string, summary_l: string | undefined, @@ -26,10 +33,16 @@ ) { kind = kind_l path = undefined + dirtyPath = false + onBehalfOfEmail = undefined initialPath = initialPath_l + initialSummary = summary_l ?? '' summary = summary_l loadOwner() drawer.openDrawer() + if (kind === 'flow') { + onBehalfOfEmail = await checkFlowOnBehalfOf($workspaceStore!, initialPath_l) + } } function loadOwner() { @@ -37,51 +50,13 @@ } async function updatePath() { - if (kind == 'flow') { - const flow = await FlowService.getFlowByPath({ + if (kind === 'flow' || kind === 'script' || kind === 'app') { + await updateItemPathAndSummary({ workspace: $workspaceStore!, - path: initialPath - }) - await FlowService.updateFlow({ - workspace: $workspaceStore!, - path: initialPath, - requestBody: { - path: path ?? '', - summary: summary ?? '', - description: flow.description, - value: flow.value, - schema: flow.schema, - tag: flow.tag, - dedicated_worker: flow.dedicated_worker, - ws_error_handler_muted: flow.ws_error_handler_muted, - visible_to_runner_only: flow.visible_to_runner_only, - on_behalf_of_email: flow.on_behalf_of_email - } - }) - } else if (kind == 'script') { - const script = await ScriptService.getScriptByPath({ - workspace: $workspaceStore!, - path: initialPath - }) - script.summary = summary ?? '' - await ScriptService.createScript({ - workspace: $workspaceStore!, - requestBody: { - ...script, - description: script.description ?? '', - lock: script.lock, - parent_hash: script.hash, - path: path ?? '' - } - }) - } else if (kind == 'app') { - await AppService.updateApp({ - workspace: $workspaceStore!, - path: initialPath, - requestBody: { - path: path != initialPath ? path : undefined, - summary - } + kind, + initialPath, + newPath: path ?? '', + newSummary: summary ?? '' }) } dispatch('update', path) @@ -92,24 +67,33 @@ {#if !own} - + Since you do not own this item, you cannot move this item (you can however fork it) {/if} -

Summary

- + {#if own && onBehalfOfEmail} + + This flow will be redeployed on behalf of you ({$userStore?.email}) instead of {onBehalfOfEmail} + + {/if} + -

Path

-
- -
+ {#snippet actions()} - + {/snippet}
diff --git a/frontend/src/lib/components/SummaryPathDisplay.svelte b/frontend/src/lib/components/SummaryPathDisplay.svelte index ed2387167e..1d1e5bd7f7 100644 --- a/frontend/src/lib/components/SummaryPathDisplay.svelte +++ b/frontend/src/lib/components/SummaryPathDisplay.svelte @@ -1,15 +1,19 @@ -{#if editable || onEdit} +{#if editable || onSaved} {/snippet} {#snippet content({ close })} -
- {#if onEdit} -