box-ui-elements 23.4.0-beta.36 → 23.4.0-beta.37

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 (69) hide show
  1. package/dist/explorer.js +1 -1
  2. package/dist/preview.js +1 -1
  3. package/dist/sidebar.js +1 -1
  4. package/es/elements/content-preview/PreviewNavigation.js +0 -2
  5. package/es/elements/content-preview/PreviewNavigation.js.flow +0 -2
  6. package/es/elements/content-preview/PreviewNavigation.js.map +1 -1
  7. package/es/elements/content-sidebar/versions/VersionsSidebarContainer.js +29 -7
  8. package/es/elements/content-sidebar/versions/VersionsSidebarContainer.js.flow +44 -5
  9. package/es/elements/content-sidebar/versions/VersionsSidebarContainer.js.map +1 -1
  10. package/es/elements/content-sidebar/withSidebarAnnotations.js +141 -35
  11. package/es/elements/content-sidebar/withSidebarAnnotations.js.flow +199 -37
  12. package/es/elements/content-sidebar/withSidebarAnnotations.js.map +1 -1
  13. package/i18n/bn-IN.js +1 -1
  14. package/i18n/bn-IN.properties +4 -0
  15. package/i18n/da-DK.js +1 -1
  16. package/i18n/da-DK.properties +4 -0
  17. package/i18n/de-DE.js +1 -1
  18. package/i18n/de-DE.properties +4 -0
  19. package/i18n/en-AU.js +1 -1
  20. package/i18n/en-AU.properties +4 -0
  21. package/i18n/en-CA.js +1 -1
  22. package/i18n/en-CA.properties +4 -0
  23. package/i18n/en-GB.js +1 -1
  24. package/i18n/en-GB.properties +4 -0
  25. package/i18n/es-419.js +1 -1
  26. package/i18n/es-419.properties +4 -0
  27. package/i18n/es-ES.js +1 -1
  28. package/i18n/es-ES.properties +4 -0
  29. package/i18n/fi-FI.js +1 -1
  30. package/i18n/fi-FI.properties +4 -0
  31. package/i18n/fr-CA.js +1 -1
  32. package/i18n/fr-CA.properties +4 -0
  33. package/i18n/fr-FR.js +1 -1
  34. package/i18n/fr-FR.properties +4 -0
  35. package/i18n/hi-IN.js +1 -1
  36. package/i18n/hi-IN.properties +4 -0
  37. package/i18n/it-IT.js +1 -1
  38. package/i18n/it-IT.properties +4 -0
  39. package/i18n/ja-JP.js +1 -1
  40. package/i18n/ja-JP.properties +4 -0
  41. package/i18n/ko-KR.js +1 -1
  42. package/i18n/ko-KR.properties +4 -0
  43. package/i18n/nb-NO.js +1 -1
  44. package/i18n/nb-NO.properties +4 -0
  45. package/i18n/nl-NL.js +1 -1
  46. package/i18n/nl-NL.properties +4 -0
  47. package/i18n/pl-PL.js +1 -1
  48. package/i18n/pl-PL.properties +4 -0
  49. package/i18n/pt-BR.js +1 -1
  50. package/i18n/pt-BR.properties +4 -0
  51. package/i18n/ru-RU.js +1 -1
  52. package/i18n/ru-RU.properties +4 -0
  53. package/i18n/sv-SE.js +1 -1
  54. package/i18n/sv-SE.properties +4 -0
  55. package/i18n/tr-TR.js +1 -1
  56. package/i18n/tr-TR.properties +4 -0
  57. package/i18n/zh-CN.js +1 -1
  58. package/i18n/zh-CN.properties +4 -0
  59. package/i18n/zh-TW.js +1 -1
  60. package/i18n/zh-TW.properties +4 -0
  61. package/package.json +1 -1
  62. package/src/elements/content-preview/PreviewNavigation.js +0 -2
  63. package/src/elements/content-preview/__tests__/PreviewNavigation.test.js +12 -12
  64. package/src/elements/content-sidebar/__tests__/withSidebarAnnotations.rtl.test.js +1152 -0
  65. package/src/elements/content-sidebar/versions/VersionsSidebarContainer.js +44 -5
  66. package/src/elements/content-sidebar/versions/__tests__/VersionsSidebarContainer.test.js +200 -43
  67. package/src/elements/content-sidebar/versions/__tests__/__snapshots__/VersionsSidebarContainer.test.js.snap +2 -2
  68. package/src/elements/content-sidebar/withSidebarAnnotations.js +199 -37
  69. package/src/elements/content-sidebar/__tests__/withSidebarAnnotations.test.js +0 -626
@@ -24,7 +24,12 @@ import { withAPIContext } from '../../common/api-context';
24
24
  import type { FeatureConfig } from '../../common/feature-checking';
25
25
  import type { VersionActionCallback, VersionChangeCallback, SidebarLoadCallback } from './flowTypes';
26
26
  import type { BoxItemVersion, BoxItem, FileVersions } from '../../../common/types/core';
27
- import { ViewType, type ViewTypeValues } from '../../common/types/SidebarNavigation';
27
+ import {
28
+ ViewType,
29
+ type ViewTypeValues,
30
+ type InternalSidebarNavigation,
31
+ type InternalSidebarNavigationHandler,
32
+ } from '../../common/types/SidebarNavigation';
28
33
 
29
34
  type Props = {
30
35
  api: API,
@@ -32,6 +37,8 @@ type Props = {
32
37
  fileId: string,
33
38
  hasSidebarInitialized?: boolean,
34
39
  history: RouterHistory,
40
+ internalSidebarNavigation?: InternalSidebarNavigation,
41
+ internalSidebarNavigationHandler?: InternalSidebarNavigationHandler,
35
42
  match: Match,
36
43
  onLoad: SidebarLoadCallback,
37
44
  onUpgradeClick?: () => void,
@@ -42,6 +49,7 @@ type Props = {
42
49
  onVersionPromote: VersionActionCallback,
43
50
  onVersionRestore: VersionActionCallback,
44
51
  parentName: ViewTypeValues,
52
+ routerDisabled?: boolean,
45
53
  versionId?: string,
46
54
  };
47
55
 
@@ -264,8 +272,20 @@ class VersionsSidebarContainer extends React.Component<Props, State> {
264
272
  }
265
273
 
266
274
  updateVersion = (versionId?: ?string): void => {
267
- const { history, match } = this.props;
268
- return history.push(generatePath(match.path, { ...match.params, versionId }));
275
+ const { history, match, routerDisabled, internalSidebarNavigationHandler, internalSidebarNavigation } =
276
+ this.props;
277
+
278
+ if (routerDisabled && internalSidebarNavigationHandler) {
279
+ const navigationUpdate: InternalSidebarNavigation = { ...internalSidebarNavigation };
280
+ if (versionId) {
281
+ navigationUpdate.versionId = versionId;
282
+ } else {
283
+ delete navigationUpdate.versionId;
284
+ }
285
+ internalSidebarNavigationHandler(navigationUpdate);
286
+ } else {
287
+ history.push(generatePath(match.path, { ...match.params, versionId }));
288
+ }
269
289
  };
270
290
 
271
291
  updateVersionToCurrent = (): void => {
@@ -287,21 +307,40 @@ class VersionsSidebarContainer extends React.Component<Props, State> {
287
307
  };
288
308
 
289
309
  render() {
290
- const { fileId, parentName, onUpgradeClick } = this.props;
310
+ const {
311
+ fileId,
312
+ parentName,
313
+ onUpgradeClick,
314
+ routerDisabled,
315
+ internalSidebarNavigation,
316
+ internalSidebarNavigationHandler,
317
+ } = this.props;
291
318
 
292
319
  if (onUpgradeClick) {
293
- return <StaticVersionsSidebar onUpgradeClick={onUpgradeClick} parentName={parentName} {...this.state} />;
320
+ return (
321
+ <StaticVersionsSidebar
322
+ onUpgradeClick={onUpgradeClick}
323
+ parentName={parentName}
324
+ routerDisabled={routerDisabled}
325
+ internalSidebarNavigation={internalSidebarNavigation}
326
+ internalSidebarNavigationHandler={internalSidebarNavigationHandler}
327
+ {...this.state}
328
+ />
329
+ );
294
330
  }
295
331
 
296
332
  return (
297
333
  <VersionsSidebar
298
334
  fileId={fileId}
335
+ internalSidebarNavigation={internalSidebarNavigation}
336
+ internalSidebarNavigationHandler={internalSidebarNavigationHandler}
299
337
  onDelete={this.handleActionDelete}
300
338
  onDownload={this.handleActionDownload}
301
339
  onPreview={this.handleActionPreview}
302
340
  onPromote={this.handleActionPromote}
303
341
  onRestore={this.handleActionRestore}
304
342
  parentName={parentName}
343
+ routerDisabled={routerDisabled}
305
344
  {...this.state}
306
345
  />
307
346
  );
@@ -1,7 +1,12 @@
1
1
  import * as React from 'react';
2
2
  import { shallow } from 'enzyme/build';
3
+ import { createBrowserHistory } from 'history';
4
+ import { Router } from 'react-router-dom';
5
+ import { render, waitFor, act, screen } from '../../../../test-utils/testing-library';
3
6
  import messages from '../messages';
4
7
  import openUrlInsideIframe from '../../../../utils/iframe';
8
+ import VersionsSidebarAPI from '../VersionsSidebarAPI';
9
+ import VersionsSidebar from '../VersionsSidebar';
5
10
  import { VersionsSidebarContainerComponent } from '../VersionsSidebarContainer';
6
11
 
7
12
  jest.mock('react-router-dom', () => ({
@@ -18,6 +23,10 @@ jest.mock('../../../../utils/iframe', () => ({
18
23
  default: jest.fn(),
19
24
  }));
20
25
 
26
+ jest.mock('../VersionsSidebarAPI');
27
+
28
+ jest.mock('../VersionsSidebar', () => jest.fn(() => <div data-testid="versions-sidebar" />));
29
+
21
30
  const versions = [
22
31
  { id: '123', name: 'Version 1' },
23
32
  { id: '456', name: 'Version 2' },
@@ -25,73 +34,221 @@ const versions = [
25
34
  ];
26
35
 
27
36
  describe('elements/content-sidebar/versions/VersionsSidebarContainer', () => {
28
- const versionsAPI = {
37
+ const mockedAPIMethods = {
38
+ fetchData: jest.fn(),
39
+ deleteVersion: jest.fn(),
40
+ fetchVersion: jest.fn(),
41
+ fetchDownloadUrl: jest.fn(),
42
+ promoteVersion: jest.fn(),
43
+ restoreVersion: jest.fn(),
29
44
  addPermissions: jest.fn(),
30
45
  sortVersions: jest.fn(),
31
46
  };
47
+
48
+ const versionsAPI = {
49
+ ...mockedAPIMethods,
50
+ };
51
+
32
52
  const api = {
33
53
  getVersionsAPI: () => versionsAPI,
34
54
  };
35
- const getWrapper = ({ ...props } = {}) =>
36
- shallow(<VersionsSidebarContainerComponent api={api} fileId="12345" {...props} />);
37
55
 
38
- describe('componentDidUpdate', () => {
39
- let onVersionChange;
40
- let wrapper;
41
- let instance;
56
+ VersionsSidebarAPI.mockImplementation(() => mockedAPIMethods);
42
57
 
43
- beforeEach(() => {
44
- onVersionChange = jest.fn();
45
- wrapper = getWrapper({ onVersionChange, refreshIdentity: false });
46
- instance = wrapper.instance();
47
- });
58
+ const getWrapper = (props = {}) =>
59
+ shallow(<VersionsSidebarContainerComponent api={api} fileId="12345" {...props} />);
48
60
 
49
- test('should verify the selected version id exists when it changes', () => {
50
- const version = { id: '45678' };
51
- const currentVersion = { id: '54321' };
61
+ const history = createBrowserHistory();
52
62
 
53
- instance.verifyVersion = jest.fn();
63
+ const renderComponent = (props = {}) => {
64
+ return render(
65
+ <Router history={history}>
66
+ <VersionsSidebarContainerComponent api={api} fileId="12345" match={{}} history={history} {...props} />
67
+ </Router>,
68
+ );
69
+ };
54
70
 
55
- wrapper.setState({ versions: [currentVersion, version] });
56
- wrapper.setProps({ versionId: '45678' });
71
+ const renderComponentWithoutRouter = (props = {}) => {
72
+ return render(<VersionsSidebarContainerComponent api={api} fileId="12345" routerDisabled={true} {...props} />);
73
+ };
57
74
 
58
- expect(instance.verifyVersion).toHaveBeenCalled();
59
- });
75
+ beforeEach(() => {
76
+ jest.clearAllMocks();
77
+ mockedAPIMethods.fetchData.mockResolvedValue([{}, {}]);
78
+ mockedAPIMethods.deleteVersion.mockResolvedValue();
79
+ mockedAPIMethods.fetchVersion.mockResolvedValue({});
80
+ mockedAPIMethods.fetchDownloadUrl.mockResolvedValue();
81
+ mockedAPIMethods.promoteVersion.mockResolvedValue();
82
+ mockedAPIMethods.restoreVersion.mockResolvedValue();
60
83
  });
61
84
 
62
85
  describe('componentDidMount', () => {
86
+ beforeEach(() => {
87
+ history.push = jest.fn();
88
+ });
89
+
63
90
  test('should call onLoad after a successful fetchData() call', async () => {
64
91
  const onLoad = jest.fn();
65
- const fetchData = jest.fn(() => Promise.resolve());
66
- const instance = getWrapper({ onLoad }).instance();
67
92
 
68
- instance.fetchData = fetchData;
93
+ await act(async () => {
94
+ renderComponent({ onLoad });
95
+ });
69
96
 
70
- await instance.componentDidMount();
71
- expect(onLoad).toHaveBeenCalled();
97
+ await waitFor(() => {
98
+ expect(onLoad).toHaveBeenCalledTimes(1);
99
+ });
72
100
  });
73
101
  });
74
102
 
75
103
  describe('handleActionDelete', () => {
76
- test('should call api endpoint helpers', () => {
77
- const handleDelete = jest.fn();
78
- const wrapper = getWrapper({ onVersionDelete: handleDelete, versionId: '123' });
79
- const instance = wrapper.instance();
80
- const version = { id: '456' };
81
- const newVersion = { id: '456', trash_at: '' };
82
-
83
- instance.api.deleteVersion = jest.fn().mockResolvedValueOnce();
84
- instance.api.fetchVersion = jest.fn().mockResolvedValueOnce(newVersion);
85
- instance.findVersion = jest.fn(() => version);
86
- instance.handleDeleteSuccess = jest.fn();
104
+ test.each`
105
+ scenario | versionIdToDelete | selectedVersionId | shouldCallHistoryPush | expectedHistoryPath
106
+ ${'non-selected version'} | ${'456'} | ${'123'} | ${false} | ${null}
107
+ ${'currently selected version'} | ${'456'} | ${'456'} | ${true} | ${'/versions/123'}
108
+ `(
109
+ 'should handle delete operation correctly when deleting $scenario',
110
+ async ({ versionIdToDelete, selectedVersionId, shouldCallHistoryPush, expectedHistoryPath }) => {
111
+ const handleDelete = jest.fn();
112
+ const newVersion = { id: versionIdToDelete, trash_at: '' };
113
+ const versionToDelete = {
114
+ id: versionIdToDelete,
115
+ name: 'Version 1',
116
+ created_at: '2023-01-01T00:00:00Z',
117
+ };
118
+ const mostRecentVersion = { id: '123', name: 'Current Version', created_at: '2023-01-02T00:00:00Z' };
119
+
120
+ let triggerDelete;
121
+ VersionsSidebar.mockImplementation(({ onDelete, versions: versionsList }) => {
122
+ triggerDelete = () => onDelete(versionIdToDelete);
123
+ return (
124
+ <div data-testid="versions-sidebar">
125
+ {versionsList && versionsList.length > 0 && (
126
+ <div data-testid="versions-loaded">Versions loaded</div>
127
+ )}
128
+ </div>
129
+ );
130
+ });
131
+
132
+ // Include both versions so verifyVersion can find the current version
133
+ const mockVersionsResponse = { entries: [mostRecentVersion, versionToDelete], total_count: 2 };
134
+ const mockFileResponse = { version_limit: null };
135
+
136
+ mockedAPIMethods.addPermissions.mockReturnValue(mockVersionsResponse);
137
+ mockedAPIMethods.fetchData.mockResolvedValue([mockFileResponse, mockVersionsResponse]);
138
+ mockedAPIMethods.fetchVersion.mockResolvedValue(newVersion);
139
+
140
+ const historyPushSpy = jest.fn();
141
+
142
+ renderComponent({
143
+ onVersionDelete: handleDelete,
144
+ versionId: selectedVersionId,
145
+ history: { ...history, push: historyPushSpy },
146
+ match: { path: '/versions/:versionId', params: { versionId: selectedVersionId } },
147
+ });
148
+
149
+ await waitFor(() => {
150
+ expect(screen.getByTestId('versions-sidebar')).toBeInTheDocument();
151
+ });
152
+ await waitFor(() => {
153
+ expect(screen.queryByTestId('versions-loaded')).toBeInTheDocument();
154
+ });
155
+
156
+ await act(async () => {
157
+ triggerDelete();
158
+ });
159
+
160
+ await waitFor(() => {
161
+ expect(mockedAPIMethods.deleteVersion).toHaveBeenCalledWith(versionToDelete);
162
+ expect(mockedAPIMethods.fetchVersion).toHaveBeenCalledWith(versionToDelete.id);
163
+ expect(handleDelete).toHaveBeenCalledWith(versionToDelete.id);
164
+
165
+ if (shouldCallHistoryPush) {
166
+ expect(historyPushSpy).toHaveBeenCalledWith(expect.stringContaining(expectedHistoryPath));
167
+ } else {
168
+ expect(historyPushSpy).not.toHaveBeenCalled();
169
+ }
170
+ });
171
+ },
172
+ );
173
+ });
87
174
 
88
- instance.handleActionDelete(version.id).then(() => {
89
- expect(instance.api.deleteVersion).toHaveBeenCalledWith(version);
90
- expect(instance.api.fetchVersion).toHaveBeenCalled();
91
- expect(instance.handleDeleteSuccess).toHaveBeenCalledWith(newVersion);
92
- expect(handleDelete).toHaveBeenCalledWith(version.id);
93
- });
94
- });
175
+ describe('handleActionDelete - Router Disabled', () => {
176
+ test.each`
177
+ scenario | versionIdToDelete | selectedVersionId | shouldCallNavigationHandler | expectedNavigationCall
178
+ ${'non-selected version'} | ${'456'} | ${'123'} | ${false} | ${null}
179
+ ${'currently selected version'} | ${'456'} | ${'456'} | ${true} | ${{ versionId: '123' }}
180
+ `(
181
+ 'should handle delete operation correctly when deleting $scenario',
182
+ async ({ versionIdToDelete, selectedVersionId, shouldCallNavigationHandler, expectedNavigationCall }) => {
183
+ const handleDelete = jest.fn();
184
+ const mockInternalSidebarNavigationHandler = jest.fn();
185
+ const newVersion = { id: versionIdToDelete, trash_at: '' };
186
+ const versionToDelete = {
187
+ id: versionIdToDelete,
188
+ name: 'Version 1',
189
+ created_at: '2023-01-01T00:00:00Z',
190
+ };
191
+ const mostRecentVersion = { id: '123', name: 'Current Version', created_at: '2023-01-02T00:00:00Z' };
192
+ const mockInternalSidebarNavigation = {
193
+ sidebar: 'activity',
194
+ activeFeedEntryType: 'comments',
195
+ activeFeedEntryId: '789',
196
+ };
197
+
198
+ let triggerDelete;
199
+ VersionsSidebar.mockImplementation(({ onDelete, versions: versionsList }) => {
200
+ triggerDelete = () => onDelete(versionIdToDelete);
201
+ return (
202
+ <div data-testid="versions-sidebar">
203
+ {versionsList && versionsList.length > 0 && (
204
+ <div data-testid="versions-loaded">Versions loaded</div>
205
+ )}
206
+ </div>
207
+ );
208
+ });
209
+
210
+ // Include both versions so verifyVersion can find the current version
211
+ const mockVersionsResponse = { entries: [mostRecentVersion, versionToDelete], total_count: 2 };
212
+ const mockFileResponse = { version_limit: null };
213
+
214
+ mockedAPIMethods.addPermissions.mockReturnValue(mockVersionsResponse);
215
+ mockedAPIMethods.fetchData.mockResolvedValue([mockFileResponse, mockVersionsResponse]);
216
+ mockedAPIMethods.fetchVersion.mockResolvedValue(newVersion);
217
+
218
+ renderComponentWithoutRouter({
219
+ onVersionDelete: handleDelete,
220
+ versionId: selectedVersionId,
221
+ internalSidebarNavigation: mockInternalSidebarNavigation,
222
+ internalSidebarNavigationHandler: mockInternalSidebarNavigationHandler,
223
+ });
224
+
225
+ await waitFor(() => {
226
+ expect(screen.getByTestId('versions-sidebar')).toBeInTheDocument();
227
+ });
228
+ await waitFor(() => {
229
+ expect(screen.queryByTestId('versions-loaded')).toBeInTheDocument();
230
+ });
231
+
232
+ await act(async () => {
233
+ triggerDelete();
234
+ });
235
+
236
+ await waitFor(() => {
237
+ expect(mockedAPIMethods.deleteVersion).toHaveBeenCalledWith(versionToDelete);
238
+ expect(mockedAPIMethods.fetchVersion).toHaveBeenCalledWith(versionToDelete.id);
239
+ expect(handleDelete).toHaveBeenCalledWith(versionToDelete.id);
240
+
241
+ if (shouldCallNavigationHandler) {
242
+ expect(mockInternalSidebarNavigationHandler).toHaveBeenCalledWith({
243
+ ...mockInternalSidebarNavigation,
244
+ ...expectedNavigationCall,
245
+ });
246
+ } else {
247
+ expect(mockInternalSidebarNavigationHandler).not.toHaveBeenCalled();
248
+ }
249
+ });
250
+ },
251
+ );
95
252
  });
96
253
 
97
254
  describe('handleActionDownload', () => {
@@ -20,7 +20,7 @@ exports[`elements/content-sidebar/versions/VersionsSidebarContainer handleFetchE
20
20
  `;
21
21
 
22
22
  exports[`elements/content-sidebar/versions/VersionsSidebarContainer handleFetchError should set state to default values with error message 1`] = `
23
- <VersionsSidebar
23
+ <mockConstructor
24
24
  error={
25
25
  {
26
26
  "defaultMessage": "File versions could not be retrieved.",
@@ -44,7 +44,7 @@ exports[`elements/content-sidebar/versions/VersionsSidebarContainer handleFetchE
44
44
  `;
45
45
 
46
46
  exports[`elements/content-sidebar/versions/VersionsSidebarContainer render should match its snapshot 1`] = `
47
- <VersionsSidebar
47
+ <mockConstructor
48
48
  fileId="12345"
49
49
  isArchived={false}
50
50
  isLoading={true}