{#if menuOpen} goto('/schedules')} bind:this={scheduleEditor} /> {/if} {#snippet chatBadge()} {/snippet} {#snippet badges()} {#if flow.archived} archived {/if} dispatch('change')} /> {#if flow.labels?.length} {#each flow.labels.slice(0, 3) as label} {label} {/each} {#if flow.labels.length > 3} 'Label: ' + l) .join('\n')}>+{flow.labels.length - 3} {/if} {/if} {/snippet} {#snippet actions()} {#if !$userStore?.operator} {#if showEditButton && flow.canWrite && !flow.archived} 0 ? flow.summary : flow.path}`} aiDescription={`Edits the flow ${flow.summary?.length > 0 ? flow.summary : flow.path}`} > Edit {/if} {#if !isCloudHosted() && editInForkAllowed($workspaceStore, $userWorkspaces) && (!showEditButton || !flow.canWrite)} {/if} {/if} 0 ? flow.summary : flow.path}`} aiDescription={`Open dropdown for flow ${flow.summary?.length > 0 ? flow.summary : flow.path} options`} items={async () => { let { draft_only, path, archived } = flow let owner = isOwner(path, $userStore, $workspaceStore) const canEdit = flow.canWrite && showEditButton if (draft_only) { return [ { displayName: 'Delete', icon: Trash, action: (event) => { // @ts-ignore if (event?.shiftKey) { deleteFlow(path) } else { deleteConfirmedCallback = () => { deleteFlow(path) } } }, type: 'delete', // A draft-only row is always the authed user's own draft (the // list endpoint only surfaces own/legacy draft-only rows), so // discarding it never requires write permission on the path. disabled: !showEditButton, hide: $userStore?.operator && !$operatorBuilderFlows } ] } return [ { displayName: 'View runs', icon: List, href: `${base}/runs/${path}` }, { displayName: 'Duplicate/Fork', icon: GitFork, href: `${base}/flows/add?template=${path}`, disabled: !showEditButton, hide: $userStore?.operator && !$operatorBuilderFlows }, { displayName: editInForkLabel($workspaceStore, $userWorkspaces), icon: Pen, // No `href`: the handler resolves the destination asynchronously, and a melt // menu item's anchor navigates before a delegated onclick can preventDefault it. action: (e) => onEditInForkClick(e, 'flow', path), hide: $userStore?.operator || isCloudHosted() || !editInForkAllowed($workspaceStore, $userWorkspaces) }, { displayName: 'Audit logs', icon: Eye, href: `${base}/audit_logs?resource=${path}`, hide: $userStore?.operator }, { displayName: 'Move/Rename', icon: FolderOpen, action: () => { moveDrawer.openDrawer(path, flow.summary, 'flow') }, disabled: !owner || archived || !canEdit, hide: $userStore?.operator && !$operatorBuilderFlows }, { displayName: 'Copy path', icon: Copy, action: () => { copyToClipboard(path) } }, ...(isDeployable('flow', path, await getDeployUiSettings()) ? [ { displayName: 'Deploy to staging/prod', icon: ChevronUpSquare, action: () => { deploymentDrawer.openDrawer(path, 'flow') }, disabled: archived, hide: $userStore?.operator } ] : []), { displayName: 'Deployments', icon: HistoryIcon, action: () => { flowHistory?.open() }, hide: $userStore?.operator && !$operatorBuilderFlows }, { displayName: 'Schedule', icon: Calendar, action: () => { scheduleEditor?.openNew(true, path) }, disabled: archived, hide: $userStore?.operator && !$operatorBuilderFlows }, { displayName: 'Permissions', icon: Shield, action: () => { shareModal.openDrawer && shareModal.openDrawer(path, 'flow') }, hide: $userStore?.operator && !$operatorBuilderFlows }, { displayName: archived ? 'Unarchive' : 'Archive', icon: Archive, action: () => { path && archiveFlow(path, !archived) }, type: 'delete', disabled: !owner || !canEdit, hide: $userStore?.operator && !$operatorBuilderFlows }, { displayName: 'Delete', icon: Trash, action: (event) => { // @ts-ignore if (event?.shiftKey) { deleteFlow(path) } else { deleteConfirmedCallback = () => { deleteFlow(path) } } }, type: 'delete', disabled: !owner || !canEdit, hide: $userStore?.operator && !$operatorBuilderFlows } ] }} on:open={() => { menuOpen = true }} /> {/snippet}