box-ui-elements 23.4.0-beta.22 → 23.4.0-beta.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/explorer.js +1 -1
  2. package/dist/openwith.js +1 -1
  3. package/dist/picker.js +1 -1
  4. package/dist/preview.js +1 -1
  5. package/dist/sharing.js +1 -1
  6. package/dist/sidebar.js +1 -1
  7. package/dist/uploader.js +1 -1
  8. package/es/api/uploads/BaseUpload.js +4 -0
  9. package/es/api/uploads/BaseUpload.js.flow +5 -1
  10. package/es/api/uploads/BaseUpload.js.map +1 -1
  11. package/es/api/uploads/MultiputUpload.js +7 -0
  12. package/es/api/uploads/MultiputUpload.js.flow +11 -6
  13. package/es/api/uploads/MultiputUpload.js.map +1 -1
  14. package/es/api/uploads/PlainUpload.js +2 -1
  15. package/es/api/uploads/PlainUpload.js.flow +3 -2
  16. package/es/api/uploads/PlainUpload.js.map +1 -1
  17. package/es/components/flyout/OverlayHeader.js +6 -3
  18. package/es/components/flyout/OverlayHeader.js.map +1 -1
  19. package/es/elements/common/nav-router/NavRouter.js +7 -3
  20. package/es/elements/common/nav-router/NavRouter.js.flow +10 -1
  21. package/es/elements/common/nav-router/NavRouter.js.map +1 -1
  22. package/es/elements/common/nav-router/types.js.map +1 -1
  23. package/es/elements/common/nav-router/withNavRouter.js +10 -1
  24. package/es/elements/common/nav-router/withNavRouter.js.flow +5 -0
  25. package/es/elements/common/nav-router/withNavRouter.js.map +1 -1
  26. package/es/elements/common/routing/withRouterAndRef.js +17 -3
  27. package/es/elements/common/routing/withRouterAndRef.js.flow +11 -3
  28. package/es/elements/common/routing/withRouterAndRef.js.map +1 -1
  29. package/es/elements/content-explorer/stories/tests/ContentExplorer-visual.stories.js +22 -13
  30. package/es/elements/content-explorer/stories/tests/ContentExplorer-visual.stories.js.flow +30 -17
  31. package/es/elements/content-explorer/stories/tests/ContentExplorer-visual.stories.js.map +1 -1
  32. package/es/elements/content-sidebar/ContentSidebar.js +3 -1
  33. package/es/elements/content-sidebar/ContentSidebar.js.flow +2 -1
  34. package/es/elements/content-sidebar/ContentSidebar.js.map +1 -1
  35. package/es/elements/content-sidebar/SidebarToggle.js +27 -9
  36. package/es/elements/content-sidebar/SidebarToggle.js.flow +29 -6
  37. package/es/elements/content-sidebar/SidebarToggle.js.map +1 -1
  38. package/es/elements/content-sidebar/stories/tests/MetadataSidebarRedesign-visual.stories.js +12 -1
  39. package/es/elements/content-sidebar/stories/tests/MetadataSidebarRedesign-visual.stories.js.map +1 -1
  40. package/es/elements/content-uploader/ContentUploader.js +7 -3
  41. package/es/elements/content-uploader/ContentUploader.js.map +1 -1
  42. package/es/elements/content-uploader/ItemAction.js +8 -3
  43. package/es/elements/content-uploader/ItemAction.js.map +1 -1
  44. package/es/features/header-flyout/HeaderFlyout.js +6 -3
  45. package/es/features/header-flyout/HeaderFlyout.js.flow +15 -2
  46. package/es/features/header-flyout/HeaderFlyout.js.map +1 -1
  47. package/es/src/components/flyout/OverlayHeader.d.ts +3 -1
  48. package/es/src/elements/common/nav-router/NavRouter.d.ts +3 -1
  49. package/es/src/elements/common/nav-router/types.d.ts +2 -0
  50. package/es/src/elements/content-uploader/ContentUploader.d.ts +1 -1
  51. package/package.json +1 -1
  52. package/src/api/uploads/BaseUpload.js +5 -1
  53. package/src/api/uploads/MultiputUpload.js +11 -6
  54. package/src/api/uploads/PlainUpload.js +3 -2
  55. package/src/api/uploads/__tests__/BaseUpload.test.js +14 -0
  56. package/src/components/flyout/OverlayHeader.tsx +7 -3
  57. package/src/components/flyout/__tests__/OverlayHeader.test.js +25 -0
  58. package/src/elements/common/nav-router/NavRouter.js.flow +10 -1
  59. package/src/elements/common/nav-router/NavRouter.tsx +9 -3
  60. package/src/elements/common/nav-router/__tests__/withNavRouter.test.tsx +34 -20
  61. package/src/elements/common/nav-router/types.ts +2 -0
  62. package/src/elements/common/nav-router/withNavRouter.js.flow +5 -0
  63. package/src/elements/common/nav-router/withNavRouter.tsx +9 -1
  64. package/src/elements/common/routing/__tests__/withRouterAndRef.test.js +64 -12
  65. package/src/elements/common/routing/withRouterAndRef.js +11 -3
  66. package/src/elements/content-explorer/stories/tests/ContentExplorer-visual.stories.js +30 -17
  67. package/src/elements/content-sidebar/ContentSidebar.js +2 -1
  68. package/src/elements/content-sidebar/SidebarToggle.js +29 -6
  69. package/src/elements/content-sidebar/__tests__/SidebarToggle.test.js +74 -10
  70. package/src/elements/content-sidebar/stories/tests/MetadataSidebarRedesign-visual.stories.tsx +14 -1
  71. package/src/elements/content-uploader/ContentUploader.tsx +7 -3
  72. package/src/elements/content-uploader/ItemAction.tsx +8 -2
  73. package/src/features/header-flyout/HeaderFlyout.js +15 -2
  74. package/src/features/header-flyout/__tests__/__snapshots__/HeaderFlyout.test.js.snap +9 -3
  75. package/src/elements/content-sidebar/__tests__/__snapshots__/SidebarToggle.test.js.snap +0 -19
@@ -1,23 +1,87 @@
1
1
  import * as React from 'react';
2
- import { shallow } from 'enzyme/build';
2
+ import { render, screen, userEvent } from '../../../test-utils/testing-library';
3
3
  import { SidebarToggleComponent as SidebarToggle } from '../SidebarToggle';
4
4
 
5
5
  describe('elements/content-sidebar/SidebarToggle', () => {
6
6
  const historyMock = { replace: jest.fn() };
7
- const getWrapper = (props = {}) => shallow(<SidebarToggle history={historyMock} {...props} />);
7
+
8
+ beforeEach(() => {
9
+ jest.clearAllMocks();
10
+ });
11
+
12
+ const renderSidebarToggle = (props = {}) => {
13
+ return render(<SidebarToggle history={historyMock} {...props} />);
14
+ };
8
15
 
9
16
  test.each`
10
- isOpen | location
17
+ isOpen | expectedState
11
18
  ${true} | ${{ state: { open: false } }}
12
19
  ${false} | ${{ state: { open: true } }}
13
- `('should render and handle clicks correctly when isOpen is $isOpen', ({ isOpen, location }) => {
14
- const event = { preventDefault: jest.fn() };
15
- const wrapper = getWrapper({ isOpen });
20
+ `('should render and handle clicks correctly when isOpen is $isOpen', async ({ isOpen, expectedState }) => {
21
+ const user = userEvent();
22
+ renderSidebarToggle({ isOpen });
23
+
24
+ const toggleButton = screen.getByTestId('sidebartoggle');
25
+ expect(toggleButton).toBeInTheDocument();
26
+
27
+ await user.click(toggleButton);
28
+
29
+ expect(historyMock.replace).toHaveBeenCalledWith(expectedState);
30
+ });
31
+ });
16
32
 
17
- wrapper.simulate('click', event);
33
+ describe('elements/content-sidebar/SidebarToggle - Router Disabled', () => {
34
+ const mockInternalSidebarNavigationHandler = jest.fn();
35
+ const defaultProps = {
36
+ routerDisabled: true,
37
+ internalSidebarNavigation: { sidebar: 'activity' },
38
+ internalSidebarNavigationHandler: mockInternalSidebarNavigationHandler,
39
+ };
18
40
 
19
- expect(event.preventDefault).toHaveBeenCalled();
20
- expect(historyMock.replace).toHaveBeenCalledWith(location);
21
- expect(wrapper).toMatchSnapshot();
41
+ beforeEach(() => {
42
+ jest.clearAllMocks();
22
43
  });
44
+
45
+ const renderSidebarToggle = (props = {}) => {
46
+ return render(<SidebarToggle {...defaultProps} {...props} />);
47
+ };
48
+
49
+ test.each`
50
+ isOpen | expectedNavigation
51
+ ${true} | ${{ sidebar: 'activity', open: false }}
52
+ ${false} | ${{ sidebar: 'activity', open: true }}
53
+ `('should handle toggle clicks correctly when isOpen is $isOpen', async ({ isOpen, expectedNavigation }) => {
54
+ const user = userEvent();
55
+ renderSidebarToggle({ isOpen });
56
+
57
+ const toggleButton = screen.getByTestId('sidebartoggle');
58
+ expect(toggleButton).toBeInTheDocument();
59
+ await user.click(toggleButton);
60
+
61
+ expect(mockInternalSidebarNavigationHandler).toHaveBeenCalledWith(expectedNavigation, true);
62
+ });
63
+
64
+ test('should handle complex navigation state correctly', async () => {
65
+ const user = userEvent();
66
+ const complexNavigation = {
67
+ sidebar: 'activity',
68
+ versionId: '123',
69
+ activeFeedEntryType: 'comments',
70
+ activeFeedEntryId: '456',
71
+ };
72
+
73
+ renderSidebarToggle({
74
+ isOpen: true,
75
+ internalSidebarNavigation: complexNavigation,
76
+ });
77
+
78
+ const toggleButton = screen.getByTestId('sidebartoggle');
79
+ await user.click(toggleButton);
80
+
81
+ expect(mockInternalSidebarNavigationHandler).toHaveBeenCalledWith({
82
+ ...complexNavigation,
83
+ open: false,
84
+ }, true);
85
+ });
86
+
23
87
  });
@@ -344,6 +344,19 @@ export const SwitchEditingTemplateInstances: StoryObj<typeof MetadataSidebarRede
344
344
  fileId: '416047501580',
345
345
  metadataSidebarProps: defaultMetadataSidebarProps,
346
346
  },
347
+ parameters: {
348
+ msw: {
349
+ handlers: [
350
+ ...defaultMockHandlers,
351
+ http.get(`/2.0/files/416047501580`, () => {
352
+ return HttpResponse.json(mockFileRequest.response);
353
+ }),
354
+ http.get(`/2.0/files/416047501580/metadata`, () => {
355
+ return HttpResponse.json(mockMetadataInstances.response);
356
+ }),
357
+ ],
358
+ },
359
+ },
347
360
  play: async ({ canvasElement }) => {
348
361
  const canvas = within(canvasElement);
349
362
  // open and edit a new template
@@ -543,7 +556,7 @@ export const SuggestionForNewlyCreatedTemplateInstance: StoryObj<typeof Metadata
543
556
  const autofillButton = await canvas.findByRole('button', { name: 'Autofill' });
544
557
  userEvent.click(autofillButton);
545
558
 
546
- const suggestion = await canvas.findByText('4/1/2024');
559
+ const suggestion = await canvas.findByText('4/1/2024', {}, { timeout: 5000 });
547
560
  expect(suggestion).toBeInTheDocument();
548
561
  },
549
562
  };
@@ -34,6 +34,7 @@ import {
34
34
  CLIENT_NAME_CONTENT_UPLOADER,
35
35
  DEFAULT_HOSTNAME_API,
36
36
  DEFAULT_HOSTNAME_UPLOAD,
37
+ ERROR_CODE_ITEM_NAME_IN_USE,
37
38
  ERROR_CODE_UPLOAD_FILE_LIMIT,
38
39
  STATUS_COMPLETE,
39
40
  STATUS_ERROR,
@@ -90,7 +91,7 @@ export interface ContentUploaderProps {
90
91
  onResume: (item: UploadItem) => void;
91
92
  onUpgradeCTAClick?: () => void;
92
93
  onUpload: (item?: UploadItem | BoxItem) => void;
93
- overwrite: boolean;
94
+ overwrite: boolean | 'error';
94
95
  requestInterceptor?: (response: AxiosResponse) => void;
95
96
  responseInterceptor?: (config: AxiosRequestConfig) => void;
96
97
  rootFolderId: string;
@@ -1083,7 +1084,7 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
1083
1084
  */
1084
1085
  onClick = (item: UploadItem) => {
1085
1086
  const { chunked, isResumableUploadsEnabled, onClickCancel, onClickResume, onClickRetry } = this.props;
1086
- const { file, status } = item;
1087
+ const { file, status, error } = item;
1087
1088
  const isChunkedUpload =
1088
1089
  chunked && !item.isFolder && file.size > CHUNKED_UPLOAD_MIN_SIZE_BYTES && isMultiputSupported();
1089
1090
  const isResumable = isResumableUploadsEnabled && isChunkedUpload && item.api.sessionId;
@@ -1097,7 +1098,10 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
1097
1098
  onClickCancel(item);
1098
1099
  break;
1099
1100
  case STATUS_ERROR:
1100
- if (isResumable) {
1101
+ if (error?.code === ERROR_CODE_ITEM_NAME_IN_USE) {
1102
+ this.removeFileFromUploadQueue(item);
1103
+ onClickCancel(item);
1104
+ } else if (isResumable) {
1101
1105
  item.bytesUploadedOnLastResume = item.api.totalUploadedBytes;
1102
1106
  this.resumeFile(item);
1103
1107
  onClickResume(item);
@@ -8,6 +8,7 @@ import { Size5, SurfaceStatusSurfaceSuccess } from '@box/blueprint-web-assets/to
8
8
  import IconInProgress from './IconInProgress';
9
9
 
10
10
  import {
11
+ ERROR_CODE_ITEM_NAME_IN_USE,
11
12
  ERROR_CODE_UPLOAD_FILE_SIZE_LIMIT_EXCEEDED,
12
13
  STATUS_COMPLETE,
13
14
  STATUS_ERROR,
@@ -70,8 +71,13 @@ const ItemAction = ({
70
71
  }
71
72
  break;
72
73
  case STATUS_ERROR:
73
- Icon = ArrowCurveForward;
74
- tooltip = isResumableUploadsEnabled ? messages.resume : messages.retry;
74
+ if (code === ERROR_CODE_ITEM_NAME_IN_USE) {
75
+ Icon = XMark;
76
+ tooltip = messages.uploadsCancelButtonTooltip;
77
+ } else {
78
+ Icon = ArrowCurveForward;
79
+ tooltip = isResumableUploadsEnabled ? messages.resume : messages.retry;
80
+ }
75
81
  break;
76
82
  case STATUS_IN_PROGRESS:
77
83
  case STATUS_STAGED:
@@ -20,6 +20,8 @@ type Props = FlyoutProps & {
20
20
  header?: React.Element<any>,
21
21
  /** Optional function to get the scrollRef in parent components */
22
22
  scrollRefFn?: any => any,
23
+ /** Are OverlayHeader actions enabled */
24
+ isOverlayHeaderActionEnabled?: boolean,
23
25
  };
24
26
 
25
27
  class HeaderFlyout extends React.Component<Props> {
@@ -30,7 +32,16 @@ class HeaderFlyout extends React.Component<Props> {
30
32
  };
31
33
 
32
34
  render() {
33
- const { header, footer, flyoutButton, children, scrollRefFn, className, ...rest } = this.props;
35
+ const {
36
+ header,
37
+ footer,
38
+ flyoutButton,
39
+ children,
40
+ scrollRefFn,
41
+ className,
42
+ isOverlayHeaderActionEnabled = false,
43
+ ...rest
44
+ } = this.props;
34
45
 
35
46
  return (
36
47
  <Flyout
@@ -42,7 +53,9 @@ class HeaderFlyout extends React.Component<Props> {
42
53
  >
43
54
  {flyoutButton}
44
55
  <Overlay className="header-flyout-overlay">
45
- <OverlayHeader>{header && <h4 className="header-flyout-title">{header}</h4>}</OverlayHeader>
56
+ <OverlayHeader isOverlayHeaderActionEnabled={isOverlayHeaderActionEnabled}>
57
+ {header && <h4 className="header-flyout-title">{header}</h4>}
58
+ </OverlayHeader>
46
59
  <div className="header-flyout-list-container">
47
60
  <div
48
61
  className={classNames('flyout-list-container-body', {
@@ -21,7 +21,9 @@ exports[`components/core/header/components/HeaderFlyout render() should include
21
21
  <Overlay
22
22
  className="header-flyout-overlay"
23
23
  >
24
- <OverlayHeader>
24
+ <OverlayHeader
25
+ isOverlayHeaderActionEnabled={false}
26
+ >
25
27
  <h4
26
28
  className="header-flyout-title"
27
29
  >
@@ -78,7 +80,9 @@ exports[`components/core/header/components/HeaderFlyout render() should render d
78
80
  <Overlay
79
81
  className="header-flyout-overlay"
80
82
  >
81
- <OverlayHeader />
83
+ <OverlayHeader
84
+ isOverlayHeaderActionEnabled={false}
85
+ />
82
86
  <div
83
87
  className="header-flyout-list-container"
84
88
  >
@@ -123,7 +127,9 @@ exports[`components/core/header/components/HeaderFlyout render() should render t
123
127
  <Overlay
124
128
  className="header-flyout-overlay"
125
129
  >
126
- <OverlayHeader />
130
+ <OverlayHeader
131
+ isOverlayHeaderActionEnabled={false}
132
+ />
127
133
  <div
128
134
  className="header-flyout-list-container"
129
135
  >
@@ -1,19 +0,0 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
2
-
3
- exports[`elements/content-sidebar/SidebarToggle should render and handle clicks correctly when isOpen is false 1`] = `
4
- <SidebarToggleButton
5
- data-resin-target="sidebartoggle"
6
- data-testid="sidebartoggle"
7
- isOpen={false}
8
- onClick={[Function]}
9
- />
10
- `;
11
-
12
- exports[`elements/content-sidebar/SidebarToggle should render and handle clicks correctly when isOpen is true 1`] = `
13
- <SidebarToggleButton
14
- data-resin-target="sidebartoggle"
15
- data-testid="sidebartoggle"
16
- isOpen={true}
17
- onClick={[Function]}
18
- />
19
- `;