Skip to content

Commit 6953a8b

Browse files
committed
feat(bounding-box): integrate bounding boxes with metadata form
1 parent 5368ed3 commit 6953a8b

File tree

11 files changed

+510
-8
lines changed

11 files changed

+510
-8
lines changed

src/elements/content-preview/ContentPreview.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ class ContentPreview extends React.PureComponent<Props, State> {
290290
contentOpenWithProps: {},
291291
contentSidebarProps: {},
292292
enableThumbnailsSidebar: false,
293+
enableBoundingBoxHighlights: false,
293294
hasHeader: false,
294295
hideSidebar: false,
295296
language: DEFAULT_LOCALE,
@@ -895,6 +896,7 @@ class ContentPreview extends React.PureComponent<Props, State> {
895896
annotatorState: { activeAnnotationId } = {},
896897
renderCustomPreview,
897898
enableThumbnailsSidebar,
899+
enableBoundingBoxHighlights,
898900
features,
899901
fileOptions,
900902
onAnnotatorEvent,
@@ -944,6 +946,7 @@ class ContentPreview extends React.PureComponent<Props, State> {
944946
const previewOptions = {
945947
advancedContentInsights, // will be removed once preview package will be updated to utilize feature flip for ACI
946948
container: `#${this.id} .bcpr-content`,
949+
enableBoundingBoxHighlights,
947950
enableThumbnailsSidebar,
948951
features,
949952
fileOptions: fileOpts,

src/elements/content-preview/__tests__/ContentPreview.test.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,34 @@ describe('elements/content-preview/ContentPreview', () => {
343343
);
344344
});
345345

346+
test('should pass enableBoundingBoxHighlights to preview options when enabled', async () => {
347+
const wrapper = getWrapper({ ...props, enableBoundingBoxHighlights: true });
348+
wrapper.setState({ file });
349+
const instance = wrapper.instance();
350+
await instance.loadPreview();
351+
expect(instance.preview.show).toHaveBeenCalledWith(
352+
file.id,
353+
expect.any(Function),
354+
expect.objectContaining({
355+
enableBoundingBoxHighlights: true,
356+
}),
357+
);
358+
});
359+
360+
test('should default enableBoundingBoxHighlights to false in preview options', async () => {
361+
const wrapper = getWrapper(props);
362+
wrapper.setState({ file });
363+
const instance = wrapper.instance();
364+
await instance.loadPreview();
365+
expect(instance.preview.show).toHaveBeenCalledWith(
366+
file.id,
367+
expect.any(Function),
368+
expect.objectContaining({
369+
enableBoundingBoxHighlights: false,
370+
}),
371+
);
372+
});
373+
346374
test('should call preview show with file version params if provided', async () => {
347375
const wrapper = getWrapper(props);
348376
wrapper.setState({

src/elements/content-sidebar/MetadataInstanceEditor.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
MetadataInstanceForm,
33
type FormValues,
44
type JSONPatchOperations,
5+
type MetadataTemplateField,
56
type MetadataTemplateInstance,
67
} from '@box/metadata-editor';
78
import { TaxonomyOptionsFetcher } from '@box/metadata-editor/lib/components/metadata-editor-fields/components/metadata-taxonomy-field/types.js';
@@ -34,6 +35,8 @@ export interface MetadataInstanceEditorProps {
3435
template: MetadataTemplateInstance;
3536
isAdvancedExtractAgentEnabled?: boolean;
3637
isConfidenceScoreReviewEnabled?: boolean;
38+
onSelectMetadataField?: (field: MetadataTemplateField | null) => void;
39+
selectedMetadataFieldId?: string | null;
3740
}
3841

3942
const MetadataInstanceEditor: React.FC<MetadataInstanceEditorProps> = ({
@@ -57,6 +60,8 @@ const MetadataInstanceEditor: React.FC<MetadataInstanceEditorProps> = ({
5760
template,
5861
isAdvancedExtractAgentEnabled = false,
5962
isConfidenceScoreReviewEnabled = false,
63+
onSelectMetadataField,
64+
selectedMetadataFieldId,
6065
}) => {
6166
const previewContext: PreviewContextType | null = useContext(PreviewContext);
6267
const customRef = previewContext?.previewBodyRef?.current;
@@ -84,6 +89,8 @@ const MetadataInstanceEditor: React.FC<MetadataInstanceEditorProps> = ({
8489
taxonomyOptionsFetcher={taxonomyOptionsFetcher}
8590
isAdvancedExtractAgentEnabled={isAdvancedExtractAgentEnabled}
8691
isConfidenceScoreReviewEnabled={isConfidenceScoreReviewEnabled}
92+
onSelectMetadataField={onSelectMetadataField}
93+
selectedMetadataFieldId={selectedMetadataFieldId}
8794
customRef={customRef}
8895
/>
8996
);

src/elements/content-sidebar/MetadataSidebarRedesign.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
} from '@box/metadata-editor';
2121
import { TreeQueryInput } from '@box/combobox-with-api';
2222

23+
import type { BoxAnnotationsBoundingBox } from './types/BoxAISidebarTypes';
2324
import API from '../../api';
2425
import SidebarContent from './SidebarContent';
2526
import { withAPIContext } from '../common/api-context';
@@ -44,6 +45,7 @@ import { convertTemplateToTemplateInstance } from './utils/convertTemplateToTemp
4445
import { isExtensionSupportedForMetadataSuggestions } from './utils/isExtensionSupportedForMetadataSuggestions';
4546
import { metadataTaxonomyFetcher, metadataTaxonomyNodeAncestorsFetcher } from './fetchers/metadataTaxonomyFetcher';
4647
import { useMetadataSidebarFilteredTemplates } from './hooks/useMetadataSidebarFilteredTemplates';
48+
import useMetadataFieldSelection from './hooks/useMetadataFieldSelection';
4749

4850
const MARK_NAME_JS_READY = `${ORIGIN_METADATA_SIDEBAR_REDESIGN}_${EVENT_JS_READY}`;
4951

@@ -59,6 +61,10 @@ interface PropsWithoutContext extends ExternalProps {
5961
fileExtension?: string;
6062
fileId: string;
6163
filteredTemplateIds?: string[];
64+
getPreview?: () => {
65+
showBoundingBoxHighlights?: (boundingBoxes: BoxAnnotationsBoundingBox[]) => void;
66+
hideBoundingBoxHighlights?: () => void;
67+
};
6268
hasSidebarInitialized?: boolean;
6369
}
6470

@@ -89,6 +95,7 @@ function MetadataSidebarRedesign({
8995
fileExtension,
9096
fileId,
9197
filteredTemplateIds = [],
98+
getPreview,
9299
history,
93100
onError,
94101
onSuccess,
@@ -127,6 +134,7 @@ function MetadataSidebarRedesign({
127134
const [isUnsavedChangesModalOpen, setIsUnsavedChangesModalOpen] = useState<boolean>(false);
128135
const [isDeleteButtonDisabled, setIsDeleteButtonDisabled] = useState<boolean>(false);
129136
const [shouldShowOnlyReviewFields, setShouldShowOnlyReviewFields] = useState<boolean>(false);
137+
const { selectedMetadataFieldId, handleSelectMetadataField } = useMetadataFieldSelection(getPreview);
130138
const [appliedTemplateInstances, setAppliedTemplateInstances] =
131139
useState<Array<MetadataTemplateInstance | MetadataTemplate>>(templateInstances);
132140
const [pendingTemplateToEdit, setPendingTemplateToEdit] = useState<MetadataTemplateInstance | null>(null);
@@ -332,6 +340,8 @@ function MetadataSidebarRedesign({
332340
template={editingTemplate}
333341
isAdvancedExtractAgentEnabled={isAdvancedExtractAgentEnabled}
334342
isConfidenceScoreReviewEnabled={isConfidenceScoreReviewEnabled}
343+
onSelectMetadataField={handleSelectMetadataField}
344+
selectedMetadataFieldId={selectedMetadataFieldId}
335345
/>
336346
)}
337347
{showList && (
@@ -345,6 +355,8 @@ function MetadataSidebarRedesign({
345355
setIsDeleteButtonDisabled(false);
346356
setShouldShowOnlyReviewFields(shouldEnableReviewFilter);
347357
}}
358+
onSelectMetadataField={handleSelectMetadataField}
359+
selectedMetadataFieldId={selectedMetadataFieldId}
348360
templateInstances={templateInstancesList}
349361
taxonomyNodeFetcher={taxonomyNodeFetcher}
350362
isConfidenceScoreReviewEnabled={isConfidenceScoreReviewEnabled}

src/elements/content-sidebar/SidebarPanels.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,7 @@ class SidebarPanels extends React.Component<Props, State> {
490490
? match.params.filteredTemplateIds.split(',')
491491
: []
492492
}
493+
getPreview={getPreview}
493494
hasSidebarInitialized={isInitialized}
494495
isBoxAiSuggestionsEnabled={isMetadataAiSuggestionsEnabled}
495496
ref={this.metadataSidebar}

src/elements/content-sidebar/__tests__/MetadataSidebarRedesign.test.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,18 @@ import {
99
type MetadataSidebarRedesignProps,
1010
} from '../MetadataSidebarRedesign';
1111
import useSidebarMetadataFetcher, { STATUS } from '../hooks/useSidebarMetadataFetcher';
12+
import useMetadataFieldSelection from '../hooks/useMetadataFieldSelection';
1213

1314
jest.mock('../hooks/useSidebarMetadataFetcher');
1415
const mockUseSidebarMetadataFetcher = useSidebarMetadataFetcher as jest.MockedFunction<
1516
typeof useSidebarMetadataFetcher
1617
>;
1718

19+
jest.mock('../hooks/useMetadataFieldSelection');
20+
const mockUseMetadataFieldSelection = useMetadataFieldSelection as jest.MockedFunction<
21+
typeof useMetadataFieldSelection
22+
>;
23+
1824
const getStructuredTextRep = jest.fn().mockResolvedValue('structured-text-rep');
1925
const api = {
2026
options: {
@@ -117,6 +123,11 @@ describe('elements/content-sidebar/Metadata/MetadataSidebarRedesign', () => {
117123
};
118124

119125
beforeEach(() => {
126+
mockUseMetadataFieldSelection.mockReturnValue({
127+
selectedMetadataFieldId: null,
128+
handleSelectMetadataField: jest.fn(),
129+
});
130+
120131
mockUseSidebarMetadataFetcher.mockReturnValue({
121132
clearExtractError: jest.fn(),
122133
extractSuggestions: jest.fn(),
@@ -500,4 +511,11 @@ describe('elements/content-sidebar/Metadata/MetadataSidebarRedesign', () => {
500511
expect(createSessionRequest).not.toHaveBeenCalledTimes(1);
501512
expect(createSessionRequest).not.toHaveBeenCalledWith({ items: [{ id: undefined }] }, undefined);
502513
});
514+
515+
test('should pass getPreview to useMetadataFieldSelection', () => {
516+
const getPreview = jest.fn();
517+
renderComponent({ getPreview });
518+
519+
expect(mockUseMetadataFieldSelection).toHaveBeenCalledWith(getPreview);
520+
});
503521
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import clampPercentage from '../utils/clampPercentage';
2+
3+
describe('clampPercentage', () => {
4+
test.each([
5+
[50, 50],
6+
[0, 0],
7+
[100, 100],
8+
[-0.5, 0],
9+
[100.5, 100],
10+
[99.999, 99.999],
11+
])('clampPercentage(%s) should return %s', (input, expected) => {
12+
expect(clampPercentage(input)).toBe(expected);
13+
});
14+
});

0 commit comments

Comments
 (0)