Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
coopwire-hypothesis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
孙灵跃 Leon Sun
coopwire-hypothesis
Commits
bcd4f9b5
Commit
bcd4f9b5
authored
Jul 20, 2020
by
Lyza Danger Gardner
Committed by
Lyza Gardner
Jul 23, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add `useRootThread` hook
Refactor root-thread usage by UI components to be via a preact hook
parent
e76b5470
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
50 additions
and
61 deletions
+50
-61
annotation-viewer-content.js
src/sidebar/components/annotation-viewer-content.js
+4
-13
use-root-thread.js
src/sidebar/components/hooks/use-root-thread.js
+17
-0
search-status-bar.js
src/sidebar/components/search-status-bar.js
+6
-11
sidebar-content.js
src/sidebar/components/sidebar-content.js
+2
-6
stream-content.js
src/sidebar/components/stream-content.js
+4
-6
annotation-viewer-content-test.js
...sidebar/components/test/annotation-viewer-content-test.js
+3
-3
search-status-bar-test.js
src/sidebar/components/test/search-status-bar-test.js
+7
-8
sidebar-content-test.js
src/sidebar/components/test/sidebar-content-test.js
+3
-5
stream-content-test.js
src/sidebar/components/test/stream-content-test.js
+4
-9
No files found.
src/sidebar/components/annotation-viewer-content.js
View file @
bcd4f9b5
...
@@ -4,6 +4,7 @@ import propTypes from 'prop-types';
...
@@ -4,6 +4,7 @@ import propTypes from 'prop-types';
import
useStore
from
'../store/use-store'
;
import
useStore
from
'../store/use-store'
;
import
{
withServices
}
from
'../util/service-context'
;
import
{
withServices
}
from
'../util/service-context'
;
import
useRootThread
from
'./hooks/use-root-thread'
;
import
ThreadList
from
'./thread-list'
;
import
ThreadList
from
'./thread-list'
;
import
SidebarContentError
from
'./sidebar-content-error'
;
import
SidebarContentError
from
'./sidebar-content-error'
;
...
@@ -11,17 +12,11 @@ import SidebarContentError from './sidebar-content-error';
...
@@ -11,17 +12,11 @@ import SidebarContentError from './sidebar-content-error';
/**
/**
* The main content for the single annotation page (aka. https://hypothes.is/a/<annotation ID>)
* The main content for the single annotation page (aka. https://hypothes.is/a/<annotation ID>)
*/
*/
function
AnnotationViewerContent
({
function
AnnotationViewerContent
({
loadAnnotationsService
,
onLogin
})
{
loadAnnotationsService
,
onLogin
,
rootThread
:
rootThreadService
,
})
{
const
annotationId
=
useStore
(
store
=>
store
.
routeParams
().
id
);
const
annotationId
=
useStore
(
store
=>
store
.
routeParams
().
id
);
const
clearAnnotations
=
useStore
(
store
=>
store
.
clearAnnotations
);
const
clearAnnotations
=
useStore
(
store
=>
store
.
clearAnnotations
);
const
highlightAnnotations
=
useStore
(
store
=>
store
.
highlightAnnotations
);
const
highlightAnnotations
=
useStore
(
store
=>
store
.
highlightAnnotations
);
const
rootThread
=
useStore
(
store
=>
const
rootThread
=
useRootThread
();
rootThreadService
.
thread
(
store
.
getState
())
);
const
setExpanded
=
useStore
(
store
=>
store
.
setExpanded
);
const
setExpanded
=
useStore
(
store
=>
store
.
setExpanded
);
const
userid
=
useStore
(
store
=>
store
.
profile
().
userid
);
const
userid
=
useStore
(
store
=>
store
.
profile
().
userid
);
...
@@ -100,12 +95,8 @@ AnnotationViewerContent.propTypes = {
...
@@ -100,12 +95,8 @@ AnnotationViewerContent.propTypes = {
// Injected.
// Injected.
loadAnnotationsService
:
propTypes
.
object
,
loadAnnotationsService
:
propTypes
.
object
,
rootThread
:
propTypes
.
object
,
};
};
AnnotationViewerContent
.
injectedProps
=
[
AnnotationViewerContent
.
injectedProps
=
[
'loadAnnotationsService'
];
'loadAnnotationsService'
,
'rootThread'
,
];
export
default
withServices
(
AnnotationViewerContent
);
export
default
withServices
(
AnnotationViewerContent
);
src/sidebar/components/hooks/use-root-thread.js
0 → 100644
View file @
bcd4f9b5
import
{
useService
}
from
'../../util/service-context'
;
import
useStore
from
'../../store/use-store'
;
/**
* Gather together state relevant to building a root thread of annotations and
* replies and return an updated root thread when changes occur.
*/
export
default
function
useRootThread
()
{
const
rootThreadService
=
useService
(
'rootThread'
);
// Use a to-be-written selector to get relevant selection state, e.g.
// filters and forced-visible annotations, etc.
// const selectionState = useStore(store => store.getSelectionState());
// const route = useStore(store => store.routeName());
// const annotations = useStore(store => store.annotations());
// return useMemo(() => rootThreadService.buildRootThread(annotations, selectionState, route), [annotations, selectionState, route]);
return
useStore
(
store
=>
rootThreadService
.
thread
(
store
.
getState
()));
}
src/sidebar/components/search-status-bar.js
View file @
bcd4f9b5
import
{
createElement
}
from
'preact'
;
import
{
createElement
}
from
'preact'
;
import
{
useMemo
}
from
'preact/hooks'
;
import
{
useMemo
}
from
'preact/hooks'
;
import
propTypes
from
'prop-types'
;
import
useStore
from
'../store/use-store'
;
import
useStore
from
'../store/use-store'
;
import
uiConstants
from
'../ui-constants'
;
import
uiConstants
from
'../ui-constants'
;
import
{
withServices
}
from
'../util/service-context
'
;
import
useRootThread
from
'./hooks/use-root-thread
'
;
import
Button
from
'./button'
;
import
Button
from
'./button'
;
...
@@ -25,8 +24,8 @@ const countVisibleAnns = annThread => {
...
@@ -25,8 +24,8 @@ const countVisibleAnns = annThread => {
* UI for displaying information about the currently-applied filtering of
* UI for displaying information about the currently-applied filtering of
* annotations, and, in some cases, a mechanism for clearing the filter(s).
* annotations, and, in some cases, a mechanism for clearing the filter(s).
* */
* */
function
SearchStatusBar
(
{
rootThread
}
)
{
function
SearchStatusBar
()
{
const
thread
=
use
Store
(
store
=>
rootThread
.
thread
(
store
.
getState
())
);
const
thread
=
use
RootThread
(
);
const
actions
=
useStore
(
store
=>
({
const
actions
=
useStore
(
store
=>
({
clearSelection
:
store
.
clearSelection
,
clearSelection
:
store
.
clearSelection
,
...
@@ -170,11 +169,7 @@ function SearchStatusBar({ rootThread }) {
...
@@ -170,11 +169,7 @@ function SearchStatusBar({ rootThread }) {
);
);
}
}
SearchStatusBar
.
propTypes
=
{
// Necessary for test-mocking purposes (`mockImportedComponents`)
// Injected services.
SearchStatusBar
.
propTypes
=
{};
rootThread
:
propTypes
.
object
.
isRequired
,
};
SearchStatusBar
.
injectedProps
=
[
'rootThread'
];
export
default
withServices
(
SearchStatusBar
)
;
export
default
SearchStatusBar
;
src/sidebar/components/sidebar-content.js
View file @
bcd4f9b5
...
@@ -2,6 +2,7 @@ import { createElement } from 'preact';
...
@@ -2,6 +2,7 @@ import { createElement } from 'preact';
import
propTypes
from
'prop-types'
;
import
propTypes
from
'prop-types'
;
import
{
useEffect
,
useRef
}
from
'preact/hooks'
;
import
{
useEffect
,
useRef
}
from
'preact/hooks'
;
import
useRootThread
from
'./hooks/use-root-thread'
;
import
{
withServices
}
from
'../util/service-context'
;
import
{
withServices
}
from
'../util/service-context'
;
import
useStore
from
'../store/use-store'
;
import
useStore
from
'../store/use-store'
;
import
{
tabForAnnotation
}
from
'../util/tabs'
;
import
{
tabForAnnotation
}
from
'../util/tabs'
;
...
@@ -22,12 +23,9 @@ function SidebarContent({
...
@@ -22,12 +23,9 @@ function SidebarContent({
onLogin
,
onLogin
,
onSignUp
,
onSignUp
,
loadAnnotationsService
,
loadAnnotationsService
,
rootThread
:
rootThreadService
,
streamer
,
streamer
,
})
{
})
{
const
rootThread
=
useStore
(
store
=>
const
rootThread
=
useRootThread
();
rootThreadService
.
thread
(
store
.
getState
())
);
// Store state values
// Store state values
const
focusedGroupId
=
useStore
(
store
=>
store
.
focusedGroupId
());
const
focusedGroupId
=
useStore
(
store
=>
store
.
focusedGroupId
());
...
@@ -153,14 +151,12 @@ SidebarContent.propTypes = {
...
@@ -153,14 +151,12 @@ SidebarContent.propTypes = {
// Injected
// Injected
frameSync
:
propTypes
.
object
,
frameSync
:
propTypes
.
object
,
loadAnnotationsService
:
propTypes
.
object
,
loadAnnotationsService
:
propTypes
.
object
,
rootThread
:
propTypes
.
object
,
streamer
:
propTypes
.
object
,
streamer
:
propTypes
.
object
,
};
};
SidebarContent
.
injectedProps
=
[
SidebarContent
.
injectedProps
=
[
'frameSync'
,
'frameSync'
,
'loadAnnotationsService'
,
'loadAnnotationsService'
,
'rootThread'
,
'streamer'
,
'streamer'
,
];
];
...
...
src/sidebar/components/stream-content.js
View file @
bcd4f9b5
...
@@ -4,6 +4,7 @@ import propTypes from 'prop-types';
...
@@ -4,6 +4,7 @@ import propTypes from 'prop-types';
import
*
as
searchFilter
from
'../util/search-filter'
;
import
*
as
searchFilter
from
'../util/search-filter'
;
import
{
withServices
}
from
'../util/service-context'
;
import
{
withServices
}
from
'../util/service-context'
;
import
useRootThread
from
'./hooks/use-root-thread'
;
import
useStore
from
'../store/use-store'
;
import
useStore
from
'../store/use-store'
;
import
ThreadList
from
'./thread-list'
;
import
ThreadList
from
'./thread-list'
;
...
@@ -11,7 +12,7 @@ import ThreadList from './thread-list';
...
@@ -11,7 +12,7 @@ import ThreadList from './thread-list';
/**
/**
* The main content of the "stream" route (https://hypothes.is/stream)
* The main content of the "stream" route (https://hypothes.is/stream)
*/
*/
function
StreamContent
({
api
,
rootThread
:
rootThreadService
,
toastMessenger
})
{
function
StreamContent
({
api
,
toastMessenger
})
{
const
addAnnotations
=
useStore
(
store
=>
store
.
addAnnotations
);
const
addAnnotations
=
useStore
(
store
=>
store
.
addAnnotations
);
const
annotationFetchStarted
=
useStore
(
const
annotationFetchStarted
=
useStore
(
store
=>
store
.
annotationFetchStarted
store
=>
store
.
annotationFetchStarted
...
@@ -68,9 +69,7 @@ function StreamContent({ api, rootThread: rootThreadService, toastMessenger }) {
...
@@ -68,9 +69,7 @@ function StreamContent({ api, rootThread: rootThreadService, toastMessenger }) {
toastMessenger
,
toastMessenger
,
]);
]);
const
rootThread
=
useStore
(
store
=>
const
rootThread
=
useRootThread
();
rootThreadService
.
thread
(
store
.
getState
())
);
return
<
ThreadList
thread
=
{
rootThread
}
/>
;
return
<
ThreadList
thread
=
{
rootThread
}
/>
;
}
}
...
@@ -78,10 +77,9 @@ function StreamContent({ api, rootThread: rootThreadService, toastMessenger }) {
...
@@ -78,10 +77,9 @@ function StreamContent({ api, rootThread: rootThreadService, toastMessenger }) {
StreamContent
.
propTypes
=
{
StreamContent
.
propTypes
=
{
// Injected services.
// Injected services.
api
:
propTypes
.
object
,
api
:
propTypes
.
object
,
rootThread
:
propTypes
.
object
,
toastMessenger
:
propTypes
.
object
,
toastMessenger
:
propTypes
.
object
,
};
};
StreamContent
.
injectedProps
=
[
'api'
,
'
rootThread'
,
'
toastMessenger'
];
StreamContent
.
injectedProps
=
[
'api'
,
'toastMessenger'
];
export
default
withServices
(
StreamContent
);
export
default
withServices
(
StreamContent
);
src/sidebar/components/test/annotation-viewer-content-test.js
View file @
bcd4f9b5
...
@@ -11,7 +11,7 @@ import AnnotationViewerContent, {
...
@@ -11,7 +11,7 @@ import AnnotationViewerContent, {
describe
(
'AnnotationViewerContent'
,
()
=>
{
describe
(
'AnnotationViewerContent'
,
()
=>
{
let
fakeStore
;
let
fakeStore
;
let
fakeOnLogin
;
let
fakeOnLogin
;
let
fakeRootThread
;
let
fake
Use
RootThread
;
let
fakeLoadAnnotationsService
;
let
fakeLoadAnnotationsService
;
beforeEach
(()
=>
{
beforeEach
(()
=>
{
...
@@ -30,10 +30,11 @@ describe('AnnotationViewerContent', () => {
...
@@ -30,10 +30,11 @@ describe('AnnotationViewerContent', () => {
fakeOnLogin
=
sinon
.
stub
();
fakeOnLogin
=
sinon
.
stub
();
fake
RootThread
=
{
thread
:
sinon
.
stub
().
returns
({})
}
;
fake
UseRootThread
=
sinon
.
stub
().
returns
({})
;
$imports
.
$mock
(
mockImportedComponents
());
$imports
.
$mock
(
mockImportedComponents
());
$imports
.
$mock
({
$imports
.
$mock
({
'./hooks/use-root-thread'
:
fakeUseRootThread
,
'../store/use-store'
:
callback
=>
callback
(
fakeStore
),
'../store/use-store'
:
callback
=>
callback
(
fakeStore
),
});
});
});
});
...
@@ -47,7 +48,6 @@ describe('AnnotationViewerContent', () => {
...
@@ -47,7 +48,6 @@ describe('AnnotationViewerContent', () => {
<
AnnotationViewerContent
<
AnnotationViewerContent
loadAnnotationsService
=
{
fakeLoadAnnotationsService
}
loadAnnotationsService
=
{
fakeLoadAnnotationsService
}
onLogin
=
{
fakeOnLogin
}
onLogin
=
{
fakeOnLogin
}
rootThread
=
{
fakeRootThread
}
{...
props
}
{...
props
}
/
>
/
>
);
);
...
...
src/sidebar/components/test/search-status-bar-test.js
View file @
bcd4f9b5
...
@@ -8,17 +8,15 @@ import { checkAccessibility } from '../../../test-util/accessibility';
...
@@ -8,17 +8,15 @@ import { checkAccessibility } from '../../../test-util/accessibility';
import
mockImportedComponents
from
'../../../test-util/mock-imported-components'
;
import
mockImportedComponents
from
'../../../test-util/mock-imported-components'
;
describe
(
'SearchStatusBar'
,
()
=>
{
describe
(
'SearchStatusBar'
,
()
=>
{
let
fakeRootThread
;
let
fake
Use
RootThread
;
let
fakeStore
;
let
fakeStore
;
function
createComponent
(
props
)
{
function
createComponent
(
props
)
{
return
mount
(
<
SearchStatusBar
rootThread
=
{
fakeRootThread
}
{...
props
}
/>
)
;
return
mount
(
<
SearchStatusBar
{...
props
}
/>
)
;
}
}
beforeEach
(()
=>
{
beforeEach
(()
=>
{
fakeRootThread
=
{
fakeUseRootThread
=
sinon
.
stub
().
returns
({
children
:
[]
});
thread
:
sinon
.
stub
().
returns
({
children
:
[]
}),
};
fakeStore
=
{
fakeStore
=
{
getState
:
sinon
.
stub
().
returns
({
getState
:
sinon
.
stub
().
returns
({
selection
:
{},
selection
:
{},
...
@@ -32,6 +30,7 @@ describe('SearchStatusBar', () => {
...
@@ -32,6 +30,7 @@ describe('SearchStatusBar', () => {
$imports
.
$mock
(
mockImportedComponents
());
$imports
.
$mock
(
mockImportedComponents
());
$imports
.
$mock
({
$imports
.
$mock
({
'./hooks/use-root-thread'
:
fakeUseRootThread
,
'../store/use-store'
:
callback
=>
callback
(
fakeStore
),
'../store/use-store'
:
callback
=>
callback
(
fakeStore
),
});
});
});
});
...
@@ -105,7 +104,7 @@ describe('SearchStatusBar', () => {
...
@@ -105,7 +104,7 @@ describe('SearchStatusBar', () => {
},
},
].
forEach
(
test
=>
{
].
forEach
(
test
=>
{
it
(
test
.
description
,
()
=>
{
it
(
test
.
description
,
()
=>
{
fake
RootThread
.
t
hread
.
returns
({
fake
UseRootT
hread
.
returns
({
children
:
test
.
children
,
children
:
test
.
children
,
});
});
...
@@ -156,7 +155,7 @@ describe('SearchStatusBar', () => {
...
@@ -156,7 +155,7 @@ describe('SearchStatusBar', () => {
},
},
].
forEach
(
test
=>
{
].
forEach
(
test
=>
{
it
(
test
.
description
,
()
=>
{
it
(
test
.
description
,
()
=>
{
fake
RootThread
.
t
hread
.
returns
({
fake
UseRootT
hread
.
returns
({
children
:
test
.
children
,
children
:
test
.
children
,
});
});
const
wrapper
=
createComponent
({});
const
wrapper
=
createComponent
({});
...
@@ -169,7 +168,7 @@ describe('SearchStatusBar', () => {
...
@@ -169,7 +168,7 @@ describe('SearchStatusBar', () => {
});
});
it
(
'should not display user-focused mode text if filtered mode is (also) applied'
,
()
=>
{
it
(
'should not display user-focused mode text if filtered mode is (also) applied'
,
()
=>
{
fake
RootThread
.
t
hread
.
returns
({
fake
UseRootT
hread
.
returns
({
children
:
[
children
:
[
{
id
:
'1'
,
visible
:
true
,
children
:
[]
},
{
id
:
'1'
,
visible
:
true
,
children
:
[]
},
{
id
:
'2'
,
visible
:
true
,
children
:
[]
},
{
id
:
'2'
,
visible
:
true
,
children
:
[]
},
...
...
src/sidebar/components/test/sidebar-content-test.js
View file @
bcd4f9b5
...
@@ -10,7 +10,7 @@ import mockImportedComponents from '../../../test-util/mock-imported-components'
...
@@ -10,7 +10,7 @@ import mockImportedComponents from '../../../test-util/mock-imported-components'
describe
(
'SidebarContent'
,
()
=>
{
describe
(
'SidebarContent'
,
()
=>
{
let
fakeFrameSync
;
let
fakeFrameSync
;
let
fakeLoadAnnotationsService
;
let
fakeLoadAnnotationsService
;
let
fake
RootThreadService
;
let
fake
UseRootThread
;
let
fakeStore
;
let
fakeStore
;
let
fakeStreamer
;
let
fakeStreamer
;
let
fakeTabsUtil
;
let
fakeTabsUtil
;
...
@@ -22,7 +22,6 @@ describe('SidebarContent', () => {
...
@@ -22,7 +22,6 @@ describe('SidebarContent', () => {
onSignUp
=
{()
=>
null
}
onSignUp
=
{()
=>
null
}
frameSync
=
{
fakeFrameSync
}
frameSync
=
{
fakeFrameSync
}
loadAnnotationsService
=
{
fakeLoadAnnotationsService
}
loadAnnotationsService
=
{
fakeLoadAnnotationsService
}
rootThread
=
{
fakeRootThreadService
}
streamer
=
{
fakeStreamer
}
streamer
=
{
fakeStreamer
}
{...
props
}
{...
props
}
/
>
/
>
...
@@ -36,9 +35,7 @@ describe('SidebarContent', () => {
...
@@ -36,9 +35,7 @@ describe('SidebarContent', () => {
fakeLoadAnnotationsService
=
{
fakeLoadAnnotationsService
=
{
load
:
sinon
.
stub
(),
load
:
sinon
.
stub
(),
};
};
fakeRootThreadService
=
{
fakeUseRootThread
=
sinon
.
stub
().
returns
({});
thread
:
sinon
.
stub
().
returns
({}),
};
fakeStreamer
=
{
fakeStreamer
=
{
connect
:
sinon
.
stub
(),
connect
:
sinon
.
stub
(),
};
};
...
@@ -69,6 +66,7 @@ describe('SidebarContent', () => {
...
@@ -69,6 +66,7 @@ describe('SidebarContent', () => {
$imports
.
$mock
(
mockImportedComponents
());
$imports
.
$mock
(
mockImportedComponents
());
$imports
.
$mock
({
$imports
.
$mock
({
'./hooks/use-root-thread'
:
fakeUseRootThread
,
'../store/use-store'
:
callback
=>
callback
(
fakeStore
),
'../store/use-store'
:
callback
=>
callback
(
fakeStore
),
'../util/tabs'
:
fakeTabsUtil
,
'../util/tabs'
:
fakeTabsUtil
,
});
});
...
...
src/sidebar/components/test/stream-content-test.js
View file @
bcd4f9b5
...
@@ -8,7 +8,7 @@ import StreamContent, { $imports } from '../stream-content';
...
@@ -8,7 +8,7 @@ import StreamContent, { $imports } from '../stream-content';
describe
(
'StreamContent'
,
()
=>
{
describe
(
'StreamContent'
,
()
=>
{
let
fakeApi
;
let
fakeApi
;
let
fakeRootThread
;
let
fake
Use
RootThread
;
let
fakeSearchFilter
;
let
fakeSearchFilter
;
let
fakeStore
;
let
fakeStore
;
let
fakeToastMessenger
;
let
fakeToastMessenger
;
...
@@ -18,9 +18,7 @@ describe('StreamContent', () => {
...
@@ -18,9 +18,7 @@ describe('StreamContent', () => {
search
:
sinon
.
stub
().
resolves
({
rows
:
[],
replies
:
[],
total
:
0
}),
search
:
sinon
.
stub
().
resolves
({
rows
:
[],
replies
:
[],
total
:
0
}),
};
};
fakeRootThread
=
{
fakeUseRootThread
=
sinon
.
stub
();
thread
:
sinon
.
stub
().
returns
({}),
};
fakeSearchFilter
=
{
fakeSearchFilter
=
{
toObject
:
sinon
.
stub
().
returns
({}),
toObject
:
sinon
.
stub
().
returns
({}),
...
@@ -42,6 +40,7 @@ describe('StreamContent', () => {
...
@@ -42,6 +40,7 @@ describe('StreamContent', () => {
$imports
.
$mock
(
mockImportedComponents
());
$imports
.
$mock
(
mockImportedComponents
());
$imports
.
$mock
({
$imports
.
$mock
({
'./hooks/use-root-thread'
:
fakeUseRootThread
,
'../store/use-store'
:
callback
=>
callback
(
fakeStore
),
'../store/use-store'
:
callback
=>
callback
(
fakeStore
),
'../util/search-filter'
:
fakeSearchFilter
,
'../util/search-filter'
:
fakeSearchFilter
,
});
});
...
@@ -53,11 +52,7 @@ describe('StreamContent', () => {
...
@@ -53,11 +52,7 @@ describe('StreamContent', () => {
function
createComponent
()
{
function
createComponent
()
{
return
mount
(
return
mount
(
<
StreamContent
<
StreamContent
api
=
{
fakeApi
}
toastMessenger
=
{
fakeToastMessenger
}
/
>
api
=
{
fakeApi
}
rootThread
=
{
fakeRootThread
}
toastMessenger
=
{
fakeToastMessenger
}
/
>
);
);
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment