fix: hide template selector after shared workflow accept (#9913)

## Summary

Hide the template selector when a first-time cloud user accepts a shared
workflow from a share link, so the shared workflow opens without the
onboarding template dialog lingering.

## Changes

- **What**: Added shared-workflow loader behavior to close the global
template selector on accept actions (`copy-and-open` and `open-only`)
while keeping cancel behavior unchanged.
- **What**: Added targeted unit tests covering hide-on-accept and
no-hide-on-cancel behavior in the shared workflow URL loader.

## Review Focus

Confirm that share-link accept paths now dismiss the template selector
and that cancel still leaves it available.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9913-fix-hide-template-selector-after-shared-workflow-accept-3236d73d365081099c04e350d499fad2)
by [Unito](https://www.unito.io)

Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Alexander Brown
2026-03-14 01:05:31 -07:00
committed by GitHub
parent 11fc09220c
commit bb6f00dc68
2 changed files with 47 additions and 0 deletions

View File

@@ -78,6 +78,7 @@ vi.mock('vue-i18n', () => ({
const mockShowLayoutDialog = vi.hoisted(() => vi.fn())
const mockCloseDialog = vi.hoisted(() => vi.fn())
const mockHideTemplateSelector = vi.hoisted(() => vi.fn())
vi.mock('@/services/dialogService', () => ({
useDialogService: () => ({
@@ -91,6 +92,12 @@ vi.mock('@/stores/dialogStore', () => ({
})
}))
vi.mock('@/composables/useWorkflowTemplateSelectorDialog', () => ({
useWorkflowTemplateSelectorDialog: () => ({
hide: mockHideTemplateSelector
})
}))
function makePayload(
overrides: Partial<SharedWorkflowPayload> = {}
): SharedWorkflowPayload {
@@ -173,6 +180,18 @@ describe('useSharedWorkflowUrlLoader', () => {
)
})
it('hides template selector when user confirms opening shared workflow', async () => {
mockQueryParams = { share: 'share-id-1' }
mockShowLayoutDialog.mockImplementation(() => {
resolveDialogWithConfirm(makePayload())
})
const { loadSharedWorkflowFromUrl } = useSharedWorkflowUrlLoader()
await loadSharedWorkflowFromUrl()
expect(mockHideTemplateSelector).toHaveBeenCalledTimes(1)
})
it('does not load graph when user cancels dialog', async () => {
mockQueryParams = { share: 'share-id-1' }
mockShowLayoutDialog.mockImplementation(() => {
@@ -190,6 +209,18 @@ describe('useSharedWorkflowUrlLoader', () => {
)
})
it('does not hide template selector when user cancels shared workflow dialog', async () => {
mockQueryParams = { share: 'share-id-1' }
mockShowLayoutDialog.mockImplementation(() => {
resolveDialogWithCancel()
})
const { loadSharedWorkflowFromUrl } = useSharedWorkflowUrlLoader()
await loadSharedWorkflowFromUrl()
expect(mockHideTemplateSelector).not.toHaveBeenCalled()
})
it('calls import when non-owned assets exist and user confirms', async () => {
mockQueryParams = { share: 'share-id-1' }
const payload = makePayload({
@@ -241,6 +272,18 @@ describe('useSharedWorkflowUrlLoader', () => {
expect(mockImportPublishedAssets).not.toHaveBeenCalled()
})
it('hides template selector when user chooses open-only', async () => {
mockQueryParams = { share: 'share-id-1' }
mockShowLayoutDialog.mockImplementation(() => {
resolveDialogWithOpenOnly(makePayload())
})
const { loadSharedWorkflowFromUrl } = useSharedWorkflowUrlLoader()
await loadSharedWorkflowFromUrl()
expect(mockHideTemplateSelector).toHaveBeenCalledTimes(1)
})
it('shows toast on import failure and returns loaded-without-assets', async () => {
mockQueryParams = { share: 'share-id-1' }
const payload = makePayload({

View File

@@ -2,6 +2,7 @@ import { useToast } from 'primevue/usetoast'
import { useI18n } from 'vue-i18n'
import { useRoute, useRouter } from 'vue-router'
import { useWorkflowTemplateSelectorDialog } from '@/composables/useWorkflowTemplateSelectorDialog'
import OpenSharedWorkflowDialogContent from '@/platform/workflow/sharing/components/OpenSharedWorkflowDialogContent.vue'
import type { SharedWorkflowPayload } from '@/platform/workflow/sharing/types/shareTypes'
import {
@@ -35,6 +36,7 @@ export function useSharedWorkflowUrlLoader() {
const workflowShareService = useWorkflowShareService()
const dialogService = useDialogService()
const dialogStore = useDialogStore()
const templateSelectorDialog = useWorkflowTemplateSelectorDialog()
const SHARE_NAMESPACE = PRESERVED_QUERY_NAMESPACES.SHARE
function isValidParameter(param: string): boolean {
@@ -133,6 +135,8 @@ export function useSharedWorkflowUrlLoader() {
return 'cancelled'
}
templateSelectorDialog.hide()
const { payload } = result
const workflowName = payload.name || t('openSharedWorkflow.dialogTitle')
const nonOwnedAssets = payload.assets.filter((a) => !a.in_library)