box-ui-elements 23.4.0-beta.15 → 23.4.0-beta.17
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.
- package/dist/explorer.js +1 -1
- package/dist/picker.js +1 -1
- package/dist/preview.js +1 -1
- package/dist/preview.js.LICENSE.txt +10 -0
- package/dist/sharing.js +1 -1
- package/dist/sidebar.js +1 -1
- package/dist/sidebar.js.LICENSE.txt +10 -0
- package/dist/uploader.js +1 -1
- package/es/elements/common/annotator-context/types.js.flow +2 -2
- package/es/elements/common/annotator-context/types.js.map +1 -1
- package/es/elements/common/annotator-context/withAnnotations.js +29 -10
- package/es/elements/common/annotator-context/withAnnotations.js.flow +10 -3
- package/es/elements/common/annotator-context/withAnnotations.js.map +1 -1
- package/es/elements/common/annotator-context/withAnnotatorContext.js +47 -23
- package/es/elements/common/annotator-context/withAnnotatorContext.js.flow +1 -0
- package/es/elements/common/annotator-context/withAnnotatorContext.js.map +1 -1
- package/es/elements/common/nav-button/BackButton.js +5 -8
- package/es/elements/common/nav-button/BackButton.js.flow +8 -18
- package/es/elements/common/nav-button/BackButton.js.map +1 -1
- package/es/elements/common/types/SidebarNavigation.flow.js +14 -0
- package/es/elements/common/types/SidebarNavigation.flow.js.flow +52 -0
- package/es/elements/common/types/SidebarNavigation.flow.js.map +1 -0
- package/es/elements/common/types/SidebarNavigation.js +16 -0
- package/es/elements/common/types/SidebarNavigation.js.map +1 -0
- package/es/elements/content-sidebar/stories/tests/MetadataSidebarRedesign-visual.stories.js +4 -13
- package/es/elements/content-sidebar/stories/tests/MetadataSidebarRedesign-visual.stories.js.map +1 -1
- package/es/elements/content-sidebar/versions/StaticVersionSidebar.js +6 -3
- package/es/elements/content-sidebar/versions/StaticVersionSidebar.js.flow +47 -42
- package/es/elements/content-sidebar/versions/StaticVersionSidebar.js.map +1 -1
- package/es/elements/content-sidebar/versions/VersionsSidebar.js +6 -3
- package/es/elements/content-sidebar/versions/VersionsSidebar.js.flow +48 -39
- package/es/elements/content-sidebar/versions/VersionsSidebar.js.map +1 -1
- package/es/src/elements/common/annotator-context/types.d.ts +2 -2
- package/es/src/elements/common/annotator-context/withAnnotations.d.ts +5 -0
- package/es/src/elements/common/annotator-context/withAnnotatorContext.d.ts +4 -1
- package/es/src/elements/common/types/SidebarNavigation.d.ts +37 -0
- package/es/src/test-utils/testing-library.d.ts +2 -1
- package/es/test-utils/testing-library.js +4 -1
- package/es/test-utils/testing-library.js.map +1 -1
- package/package.json +35 -37
- package/src/elements/common/annotator-context/__tests__/withAnnotations.test.tsx +46 -0
- package/src/elements/common/annotator-context/__tests__/withAnnotatorContext.test.tsx +116 -20
- package/src/elements/common/annotator-context/types.js.flow +2 -2
- package/src/elements/common/annotator-context/types.ts +2 -2
- package/src/elements/common/annotator-context/withAnnotations.js.flow +10 -3
- package/src/elements/common/annotator-context/withAnnotations.tsx +35 -6
- package/src/elements/common/annotator-context/withAnnotatorContext.js.flow +1 -0
- package/src/elements/common/annotator-context/withAnnotatorContext.tsx +61 -29
- package/src/elements/common/nav-button/BackButton.js +8 -18
- package/src/elements/common/nav-button/__tests__/BackButton.test.js +36 -27
- package/src/elements/common/types/SidebarNavigation.flow.js +52 -0
- package/src/elements/common/types/SidebarNavigation.ts +47 -0
- package/src/elements/content-sidebar/stories/tests/MetadataSidebarRedesign-visual.stories.tsx +5 -13
- package/src/elements/content-sidebar/versions/StaticVersionSidebar.js +47 -42
- package/src/elements/content-sidebar/versions/VersionsSidebar.js +48 -39
- package/src/elements/content-sidebar/versions/__tests__/StaticVersionSidebar.test.js +171 -0
- package/src/elements/content-sidebar/versions/__tests__/VersionsSidebar.test.js +147 -20
- package/src/test-utils/testing-library.tsx +4 -1
- package/i18n.config.js +0 -9
- package/src/elements/common/nav-button/__tests__/__snapshots__/BackButton.test.js.snap +0 -64
- package/src/elements/content-sidebar/versions/__tests__/__snapshots__/VersionsSidebar.test.js.snap +0 -92
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { render } from '../../../../test-utils/testing-library';
|
|
3
3
|
import withAnnotatorContext, { WithAnnotatorContextProps } from '../withAnnotatorContext';
|
|
4
4
|
import { Action } from '../types';
|
|
5
5
|
|
|
@@ -13,18 +13,59 @@ describe('elements/common/annotator-context/withAnnotatorContext', () => {
|
|
|
13
13
|
className?: string | undefined;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
type WrappedComponentProps<T> = ComponentProps & WithAnnotatorContextProps; // T is supposed to be allowed component props
|
|
16
|
+
type WrappedComponentProps = ComponentProps & WithAnnotatorContextProps;
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
beforeEach(() => jest.resetAllMocks());
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
test('should apply the annotator context to the wrapped component as a prop', () => {
|
|
21
|
+
const annotatorState = {
|
|
22
|
+
annotation: { foo: 'bar' },
|
|
23
|
+
action: Action.CREATE_START,
|
|
24
|
+
};
|
|
25
|
+
const mockEmitActiveAnnotationChangeEvent = jest.fn();
|
|
26
|
+
const mockEmitAnnotationRemoveEvent = jest.fn();
|
|
27
|
+
const mockEmitAnnotationReplyCreateEvent = jest.fn();
|
|
28
|
+
const mockEmitAnnotationReplyDeleteEvent = jest.fn();
|
|
29
|
+
const mockMmitAnnotationReplyUpdateEvent = jest.fn();
|
|
30
|
+
const mockEmitAnnotationUpdateEvent = jest.fn();
|
|
31
|
+
const mockGetAnnotationsMatchPath = jest.fn();
|
|
32
|
+
const mockGetAnnotationsPath = jest.fn();
|
|
22
33
|
|
|
23
|
-
|
|
34
|
+
mockContext.mockReturnValue({
|
|
35
|
+
state: annotatorState,
|
|
36
|
+
emitActiveAnnotationChangeEvent: mockEmitActiveAnnotationChangeEvent,
|
|
37
|
+
emitAnnotationRemoveEvent: mockEmitAnnotationRemoveEvent,
|
|
38
|
+
emitAnnotationReplyCreateEvent: mockEmitAnnotationReplyCreateEvent,
|
|
39
|
+
emitAnnotationReplyDeleteEvent: mockEmitAnnotationReplyDeleteEvent,
|
|
40
|
+
emitAnnotationReplyUpdateEvent: mockMmitAnnotationReplyUpdateEvent,
|
|
41
|
+
emitAnnotationUpdateEvent: mockEmitAnnotationUpdateEvent,
|
|
42
|
+
getAnnotationsMatchPath: mockGetAnnotationsMatchPath,
|
|
43
|
+
getAnnotationsPath: mockGetAnnotationsPath,
|
|
44
|
+
});
|
|
24
45
|
|
|
25
|
-
|
|
46
|
+
const MockComponent = jest.fn<JSX.Element | null, [WrappedComponentProps]>(() => null);
|
|
47
|
+
const WrappedWithMockComponent = withAnnotatorContext(MockComponent);
|
|
26
48
|
|
|
27
|
-
|
|
49
|
+
render(<WrappedWithMockComponent />);
|
|
50
|
+
|
|
51
|
+
expect(MockComponent).toHaveBeenCalledTimes(1);
|
|
52
|
+
const props = MockComponent.mock.calls[0][0];
|
|
53
|
+
|
|
54
|
+
expect(props.annotatorState).toEqual({
|
|
55
|
+
annotation: { foo: 'bar' },
|
|
56
|
+
action: Action.CREATE_START,
|
|
57
|
+
});
|
|
58
|
+
expect(props.emitActiveAnnotationChangeEvent).toBe(mockEmitActiveAnnotationChangeEvent);
|
|
59
|
+
expect(props.emitAnnotationRemoveEvent).toBe(mockEmitAnnotationRemoveEvent);
|
|
60
|
+
expect(props.emitAnnotationReplyCreateEvent).toBe(mockEmitAnnotationReplyCreateEvent);
|
|
61
|
+
expect(props.emitAnnotationReplyDeleteEvent).toBe(mockEmitAnnotationReplyDeleteEvent);
|
|
62
|
+
expect(props.emitAnnotationReplyUpdateEvent).toBe(mockMmitAnnotationReplyUpdateEvent);
|
|
63
|
+
expect(props.emitAnnotationUpdateEvent).toBe(mockEmitAnnotationUpdateEvent);
|
|
64
|
+
expect(props.getAnnotationsMatchPath).toBe(mockGetAnnotationsMatchPath);
|
|
65
|
+
expect(props.getAnnotationsPath).toBe(mockGetAnnotationsPath);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('should apply the annotator context to the wrapped component without router props when routerDisabled is true', () => {
|
|
28
69
|
const annotatorState = {
|
|
29
70
|
annotation: { foo: 'bar' },
|
|
30
71
|
action: Action.CREATE_START,
|
|
@@ -50,22 +91,77 @@ describe('elements/common/annotator-context/withAnnotatorContext', () => {
|
|
|
50
91
|
getAnnotationsPath: mockGetAnnotationsPath,
|
|
51
92
|
});
|
|
52
93
|
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
|
|
94
|
+
const MockComponent = jest.fn<JSX.Element | null, [WrappedComponentProps]>(() => null);
|
|
95
|
+
const WrappedWithMockComponent = withAnnotatorContext(MockComponent);
|
|
96
|
+
|
|
97
|
+
render(<WrappedWithMockComponent routerDisabled={true} />);
|
|
98
|
+
|
|
99
|
+
expect(MockComponent).toHaveBeenCalledTimes(1);
|
|
100
|
+
const props = MockComponent.mock.calls[0][0];
|
|
56
101
|
|
|
57
|
-
expect(wrappedComponent.exists()).toBeTruthy();
|
|
58
102
|
expect(props.annotatorState).toEqual({
|
|
59
103
|
annotation: { foo: 'bar' },
|
|
60
104
|
action: Action.CREATE_START,
|
|
61
105
|
});
|
|
62
|
-
expect(props.emitActiveAnnotationChangeEvent).
|
|
63
|
-
expect(props.emitAnnotationRemoveEvent).
|
|
64
|
-
expect(props.emitAnnotationReplyCreateEvent).
|
|
65
|
-
expect(props.emitAnnotationReplyDeleteEvent).
|
|
66
|
-
expect(props.emitAnnotationReplyUpdateEvent).
|
|
67
|
-
expect(props.emitAnnotationUpdateEvent).
|
|
68
|
-
|
|
69
|
-
|
|
106
|
+
expect(props.emitActiveAnnotationChangeEvent).toBe(mockEmitActiveAnnotationChangeEvent);
|
|
107
|
+
expect(props.emitAnnotationRemoveEvent).toBe(mockEmitAnnotationRemoveEvent);
|
|
108
|
+
expect(props.emitAnnotationReplyCreateEvent).toBe(mockEmitAnnotationReplyCreateEvent);
|
|
109
|
+
expect(props.emitAnnotationReplyDeleteEvent).toBe(mockEmitAnnotationReplyDeleteEvent);
|
|
110
|
+
expect(props.emitAnnotationReplyUpdateEvent).toBe(mockMmitAnnotationReplyUpdateEvent);
|
|
111
|
+
expect(props.emitAnnotationUpdateEvent).toBe(mockEmitAnnotationUpdateEvent);
|
|
112
|
+
|
|
113
|
+
// Router-related props should not be passed when routerDisabled is true
|
|
114
|
+
expect(props.getAnnotationsMatchPath).toBeUndefined();
|
|
115
|
+
expect(props.getAnnotationsPath).toBeUndefined();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('should apply the annotator context to the wrapped component without router props when routerDisabled in feature flags is true', () => {
|
|
119
|
+
const annotatorState = {
|
|
120
|
+
annotation: { foo: 'bar' },
|
|
121
|
+
action: Action.CREATE_START,
|
|
122
|
+
};
|
|
123
|
+
const mockEmitActiveAnnotationChangeEvent = jest.fn();
|
|
124
|
+
const mockEmitAnnotationRemoveEvent = jest.fn();
|
|
125
|
+
const mockEmitAnnotationReplyCreateEvent = jest.fn();
|
|
126
|
+
const mockEmitAnnotationReplyDeleteEvent = jest.fn();
|
|
127
|
+
const mockMmitAnnotationReplyUpdateEvent = jest.fn();
|
|
128
|
+
const mockEmitAnnotationUpdateEvent = jest.fn();
|
|
129
|
+
const mockGetAnnotationsMatchPath = jest.fn();
|
|
130
|
+
const mockGetAnnotationsPath = jest.fn();
|
|
131
|
+
|
|
132
|
+
mockContext.mockReturnValue({
|
|
133
|
+
state: annotatorState,
|
|
134
|
+
emitActiveAnnotationChangeEvent: mockEmitActiveAnnotationChangeEvent,
|
|
135
|
+
emitAnnotationRemoveEvent: mockEmitAnnotationRemoveEvent,
|
|
136
|
+
emitAnnotationReplyCreateEvent: mockEmitAnnotationReplyCreateEvent,
|
|
137
|
+
emitAnnotationReplyDeleteEvent: mockEmitAnnotationReplyDeleteEvent,
|
|
138
|
+
emitAnnotationReplyUpdateEvent: mockMmitAnnotationReplyUpdateEvent,
|
|
139
|
+
emitAnnotationUpdateEvent: mockEmitAnnotationUpdateEvent,
|
|
140
|
+
getAnnotationsMatchPath: mockGetAnnotationsMatchPath,
|
|
141
|
+
getAnnotationsPath: mockGetAnnotationsPath,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const MockComponent = jest.fn<JSX.Element | null, [WrappedComponentProps]>(() => null);
|
|
145
|
+
const WrappedWithMockComponent = withAnnotatorContext(MockComponent);
|
|
146
|
+
|
|
147
|
+
render(<WrappedWithMockComponent features={{ routerDisabled: { value: true } }} />);
|
|
148
|
+
|
|
149
|
+
expect(MockComponent).toHaveBeenCalledTimes(1);
|
|
150
|
+
const props = MockComponent.mock.calls[0][0];
|
|
151
|
+
|
|
152
|
+
expect(props.annotatorState).toEqual({
|
|
153
|
+
annotation: { foo: 'bar' },
|
|
154
|
+
action: Action.CREATE_START,
|
|
155
|
+
});
|
|
156
|
+
expect(props.emitActiveAnnotationChangeEvent).toBe(mockEmitActiveAnnotationChangeEvent);
|
|
157
|
+
expect(props.emitAnnotationRemoveEvent).toBe(mockEmitAnnotationRemoveEvent);
|
|
158
|
+
expect(props.emitAnnotationReplyCreateEvent).toBe(mockEmitAnnotationReplyCreateEvent);
|
|
159
|
+
expect(props.emitAnnotationReplyDeleteEvent).toBe(mockEmitAnnotationReplyDeleteEvent);
|
|
160
|
+
expect(props.emitAnnotationReplyUpdateEvent).toBe(mockMmitAnnotationReplyUpdateEvent);
|
|
161
|
+
expect(props.emitAnnotationUpdateEvent).toBe(mockEmitAnnotationUpdateEvent);
|
|
162
|
+
|
|
163
|
+
// Router-related props should not be passed when routerDisabled is true
|
|
164
|
+
expect(props.getAnnotationsMatchPath).toBeUndefined();
|
|
165
|
+
expect(props.getAnnotationsPath).toBeUndefined();
|
|
70
166
|
});
|
|
71
167
|
});
|
|
@@ -74,8 +74,8 @@ export interface AnnotatorContext {
|
|
|
74
74
|
annotation: Object,
|
|
75
75
|
isStartEvent?: boolean
|
|
76
76
|
) => void;
|
|
77
|
-
getAnnotationsMatchPath
|
|
78
|
-
getAnnotationsPath
|
|
77
|
+
getAnnotationsMatchPath?: GetMatchPath;
|
|
78
|
+
getAnnotationsPath?: (fileVersionId?: string, annotationId?: string) => string;
|
|
79
79
|
state: AnnotatorState;
|
|
80
80
|
}
|
|
81
81
|
declare export var Status: {|
|
|
@@ -53,8 +53,8 @@ export interface AnnotatorContext {
|
|
|
53
53
|
emitAnnotationReplyDeleteEvent?: (id: string, annotationId: string, isStartEvent?: boolean) => void;
|
|
54
54
|
emitAnnotationReplyUpdateEvent?: (reply: Object, annotationId: string, isStartEvent?: boolean) => void;
|
|
55
55
|
emitAnnotationUpdateEvent?: (annotation: Object, isStartEvent?: boolean) => void;
|
|
56
|
-
getAnnotationsMatchPath
|
|
57
|
-
getAnnotationsPath
|
|
56
|
+
getAnnotationsMatchPath?: GetMatchPath;
|
|
57
|
+
getAnnotationsPath?: (fileVersionId?: string, annotationId?: string) => string;
|
|
58
58
|
state: AnnotatorState;
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -18,6 +18,10 @@ import {
|
|
|
18
18
|
MatchParams,
|
|
19
19
|
Status
|
|
20
20
|
} from "./types";
|
|
21
|
+
import { SidebarNavigation } from '../types/SidebarNavigation';
|
|
22
|
+
import { type FeatureConfig } from '../feature-checking';
|
|
23
|
+
|
|
24
|
+
|
|
21
25
|
export type ActiveChangeEvent = {
|
|
22
26
|
annotationId: string | null,
|
|
23
27
|
fileVersionId: string,
|
|
@@ -48,11 +52,11 @@ export type ComponentWithAnnotations = {
|
|
|
48
52
|
isStartEvent?: boolean
|
|
49
53
|
) => void,
|
|
50
54
|
getAction: (eventData: AnnotationActionEvent) => Action,
|
|
51
|
-
getAnnotationsPath
|
|
55
|
+
getAnnotationsPath?: (
|
|
52
56
|
fileVersionId?: string,
|
|
53
57
|
annotationId?: string | null
|
|
54
58
|
) => string,
|
|
55
|
-
getMatchPath
|
|
59
|
+
getMatchPath?: GetMatchPath,
|
|
56
60
|
handleActiveChange: ActiveChangeEventHandler,
|
|
57
61
|
handleAnnotationChangeEvent: (id: string | null) => void,
|
|
58
62
|
handleAnnotationCreate: (eventData: AnnotationActionEvent) => void,
|
|
@@ -70,6 +74,7 @@ export type ComponentWithAnnotations = {
|
|
|
70
74
|
...
|
|
71
75
|
};
|
|
72
76
|
export type WithAnnotationsProps = {
|
|
77
|
+
features?: FeatureConfig;
|
|
73
78
|
location?: Location,
|
|
74
79
|
onAnnotator: (annotator: Annotator) => void,
|
|
75
80
|
onError?: (
|
|
@@ -78,7 +83,9 @@ export type WithAnnotationsProps = {
|
|
|
78
83
|
contextInfo?: { [key: string]: mixed, ... }
|
|
79
84
|
) => void,
|
|
80
85
|
onPreviewDestroy: (shouldReset?: boolean) => void,
|
|
81
|
-
|
|
86
|
+
routerDisabled?: boolean;
|
|
87
|
+
sidebarNavigation?: SidebarNavigation;
|
|
88
|
+
...
|
|
82
89
|
};
|
|
83
90
|
export type WithAnnotationsComponent<P> = React.ComponentClass<
|
|
84
91
|
P & WithAnnotationsProps
|
|
@@ -3,7 +3,9 @@ import getProp from 'lodash/get';
|
|
|
3
3
|
import { generatePath, match as matchType, matchPath } from 'react-router-dom';
|
|
4
4
|
import { Location } from 'history';
|
|
5
5
|
import AnnotatorContext from './AnnotatorContext';
|
|
6
|
+
import { isFeatureEnabled, type FeatureConfig } from '../feature-checking';
|
|
6
7
|
import { Action, Annotator, AnnotationActionEvent, AnnotatorState, GetMatchPath, MatchParams, Status } from './types';
|
|
8
|
+
import { FeedEntryType, SidebarNavigation } from '../types/SidebarNavigation';
|
|
7
9
|
|
|
8
10
|
export type ActiveChangeEvent = {
|
|
9
11
|
annotationId: string | null;
|
|
@@ -41,10 +43,13 @@ export type ComponentWithAnnotations = {
|
|
|
41
43
|
};
|
|
42
44
|
|
|
43
45
|
export type WithAnnotationsProps = {
|
|
46
|
+
features?: FeatureConfig;
|
|
44
47
|
location?: Location;
|
|
45
48
|
onAnnotator: (annotator: Annotator) => void;
|
|
46
49
|
onError?: (error: Error, code: string, contextInfo?: Record<string, unknown>) => void;
|
|
47
50
|
onPreviewDestroy: (shouldReset?: boolean) => void;
|
|
51
|
+
routerDisabled?: boolean;
|
|
52
|
+
sidebarNavigation?: SidebarNavigation;
|
|
48
53
|
};
|
|
49
54
|
|
|
50
55
|
export type WithAnnotationsComponent<P> = React.ComponentClass<P & WithAnnotationsProps>;
|
|
@@ -71,10 +76,26 @@ export default function withAnnotations<P extends object>(
|
|
|
71
76
|
constructor(props: P & WithAnnotationsProps) {
|
|
72
77
|
super(props);
|
|
73
78
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const
|
|
79
|
+
const { routerDisabled, sidebarNavigation } = props;
|
|
80
|
+
let activeAnnotationId = null;
|
|
81
|
+
|
|
82
|
+
const isRouterDisabled = routerDisabled || isFeatureEnabled(props?.features, 'routerDisabled.value');
|
|
83
|
+
|
|
84
|
+
if (isRouterDisabled) {
|
|
85
|
+
if (
|
|
86
|
+
sidebarNavigation &&
|
|
87
|
+
'activeFeedEntryType' in sidebarNavigation &&
|
|
88
|
+
sidebarNavigation.activeFeedEntryType === FeedEntryType.ANNOTATIONS &&
|
|
89
|
+
'activeFeedEntryId' in sidebarNavigation
|
|
90
|
+
) {
|
|
91
|
+
activeAnnotationId = sidebarNavigation.activeFeedEntryId;
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
// Determine by url if there is already a deeply linked annotation
|
|
95
|
+
const { location } = props;
|
|
96
|
+
const match = this.getMatchPath(location);
|
|
97
|
+
activeAnnotationId = getProp(match, 'params.annotationId', null);
|
|
98
|
+
}
|
|
78
99
|
|
|
79
100
|
// Seed the initial state with the activeAnnotationId if any from the location path
|
|
80
101
|
this.state = { ...defaultState, activeAnnotationId };
|
|
@@ -192,6 +213,7 @@ export default function withAnnotations<P extends object>(
|
|
|
192
213
|
});
|
|
193
214
|
}
|
|
194
215
|
|
|
216
|
+
// remove this method with routerDisabled switch
|
|
195
217
|
getMatchPath(location?: Location): matchType<MatchParams> | null {
|
|
196
218
|
const pathname = getProp(location, 'pathname', '');
|
|
197
219
|
return matchPath<MatchParams>(pathname, {
|
|
@@ -319,6 +341,14 @@ export default function withAnnotations<P extends object>(
|
|
|
319
341
|
};
|
|
320
342
|
|
|
321
343
|
render(): JSX.Element {
|
|
344
|
+
const isRouterDisabled =
|
|
345
|
+
this.props?.routerDisabled || isFeatureEnabled(this.props?.features, 'routerDisabled.value');
|
|
346
|
+
const annotationsRouterProps = isRouterDisabled
|
|
347
|
+
? {}
|
|
348
|
+
: {
|
|
349
|
+
getAnnotationsMatchPath: this.getMatchPath,
|
|
350
|
+
getAnnotationsPath: this.getAnnotationsPath,
|
|
351
|
+
};
|
|
322
352
|
return (
|
|
323
353
|
<AnnotatorContext.Provider
|
|
324
354
|
value={{
|
|
@@ -328,8 +358,7 @@ export default function withAnnotations<P extends object>(
|
|
|
328
358
|
emitAnnotationReplyDeleteEvent: this.emitAnnotationReplyDeleteEvent,
|
|
329
359
|
emitAnnotationReplyUpdateEvent: this.emitAnnotationReplyUpdateEvent,
|
|
330
360
|
emitAnnotationUpdateEvent: this.emitAnnotationUpdateEvent,
|
|
331
|
-
|
|
332
|
-
getAnnotationsPath: this.getAnnotationsPath,
|
|
361
|
+
...annotationsRouterProps,
|
|
333
362
|
state: this.state,
|
|
334
363
|
}}
|
|
335
364
|
>
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import * as React from "react";
|
|
8
8
|
import AnnotatorContext from "./AnnotatorContext";
|
|
9
9
|
import { AnnotatorState, GetMatchPath } from "./types";
|
|
10
|
+
|
|
10
11
|
export interface WithAnnotatorContextProps {
|
|
11
12
|
annotatorState?: AnnotatorState;
|
|
12
13
|
emitActiveAnnotationChangeEvent?: (id: string) => void;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import AnnotatorContext from './AnnotatorContext';
|
|
3
|
+
import { isFeatureEnabled, type FeatureConfig } from '../feature-checking';
|
|
3
4
|
import { AnnotatorState, GetMatchPath } from './types';
|
|
4
5
|
|
|
5
6
|
export interface WithAnnotatorContextProps {
|
|
@@ -20,33 +21,64 @@ export interface WithAnnotatorContextProps {
|
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
export default function withAnnotatorContext<P extends {}>(WrappedComponent: React.ComponentType<P>) {
|
|
23
|
-
return React.forwardRef<React.ComponentType<P>, P
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
24
|
+
return React.forwardRef<React.ComponentType<P>, P & { routerDisabled?: boolean; features?: FeatureConfig }>(
|
|
25
|
+
(props, ref) => {
|
|
26
|
+
if (props?.routerDisabled === true || isFeatureEnabled(props?.features, 'routerDisabled.value')) {
|
|
27
|
+
return (
|
|
28
|
+
<AnnotatorContext.Consumer>
|
|
29
|
+
{({
|
|
30
|
+
emitActiveAnnotationChangeEvent,
|
|
31
|
+
emitAnnotationRemoveEvent,
|
|
32
|
+
emitAnnotationReplyCreateEvent,
|
|
33
|
+
emitAnnotationReplyDeleteEvent,
|
|
34
|
+
emitAnnotationReplyUpdateEvent,
|
|
35
|
+
emitAnnotationUpdateEvent,
|
|
36
|
+
state,
|
|
37
|
+
}) => (
|
|
38
|
+
<WrappedComponent
|
|
39
|
+
ref={ref}
|
|
40
|
+
{...props}
|
|
41
|
+
annotatorState={state}
|
|
42
|
+
emitActiveAnnotationChangeEvent={emitActiveAnnotationChangeEvent}
|
|
43
|
+
emitAnnotationRemoveEvent={emitAnnotationRemoveEvent}
|
|
44
|
+
emitAnnotationReplyCreateEvent={emitAnnotationReplyCreateEvent}
|
|
45
|
+
emitAnnotationReplyDeleteEvent={emitAnnotationReplyDeleteEvent}
|
|
46
|
+
emitAnnotationReplyUpdateEvent={emitAnnotationReplyUpdateEvent}
|
|
47
|
+
emitAnnotationUpdateEvent={emitAnnotationUpdateEvent}
|
|
48
|
+
/>
|
|
49
|
+
)}
|
|
50
|
+
</AnnotatorContext.Consumer>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
return (
|
|
54
|
+
<AnnotatorContext.Consumer>
|
|
55
|
+
{({
|
|
56
|
+
emitActiveAnnotationChangeEvent,
|
|
57
|
+
emitAnnotationRemoveEvent,
|
|
58
|
+
emitAnnotationReplyCreateEvent,
|
|
59
|
+
emitAnnotationReplyDeleteEvent,
|
|
60
|
+
emitAnnotationReplyUpdateEvent,
|
|
61
|
+
emitAnnotationUpdateEvent,
|
|
62
|
+
getAnnotationsMatchPath,
|
|
63
|
+
getAnnotationsPath,
|
|
64
|
+
state,
|
|
65
|
+
}) => (
|
|
66
|
+
<WrappedComponent
|
|
67
|
+
ref={ref}
|
|
68
|
+
{...props}
|
|
69
|
+
annotatorState={state}
|
|
70
|
+
emitActiveAnnotationChangeEvent={emitActiveAnnotationChangeEvent}
|
|
71
|
+
emitAnnotationRemoveEvent={emitAnnotationRemoveEvent}
|
|
72
|
+
emitAnnotationReplyCreateEvent={emitAnnotationReplyCreateEvent}
|
|
73
|
+
emitAnnotationReplyDeleteEvent={emitAnnotationReplyDeleteEvent}
|
|
74
|
+
emitAnnotationReplyUpdateEvent={emitAnnotationReplyUpdateEvent}
|
|
75
|
+
emitAnnotationUpdateEvent={emitAnnotationUpdateEvent}
|
|
76
|
+
getAnnotationsMatchPath={getAnnotationsMatchPath}
|
|
77
|
+
getAnnotationsPath={getAnnotationsPath}
|
|
78
|
+
/>
|
|
79
|
+
)}
|
|
80
|
+
</AnnotatorContext.Consumer>
|
|
81
|
+
);
|
|
82
|
+
},
|
|
83
|
+
);
|
|
52
84
|
}
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
import * as React from 'react';
|
|
8
8
|
import classNames from 'classnames';
|
|
9
9
|
import { FormattedMessage } from 'react-intl';
|
|
10
|
-
import { Route, type Location } from 'react-router-dom';
|
|
11
10
|
import IconNavigateLeft from '../../../icons/general/IconNavigateLeft';
|
|
12
11
|
import messages from '../messages';
|
|
13
12
|
import PlainButton from '../../../components/plain-button';
|
|
@@ -15,25 +14,16 @@ import './BackButton.scss';
|
|
|
15
14
|
|
|
16
15
|
type Props = {
|
|
17
16
|
className?: string,
|
|
18
|
-
|
|
17
|
+
onClick: () => void,
|
|
19
18
|
};
|
|
20
19
|
|
|
21
|
-
const BackButton = ({ className,
|
|
22
|
-
<
|
|
23
|
-
{
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
{...rest}
|
|
29
|
-
>
|
|
30
|
-
<IconNavigateLeft height={24} width={24} />
|
|
31
|
-
<span className="accessibility-hidden">
|
|
32
|
-
<FormattedMessage {...messages.back} />
|
|
33
|
-
</span>
|
|
34
|
-
</PlainButton>
|
|
35
|
-
)}
|
|
36
|
-
</Route>
|
|
20
|
+
const BackButton = ({ className, onClick, ...rest }: Props) => (
|
|
21
|
+
<PlainButton className={classNames('bdl-BackButton', className)} onClick={onClick} type="button" {...rest}>
|
|
22
|
+
<IconNavigateLeft height={24} width={24} />
|
|
23
|
+
<span className="accessibility-hidden">
|
|
24
|
+
<FormattedMessage {...messages.back} />
|
|
25
|
+
</span>
|
|
26
|
+
</PlainButton>
|
|
37
27
|
);
|
|
38
28
|
|
|
39
29
|
export default BackButton;
|
|
@@ -1,43 +1,52 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { mount } from 'enzyme';
|
|
2
|
+
import { render, screen, userEvent } from '../../../../test-utils/testing-library';
|
|
4
3
|
import { BackButton } from '..';
|
|
5
4
|
|
|
6
5
|
describe('elements/common/nav-button/BackButton', () => {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
</MemoryRouter>,
|
|
12
|
-
);
|
|
13
|
-
const getHistory = wrapper => wrapper.find(Router).prop('history');
|
|
14
|
-
|
|
15
|
-
test('should match its snapshot', () => {
|
|
16
|
-
const wrapper = getWrapper();
|
|
17
|
-
const button = wrapper.find(BackButton).first();
|
|
18
|
-
|
|
19
|
-
expect(button).toMatchSnapshot();
|
|
6
|
+
const mockOnClick = jest.fn();
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
mockOnClick.mockClear();
|
|
20
10
|
});
|
|
21
11
|
|
|
22
|
-
test('should
|
|
23
|
-
|
|
24
|
-
const history = getHistory(wrapper);
|
|
12
|
+
test('should render back button with navigation icon and accessible text', () => {
|
|
13
|
+
render(<BackButton onClick={mockOnClick} />);
|
|
25
14
|
|
|
26
|
-
|
|
15
|
+
const button = screen.getByRole('button');
|
|
16
|
+
expect(button).toBeInTheDocument();
|
|
17
|
+
expect(button).toHaveClass('bdl-BackButton');
|
|
27
18
|
|
|
28
|
-
|
|
19
|
+
expect(screen.getByText('Back')).toBeInTheDocument();
|
|
29
20
|
|
|
30
|
-
|
|
21
|
+
const icon = button.querySelector('svg');
|
|
22
|
+
expect(icon).toBeInTheDocument();
|
|
23
|
+
expect(icon).toHaveClass('icon-navigate-left');
|
|
31
24
|
});
|
|
32
25
|
|
|
33
|
-
test('should call
|
|
34
|
-
const
|
|
35
|
-
|
|
26
|
+
test('should call onClick handler when clicked', async () => {
|
|
27
|
+
const user = userEvent();
|
|
28
|
+
|
|
29
|
+
render(<BackButton onClick={mockOnClick} />);
|
|
36
30
|
|
|
37
|
-
|
|
31
|
+
const button = screen.getByRole('button');
|
|
32
|
+
await user.click(button);
|
|
33
|
+
|
|
34
|
+
expect(mockOnClick).toHaveBeenCalledTimes(1);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('should pass through additional props', () => {
|
|
38
|
+
render(<BackButton onClick={mockOnClick} data-testid="test-back-button" data-resin-target="back" />);
|
|
39
|
+
|
|
40
|
+
const button = screen.getByTestId('test-back-button');
|
|
41
|
+
expect(button).toBeInTheDocument();
|
|
42
|
+
expect(button).toHaveAttribute('data-resin-target', 'back');
|
|
43
|
+
});
|
|
38
44
|
|
|
39
|
-
|
|
45
|
+
test('should apply custom className alongside default class', () => {
|
|
46
|
+
render(<BackButton onClick={mockOnClick} className="custom-class" />);
|
|
40
47
|
|
|
41
|
-
|
|
48
|
+
const button = screen.getByRole('button');
|
|
49
|
+
expect(button).toHaveClass('bdl-BackButton');
|
|
50
|
+
expect(button).toHaveClass('custom-class');
|
|
42
51
|
});
|
|
43
52
|
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/* @flow */
|
|
2
|
+
|
|
3
|
+
export const ViewType = Object.freeze({
|
|
4
|
+
BOXAI: 'boxai',
|
|
5
|
+
SKILLS: 'skills',
|
|
6
|
+
ACTIVITY: 'activity',
|
|
7
|
+
DETAILS: 'details',
|
|
8
|
+
METADATA: 'metadata',
|
|
9
|
+
DOCGEN: 'docgen',
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export const FeedEntryType = Object.freeze({
|
|
13
|
+
ANNOTATIONS: 'annotations',
|
|
14
|
+
COMMENTS: 'comments',
|
|
15
|
+
TASKS: 'tasks',
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export type ViewTypeValues = $Values<typeof ViewType>;
|
|
19
|
+
export type FeedEntryTypeValues = $Values<typeof FeedEntryType>;
|
|
20
|
+
|
|
21
|
+
type VersionSidebarView = {
|
|
22
|
+
sidebar: 'activity' | 'details',
|
|
23
|
+
versionId: string,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type ActivityAnnotationsSidebarView = {
|
|
27
|
+
sidebar: 'activity',
|
|
28
|
+
activeFeedEntryType: 'annotations',
|
|
29
|
+
fileVersionId: string,
|
|
30
|
+
activeFeedEntryId: string,
|
|
31
|
+
};
|
|
32
|
+
type ActivityCommentsSidebarView = {
|
|
33
|
+
sidebar: 'activity',
|
|
34
|
+
activeFeedEntryType: 'comments' | 'tasks',
|
|
35
|
+
activeFeedEntryId: string,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type SidebarNavigation =
|
|
39
|
+
| {|
|
|
40
|
+
sidebar: ViewTypeValues,
|
|
41
|
+
|}
|
|
42
|
+
| VersionSidebarView
|
|
43
|
+
| ActivityCommentsSidebarView
|
|
44
|
+
| ActivityAnnotationsSidebarView;
|
|
45
|
+
|
|
46
|
+
export type InternalSidebarNavigation = SidebarNavigation & {
|
|
47
|
+
open: boolean,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export type SidebarNavigationHandler = (sidebar: SidebarNavigation, replace?: boolean) => void;
|
|
51
|
+
|
|
52
|
+
export type InternalSidebarNavigationHandler = (sidebar: InternalSidebarNavigation, replace?: boolean) => void;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export enum ViewType {
|
|
2
|
+
BOXAI = 'boxai',
|
|
3
|
+
SKILLS = 'skills',
|
|
4
|
+
ACTIVITY = 'activity',
|
|
5
|
+
DETAILS = 'details',
|
|
6
|
+
METADATA = 'metadata',
|
|
7
|
+
DOCGEN = 'docgen',
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export enum FeedEntryType {
|
|
11
|
+
ANNOTATIONS = 'annotations',
|
|
12
|
+
COMMENTS = 'comments',
|
|
13
|
+
TASKS = 'tasks',
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type VersionSidebarView = {
|
|
17
|
+
sidebar: ViewType.ACTIVITY | ViewType.DETAILS;
|
|
18
|
+
versionId: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type ActivityAnnotationsSidebarView = {
|
|
22
|
+
sidebar: ViewType.ACTIVITY;
|
|
23
|
+
activeFeedEntryType: FeedEntryType.ANNOTATIONS;
|
|
24
|
+
fileVersionId: string;
|
|
25
|
+
activeFeedEntryId: string;
|
|
26
|
+
};
|
|
27
|
+
type ActivityCommentsSidebarView = {
|
|
28
|
+
sidebar: ViewType.ACTIVITY;
|
|
29
|
+
activeFeedEntryType: FeedEntryType.COMMENTS | FeedEntryType.TASKS;
|
|
30
|
+
activeFeedEntryId: string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type SidebarNavigation =
|
|
34
|
+
| {
|
|
35
|
+
sidebar: ViewType;
|
|
36
|
+
}
|
|
37
|
+
| VersionSidebarView
|
|
38
|
+
| ActivityCommentsSidebarView
|
|
39
|
+
| ActivityAnnotationsSidebarView;
|
|
40
|
+
|
|
41
|
+
export type InternalSidebarNavigation = SidebarNavigation & {
|
|
42
|
+
open: boolean;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type SidebarNavigationHandler = (sidebar: SidebarNavigation, replace?: boolean) => void;
|
|
46
|
+
|
|
47
|
+
export type InternalSidebarNavigationHandler = (sidebar: InternalSidebarNavigation, replace?: boolean) => void;
|