Skip to content

Commit

Permalink
feat(taxonomy): added view/create/updated taxonomy field support (#3716)
Browse files Browse the repository at this point in the history
* feat(taxonomy): added create/updated taxonomy support

* feat(taxonomy): fixed tests and lint errors
  • Loading branch information
TylerGauntlett authored Oct 21, 2024
1 parent 5a117ae commit cccb0b0
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 20 deletions.
32 changes: 25 additions & 7 deletions src/api/Metadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import uniqueId from 'lodash/uniqueId';
import isEmpty from 'lodash/isEmpty';
import { getBadItemError, getBadPermissionsError, isUserCorrectableError } from '../utils/error';
import { getTypedFileId } from '../utils/file';
import { handleOnAbort } from './utils';
import { handleOnAbort, formatMetadataFieldValue } from './utils';
import File from './File';
import {
HEADER_CONTENT_TYPE,
Expand Down Expand Up @@ -226,14 +226,17 @@ class Metadata extends File {
* Gets metadata instances for a Box file
*
* @param {string} id - file id
* @param {boolean} isMetadataRedesign - feature flag
* @return {Object} array of metadata instances
*/
async getInstances(id: string): Promise<Array<MetadataInstanceV2>> {
async getInstances(id: string, isMetadataRedesign: boolean = false): Promise<Array<MetadataInstanceV2>> {
this.errorCode = ERROR_CODE_FETCH_METADATA;
const baseUrl = this.getMetadataUrl(id);
const url = isMetadataRedesign ? `${baseUrl}?view=hydrated` : baseUrl;
let instances = {};
try {
instances = await this.xhr.get({
url: this.getMetadataUrl(id),
url,
id: getTypedFileId(id),
});
} catch (e) {
Expand Down Expand Up @@ -377,9 +380,11 @@ class Metadata extends File {
// Get Metadata Fields for Instances created from predefined template
const templateFields = template.fields || [];
templateFields.forEach(field => {
const value = formatMetadataFieldValue(field, instance[field.key]);

fields.push({
...field,
value: instance[field.key],
value,
});
});
} else {
Expand Down Expand Up @@ -501,7 +506,7 @@ class Metadata extends File {
try {
const customPropertiesTemplate: MetadataTemplate = this.getCustomPropertiesTemplate();
const [instances, globalTemplates, enterpriseTemplates] = await Promise.all([
this.getInstances(id),
this.getInstances(id, isMetadataRedesign),
this.getTemplates(id, METADATA_SCOPE_GLOBAL),
hasMetadataFeature ? this.getTemplates(id, METADATA_SCOPE_ENTERPRISE) : Promise.resolve([]),
]);
Expand Down Expand Up @@ -887,11 +892,24 @@ class Metadata extends File {
try {
const fieldsValues = template.fields.reduce((acc, obj) => {
let { value } = obj;

// API does not accept string for float type
if (obj.type === 'float' && value) value = parseFloat(obj.value);
if (obj.type === 'float' && value) {
value = parseFloat(obj.value);
}

// API does not accept empty string for enum type
if (obj.type === 'enum' && value && value.length === 0) value = undefined;
if (obj.type === 'enum' && value && value.length === 0) {
value = undefined;
}

// API expects values as an array of strings
if (obj.type === 'taxonomy' && value && Array.isArray(value)) {
value = value.map(option => option.value);
}

acc[obj.key] = value;

return acc;
}, {});

Expand Down
28 changes: 21 additions & 7 deletions src/api/__tests__/Metadata.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { handleOnAbort } from '../utils';
let metadata: Metadata;

jest.mock('../utils', () => ({
...jest.requireActual('../utils'),
handleOnAbort: jest.fn(),
}));

Expand Down Expand Up @@ -443,6 +444,19 @@ describe('api/Metadata', () => {
id: 'file_id',
});
});
test('should apply hydrated query string param for isMetadataRedesign', async () => {
metadata.getMetadataUrl = jest.fn().mockReturnValueOnce('metadata_url');
metadata.xhr.get = jest.fn().mockReturnValueOnce({
data: {
entries: [],
},
});
await metadata.getInstances('id', true);
expect(metadata.xhr.get).toHaveBeenCalledWith({
url: 'metadata_url?view=hydrated',
id: 'file_id',
});
});
});

describe('getUserAddableTemplates()', () => {
Expand Down Expand Up @@ -810,7 +824,7 @@ describe('api/Metadata', () => {
expect(metadata.isDestroyed).toHaveBeenCalled();
expect(metadata.getCache).toHaveBeenCalled();
expect(metadata.getMetadataCacheKey).toHaveBeenCalledWith(file.id);
expect(metadata.getInstances).toHaveBeenCalledWith(file.id);
expect(metadata.getInstances).toHaveBeenCalledWith(file.id, false);
expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'global');
expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'enterprise');
expect(metadata.extractClassification).toBeCalledWith('id', 'instances');
Expand Down Expand Up @@ -865,7 +879,7 @@ describe('api/Metadata', () => {
expect(metadata.isDestroyed).toHaveBeenCalled();
expect(metadata.getCache).toHaveBeenCalled();
expect(metadata.getMetadataCacheKey).toHaveBeenCalledWith(file.id);
expect(metadata.getInstances).toHaveBeenCalledWith(file.id);
expect(metadata.getInstances).toHaveBeenCalledWith(file.id, true);
expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'global');
expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'enterprise');
expect(metadata.extractClassification).toBeCalledWith('id', 'instances');
Expand Down Expand Up @@ -922,7 +936,7 @@ describe('api/Metadata', () => {
expect(metadata.isDestroyed).toHaveBeenCalled();
expect(metadata.getCache).toHaveBeenCalled();
expect(metadata.getMetadataCacheKey).toHaveBeenCalledWith(file.id);
expect(metadata.getInstances).toHaveBeenCalledWith(file.id);
expect(metadata.getInstances).toHaveBeenCalledWith(file.id, false);
expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'global');
expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'enterprise');
expect(metadata.extractClassification).toBeCalledWith('id', 'instances');
Expand Down Expand Up @@ -980,7 +994,7 @@ describe('api/Metadata', () => {
expect(metadata.isDestroyed).toHaveBeenCalled();
expect(metadata.getCache).toHaveBeenCalled();
expect(metadata.getMetadataCacheKey).toHaveBeenCalledWith(file.id);
expect(metadata.getInstances).toHaveBeenCalledWith(file.id);
expect(metadata.getInstances).toHaveBeenCalledWith(file.id, false);
expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'global');
expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'enterprise');
expect(metadata.extractClassification).toBeCalledWith('id', 'instances');
Expand Down Expand Up @@ -1037,7 +1051,7 @@ describe('api/Metadata', () => {
expect(metadata.isDestroyed).toHaveBeenCalled();
expect(metadata.getCache).toHaveBeenCalled();
expect(metadata.getMetadataCacheKey).toHaveBeenCalledWith(file.id);
expect(metadata.getInstances).toHaveBeenCalledWith(file.id);
expect(metadata.getInstances).toHaveBeenCalledWith(file.id, false);
expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'global');
expect(metadata.getTemplates).not.toHaveBeenCalledWith(file.id, 'enterprise');
expect(metadata.extractClassification).toBeCalledWith('id', 'instances');
Expand Down Expand Up @@ -1092,7 +1106,7 @@ describe('api/Metadata', () => {
expect(metadata.isDestroyed).not.toHaveBeenCalled();
expect(metadata.getCache).toHaveBeenCalled();
expect(metadata.getMetadataCacheKey).toHaveBeenCalledWith(file.id);
expect(metadata.getInstances).toHaveBeenCalledWith(file.id);
expect(metadata.getInstances).toHaveBeenCalledWith(file.id, false);
expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'global');
expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'enterprise');
expect(metadata.getEditors).not.toHaveBeenCalled();
Expand Down Expand Up @@ -1132,7 +1146,7 @@ describe('api/Metadata', () => {
expect(metadata.isDestroyed).toHaveBeenCalled();
expect(metadata.getCache).toHaveBeenCalled();
expect(metadata.getMetadataCacheKey).toHaveBeenCalledWith(file.id);
expect(metadata.getInstances).toHaveBeenCalledWith(file.id);
expect(metadata.getInstances).toHaveBeenCalledWith(file.id, false);
expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'global');
expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'enterprise');
expect(metadata.extractClassification).toBeCalledWith('id', 'instances');
Expand Down
31 changes: 30 additions & 1 deletion src/api/__tests__/utils.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import Xhr from '../../utils/Xhr';
import { getAbortError } from '../../utils/error';
import { formatComment, handleOnAbort } from '../utils';
import { formatComment, formatMetadataFieldValue, handleOnAbort } from '../utils';
import { threadedComments, threadedCommentsFormatted } from '../fixtures';
import { FIELD_TYPE_STRING, FIELD_TYPE_TAXONOMY } from '../../features/metadata-instance-fields/constants';

jest.mock('../../utils/Xhr', () => {
return jest.fn().mockImplementation(() => ({
Expand All @@ -26,4 +27,32 @@ describe('api/utils', () => {
expect(xhr.abort).toHaveBeenCalled();
});
});

describe('formatMetadataFieldValue()', () => {
test('should format string field value', async () => {
const stringField = {
displayName: 'State',
id: '1',
key: 'stateField',
type: FIELD_TYPE_STRING,
};
const value = 'California';

expect(formatMetadataFieldValue(stringField, value)).toEqual(value);
});

test('should format taxonomy field value', async () => {
const taxonomyField = {
displayName: 'State',
id: '1',
key: 'stateField',
type: FIELD_TYPE_TAXONOMY,
};
const id = '123-456';
const displayName = 'California';
const expectedValue = [{ value: id, displayValue: displayName }];

expect(formatMetadataFieldValue(taxonomyField, [{ id, displayName }])).toEqual(expectedValue);
});
});
});
21 changes: 16 additions & 5 deletions src/api/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
import type Xhr from '../utils/Xhr';
import type { Comment } from '../common/types/feed';
import { getAbortError } from '../utils/error';
import type { MetadataTemplateField, MetadataFieldValue } from '../common/types/metadata';
import { FIELD_TYPE_TAXONOMY } from '../features/metadata-instance-fields/constants';

/**
* Formats comment data (including replies) for use in components.
*
* @param {Comment} comment - An individual comment entry from the API
* @return {Comment} Updated comment
*/
export const formatComment = (comment: Comment): Comment => {
const formatComment = (comment: Comment): Comment => {
const formattedComment = {
...comment,
tagged_message: comment.message,
Expand All @@ -27,12 +29,21 @@ export const formatComment = (comment: Comment): Comment => {
return formattedComment;
};

export const handleOnAbort = (xhr: Xhr) => {
const formatMetadataFieldValue = (field: MetadataTemplateField, value: MetadataFieldValue): MetadataFieldValue => {
if (field.type === FIELD_TYPE_TAXONOMY && Array.isArray(value)) {
return value.map((option: { id: string, displayName: string }) => ({
value: option.id,
displayValue: option.displayName,
}));
}

return value;
};

const handleOnAbort = (xhr: Xhr) => {
xhr.abort();

throw getAbortError();
};

export default {
formatComment,
};
export { formatComment, formatMetadataFieldValue, handleOnAbort };

0 comments on commit cccb0b0

Please sign in to comment.