-
Notifications
You must be signed in to change notification settings - Fork 305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(taxonomy): added metadata taxonomy field support #3710
Changes from all commits
69402b7
0f3038e
6bf4326
1d70fd6
c58d515
5a4998a
39df79b
5193584
48806bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ import { | |
type JSONPatchOperations, | ||
type MetadataTemplate, | ||
type MetadataTemplateInstance, | ||
type PaginationQueryInput, | ||
} from '@box/metadata-editor'; | ||
|
||
import API from '../../api'; | ||
|
@@ -35,6 +36,7 @@ import './MetadataSidebarRedesign.scss'; | |
import MetadataInstanceEditor from './MetadataInstanceEditor'; | ||
import { convertTemplateToTemplateInstance } from './utils/convertTemplateToTemplateInstance'; | ||
import { isExtensionSupportedForMetadataSuggestions } from './utils/isExtensionSupportedForMetadataSuggestions'; | ||
import { metadataTaxonomyFetcher } from './fetchers/metadataTaxonomyFetcher'; | ||
|
||
const MARK_NAME_JS_READY = `${ORIGIN_METADATA_SIDEBAR_REDESIGN}_${EVENT_JS_READY}`; | ||
|
||
|
@@ -169,6 +171,14 @@ function MetadataSidebarRedesign({ api, elementId, fileId, onError, isFeatureEna | |
const showList = !showEditor && templateInstances.length > 0 && !editingTemplate; | ||
const areAiSuggestionsAvailable = isExtensionSupportedForMetadataSuggestions(file?.extension ?? ''); | ||
|
||
const taxonomyOptionsFetcher = async ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: i don't think the |
||
scope: string, | ||
templateKey: string, | ||
fieldKey: string, | ||
level: number, | ||
options: PaginationQueryInput, | ||
) => metadataTaxonomyFetcher(api, fileId, scope, templateKey, fieldKey, level, options); | ||
|
||
return ( | ||
<SidebarContent | ||
actions={metadataDropdown} | ||
|
@@ -198,6 +208,7 @@ function MetadataSidebarRedesign({ api, elementId, fileId, onError, isFeatureEna | |
onDiscardUnsavedChanges={handleDiscardUnsavedChanges} | ||
onSubmit={handleSubmit} | ||
setIsUnsavedChangesModalOpen={setIsUnsavedChangesModalOpen} | ||
taxonomyOptionsFetcher={taxonomyOptionsFetcher} | ||
template={editingTemplate} | ||
/> | ||
)} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import type { PaginationQueryInput } from '@box/metadata-editor'; | ||
import { metadataTaxonomyFetcher } from '../fetchers/metadataTaxonomyFetcher'; | ||
import type API from '../../../api'; | ||
|
||
describe('metadataTaxonomyFetcher', () => { | ||
let apiMock: jest.Mocked<API>; | ||
const fileId = '12345'; | ||
const scope = 'global'; | ||
const templateKey = 'template_123'; | ||
const fieldKey = 'field_abc'; | ||
const level = 1; | ||
const options: PaginationQueryInput = { marker: 'marker_1' }; | ||
|
||
beforeEach(() => { | ||
apiMock = { | ||
getMetadataAPI: jest.fn().mockReturnValue({ | ||
getMetadataOptions: jest.fn(), | ||
}), | ||
}; | ||
}); | ||
|
||
test('should fetch metadata options and return formatted data', async () => { | ||
const mockMetadataOptions = { | ||
entries: [ | ||
{ id: 'opt1', display_name: 'Option 1' }, | ||
{ id: 'opt2', display_name: 'Option 2' }, | ||
], | ||
}; | ||
|
||
apiMock.getMetadataAPI(false).getMetadataOptions.mockResolvedValue(mockMetadataOptions); | ||
|
||
const result = await metadataTaxonomyFetcher(apiMock, fileId, scope, templateKey, fieldKey, level, options); | ||
|
||
const expectedResult = { | ||
options: [ | ||
{ value: 'opt1', displayValue: 'Option 1' }, | ||
{ value: 'opt2', displayValue: 'Option 2' }, | ||
], | ||
marker: 'marker_1', | ||
}; | ||
|
||
expect(apiMock.getMetadataAPI).toHaveBeenCalledWith(false); | ||
expect(apiMock.getMetadataAPI(false).getMetadataOptions).toHaveBeenCalledWith( | ||
fileId, | ||
scope, | ||
templateKey, | ||
fieldKey, | ||
level, | ||
options, | ||
); | ||
expect(result).toEqual(expectedResult); | ||
}); | ||
|
||
test('should handle empty entries array', async () => { | ||
const mockMetadataOptions = { | ||
entries: [], | ||
}; | ||
|
||
apiMock.getMetadataAPI(false).getMetadataOptions.mockResolvedValue(mockMetadataOptions); | ||
|
||
const result = await metadataTaxonomyFetcher(apiMock, fileId, scope, templateKey, fieldKey, level, options); | ||
|
||
const expectedResult = { | ||
options: [], | ||
marker: 'marker_1', | ||
}; | ||
|
||
expect(result).toEqual(expectedResult); | ||
}); | ||
|
||
test('should set marker to null if not provided in options', async () => { | ||
const mockMetadataOptions = { | ||
entries: [{ id: 'opt1', display_name: 'Option 1' }], | ||
}; | ||
|
||
apiMock.getMetadataAPI(false).getMetadataOptions.mockResolvedValue(mockMetadataOptions); | ||
|
||
const result = await metadataTaxonomyFetcher(apiMock, fileId, scope, templateKey, fieldKey, level, {}); | ||
|
||
const expectedResult = { | ||
options: [{ value: 'opt1', displayValue: 'Option 1' }], | ||
marker: null, | ||
}; | ||
|
||
expect(result).toEqual(expectedResult); | ||
}); | ||
|
||
test('should throw an error if getMetadataOptions fails', async () => { | ||
const error = new Error('API Error'); | ||
apiMock.getMetadataAPI(false).getMetadataOptions.mockRejectedValue(error); | ||
|
||
await expect( | ||
metadataTaxonomyFetcher(apiMock, fileId, scope, templateKey, fieldKey, level, options), | ||
).rejects.toThrow('API Error'); | ||
}); | ||
}); |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this repo favors |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import type { PaginationQueryInput } from '@box/metadata-editor'; | ||
import type API from '../../../api'; | ||
import type { MetadataOptionEntry } from '../../../common/types/metadata'; | ||
|
||
export const metadataTaxonomyFetcher = async ( | ||
api: API, | ||
fileId: string, | ||
scope: string, | ||
templateKey: string, | ||
fieldKey: string, | ||
level: number, | ||
options: PaginationQueryInput, | ||
) => { | ||
const metadataOptions = await api | ||
.getMetadataAPI(false) | ||
.getMetadataOptions(fileId, scope, templateKey, fieldKey, level, options); | ||
const { marker = null } = options; | ||
|
||
return { | ||
options: metadataOptions.entries.map((metadataOption: MetadataOptionEntry) => ({ | ||
value: metadataOption.id, | ||
displayValue: metadataOption.display_name, | ||
})), | ||
marker, | ||
}; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit but should this be camel cased?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is intentional as the query string param is required in snake case (ie
/metadata?query_text=search
)