From ecd4c80873ae0d447fd5dbfdcf622775eeeb206e Mon Sep 17 00:00:00 2001 From: Jakub Kida <88503034+JakubKida@users.noreply.github.com> Date: Wed, 14 Aug 2024 22:53:07 +0200 Subject: [PATCH] feat(api): add handling empty metadata suggestions (#3608) * feat: add handling empty metadata suggestions * fix: const value naming --------- Co-authored-by: Jakub Kida Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: greg-in-a-box <103291617+greg-in-a-box@users.noreply.github.com> --- src/api/Metadata.js | 8 ++++ src/api/__tests__/Metadata.test.js | 66 +++++++++++++++++------------- src/constants.js | 1 + 3 files changed, 47 insertions(+), 28 deletions(-) diff --git a/src/api/Metadata.js b/src/api/Metadata.js index 28ce4f7d71..2d378a1c04 100644 --- a/src/api/Metadata.js +++ b/src/api/Metadata.js @@ -6,6 +6,7 @@ import getProp from 'lodash/get'; import uniqueId from 'lodash/uniqueId'; +import isEmpty from 'lodash/isEmpty'; import { getBadItemError, getBadPermissionsError, isUserCorrectableError } from '../utils/error'; import { getTypedFileId } from '../utils/file'; import File from './File'; @@ -28,6 +29,7 @@ import { ERROR_CODE_FETCH_METADATA_TEMPLATES, ERROR_CODE_FETCH_SKILLS, ERROR_CODE_FETCH_METADATA_SUGGESTIONS, + ERROR_CODE_EMPTY_METADATA_SUGGESTIONS, TYPE_FILE, } from '../constants'; @@ -786,6 +788,12 @@ class Metadata extends File { throw e; } } + + if (!isEmpty(suggestionsResponse) && getProp(suggestionsResponse, 'data.suggestions').length === 0) { + this.errorCode = ERROR_CODE_EMPTY_METADATA_SUGGESTIONS; + throw new Error('No suggestions found.'); + } + return getProp(suggestionsResponse, 'data.suggestions', []); } } diff --git a/src/api/__tests__/Metadata.test.js b/src/api/__tests__/Metadata.test.js index a84498bcad..7851df8d3b 100644 --- a/src/api/__tests__/Metadata.test.js +++ b/src/api/__tests__/Metadata.test.js @@ -17,6 +17,7 @@ import { METADATA_TEMPLATE_CLASSIFICATION, METADATA_TEMPLATE_PROPERTIES, TYPE_FILE, + ERROR_CODE_EMPTY_METADATA_SUGGESTIONS, } from '../../constants'; let metadata: Metadata; @@ -578,10 +579,7 @@ describe('api/Metadata', () => { metadata.getEditors = jest.fn().mockResolvedValueOnce('editors'); metadata.getCustomPropertiesTemplate = jest.fn().mockReturnValueOnce('custom'); metadata.getUserAddableTemplates = jest.fn().mockReturnValueOnce('templates'); - metadata.getTemplates = jest - .fn() - .mockResolvedValueOnce('global') - .mockResolvedValueOnce('enterprise'); + metadata.getTemplates = jest.fn().mockResolvedValueOnce('global').mockResolvedValueOnce('enterprise'); await metadata.getMetadata(file, jest.fn(), jest.fn(), true, { refreshCache: false }); @@ -618,10 +616,7 @@ describe('api/Metadata', () => { metadata.getEditors = jest.fn().mockResolvedValueOnce('editors'); metadata.getCustomPropertiesTemplate = jest.fn().mockReturnValueOnce('custom'); metadata.getUserAddableTemplates = jest.fn().mockReturnValueOnce('templates'); - metadata.getTemplates = jest - .fn() - .mockResolvedValueOnce('global') - .mockResolvedValueOnce('enterprise'); + metadata.getTemplates = jest.fn().mockResolvedValueOnce('global').mockResolvedValueOnce('enterprise'); await metadata.getMetadata(file, jest.fn(), jest.fn(), true); @@ -671,10 +666,7 @@ describe('api/Metadata', () => { metadata.getEditors = jest.fn().mockResolvedValueOnce('editors'); metadata.getCustomPropertiesTemplate = jest.fn().mockReturnValueOnce('custom'); metadata.getUserAddableTemplates = jest.fn().mockReturnValueOnce('templates'); - metadata.getTemplates = jest - .fn() - .mockResolvedValueOnce('global') - .mockResolvedValueOnce('enterprise'); + metadata.getTemplates = jest.fn().mockResolvedValueOnce('global').mockResolvedValueOnce('enterprise'); await metadata.getMetadata(file, jest.fn(), jest.fn(), true, { refreshCache: true }); @@ -726,10 +718,7 @@ describe('api/Metadata', () => { metadata.getEditors = jest.fn().mockResolvedValueOnce('editors'); metadata.getCustomPropertiesTemplate = jest.fn().mockReturnValueOnce('custom'); metadata.getUserAddableTemplates = jest.fn().mockReturnValueOnce('templates'); - metadata.getTemplates = jest - .fn() - .mockResolvedValueOnce('global') - .mockResolvedValueOnce('enterprise'); + metadata.getTemplates = jest.fn().mockResolvedValueOnce('global').mockResolvedValueOnce('enterprise'); await metadata.getMetadata(file, jest.fn(), jest.fn(), true, { forceFetch: true }); @@ -780,10 +769,7 @@ describe('api/Metadata', () => { metadata.getEditors = jest.fn().mockResolvedValueOnce('editors'); metadata.getCustomPropertiesTemplate = jest.fn().mockReturnValueOnce('custom'); metadata.getUserAddableTemplates = jest.fn().mockReturnValueOnce('templates'); - metadata.getTemplates = jest - .fn() - .mockResolvedValueOnce('global') - .mockResolvedValueOnce('enterprise'); + metadata.getTemplates = jest.fn().mockResolvedValueOnce('global').mockResolvedValueOnce('enterprise'); await metadata.getMetadata(file, jest.fn(), jest.fn(), false); @@ -826,10 +812,7 @@ describe('api/Metadata', () => { metadata.getEditors = jest.fn().mockResolvedValueOnce('editors'); metadata.getCustomPropertiesTemplate = jest.fn().mockReturnValueOnce('custom'); metadata.getUserAddableTemplates = jest.fn().mockReturnValueOnce('templates'); - metadata.getTemplates = jest - .fn() - .mockResolvedValueOnce('global') - .mockResolvedValueOnce('enterprise'); + metadata.getTemplates = jest.fn().mockResolvedValueOnce('global').mockResolvedValueOnce('enterprise'); await metadata.getMetadata(file, jest.fn(), jest.fn(), true); @@ -866,10 +849,7 @@ describe('api/Metadata', () => { metadata.getEditors = jest.fn().mockResolvedValueOnce('editors'); metadata.getCustomPropertiesTemplate = jest.fn().mockReturnValueOnce('custom'); metadata.getUserAddableTemplates = jest.fn().mockReturnValueOnce('templates'); - metadata.getTemplates = jest - .fn() - .mockResolvedValueOnce('global') - .mockResolvedValueOnce('enterprise'); + metadata.getTemplates = jest.fn().mockResolvedValueOnce('global').mockResolvedValueOnce('enterprise'); await metadata.getMetadata(file, jest.fn(), jest.fn(), true, { forceFetch: true }); @@ -2107,6 +2087,36 @@ describe('api/Metadata', () => { ).rejects.toThrow(new Error(`Invalid confidence level: "high"`)); }); + test('should throw an error if no suggestions were found', async () => { + const suggestionsFromServer = []; + + metadata.getMetadataSuggestionsUrl = jest.fn().mockReturnValueOnce('suggestions_url'); + metadata.xhr.get = jest.fn().mockReturnValueOnce({ + data: { + $scope: 'enterprise', + $templateKey: 'templateKey', + suggestions: suggestionsFromServer, + }, + }); + + await expect(() => + metadata.getMetadataSuggestions('id', TYPE_FILE, 'enterprise', 'templateKey'), + ).rejects.toThrow(new Error('No suggestions found.')); + + expect(metadata.errorCode).toBe(ERROR_CODE_EMPTY_METADATA_SUGGESTIONS); + expect(metadata.getMetadataSuggestionsUrl).toHaveBeenCalled(); + expect(metadata.xhr.get).toHaveBeenCalledWith({ + url: 'suggestions_url', + id: 'file_id', + params: { + item: `file_id`, + scope: 'enterprise', + template_key: 'templateKey', + confidence: METADATA_SUGGESTIONS_CONFIDENCE_EXPERIMENTAL, + }, + }); + }); + test('should return empty array of suggestions when error is 400', async () => { const error = new Error(); error.status = 400; diff --git a/src/constants.js b/src/constants.js index cdb679f4ed..3ee64d0747 100644 --- a/src/constants.js +++ b/src/constants.js @@ -271,6 +271,7 @@ export const ERROR_CODE_FETCH_ACCESS_STATS = 'fetch_access_stats_error'; export const ERROR_CODE_FETCH_SKILLS = 'fetch_skills_error'; export const ERROR_CODE_FETCH_RECENTS = 'fetch_recents_error'; export const ERROR_CODE_FETCH_METADATA_SUGGESTIONS = 'fetch_metadata_suggestions_error'; +export const ERROR_CODE_EMPTY_METADATA_SUGGESTIONS = 'empty_metadata_suggestions_error'; export const ERROR_CODE_EXECUTE_INTEGRATION = 'execute_integrations_error'; export const ERROR_CODE_EXTRACT_STRUCTURED = 'extract_structured_error'; export const ERROR_CODE_CREATE_ANNOTATION = 'create_annotation_error';