Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,10 @@
"@box/frontend": "^11.0.1",
"@box/item-icon": "^3.2.0",
"@box/languages": "^1.0.0",
"@box/metadata-editor": "^1.73.4",
"@box/metadata-editor": "^2.2.11",
"@box/metadata-filter": "^1.80.23",
"@box/metadata-template-browser": "^1.24.11",
"@box/metadata-taxonomy-picker": "^3.1.8",
"@box/metadata-template-browser": "^2.1.7",
"@box/metadata-view": "^1.53.26",
"@box/react-virtualized": "^9.22.3-rc-box.10",
"@box/readable-time": "^2.1.4",
Expand Down Expand Up @@ -306,9 +307,10 @@
"@box/content-field": "^1.40.23",
"@box/copy-input": "^1.42.16",
"@box/item-icon": "^3.2.0",
"@box/metadata-editor": "^1.73.4",
"@box/metadata-editor": "^2.2.11",
"@box/metadata-filter": "^1.80.23",
"@box/metadata-template-browser": "^1.24.11",
"@box/metadata-taxonomy-picker": "^3.1.8",
"@box/metadata-template-browser": "^2.1.7",
"@box/metadata-view": "^1.53.26",
"@box/react-virtualized": "^9.22.3-rc-box.10",
"@box/readable-time": "^2.1.4",
Expand Down
2 changes: 1 addition & 1 deletion scripts/jest/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ module.exports = {
testMatch: ['**/__tests__/**/*.test.+(js|jsx|ts|tsx)'],
testPathIgnorePatterns: ['stories.test.js$', 'stories.test.tsx$', 'stories.test.d.ts'],
transformIgnorePatterns: [
'node_modules/(?!(@box/activity-feed|@box/collaboration-popover|@box/react-virtualized/dist/es|@box/cldr-data|@box/blueprint-web|@box/blueprint-web-assets|@box/metadata-editor|@box/metadata-template-browser|@box/box-ai-content-answers|@box/box-ai-agent-selector|@box/item-icon|@box/combobox-with-api|@box/tree|@box/metadata-filter|@box/metadata-view|@box/content-field|@box/types|@box/box-item-type-selector|@box/unified-share-modal|@box/user-selector|@box/copy-input|@box/readable-time|@box/threaded-annotations|@box/uploads-manager)/)',
'node_modules/(?!(@box/activity-feed|@box/collaboration-popover|@box/react-virtualized/dist/es|@box/cldr-data|@box/blueprint-web|@box/blueprint-web-assets|@box/metadata-editor|@box/metadata-template-browser|@box/metadata-taxonomy-picker|@box/box-ai-content-answers|@box/box-ai-agent-selector|@box/item-icon|@box/combobox-with-api|@box/tree|@box/metadata-filter|@box/metadata-view|@box/content-field|@box/types|@box/box-item-type-selector|@box/unified-share-modal|@box/user-selector|@box/copy-input|@box/readable-time|@box/threaded-annotations|@box/uploads-manager)/)',
],
};
4 changes: 3 additions & 1 deletion src/elements/content-sidebar/MetadataSidebarRedesign.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,9 @@ function MetadataSidebarRedesign({

const areAiSuggestionsAvailable = isExtensionSupportedForMetadataSuggestions(file?.extension ?? '');

const metadataDropdown = isSuccess && templates && (
const canEdit = !!file?.permissions?.can_upload;

const metadataDropdown = canEdit && isSuccess && templates && (
<AddMetadataTemplateDropdown
availableTemplates={templates}
selectedTemplates={appliedTemplateInstances as MetadataTemplate[]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { userEvent } from '@testing-library/user-event';
import { RouteComponentProps } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import { type MetadataTemplate, type MetadataTemplateInstance } from '@box/metadata-editor';
import { FIELD_PERMISSIONS_CAN_UPLOAD, ERROR_CODE_METADATA_STRUCTURED_TEXT_REP } from '../../../constants';
import { ERROR_CODE_METADATA_STRUCTURED_TEXT_REP } from '../../../constants';
import { screen, render, waitFor, within } from '../../../test-utils/testing-library';
import {
MetadataSidebarRedesignComponent as MetadataSidebarRedesign,
Expand Down Expand Up @@ -101,7 +101,7 @@ describe('elements/content-sidebar/Metadata/MetadataSidebarRedesign', () => {

const mockFile = {
id: '123',
permissions: { [FIELD_PERMISSIONS_CAN_UPLOAD]: true },
permissions: { can_upload: true },
};

const renderComponent = (props = {}, features = {}) => {
Expand Down Expand Up @@ -196,6 +196,66 @@ describe('elements/content-sidebar/Metadata/MetadataSidebarRedesign', () => {
expect(screen.getByRole('button', { name: 'Add template' })).toBeInTheDocument();
});

test('should render "Add template" button when user has can_upload permission', () => {
mockUseSidebarMetadataFetcher.mockReturnValue({
clearExtractError: jest.fn(),
extractSuggestions: jest.fn(),
handleCreateMetadataInstance: jest.fn(),
handleDeleteMetadataInstance: jest.fn(),
handleUpdateMetadataInstance: jest.fn(),
templateInstances: [],
templates: mockTemplates,
errorMessage: null,
status: STATUS.SUCCESS,
file: { id: '123', permissions: { can_upload: true } },
extractErrorCode: null,
});

renderComponent();

expect(screen.getByRole('button', { name: 'Add template' })).toBeInTheDocument();
});

test('should not render "Add template" button when user lacks can_upload permission', () => {
mockUseSidebarMetadataFetcher.mockReturnValue({
clearExtractError: jest.fn(),
extractSuggestions: jest.fn(),
handleCreateMetadataInstance: jest.fn(),
handleDeleteMetadataInstance: jest.fn(),
handleUpdateMetadataInstance: jest.fn(),
templateInstances: [],
templates: mockTemplates,
errorMessage: null,
status: STATUS.SUCCESS,
file: { id: '123', permissions: { can_upload: false } },
extractErrorCode: null,
});

renderComponent();

expect(screen.queryByRole('button', { name: 'Add template' })).not.toBeInTheDocument();
});

test('should not render "Add template" button when file has no permissions', () => {
mockUseSidebarMetadataFetcher.mockReturnValue({
clearExtractError: jest.fn(),
extractSuggestions: jest.fn(),
handleCreateMetadataInstance: jest.fn(),
handleDeleteMetadataInstance: jest.fn(),
handleUpdateMetadataInstance: jest.fn(),
templateInstances: [],
templates: mockTemplates,
errorMessage: null,
status: STATUS.SUCCESS,
file: { id: '123' },
extractErrorCode: null,
});

renderComponent();

expect(screen.queryByRole('button', { name: 'Add template' })).not.toBeInTheDocument();
});

test('should have selectable "Custom Metadata" template in dropdown', async () => {
renderComponent();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ describe('useSidebarMetadataFetcher', () => {
);
});

test('should include include_confidence_score and include_reference when isConfidenceScoreEnabled is true', async () => {
test('should include only include_confidence_score when only isConfidenceScoreEnabled is true', async () => {
mockAPI.extractStructured.mockResolvedValue({
answer: { field1: 'value1' },
created_at: '2026-03-27T08:10:14.106-07:00',
Expand All @@ -632,6 +632,29 @@ describe('useSidebarMetadataFetcher', () => {

await result.current.extractSuggestions('templateKey', 'global');

expect(mockAPI.extractStructured).toHaveBeenCalledWith({
items: [{ id: mockFile.id, type: mockFile.type }],
metadata_template: { template_key: 'templateKey', scope: 'global', type: 'metadata_template' },
include_confidence_score: true,
});
expect(mockAPI.extractStructured).toHaveBeenCalledWith(
expect.not.objectContaining({
include_reference: expect.anything(),
}),
);
});

test('should include include_confidence_score and include_reference when both flags are true', async () => {
mockAPI.extractStructured.mockResolvedValue({
answer: { field1: 'value1' },
created_at: '2026-03-27T08:10:14.106-07:00',
completion_reason: 'done',
});

const { result } = setupHook('123', true, true);

await result.current.extractSuggestions('templateKey', 'global');

expect(mockAPI.extractStructured).toHaveBeenCalledWith({
items: [{ id: mockFile.id, type: mockFile.type }],
metadata_template: { template_key: 'templateKey', scope: 'global', type: 'metadata_template' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,12 +236,7 @@ function useSidebarMetadataFetcher(
const customAiAgent = agentId ? { ai_agent: { type: 'ai_agent_id', id: agentId } } : {};

const confidenceScoreParams = isConfidenceScoreEnabled ? { include_confidence_score: true } : {};

// Additive gating during the metadata_bounding_box rollout: fetch bounding boxes from AI extract API when
// when either the confidence-score coupling or the new bounding-box flag is on.
// TODO: drop the isBoundingBoxOrConfidenceScoreReviewEnabled fallback so
// fetching bounding boxes depends solely on `isBoundingBoxEnabled`.
const boundingBoxParams = isBoundingBoxOrConfidenceScoreReviewEnabled ? { include_reference: true } : {};
const boundingBoxParams = isBoundingBoxEnabled ? { include_reference: true } : {};

const requestBody: AiExtractStructured = {
items: [{ id: file.id, type: file.type }],
Expand Down Expand Up @@ -320,7 +315,7 @@ function useSidebarMetadataFetcher(
return result;
});
},
[api, file, isConfidenceScoreEnabled, isBoundingBoxOrConfidenceScoreReviewEnabled, onError, templates],
[api, file, isConfidenceScoreEnabled, isBoundingBoxEnabled, onError, templates],
);

React.useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const mockFileRequestWithoutMetadata = {
permissions: {
can_download: true,
can_preview: true,
can_upload: false,
can_upload: true,
can_comment: true,
can_rename: false,
can_delete: false,
Expand Down
21 changes: 13 additions & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1179,20 +1179,25 @@
resolved "https://registry.yarnpkg.com/@box/languages/-/languages-1.1.2.tgz#cd4266b3da62da18560d881e10b429653186be29"
integrity sha512-d64TGosx+KRmrLZj4CIyLp42LUiEbgBJ8n8cviMQwTJmfU0g+UwZqLjmQZR1j+Q9D64yV4xHzY9K1t5nInWWeQ==

"@box/metadata-editor@^1.73.4":
version "1.73.11"
resolved "https://registry.yarnpkg.com/@box/metadata-editor/-/metadata-editor-1.73.11.tgz#ab80b67d3b6257bf7019a5711d803eb277993796"
integrity sha512-eiP+im6cDvDsYqQClUpt8Xc25yweJ0P6779YC7U/i4fsl21w6+FqddjtoXBtinfVqwXgo2Jelbl4wqgK/r8CYA==
"@box/metadata-editor@^2.2.11":
version "2.2.11"
resolved "https://registry.yarnpkg.com/@box/metadata-editor/-/metadata-editor-2.2.11.tgz#6a4875e0c1f3ba3593887ad6694e2b74162853d8"
integrity sha512-ouF4cPC2kzqgVJ9hnMOqtOy+SDd7MMec/igg0EqzGXXGpo8vuIsl3M2zk4qXHS9kTXXDbK+Xq0wb7WMfCj+ccA==

"@box/metadata-filter@^1.80.23":
version "1.80.23"
resolved "https://registry.yarnpkg.com/@box/metadata-filter/-/metadata-filter-1.80.23.tgz#4eefe51151f71cc96081d5e2d036be18f1f42008"
integrity sha512-6G5vgumSbUGk0r9SgCMol9HUW/9CkiHwDL5F8wH4EeRlF75xnxLGw7Q83BMMQfpJv+kkWhjJ0C/O9u0a07nBuQ==

"@box/metadata-template-browser@^1.24.11":
version "1.24.13"
resolved "https://registry.yarnpkg.com/@box/metadata-template-browser/-/metadata-template-browser-1.24.13.tgz#95f5490bf746a3c0e1629e8ba253c60295378764"
integrity sha512-P7Njbhom5dt2tLL1LCZ3jpCK76oG0mXVn3tECCpfcw2cAthZjprzPl1tgKcyWEA1mAwuiNGKl1AcQMiIXwLJ1A==
"@box/metadata-taxonomy-picker@^3.1.8":
version "3.1.8"
resolved "https://registry.yarnpkg.com/@box/metadata-taxonomy-picker/-/metadata-taxonomy-picker-3.1.8.tgz#d72f6df53c69b75f9e3fddbdaaca39858d43aade"
integrity sha512-ahlkefldWk1OlMtbD3i8b7yrPgHDkP2IBXvcFC3R+ckSsBjxa2amo63C0lViOHUc9vjZWrutY7EqeKUtTJ7OGw==

"@box/metadata-template-browser@^2.1.7":
version "2.1.7"
resolved "https://registry.yarnpkg.com/@box/metadata-template-browser/-/metadata-template-browser-2.1.7.tgz#f31de745e40004805a230cd624912e1c5cf9547f"
integrity sha512-MzuFyzVInAR0ZqT4g3wro47DmirT39YaYIsxRborZtL1TpaQpgxZoqCWQ+/pgtuGoGHyoP+kpueO8APeC+XCGg==

"@box/metadata-view@^1.53.26":
version "1.53.26"
Expand Down
Loading