diff --git a/packages/frontend/editor-ui/src/components/ResourceLocator/ResourceLocator.test.constants.ts b/packages/frontend/editor-ui/src/components/ResourceLocator/ResourceLocator.test.constants.ts index 5829437aa7..de0822b742 100644 --- a/packages/frontend/editor-ui/src/components/ResourceLocator/ResourceLocator.test.constants.ts +++ b/packages/frontend/editor-ui/src/components/ResourceLocator/ResourceLocator.test.constants.ts @@ -103,3 +103,34 @@ export const TEST_NODE_SINGLE_MODE: INode = { options: {}, }, }; + +export const TEST_PARAMETER_SKIP_CREDENTIALS_CHECK: INodeProperties = { + ...TEST_PARAMETER_MULTI_MODE, + name: 'testParameterSkipCredentialsCheck', + modes: [ + { + displayName: 'From List', + name: 'list', + type: 'list', + typeOptions: { + searchListMethod: 'testSearch', + searchable: true, + skipCredentialsCheckInRLC: true, + }, + }, + ], +}; + +export const TEST_NODE_NO_CREDENTIALS: INode = { + ...TEST_NODE_MULTI_MODE, + name: 'Test Node - No Credentials', + parameters: { + authentication: undefined, + resource: 'test', + operation: 'get', + testParameterSkipCredentialsCheck: TEST_MODEL_VALUE, + id: '', + options: {}, + }, + credentials: undefined, +}; diff --git a/packages/frontend/editor-ui/src/components/ResourceLocator/ResourceLocator.test.ts b/packages/frontend/editor-ui/src/components/ResourceLocator/ResourceLocator.test.ts index 1755547ee6..60c71e11f1 100644 --- a/packages/frontend/editor-ui/src/components/ResourceLocator/ResourceLocator.test.ts +++ b/packages/frontend/editor-ui/src/components/ResourceLocator/ResourceLocator.test.ts @@ -9,9 +9,11 @@ import { TEST_MODEL_VALUE, TEST_NODE_MULTI_MODE, TEST_NODE_SINGLE_MODE, + TEST_NODE_NO_CREDENTIALS, TEST_PARAMETER_ADD_RESOURCE, TEST_PARAMETER_MULTI_MODE, TEST_PARAMETER_SINGLE_MODE, + TEST_PARAMETER_SKIP_CREDENTIALS_CHECK, } from './ResourceLocator.test.constants'; vi.mock('vue-router', async () => { @@ -197,6 +199,101 @@ describe('ResourceLocator', () => { }); }); + it('renders error when credentials are required and skipCredentialsCheckInRLC is false', async () => { + nodeTypesStore.getResourceLocatorResults.mockResolvedValue({ + results: [ + { + name: 'Test Resource', + value: 'test-resource', + url: 'https://test.com/test-resource', + }, + ], + paginationToken: null, + }); + nodeTypesStore.getNodeType = vi.fn().mockReturnValue({ + displayName: 'Test Node', + credentials: [ + { + name: 'testAuth', + required: true, + }, + ], + }); + + const { getByTestId, queryByTestId } = renderComponent({ + props: { + modelValue: TEST_MODEL_VALUE, + parameter: TEST_PARAMETER_MULTI_MODE, + path: `parameters.${TEST_PARAMETER_MULTI_MODE.name}`, + node: TEST_NODE_NO_CREDENTIALS, + displayTitle: 'Test Resource Locator', + expressionComputedValue: '', + isValueExpression: false, + }, + }); + + expect(getByTestId(`resource-locator-${TEST_PARAMETER_MULTI_MODE.name}`)).toBeInTheDocument(); + + await userEvent.click(getByTestId('rlc-input')); + + expect(getByTestId('rlc-error-container')).toBeInTheDocument(); + expect(getByTestId('permission-error-link')).toBeInTheDocument(); + expect(queryByTestId('rlc-item')).not.toBeInTheDocument(); + }); + + it('renders list items when skipCredentialsCheckInRLC is true even without credentials', async () => { + const TEST_ITEMS = [ + { name: 'Test Resource', value: 'test-resource', url: 'https://test.com/test-resource' }, + { + name: 'Test Resource 2', + value: 'test-resource-2', + url: 'https://test.com/test-resource-2', + }, + ]; + nodeTypesStore.getResourceLocatorResults.mockResolvedValue({ + results: TEST_ITEMS, + paginationToken: null, + }); + nodeTypesStore.getNodeType = vi.fn().mockReturnValue({ + displayName: 'Test Node', + credentials: [ + { + name: 'testAuth', + required: true, + }, + ], + }); + + const { getByTestId, getByText, getAllByTestId, queryByTestId } = renderComponent({ + props: { + modelValue: TEST_MODEL_VALUE, + parameter: TEST_PARAMETER_SKIP_CREDENTIALS_CHECK, + path: `parameters.${TEST_PARAMETER_SKIP_CREDENTIALS_CHECK.name}`, + node: TEST_NODE_NO_CREDENTIALS, + displayTitle: 'Test Resource Locator', + expressionComputedValue: '', + isValueExpression: false, + }, + }); + + expect( + getByTestId(`resource-locator-${TEST_PARAMETER_SKIP_CREDENTIALS_CHECK.name}`), + ).toBeInTheDocument(); + + await userEvent.click(getByTestId('rlc-input')); + + await waitFor(() => { + expect(nodeTypesStore.getResourceLocatorResults).toHaveBeenCalled(); + }); + + expect(getAllByTestId('rlc-item')).toHaveLength(TEST_ITEMS.length); + TEST_ITEMS.forEach((item) => { + expect(getByText(item.name)).toBeInTheDocument(); + }); + expect(queryByTestId('rlc-error-container')).not.toBeInTheDocument(); + expect(queryByTestId('permission-error-link')).not.toBeInTheDocument(); + }); + // Testing error message deduplication describe('ResourceLocator credentials error handling', () => { it.each([ diff --git a/packages/frontend/editor-ui/src/components/ResourceLocator/ResourceLocator.vue b/packages/frontend/editor-ui/src/components/ResourceLocator/ResourceLocator.vue index 7cfcebdfdb..70f44c36b0 100644 --- a/packages/frontend/editor-ui/src/components/ResourceLocator/ResourceLocator.vue +++ b/packages/frontend/editor-ui/src/components/ResourceLocator/ResourceLocator.vue @@ -186,8 +186,9 @@ const hasCredentialError = computed(() => { ); }); -const credentialsNotSet = computed(() => { +const credentialsRequiredAndNotSet = computed(() => { if (!props.node) return false; + if (skipCredentialsCheckInRLC.value) return false; const nodeType = nodeTypesStore.getNodeType(props.node.type); if (nodeType) { const usesCredentials = nodeType.credentials !== undefined && nodeType.credentials.length > 0; @@ -315,6 +316,10 @@ const currentQueryError = computed(() => { const isSearchable = computed(() => !!getPropertyArgument(currentMode.value, 'searchable')); +const skipCredentialsCheckInRLC = computed( + () => !!getPropertyArgument(currentMode.value, 'skipCredentialsCheckInRLC'), +); + const requiresSearchFilter = computed( () => !!getPropertyArgument(currentMode.value, 'searchFilterRequired'), ); @@ -666,7 +671,7 @@ async function loadResources() { const paramsKey = currentRequestKey.value; const cachedResponse = cachedResponses.value[paramsKey]; - if (credentialsNotSet.value) { + if (credentialsRequiredAndNotSet.value) { setResponse(paramsKey, { error: true }); return; } @@ -922,7 +927,7 @@ function removeOverride() {