box-ui-elements 23.4.0-beta.33 → 23.4.0-beta.34

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 (24) 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/common/types/SidebarNavigation.js +4 -2
  5. package/es/elements/common/types/SidebarNavigation.js.flow +7 -4
  6. package/es/elements/common/types/SidebarNavigation.js.map +1 -1
  7. package/es/elements/content-preview/PreviewNavigation.js +65 -2
  8. package/es/elements/content-preview/PreviewNavigation.js.flow +86 -2
  9. package/es/elements/content-preview/PreviewNavigation.js.map +1 -1
  10. package/es/elements/content-sidebar/ActivitySidebar.js +39 -7
  11. package/es/elements/content-sidebar/ActivitySidebar.js.flow +42 -6
  12. package/es/elements/content-sidebar/ActivitySidebar.js.map +1 -1
  13. package/es/src/elements/common/types/SidebarNavigation.d.ts +10 -4
  14. package/package.json +1 -1
  15. package/src/elements/common/types/SidebarNavigation.js.flow +7 -4
  16. package/src/elements/common/types/SidebarNavigation.ts +11 -3
  17. package/src/elements/content-preview/PreviewNavigation.js +86 -2
  18. package/src/elements/content-preview/__tests__/PreviewNavigation.test.js +202 -62
  19. package/src/elements/content-sidebar/ActivitySidebar.js +42 -6
  20. package/src/elements/content-sidebar/__tests__/ActivitySidebar.rtl.test.js +521 -0
  21. package/src/elements/content-sidebar/__tests__/ActivitySidebar.test.js +1 -123
  22. package/src/elements/content-sidebar/__tests__/AddTaskButton.test.js +6 -5
  23. package/src/elements/content-sidebar/versions/__tests__/StaticVersionSidebar.test.js +3 -5
  24. package/src/elements/content-preview/__tests__/__snapshots__/PreviewNavigation.test.js.snap +0 -361
@@ -1,8 +1,8 @@
1
1
  import * as React from 'react';
2
2
  import { Router } from 'react-router-dom';
3
- import noop from 'lodash/noop';
4
- import { mount } from 'enzyme';
5
- import { PreviewNavigationComponent as PreviewNavigation } from '../PreviewNavigation';
3
+ import { render, screen, userEvent } from '../../../test-utils/testing-library';
4
+ import PreviewNavigation from '../PreviewNavigation';
5
+ import { ViewType, FeedEntryType } from '../../common/types/SidebarNavigation';
6
6
 
7
7
  const historyMockDefault = {
8
8
  location: { pathname: '/activity/tasks/1234', hash: '' },
@@ -18,110 +18,250 @@ const deeplinkedMetadataHistoryMock = {
18
18
  entries: [{}],
19
19
  };
20
20
 
21
- const getWrapper = ({
22
- collection = ['a', 'b', 'c'],
23
- historyMock = historyMockDefault,
24
- onNavigateLeft = noop,
25
- onNavigateRight = noop,
26
- ...rest
27
- }) =>
28
- mount(
21
+ const onNavigateLeftMock = jest.fn();
22
+ const onNavigateRightMock = jest.fn();
23
+ const mockNavigationHandler = jest.fn();
24
+
25
+ const renderComponentWithRouter = (props = {}) => {
26
+ const {
27
+ collection = ['a', 'b', 'c'],
28
+ historyMock = historyMockDefault,
29
+ onNavigateLeft = onNavigateLeftMock,
30
+ onNavigateRight = onNavigateRightMock,
31
+ internalSidebarNavigationHandler = mockNavigationHandler,
32
+ ...rest
33
+ } = props;
34
+
35
+ return render(
29
36
  <Router history={historyMock}>
30
37
  <PreviewNavigation
31
38
  collection={collection}
32
- intl={{
33
- formatMessage: jest.fn(),
34
- }}
35
39
  onNavigateLeft={onNavigateLeft}
36
40
  onNavigateRight={onNavigateRight}
37
- history={historyMock}
41
+ internalSidebarNavigationHandler={internalSidebarNavigationHandler}
38
42
  {...rest}
39
43
  />
40
44
  </Router>,
41
45
  );
46
+ };
47
+
48
+ const renderComponentWithoutRouter = (props = {}) => {
49
+ const defaultProps = {
50
+ collection: ['a', 'b', 'c'],
51
+ currentIndex: 1,
52
+ onNavigateLeft: onNavigateLeftMock,
53
+ onNavigateRight: onNavigateRightMock,
54
+ internalSidebarNavigationHandler: mockNavigationHandler,
55
+ };
42
56
 
43
- afterEach(() => {
57
+ return render(<PreviewNavigation {...defaultProps} {...props} routerDisabled />);
58
+ };
59
+
60
+ beforeEach(() => {
44
61
  jest.resetAllMocks();
45
62
  });
46
63
 
47
64
  describe('elements/content-preview/PreviewNavigation', () => {
48
65
  describe('render()', () => {
49
66
  test('should render correctly with an empty collection', () => {
50
- const wrapper = getWrapper({ collection: [], currentIndex: 0 });
51
- expect(wrapper).toMatchSnapshot();
67
+ const { container } = renderComponentWithRouter({ collection: [], currentIndex: 0 });
68
+ expect(container.firstChild).toBeNull();
52
69
  });
53
70
 
54
- test.each([0, 1, 9])('should render correctly with a filled collection %i', ({ currentIndex }) => {
55
- const collection = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
56
- const wrapper = getWrapper({ collection, currentIndex });
57
- expect(wrapper).toMatchSnapshot();
58
- });
71
+ test.each([
72
+ { currentIndex: 0, description: 'first item', expectLeft: false, expectRight: true },
73
+ { currentIndex: 1, description: 'middle item', expectLeft: true, expectRight: true },
74
+ { currentIndex: 9, description: 'last item', expectLeft: true, expectRight: false },
75
+ ])(
76
+ 'should render correctly with a filled collection - $description',
77
+ ({ currentIndex, expectLeft, expectRight }) => {
78
+ const collection = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
79
+ renderComponentWithRouter({ collection, currentIndex });
80
+
81
+ const leftButton = screen.queryByTestId('preview-navigation-left');
82
+ const rightButton = screen.queryByTestId('preview-navigation-right');
83
+
84
+ if (expectLeft) {
85
+ expect(leftButton).toBeInTheDocument();
86
+ } else {
87
+ expect(leftButton).not.toBeInTheDocument();
88
+ }
89
+
90
+ if (expectRight) {
91
+ expect(rightButton).toBeInTheDocument();
92
+ } else {
93
+ expect(rightButton).not.toBeInTheDocument();
94
+ }
95
+ },
96
+ );
97
+
98
+ test('should render left navigation correctly from tasks deeplinked URL', async () => {
99
+ const user = userEvent();
100
+
101
+ renderComponentWithRouter({
102
+ currentIndex: 2,
103
+ historyMock: historyMockDefault,
104
+ });
59
105
 
60
- test('should render left navigation correctly from tasks deeplinked URL', () => {
61
- const onNavigateLeftMock = jest.fn();
62
- const wrapper = getWrapper({ currentIndex: 2, onNavigateLeft: onNavigateLeftMock });
106
+ const leftButton = screen.getByTestId('preview-navigation-left');
107
+ expect(leftButton).toBeInTheDocument();
63
108
 
64
- expect(wrapper.find('PlainButton')).toHaveLength(1);
65
- wrapper.find('PlainButton').simulate('click');
109
+ await user.click(leftButton);
66
110
 
67
- expect(historyMockDefault.push).toBeCalledTimes(1);
68
- expect(historyMockDefault.push).toBeCalledWith('/activity');
111
+ expect(historyMockDefault.push).toHaveBeenCalledTimes(1);
112
+ expect(historyMockDefault.push).toHaveBeenCalledWith('/activity');
69
113
  expect(onNavigateLeftMock).toHaveBeenCalled();
70
114
  });
71
115
 
72
- test('should render right navigation correctly from tasks deeplinked URL ', () => {
73
- const onNavigateRightMock = jest.fn();
74
- const wrapper = getWrapper({ currentIndex: 0, onNavigateRight: onNavigateRightMock });
116
+ test('should render right navigation correctly from tasks deeplinked URL', async () => {
117
+ const user = userEvent();
75
118
 
76
- expect(wrapper.find('PlainButton')).toHaveLength(1);
77
- wrapper.find('PlainButton').simulate('click');
119
+ renderComponentWithRouter({
120
+ currentIndex: 0,
121
+ historyMock: historyMockDefault,
122
+ });
78
123
 
79
- expect(historyMockDefault.push).toBeCalledTimes(1);
80
- expect(historyMockDefault.push).toBeCalledWith('/activity');
81
- expect(onNavigateRightMock).toHaveBeenCalled();
82
- });
83
- test('should render navigation correctly from comments deeplinked URL ', () => {
84
- const onNavigateRightMock = jest.fn();
85
- const wrapper = getWrapper({ currentIndex: 0, onNavigateRight: onNavigateRightMock });
124
+ const rightButton = screen.getByTestId('preview-navigation-right');
125
+ expect(rightButton).toBeInTheDocument();
86
126
 
87
- expect(wrapper.find('PlainButton')).toHaveLength(1);
88
- wrapper.find('PlainButton').simulate('click');
127
+ await user.click(rightButton);
89
128
 
90
- expect(historyMockDefault.push).toBeCalledTimes(1);
91
- expect(historyMockDefault.push).toBeCalledWith('/activity');
129
+ expect(historyMockDefault.push).toHaveBeenCalledTimes(1);
130
+ expect(historyMockDefault.push).toHaveBeenCalledWith('/activity');
92
131
  expect(onNavigateRightMock).toHaveBeenCalled();
93
132
  });
94
133
 
95
- test('should render right navigation correctly from metadata deeplinked URL ', () => {
96
- const onNavigateRightMock = jest.fn();
97
- const wrapper = getWrapper({
134
+ test('should render right navigation correctly from metadata deeplinked URL', async () => {
135
+ const user = userEvent();
136
+
137
+ renderComponentWithRouter({
98
138
  currentIndex: 0,
99
139
  historyMock: deeplinkedMetadataHistoryMock,
100
- onNavigateRight: onNavigateRightMock,
101
140
  });
102
141
 
103
- expect(wrapper.find('PlainButton')).toHaveLength(1);
104
- wrapper.find('PlainButton').simulate('click');
142
+ const rightButton = screen.getByTestId('preview-navigation-right');
143
+ expect(rightButton).toBeInTheDocument();
144
+
145
+ await user.click(rightButton);
105
146
 
106
- expect(deeplinkedMetadataHistoryMock.push).toBeCalledTimes(1);
107
- expect(deeplinkedMetadataHistoryMock.push).toBeCalledWith('/metadata/filteredTemplates/123,124');
147
+ expect(deeplinkedMetadataHistoryMock.push).toHaveBeenCalledTimes(1);
148
+ expect(deeplinkedMetadataHistoryMock.push).toHaveBeenCalledWith('/metadata/filteredTemplates/123,124');
108
149
  expect(onNavigateRightMock).toHaveBeenCalled();
109
150
  });
110
151
 
111
- test('should render left navigation correctly from metadata deeplinked URL ', () => {
112
- const onNavigateLeftMock = jest.fn();
113
- const wrapper = getWrapper({
152
+ test('should render left navigation correctly from metadata deeplinked URL', async () => {
153
+ const user = userEvent();
154
+
155
+ renderComponentWithRouter({
114
156
  currentIndex: 2,
115
157
  historyMock: deeplinkedMetadataHistoryMock,
116
- onNavigateLeft: onNavigateLeftMock,
117
158
  });
118
159
 
119
- expect(wrapper.find('PlainButton')).toHaveLength(1);
120
- wrapper.find('PlainButton').simulate('click');
160
+ const leftButton = screen.getByTestId('preview-navigation-left');
161
+ expect(leftButton).toBeInTheDocument();
162
+
163
+ await user.click(leftButton);
121
164
 
122
- expect(deeplinkedMetadataHistoryMock.push).toBeCalledTimes(1);
123
- expect(deeplinkedMetadataHistoryMock.push).toBeCalledWith('/metadata/filteredTemplates/123,124');
165
+ expect(deeplinkedMetadataHistoryMock.push).toHaveBeenCalledTimes(1);
166
+ expect(deeplinkedMetadataHistoryMock.push).toHaveBeenCalledWith('/metadata/filteredTemplates/123,124');
124
167
  expect(onNavigateLeftMock).toHaveBeenCalled();
125
168
  });
126
169
  });
170
+
171
+ describe('when routerDisabled is true', () => {
172
+ test('should render correctly without router', () => {
173
+ renderComponentWithoutRouter({ currentIndex: 1 });
174
+
175
+ expect(screen.getByTestId('preview-navigation-left')).toBeInTheDocument();
176
+ expect(screen.getByTestId('preview-navigation-right')).toBeInTheDocument();
177
+ });
178
+
179
+ test('should call internalSidebarNavigationHandler when left navigation button is clicked', async () => {
180
+ const mockInternalSidebarNavigation = {
181
+ sidebar: ViewType.ACTIVITY,
182
+ activeFeedEntryType: FeedEntryType.COMMENTS,
183
+ activeFeedEntryId: '123',
184
+ };
185
+ const user = userEvent();
186
+
187
+ renderComponentWithoutRouter({
188
+ internalSidebarNavigation: mockInternalSidebarNavigation,
189
+ });
190
+
191
+ const leftButton = screen.getByTestId('preview-navigation-left');
192
+ await user.click(leftButton);
193
+
194
+ expect(mockNavigationHandler).toHaveBeenCalledTimes(1);
195
+ expect(mockNavigationHandler).toHaveBeenCalledWith({ sidebar: ViewType.ACTIVITY });
196
+ expect(onNavigateLeftMock).toHaveBeenCalledTimes(1);
197
+ expect(onNavigateRightMock).not.toHaveBeenCalled();
198
+ });
199
+
200
+ test('should call internalSidebarNavigationHandler when right navigation button is clicked', async () => {
201
+ const mockInternalSidebarNavigation = {
202
+ sidebar: ViewType.ACTIVITY,
203
+ activeFeedEntryType: FeedEntryType.COMMENTS,
204
+ activeFeedEntryId: '123',
205
+ };
206
+ const user = userEvent();
207
+
208
+ renderComponentWithoutRouter({
209
+ internalSidebarNavigation: mockInternalSidebarNavigation,
210
+ });
211
+
212
+ const rightButton = screen.getByTestId('preview-navigation-right');
213
+ await user.click(rightButton);
214
+
215
+ expect(mockNavigationHandler).toHaveBeenCalledTimes(1);
216
+ expect(mockNavigationHandler).toHaveBeenCalledWith({ sidebar: ViewType.ACTIVITY });
217
+ expect(onNavigateRightMock).toHaveBeenCalledTimes(1);
218
+ expect(onNavigateLeftMock).not.toHaveBeenCalled();
219
+ });
220
+
221
+ test('should call navigation handler with metadata deeplinks when left navigation button is clicked', async () => {
222
+ const mockInternalSidebarNavigation = {
223
+ sidebar: ViewType.METADATA,
224
+ filteredTemplateIds: '123,124',
225
+ };
226
+ const user = userEvent();
227
+
228
+ renderComponentWithoutRouter({
229
+ internalSidebarNavigation: mockInternalSidebarNavigation,
230
+ });
231
+
232
+ const leftButton = screen.getByTestId('preview-navigation-left');
233
+ await user.click(leftButton);
234
+
235
+ expect(mockNavigationHandler).toHaveBeenCalledTimes(1);
236
+ expect(mockNavigationHandler).toHaveBeenCalledWith({
237
+ sidebar: ViewType.METADATA,
238
+ filteredTemplateIds: '123,124',
239
+ });
240
+ expect(onNavigateLeftMock).toHaveBeenCalledTimes(1);
241
+ expect(onNavigateRightMock).not.toHaveBeenCalled();
242
+ });
243
+
244
+ test('should call navigation handler with metadata deeplinks when right navigation button is clicked', async () => {
245
+ const mockInternalSidebarNavigation = {
246
+ sidebar: ViewType.METADATA,
247
+ filteredTemplateIds: '123,124',
248
+ };
249
+ const user = userEvent();
250
+
251
+ renderComponentWithoutRouter({
252
+ internalSidebarNavigation: mockInternalSidebarNavigation,
253
+ });
254
+
255
+ const rightButton = screen.getByTestId('preview-navigation-right');
256
+ await user.click(rightButton);
257
+
258
+ expect(mockNavigationHandler).toHaveBeenCalledTimes(1);
259
+ expect(mockNavigationHandler).toHaveBeenCalledWith({
260
+ sidebar: ViewType.METADATA,
261
+ filteredTemplateIds: '123,124',
262
+ });
263
+ expect(onNavigateRightMock).toHaveBeenCalledTimes(1);
264
+ expect(onNavigateLeftMock).not.toHaveBeenCalled();
265
+ });
266
+ });
127
267
  });
@@ -28,6 +28,7 @@ import { withFeatureConsumer, isFeatureEnabled } from '../common/feature-checkin
28
28
  import { withLogger } from '../common/logger';
29
29
  import { withRouterAndRef } from '../common/routing';
30
30
  import ActivitySidebarFilter from './ActivitySidebarFilter';
31
+ import { ViewType, FeedEntryType } from '../common/types/SidebarNavigation';
31
32
  import {
32
33
  ACTIVITY_FILTER_OPTION_ALL,
33
34
  ACTIVITY_FILTER_OPTION_RESOLVED,
@@ -76,6 +77,7 @@ import type { WithAnnotatorContextProps } from '../common/annotator-context';
76
77
  import './ActivitySidebar.scss';
77
78
 
78
79
  import type { OnAnnotationEdit, OnAnnotationStatusChange } from './activity-feed/comment/types';
80
+ import type { InternalSidebarNavigation, InternalSidebarNavigationHandler } from '../common/types/SidebarNavigation';
79
81
 
80
82
  type ExternalProps = {
81
83
  activeFeedEntryId?: string,
@@ -86,6 +88,8 @@ type ExternalProps = {
86
88
  hasReplies?: boolean,
87
89
  hasTasks?: boolean,
88
90
  hasVersions?: boolean,
91
+ internalSidebarNavigation?: InternalSidebarNavigation,
92
+ internalSidebarNavigationHandler?: InternalSidebarNavigationHandler,
89
93
  onCommentCreate: Function,
90
94
  onCommentDelete: (comment: Comment) => any,
91
95
  onCommentUpdate: () => any,
@@ -94,6 +98,7 @@ type ExternalProps = {
94
98
  onTaskDelete: (id: string) => any,
95
99
  onTaskUpdate: () => any,
96
100
  onTaskView: (id: string, isCreator: boolean) => any,
101
+ routerDisabled?: boolean,
97
102
  } & ErrorContextProps &
98
103
  WithAnnotatorContextProps;
99
104
 
@@ -547,7 +552,7 @@ class ActivitySidebar extends React.PureComponent<Props, State> {
547
552
  * @return {void}
548
553
  */
549
554
  updateReplies = (id: string, replies: Array<Comment>) => {
550
- const { activeFeedEntryId, api, file, history } = this.props;
555
+ const { activeFeedEntryId, api, file, history, internalSidebarNavigationHandler, routerDisabled } = this.props;
551
556
  const { feedItems } = this.state;
552
557
 
553
558
  if (!feedItems) {
@@ -567,7 +572,16 @@ class ActivitySidebar extends React.PureComponent<Props, State> {
567
572
  item.id === id && item === this.getCommentFeedItemByReplyId(feedItems, activeFeedEntryId),
568
573
  )
569
574
  ) {
570
- history.replace(this.getActiveCommentPath());
575
+ if (routerDisabled && internalSidebarNavigationHandler) {
576
+ internalSidebarNavigationHandler(
577
+ {
578
+ sidebar: ViewType.ACTIVITY,
579
+ },
580
+ true,
581
+ );
582
+ } else {
583
+ history.replace(this.getActiveCommentPath());
584
+ }
571
585
  }
572
586
 
573
587
  feedAPI.updateFeedItem({ replies }, id);
@@ -1108,18 +1122,36 @@ class ActivitySidebar extends React.PureComponent<Props, State> {
1108
1122
  getAnnotationsMatchPath,
1109
1123
  getAnnotationsPath,
1110
1124
  history,
1125
+ internalSidebarNavigation,
1126
+ internalSidebarNavigationHandler,
1111
1127
  location,
1112
1128
  onAnnotationSelect,
1129
+ routerDisabled,
1113
1130
  } = this.props;
1114
1131
  const annotationFileVersionId = getProp(file_version, 'id');
1115
1132
  const currentFileVersionId = getProp(file, 'file_version.id');
1116
- const match = getAnnotationsMatchPath(location);
1117
- const selectedFileVersionId = getProp(match, 'params.fileVersionId', currentFileVersionId);
1133
+
1134
+ let selectedFileVersionId = currentFileVersionId;
1135
+ if (routerDisabled && internalSidebarNavigation) {
1136
+ selectedFileVersionId = getProp(internalSidebarNavigation, 'fileVersionId', currentFileVersionId);
1137
+ } else {
1138
+ const match = getAnnotationsMatchPath(location);
1139
+ selectedFileVersionId = getProp(match, 'params.fileVersionId', currentFileVersionId);
1140
+ }
1118
1141
 
1119
1142
  emitActiveAnnotationChangeEvent(nextActiveAnnotationId);
1120
1143
 
1121
1144
  if (annotationFileVersionId && annotationFileVersionId !== selectedFileVersionId) {
1122
- history.push(getAnnotationsPath(annotationFileVersionId, nextActiveAnnotationId));
1145
+ if (routerDisabled && internalSidebarNavigationHandler) {
1146
+ internalSidebarNavigationHandler({
1147
+ sidebar: ViewType.ACTIVITY,
1148
+ activeFeedEntryId: nextActiveAnnotationId,
1149
+ activeFeedEntryType: FeedEntryType.ANNOTATIONS,
1150
+ fileVersionId: annotationFileVersionId,
1151
+ });
1152
+ } else {
1153
+ history.push(getAnnotationsPath(annotationFileVersionId, nextActiveAnnotationId));
1154
+ }
1123
1155
  }
1124
1156
 
1125
1157
  onAnnotationSelect(annotation);
@@ -1161,7 +1193,8 @@ class ActivitySidebar extends React.PureComponent<Props, State> {
1161
1193
  }
1162
1194
 
1163
1195
  renderAddTaskButton = () => {
1164
- const { isDisabled, hasTasks } = this.props;
1196
+ const { isDisabled, hasTasks, internalSidebarNavigation, internalSidebarNavigationHandler, routerDisabled } =
1197
+ this.props;
1165
1198
  const { approverSelectorContacts } = this.state;
1166
1199
  const { getApprover, getAvatarUrl, createTask, onTaskModalClose } = this;
1167
1200
 
@@ -1171,8 +1204,11 @@ class ActivitySidebar extends React.PureComponent<Props, State> {
1171
1204
 
1172
1205
  return (
1173
1206
  <AddTaskButton
1207
+ internalSidebarNavigation={internalSidebarNavigation}
1208
+ internalSidebarNavigationHandler={internalSidebarNavigationHandler}
1174
1209
  isDisabled={isDisabled}
1175
1210
  onTaskModalClose={onTaskModalClose}
1211
+ routerDisabled={routerDisabled}
1176
1212
  taskFormProps={{
1177
1213
  approvers: [],
1178
1214
  approverSelectorContacts,