feat: Refresh workflow name in workflows selector when updated (#14705)

This commit is contained in:
Mutasem Aldmour
2025-04-23 11:05:44 +02:00
committed by GitHub
parent 1e5c1fceb7
commit 418a588e89
3 changed files with 129 additions and 10 deletions

View File

@@ -0,0 +1,94 @@
import { createTestingPinia } from '@pinia/testing';
import WorkflowSelectorParameterInput, {
type Props,
} from '@/components/WorkflowSelectorParameterInput/WorkflowSelectorParameterInput.vue';
import { createComponentRenderer } from '@/__tests__/render';
import { cleanupAppModals, createAppModals, mockedStore } from '@/__tests__/utils';
import { useProjectsStore } from '@/stores/projects.store';
import { useWorkflowsStore } from '@/stores/workflows.store';
const { onDocumentVisible } = vi.hoisted(() => ({
onDocumentVisible: vi.fn(),
}));
const flushPromises = async () => await new Promise(setImmediate);
vi.mock('@/composables/useDocumentVisibility', () => ({
useDocumentVisibility: () => ({ onDocumentVisible }),
}));
const renderComponent = createComponentRenderer(WorkflowSelectorParameterInput, {
global: {
stubs: {
ResourceLocatorDropdown: true,
},
},
pinia: createTestingPinia({}),
});
const projectsStore = mockedStore(useProjectsStore);
projectsStore.isTeamProjectFeatureEnabled = false;
const workflowsStore = mockedStore(useWorkflowsStore);
describe('WorkflowSelectorParameterInput', () => {
beforeEach(() => {
createAppModals();
});
afterEach(() => {
cleanupAppModals();
});
it('should update cached workflow when page is visible', async () => {
const props: Props = {
modelValue: {
__rl: true,
value: 'workflow-id',
mode: 'list',
},
path: '',
parameter: {
displayName: 'display-name',
type: 'workflowSelector',
name: 'name',
default: '',
},
};
const { emitted } = renderComponent({ props });
await flushPromises();
expect(emitted()['update:modelValue']?.[0]).toEqual([props.modelValue]);
expect(workflowsStore.fetchWorkflow).toHaveBeenCalledWith(props.modelValue.value);
});
it('should update cached workflow when page is visible', async () => {
const props: Props = {
modelValue: {
__rl: true,
value: 'workflow-id',
mode: 'list',
},
path: '',
parameter: {
displayName: 'display-name',
type: 'workflowSelector',
name: 'name',
default: '',
},
};
const { emitted } = renderComponent({ props });
await flushPromises();
// on mount
expect(emitted()['update:modelValue']?.[0]).toEqual([props.modelValue]);
expect(workflowsStore.fetchWorkflow).toHaveBeenCalledWith(props.modelValue.value);
workflowsStore.fetchWorkflow.mockReset();
expect(onDocumentVisible).toHaveBeenCalled();
const onDocumentVisibleCallback = onDocumentVisible.mock.lastCall?.[0];
await onDocumentVisibleCallback();
expect(emitted()['update:modelValue']?.[1]).toEqual([props.modelValue]);
expect(workflowsStore.fetchWorkflow).toHaveBeenCalledWith(props.modelValue.value);
});
});

View File

@@ -23,8 +23,9 @@ import { useTelemetry } from '@/composables/useTelemetry';
import { VIEWS } from '@/constants';
import { SAMPLE_SUBWORKFLOW_WORKFLOW } from '@/constants.workflows';
import type { IWorkflowDataCreate } from '@/Interface';
import { useDocumentVisibility } from '@/composables/useDocumentVisibility';
interface Props {
export interface Props {
modelValue: INodeParameterResourceLocator;
eventBus?: EventBus;
inputSize?: 'small' | 'mini' | 'medium' | 'large' | 'xlarge';
@@ -82,6 +83,8 @@ const { hideDropdown, isDropdownVisible, showDropdown } = useWorkflowResourceLoc
inputRef,
);
const { onDocumentVisible } = useDocumentVisibility();
const {
hasMoreWorkflowsToLoad,
isLoadingResources,
@@ -146,14 +149,18 @@ function setWidth() {
}
}
function onInputChange(value: NodeParameterValue): void {
if (typeof value !== 'string') return;
function onInputChange(workflowId: NodeParameterValue): void {
if (typeof workflowId !== 'string') return;
const params: INodeParameterResourceLocator = { __rl: true, value, mode: selectedMode.value };
const params: INodeParameterResourceLocator = {
__rl: true,
value: workflowId,
mode: selectedMode.value,
};
if (isListMode.value) {
const resource = workflowsStore.getWorkflowById(value);
const resource = workflowsStore.getWorkflowById(workflowId);
if (resource?.name) {
params.cachedResultName = getWorkflowName(value);
params.cachedResultName = getWorkflowName(workflowId);
}
}
emit('update:modelValue', params);
@@ -191,7 +198,27 @@ function openWorkflow() {
window.open(getWorkflowUrl(props.modelValue.value?.toString() ?? ''), '_blank');
}
async function refreshCachedWorkflow() {
if (!props.modelValue || props.modelValue.mode !== 'list' || !props.modelValue.value) {
return;
}
const workflowId = props.modelValue.value;
if (workflowId === true) {
return;
}
try {
await workflowsStore.fetchWorkflow(`${workflowId}`);
onInputChange(workflowId);
} catch (e) {
// keep old cached value
}
}
onDocumentVisible(refreshCachedWorkflow);
onMounted(() => {
void refreshCachedWorkflow();
window.addEventListener('resize', setWidth);
setWidth();
void setWorkflowsResources();