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
21ecaa76
Unverified
Commit
21ecaa76
authored
Jul 26, 2019
by
Robert Knight
Committed by
GitHub
Jul 26, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1233 from hypothesis/move-tab-count-to-store
Move tab counts to store
parents
d1669ce3
02235b72
Changes
22
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
220 additions
and
211 deletions
+220
-211
annotation-document-info.js
src/sidebar/components/annotation-document-info.js
+1
-1
annotation.js
src/sidebar/components/annotation.js
+1
-1
moderation-banner.js
src/sidebar/components/moderation-banner.js
+1
-1
search-status-bar.js
src/sidebar/components/search-status-bar.js
+21
-21
selection-tabs.js
src/sidebar/components/selection-tabs.js
+14
-30
sidebar-content.js
src/sidebar/components/sidebar-content.js
+1
-13
annotation-document-info-test.js
src/sidebar/components/test/annotation-document-info-test.js
+1
-1
search-status-bar-test.js
src/sidebar/components/test/search-status-bar-test.js
+15
-29
selection-tabs-test.js
src/sidebar/components/test/selection-tabs-test.js
+42
-49
thread-list.js
src/sidebar/components/thread-list.js
+1
-1
frame-sync.js
src/sidebar/services/frame-sync.js
+1
-1
root-thread.js
src/sidebar/services/root-thread.js
+2
-2
annotations.js
src/sidebar/store/modules/annotations.js
+39
-1
selection.js
src/sidebar/store/modules/selection.js
+7
-3
annotations-test.js
src/sidebar/store/modules/test/annotations-test.js
+62
-0
index-test.js
src/sidebar/store/test/index-test.js
+1
-1
sidebar-content.html
src/sidebar/templates/sidebar-content.html
+2
-11
build-thread-test.js
src/sidebar/test/build-thread-test.js
+1
-1
annotation-metadata.js
src/sidebar/util/annotation-metadata.js
+0
-0
tabs.js
src/sidebar/util/tabs.js
+2
-21
annotation-metadata-test.js
src/sidebar/util/test/annotation-metadata-test.js
+2
-2
tabs-test.js
src/sidebar/util/test/tabs-test.js
+3
-21
No files found.
src/sidebar/components/annotation-document-info.js
View file @
21ecaa76
...
...
@@ -3,7 +3,7 @@
const
propTypes
=
require
(
'prop-types'
);
const
{
createElement
}
=
require
(
'preact'
);
const
annotationMetadata
=
require
(
'../annotation-metadata'
);
const
annotationMetadata
=
require
(
'../
util/
annotation-metadata'
);
/**
* Render some metadata about an annotation's document and link to it
...
...
src/sidebar/components/annotation.js
View file @
21ecaa76
'use strict'
;
const
annotationMetadata
=
require
(
'../annotation-metadata'
);
const
annotationMetadata
=
require
(
'../
util/
annotation-metadata'
);
const
events
=
require
(
'../events'
);
const
{
isThirdPartyUser
}
=
require
(
'../util/account-id'
);
const
serviceConfig
=
require
(
'../service-config'
);
...
...
src/sidebar/components/moderation-banner.js
View file @
21ecaa76
...
...
@@ -4,7 +4,7 @@ const { createElement } = require('preact');
const
classnames
=
require
(
'classnames'
);
const
propTypes
=
require
(
'prop-types'
);
const
annotationMetadata
=
require
(
'../annotation-metadata'
);
const
annotationMetadata
=
require
(
'../
util/
annotation-metadata'
);
const
useStore
=
require
(
'../store/use-store'
);
const
{
withServices
}
=
require
(
'../util/service-context'
);
...
...
src/sidebar/components/search-status-bar.js
View file @
21ecaa76
...
...
@@ -21,18 +21,24 @@ const countVisibleAnns = annThread => {
* A bar where the user can clear a selection or search and see whether
* any search results were found.
* */
function
SearchStatusBar
({
selectedTab
,
totalAnnotations
,
totalNotes
,
rootThread
,
})
{
const
storeState
=
useStore
(
store
=>
store
.
getState
());
function
SearchStatusBar
({
rootThread
})
{
const
{
directLinkedGroupFetchFailed
,
filterQuery
,
selectedAnnotationMap
,
selectedTab
,
}
=
useStore
(
store
=>
({
directLinkedGroupFetchFailed
:
store
.
getState
().
directLinkedGroupFetchFailed
,
filterQuery
:
store
.
getState
().
filterQuery
,
selectedAnnotationMap
:
store
.
getState
().
selectedAnnotationMap
,
selectedTab
:
store
.
getState
().
selectedTab
,
}));
const
clearSelection
=
useStore
(
store
=>
store
.
clearSelection
);
const
filterQuery
=
storeState
.
filterQuery
;
const
filterActive
=
!!
storeState
.
filterQuery
;
const
filterActive
=
!!
filterQuery
;
const
annotationCount
=
useStore
(
store
=>
store
.
annotationCount
());
const
noteCount
=
useStore
(
store
=>
store
.
noteCount
());
const
thread
=
rootThread
.
thread
(
storeState
);
const
thread
=
useStore
(
store
=>
rootThread
.
thread
(
store
.
getState
())
);
const
visibleCount
=
useMemo
(()
=>
{
return
countVisibleAnns
(
thread
);
...
...
@@ -51,10 +57,10 @@ function SearchStatusBar({
};
const
areNotAllAnnotationsVisible
=
()
=>
{
if
(
storeState
.
directLinkedGroupFetchFailed
)
{
if
(
directLinkedGroupFetchFailed
)
{
return
true
;
}
const
selection
=
s
toreState
.
s
electedAnnotationMap
;
const
selection
=
selectedAnnotationMap
;
if
(
!
selection
)
{
return
false
;
}
...
...
@@ -89,13 +95,13 @@ function SearchStatusBar({
{
selectedTab
===
uiConstants
.
TAB_ANNOTATIONS
&&
(
<
Fragment
>
Show
all
annotations
{
totalAnnotations
>
1
&&
<
span
>
({
totalAnnotations
})
<
/span>
}
{
annotationCount
>
1
&&
<
span
>
({
annotationCount
})
<
/span>
}
<
/Fragment
>
)}
{
selectedTab
===
uiConstants
.
TAB_NOTES
&&
(
<
Fragment
>
Show
all
notes
{
totalNotes
>
1
&&
<
span
>
({
totalNotes
})
<
/span>
}
{
noteCount
>
1
&&
<
span
>
({
noteCount
})
<
/span>
}
<
/Fragment
>
)}
<
/button
>
...
...
@@ -106,13 +112,7 @@ function SearchStatusBar({
}
SearchStatusBar
.
propTypes
=
{
selectedTab
:
propTypes
.
oneOf
([
uiConstants
.
TAB_ANNOTATIONS
,
uiConstants
.
TAB_ORPHANS
,
uiConstants
.
TAB_NOTES
,
]).
isRequired
,
totalAnnotations
:
propTypes
.
number
.
isRequired
,
totalNotes
:
propTypes
.
number
.
isRequired
,
// Injected services.
rootThread
:
propTypes
.
object
.
isRequired
,
};
...
...
src/sidebar/components/selection-tabs.js
View file @
21ecaa76
...
...
@@ -69,16 +69,14 @@ Tab.propTypes = {
* Tabbed display of annotations and notes.
*/
function
SelectionTabs
({
isWaitingToAnchorAnnotations
,
isLoading
,
selectedTab
,
totalAnnotations
,
totalNotes
,
totalOrphans
,
settings
,
session
,
})
{
function
SelectionTabs
({
isLoading
,
settings
,
session
})
{
const
selectedTab
=
useStore
(
store
=>
store
.
getState
().
selectedTab
);
const
noteCount
=
useStore
(
store
=>
store
.
noteCount
());
const
annotationCount
=
useStore
(
store
=>
store
.
annotationCount
());
const
orphanCount
=
useStore
(
store
=>
store
.
orphanCount
());
const
isWaitingToAnchorAnnotations
=
useStore
(
store
=>
store
.
isWaitingToAnchorAnnotations
()
);
// actions
const
store
=
useStore
(
store
=>
({
clearSelectedAnnotations
:
store
.
clearSelectedAnnotations
,
...
...
@@ -94,11 +92,11 @@ function SelectionTabs({
const
showAnnotationsUnavailableMessage
=
selectedTab
===
uiConstants
.
TAB_ANNOTATIONS
&&
totalAnnotations
===
0
&&
annotationCount
===
0
&&
!
isWaitingToAnchorAnnotations
;
const
showNotesUnavailableMessage
=
selectedTab
===
uiConstants
.
TAB_NOTES
&&
totalNotes
===
0
;
selectedTab
===
uiConstants
.
TAB_NOTES
&&
noteCount
===
0
;
const
showSidebarTutorial
=
sessionUtil
.
shouldShowSidebarTutorial
(
session
.
state
...
...
@@ -112,7 +110,7 @@ function SelectionTabs({
})}
>
<
Tab
count
=
{
totalAnnotations
}
count
=
{
annotationCount
}
isWaitingToAnchor
=
{
isWaitingToAnchorAnnotations
}
selected
=
{
selectedTab
===
uiConstants
.
TAB_ANNOTATIONS
}
type
=
{
uiConstants
.
TAB_ANNOTATIONS
}
...
...
@@ -121,7 +119,7 @@ function SelectionTabs({
Annotations
<
/Tab
>
<
Tab
count
=
{
totalNotes
}
count
=
{
noteCount
}
isWaitingToAnchor
=
{
isWaitingToAnchorAnnotations
}
selected
=
{
selectedTab
===
uiConstants
.
TAB_NOTES
}
type
=
{
uiConstants
.
TAB_NOTES
}
...
...
@@ -129,9 +127,9 @@ function SelectionTabs({
>
Page
Notes
<
/Tab
>
{
totalOrphans
>
0
&&
(
{
orphanCount
>
0
&&
(
<
Tab
count
=
{
totalOrphans
}
count
=
{
orphanCount
}
isWaitingToAnchor
=
{
isWaitingToAnchorAnnotations
}
selected
=
{
selectedTab
===
uiConstants
.
TAB_ORPHANS
}
type
=
{
uiConstants
.
TAB_ORPHANS
}
...
...
@@ -182,20 +180,6 @@ SelectionTabs.propTypes = {
* Are we waiting on any annotations from the server?
*/
isLoading
:
propTypes
.
bool
.
isRequired
,
/**
* Are there any annotations still waiting to anchor?
*/
isWaitingToAnchorAnnotations
:
propTypes
.
bool
.
isRequired
,
/**
* The currently selected tab (annotations, notes or orphans).
*/
selectedTab
:
propTypes
.
oneOf
([
'annotation'
,
'note'
,
'orphan'
]).
isRequired
,
/**
* The totals for each respect tab.
*/
totalAnnotations
:
propTypes
.
number
.
isRequired
,
totalNotes
:
propTypes
.
number
.
isRequired
,
totalOrphans
:
propTypes
.
number
.
isRequired
,
// Injected services.
settings
:
propTypes
.
object
.
isRequired
,
...
...
src/sidebar/components/sidebar-content.js
View file @
21ecaa76
...
...
@@ -2,7 +2,7 @@
const
events
=
require
(
'../events'
);
const
isThirdPartyService
=
require
(
'../util/is-third-party-service'
);
const
tabs
=
require
(
'../tabs'
);
const
tabs
=
require
(
'../
util/
tabs'
);
// @ngInject
function
SidebarContentController
(
...
...
@@ -22,19 +22,7 @@ function SidebarContentController(
}
const
unsubscribeAnnotationUI
=
store
.
subscribe
(
function
()
{
const
state
=
store
.
getState
();
self
.
rootThread
=
thread
();
self
.
selectedTab
=
state
.
selectedTab
;
const
counts
=
tabs
.
counts
(
state
.
annotations
);
Object
.
assign
(
self
,
{
totalNotes
:
counts
.
notes
,
totalAnnotations
:
counts
.
annotations
,
totalOrphans
:
counts
.
orphans
,
waitingToAnchorAnnotations
:
counts
.
anchoring
>
0
,
});
});
$scope
.
$on
(
'$destroy'
,
unsubscribeAnnotationUI
);
...
...
src/sidebar/components/test/annotation-document-info-test.js
View file @
21ecaa76
...
...
@@ -24,7 +24,7 @@ describe('AnnotationDocumentInfo', () => {
fakeDomainAndTitle
=
sinon
.
stub
();
fakeMetadata
=
{
domainAndTitle
:
fakeDomainAndTitle
};
AnnotationDocumentInfo
.
$imports
.
$mock
({
'../annotation-metadata'
:
fakeMetadata
,
'../
util/
annotation-metadata'
:
fakeMetadata
,
});
});
...
...
src/sidebar/components/test/search-status-bar-test.js
View file @
21ecaa76
...
...
@@ -21,11 +21,8 @@ describe('SearchStatusBar', () => {
};
fakeStore
=
{
getState
:
sinon
.
stub
(),
selectTab
:
sinon
.
stub
(),
clearSelectedAnnotations
:
sinon
.
stub
(),
clearDirectLinkedGroupFetchFailed
:
sinon
.
stub
(),
clearDirectLinkedIds
:
sinon
.
stub
(),
clearSelection
:
sinon
.
stub
(),
annotationCount
:
sinon
.
stub
().
returns
(
1
),
noteCount
:
sinon
.
stub
().
returns
(
0
),
};
SearchStatusBar
.
$imports
.
$mock
({
...
...
@@ -96,13 +93,11 @@ describe('SearchStatusBar', () => {
});
fakeStore
.
getState
.
returns
({
filterQuery
:
'tag:foo'
,
});
const
wrapper
=
createComponent
({
selectedTab
:
'annotation'
,
totalAnnotations
:
3
,
totalNotes
:
0
,
});
fakeStore
.
annotationCount
.
returns
(
3
);
const
wrapper
=
createComponent
({});
const
buttonText
=
wrapper
.
find
(
'button'
).
text
();
assert
.
equal
(
buttonText
,
'Clear search'
);
...
...
@@ -117,14 +112,11 @@ describe('SearchStatusBar', () => {
filterQuery
:
null
,
directLinkedGroupFetchFailed
:
true
,
selectedAnnotationMap
:
{
annId
:
true
},
});
const
wrapper
=
createComponent
({
selectedTab
:
'annotation'
,
totalAnnotations
:
1
,
totalNotes
:
0
,
});
const
wrapper
=
createComponent
({});
const
buttonText
=
wrapper
.
find
(
'button'
).
text
();
assert
.
equal
(
buttonText
,
'Show all annotations'
);
});
...
...
@@ -134,14 +126,11 @@ describe('SearchStatusBar', () => {
filterQuery
:
null
,
directLinkedGroupFetchFailed
:
false
,
selectedAnnotationMap
:
{
annId
:
true
},
});
const
wrapper
=
createComponent
({
selectedTab
:
'annotation'
,
totalAnnotations
:
1
,
totalNotes
:
0
,
});
const
wrapper
=
createComponent
({});
const
buttonText
=
wrapper
.
find
(
'button'
).
text
();
assert
.
equal
(
buttonText
,
'Show all annotations'
);
});
...
...
@@ -152,13 +141,11 @@ describe('SearchStatusBar', () => {
filterQuery
:
null
,
directLinkedGroupFetchFailed
:
false
,
selectedAnnotationMap
:
selectedAnnotationMap
,
});
const
wrapper
=
createComponent
({
selectedTab
:
'annotation'
,
totalAnnotations
:
1
,
totalNotes
:
0
,
});
const
wrapper
=
createComponent
({});
const
buttons
=
wrapper
.
find
(
'button'
);
assert
.
equal
(
buttons
.
length
,
0
);
});
...
...
@@ -203,13 +190,12 @@ describe('SearchStatusBar', () => {
filterQuery
:
null
,
directLinkedGroupFetchFailed
:
false
,
selectedAnnotationMap
:
{
annId
:
true
},
});
const
wrapper
=
createComponent
({
selectedTab
:
test
.
selectedTab
,
totalAnnotations
:
test
.
totalAnnotations
,
totalNotes
:
test
.
totalNotes
,
});
fakeStore
.
noteCount
.
returns
(
test
.
totalNotes
);
fakeStore
.
annotationCount
.
returns
(
test
.
totalAnnotations
);
const
wrapper
=
createComponent
({});
const
buttonText
=
wrapper
.
find
(
'button'
).
text
();
assert
.
equal
(
buttonText
,
test
.
expectedText
);
...
...
src/sidebar/components/test/selection-tabs-test.js
View file @
21ecaa76
...
...
@@ -11,23 +11,15 @@ describe('SelectionTabs', function() {
// mock services
let
fakeSession
;
let
fakeSettings
;
let
fakeStore
;
// default props
const
defaultProps
=
{
isLoading
:
false
,
isWaitingToAnchorAnnotations
:
false
,
selectedTab
:
uiConstants
.
TAB_ANNOTATIONS
,
totalAnnotations
:
123
,
totalNotes
:
456
,
totalOrphans
:
0
,
};
SelectionTabs
.
$imports
.
$mock
({
'../store/use-store'
:
callback
=>
callback
({
clearSelectedAnnotations
:
sinon
.
stub
(),
selectTab
:
sinon
.
stub
(),
}),
'../store/use-store'
:
callback
=>
callback
(
fakeStore
),
});
function
createComponent
(
props
)
{
...
...
@@ -64,6 +56,17 @@ describe('SelectionTabs', function() {
fakeSettings
=
{
enableExperimentalNewNoteButton
:
false
,
};
fakeStore
=
{
clearSelectedAnnotations
:
sinon
.
stub
(),
selectTab
:
sinon
.
stub
(),
annotationCount
:
sinon
.
stub
().
returns
(
123
),
noteCount
:
sinon
.
stub
().
returns
(
456
),
orphanCount
:
sinon
.
stub
().
returns
(
0
),
isWaitingToAnchorAnnotations
:
sinon
.
stub
().
returns
(
false
),
getState
:
sinon
.
stub
()
.
returns
({
selectedTab
:
uiConstants
.
TAB_ANNOTATIONS
}),
};
});
const
unavailableMessage
=
wrapper
=>
...
...
@@ -98,26 +101,23 @@ describe('SelectionTabs', function() {
});
it
(
'should display notes tab as selected'
,
function
()
{
const
wrapper
=
createDeepComponent
({
selectedTab
:
uiConstants
.
TAB_NOTES
,
});
fakeStore
.
getState
.
returns
({
selectedTab
:
uiConstants
.
TAB_NOTES
});
const
wrapper
=
createDeepComponent
({});
const
tabs
=
wrapper
.
find
(
'a'
);
assert
.
isTrue
(
tabs
.
at
(
1
).
hasClass
(
'is-selected'
));
});
it
(
'should display orphans tab as selected if there is 1 or more orphans'
,
function
()
{
const
wrapper
=
createDeepComponent
({
selectedTab
:
uiConstants
.
TAB_ORPHANS
,
totalOrphans
:
1
,
});
fakeStore
.
getState
.
returns
({
selectedTab
:
uiConstants
.
TAB_ORPHANS
});
fakeStore
.
orphanCount
.
returns
(
1
);
const
wrapper
=
createDeepComponent
({});
const
tabs
=
wrapper
.
find
(
'a'
);
assert
.
isTrue
(
tabs
.
at
(
2
).
hasClass
(
'is-selected'
));
});
it
(
'should not display orphans tab if there are 0 orphans'
,
function
()
{
const
wrapper
=
createDeepComponent
({
selectedTab
:
uiConstants
.
TAB_ORPHANS
,
});
fakeStore
.
getState
.
returns
({
selectedTab
:
uiConstants
.
TAB_ORPHANS
});
const
wrapper
=
createDeepComponent
({});
const
tabs
=
wrapper
.
find
(
'a'
);
assert
.
equal
(
tabs
.
length
,
2
);
});
...
...
@@ -139,51 +139,48 @@ describe('SelectionTabs', function() {
});
it
(
'should not display the new-note-btn when the notes tab is active and the new-note-btn is disabled'
,
function
()
{
const
wrapper
=
createComponent
({
selectedTab
:
uiConstants
.
TAB_NOTES
,
});
fakeStore
.
getState
.
returns
({
selectedTab
:
uiConstants
.
TAB_NOTES
});
const
wrapper
=
createComponent
({});
assert
.
equal
(
wrapper
.
find
(
NewNoteBtn
).
length
,
0
);
});
it
(
'should display the new-note-btn when the notes tab is active and the new-note-btn is enabled'
,
function
()
{
fakeSettings
.
enableExperimentalNewNoteButton
=
true
;
const
wrapper
=
createComponent
({
selectedTab
:
uiConstants
.
TAB_NOTES
,
});
fakeStore
.
getState
.
returns
({
selectedTab
:
uiConstants
.
TAB_NOTES
});
const
wrapper
=
createComponent
({});
assert
.
equal
(
wrapper
.
find
(
NewNoteBtn
).
length
,
1
);
});
it
(
'should not display a message when its loading annotation count is 0'
,
function
()
{
fakeStore
.
annotationCount
.
returns
(
0
);
const
wrapper
=
createComponent
({
totalAnnotations
:
0
,
isLoading
:
true
,
});
assert
.
isFalse
(
wrapper
.
exists
(
'.annotation-unavailable-message__label'
));
});
it
(
'should not display a message when its loading notes count is 0'
,
function
()
{
fakeStore
.
getState
.
returns
({
selectedTab
:
uiConstants
.
TAB_NOTES
});
fakeStore
.
noteCount
.
returns
(
0
);
const
wrapper
=
createComponent
({
selectedTab
:
uiConstants
.
TAB_NOTES
,
totalNotes
:
0
,
isLoading
:
true
,
});
assert
.
isFalse
(
wrapper
.
exists
(
'.annotation-unavailable-message__label'
));
});
it
(
'should not display the longer version of the no annotations message when there are no annotations and isWaitingToAnchorAnnotations is true'
,
function
()
{
fakeStore
.
annotationCount
.
returns
(
0
);
fakeStore
.
isWaitingToAnchorAnnotations
.
returns
(
true
);
const
wrapper
=
createComponent
({
totalAnnotations
:
0
,
isWaitingToAnchorAnnotations
:
true
,
isLoading
:
false
,
});
assert
.
isFalse
(
wrapper
.
exists
(
'.annotation-unavailable-message__label'
));
});
it
(
'should display the longer version of the no notes message when there are no notes'
,
function
()
{
const
wrapper
=
createComponent
({
selectedTab
:
uiConstants
.
TAB_NOTES
,
totalNotes
:
0
,
});
fakeStore
.
getState
.
returns
({
selectedTab
:
uiConstants
.
TAB_NOTES
});
fakeStore
.
noteCount
.
returns
(
0
);
const
wrapper
=
createComponent
({});
assert
.
include
(
unavailableMessage
(
wrapper
),
'There are no page notes in this group.'
...
...
@@ -192,10 +189,9 @@ describe('SelectionTabs', function() {
it
(
'should display the prompt to create a note when there are no notes and enableExperimentalNewNoteButton is true'
,
function
()
{
fakeSettings
.
enableExperimentalNewNoteButton
=
true
;
const
wrapper
=
createComponent
({
selectedTab
:
uiConstants
.
TAB_NOTES
,
totalNotes
:
0
,
});
fakeStore
.
getState
.
returns
({
selectedTab
:
uiConstants
.
TAB_NOTES
});
fakeStore
.
noteCount
.
returns
(
0
);
const
wrapper
=
createComponent
({});
assert
.
include
(
wrapper
.
find
(
'.annotation-unavailable-message__tutorial'
).
text
(),
'Create one by clicking the'
...
...
@@ -208,9 +204,8 @@ describe('SelectionTabs', function() {
});
it
(
'should display the longer version of the no annotations message when there are no annotations'
,
function
()
{
const
wrapper
=
createComponent
({
totalAnnotations
:
0
,
});
fakeStore
.
annotationCount
.
returns
(
0
);
const
wrapper
=
createComponent
({});
assert
.
include
(
unavailableMessage
(
wrapper
),
'There are no annotations in this group.'
...
...
@@ -229,10 +224,9 @@ describe('SelectionTabs', function() {
context
(
'when the sidebar tutorial is displayed'
,
function
()
{
it
(
'should display the shorter version of the no notes message when there are no notes'
,
function
()
{
fakeSession
.
state
.
preferences
.
show_sidebar_tutorial
=
true
;
const
wrapper
=
createComponent
({
totalNotes
:
0
,
selectedTab
:
uiConstants
.
TAB_NOTES
,
});
fakeStore
.
getState
.
returns
({
selectedTab
:
uiConstants
.
TAB_NOTES
});
fakeStore
.
noteCount
.
returns
(
0
);
const
wrapper
=
createComponent
({});
const
msg
=
unavailableMessage
(
wrapper
);
...
...
@@ -246,9 +240,8 @@ describe('SelectionTabs', function() {
it
(
'should display the shorter version of the no annotations message when there are no annotations'
,
function
()
{
fakeSession
.
state
.
preferences
.
show_sidebar_tutorial
=
true
;
const
wrapper
=
createComponent
({
totalAnnotations
:
0
,
});
fakeStore
.
annotationCount
.
returns
(
0
);
const
wrapper
=
createComponent
({});
const
msg
=
unavailableMessage
(
wrapper
);
...
...
src/sidebar/components/thread-list.js
View file @
21ecaa76
'use strict'
;
const
events
=
require
(
'../events'
);
const
metadata
=
require
(
'../annotation-metadata'
);
const
metadata
=
require
(
'../
util/
annotation-metadata'
);
/**
* Component which displays a virtualized list of annotation threads.
...
...
src/sidebar/services/frame-sync.js
View file @
21ecaa76
...
...
@@ -4,7 +4,7 @@ const debounce = require('lodash.debounce');
const
events
=
require
(
'../events'
);
const
bridgeEvents
=
require
(
'../../shared/bridge-events'
);
const
metadata
=
require
(
'../annotation-metadata'
);
const
metadata
=
require
(
'../
util/
annotation-metadata'
);
const
uiConstants
=
require
(
'../ui-constants'
);
/**
...
...
src/sidebar/services/root-thread.js
View file @
21ecaa76
...
...
@@ -3,8 +3,8 @@
const
buildThread
=
require
(
'../build-thread'
);
const
events
=
require
(
'../events'
);
const
memoize
=
require
(
'../util/memoize'
);
const
metadata
=
require
(
'../annotation-metadata'
);
const
tabs
=
require
(
'../tabs'
);
const
metadata
=
require
(
'../
util/
annotation-metadata'
);
const
tabs
=
require
(
'../
util/
tabs'
);
const
uiConstants
=
require
(
'../ui-constants'
);
function
truthyKeys
(
map
)
{
...
...
src/sidebar/store/modules/annotations.js
View file @
21ecaa76
...
...
@@ -5,8 +5,10 @@
'use strict'
;
const
{
createSelector
}
=
require
(
'reselect'
);
const
arrayUtil
=
require
(
'../../util/array-util'
);
const
metadata
=
require
(
'../../annotation-metadata'
);
const
metadata
=
require
(
'../../
util/
annotation-metadata'
);
const
uiConstants
=
require
(
'../../ui-constants'
);
const
selection
=
require
(
'./selection'
);
...
...
@@ -388,6 +390,38 @@ function findAnnotationByID(state, id) {
return
findByID
(
state
.
annotations
,
id
);
}
/**
* Return the number of page notes.
*/
const
noteCount
=
createSelector
(
state
=>
state
.
annotations
,
annotations
=>
arrayUtil
.
countIf
(
annotations
,
metadata
.
isPageNote
)
);
/**
* Returns the number of annotations (as opposed to notes or orphans).
*/
const
annotationCount
=
createSelector
(
state
=>
state
.
annotations
,
annotations
=>
arrayUtil
.
countIf
(
annotations
,
metadata
.
isAnnotation
)
);
/**
* Returns the number of orphaned annotations.
*/
const
orphanCount
=
createSelector
(
state
=>
state
.
annotations
,
annotations
=>
arrayUtil
.
countIf
(
annotations
,
metadata
.
isOrphan
)
);
/**
* Returns true if some annotations have not been anchored yet.
*/
const
isWaitingToAnchorAnnotations
=
createSelector
(
state
=>
state
.
annotations
,
annotations
=>
annotations
.
some
(
metadata
.
isWaitingToAnchor
)
);
module
.
exports
=
{
init
:
init
,
update
:
update
,
...
...
@@ -403,6 +437,10 @@ module.exports = {
selectors
:
{
annotationExists
,
noteCount
,
annotationCount
,
orphanCount
,
isWaitingToAnchorAnnotations
,
findAnnotationByID
,
findIDsForTags
,
savedAnnotations
,
...
...
src/sidebar/store/modules/selection.js
View file @
21ecaa76
...
...
@@ -13,9 +13,10 @@
const
{
createSelector
}
=
require
(
'reselect'
);
const
immutable
=
require
(
'seamless-immutable'
);
const
arrayUtil
=
require
(
'../../util/array-util'
);
const
metadata
=
require
(
'../../util/annotation-metadata'
);
const
toSet
=
require
(
'../../util/array-util'
).
toSet
;
const
uiConstants
=
require
(
'../../ui-constants'
);
const
tabs
=
require
(
'../../tabs'
);
const
util
=
require
(
'../util'
);
...
...
@@ -162,9 +163,12 @@ const update = {
},
ADD_ANNOTATIONS
(
state
,
action
)
{
const
counts
=
tabs
.
counts
(
action
.
annotations
);
const
noteCount
=
arrayUtil
.
countIf
(
action
.
annotations
,
metadata
.
isPageNote
);
// If there are no annotations at all, ADD_ANNOTATIONS will not be called.
const
haveOnlyPageNotes
=
counts
.
notes
===
action
.
annotations
.
length
;
const
haveOnlyPageNotes
=
noteCount
===
action
.
annotations
.
length
;
// If this is the init phase and there are only page notes, select the page notes tab.
if
(
state
.
annotations
.
length
===
0
&&
haveOnlyPageNotes
)
{
return
{
selectedTab
:
uiConstants
.
TAB_NOTES
};
...
...
src/sidebar/store/modules/test/annotations-test.js
View file @
21ecaa76
...
...
@@ -25,6 +25,68 @@ function createStore() {
// in the tests for the whole Redux store
describe
(
'annotations reducer'
,
function
()
{
describe
(
'isWaitingToAnchorAnnotations'
,
()
=>
{
it
(
'returns true if there are unanchored annotations'
,
()
=>
{
const
unanchored
=
Object
.
assign
(
fixtures
.
oldAnnotation
(),
{
$orphan
:
'undefined'
,
});
const
state
=
{
annotations
:
[
unanchored
,
fixtures
.
defaultAnnotation
()],
};
assert
.
isTrue
(
selectors
.
isWaitingToAnchorAnnotations
(
state
));
});
it
(
'returns false if all annotations are anchored'
,
()
=>
{
const
state
=
{
annotations
:
[
Object
.
assign
(
fixtures
.
oldPageNote
(),
{
$orphan
:
false
}),
Object
.
assign
(
fixtures
.
defaultAnnotation
(),
{
$orphan
:
false
}),
],
};
assert
.
isFalse
(
selectors
.
isWaitingToAnchorAnnotations
(
state
));
});
});
describe
(
'noteCount'
,
()
=>
{
it
(
'returns number of page notes'
,
()
=>
{
const
state
=
{
annotations
:
[
fixtures
.
oldPageNote
(),
fixtures
.
oldAnnotation
(),
fixtures
.
defaultAnnotation
(),
],
};
assert
.
deepEqual
(
selectors
.
noteCount
(
state
),
1
);
});
});
describe
(
'annotationCount'
,
()
=>
{
it
(
'returns number of annotations'
,
()
=>
{
const
state
=
{
annotations
:
[
fixtures
.
oldPageNote
(),
fixtures
.
oldAnnotation
(),
fixtures
.
defaultAnnotation
(),
],
};
assert
.
deepEqual
(
selectors
.
annotationCount
(
state
),
2
);
});
});
describe
(
'orphanCount'
,
()
=>
{
it
(
'returns number of orphaned annotations'
,
()
=>
{
const
orphan
=
Object
.
assign
(
fixtures
.
oldAnnotation
(),
{
$orphan
:
true
});
const
state
=
{
annotations
:
[
orphan
,
fixtures
.
oldAnnotation
(),
fixtures
.
defaultAnnotation
(),
],
};
assert
.
deepEqual
(
selectors
.
orphanCount
(
state
),
1
);
});
});
describe
(
'#savedAnnotations'
,
function
()
{
const
savedAnnotations
=
selectors
.
savedAnnotations
;
...
...
src/sidebar/store/test/index-test.js
View file @
21ecaa76
...
...
@@ -4,7 +4,7 @@ const immutable = require('seamless-immutable');
const
storeFactory
=
require
(
'../index'
);
const
annotationFixtures
=
require
(
'../../test/annotation-fixtures'
);
const
metadata
=
require
(
'../../annotation-metadata'
);
const
metadata
=
require
(
'../../
util/
annotation-metadata'
);
const
unroll
=
require
(
'../../../shared/test/util'
).
unroll
;
const
uiConstants
=
require
(
'../../ui-constants'
);
...
...
src/sidebar/templates/sidebar-content.html
View file @
21ecaa76
<selection-tabs
ng-if=
"vm.showSelectedTabs()"
is-waiting-to-anchor-annotations=
"vm.waitingToAnchorAnnotations"
is-loading=
"vm.isLoading()"
selected-tab=
"vm.selectedTab"
total-annotations=
"vm.totalAnnotations"
total-notes=
"vm.totalNotes"
total-orphans=
"vm.totalOrphans"
>
is-loading=
"vm.isLoading()"
>
</selection-tabs>
<search-status-bar
class=
"search-status-bar"
ng-if=
"!vm.isLoading()"
selected-tab=
"vm.selectedTab"
total-annotations=
"vm.totalAnnotations"
total-notes=
"vm.totalNotes"
>
ng-if=
"!vm.isLoading()"
>
</search-status-bar>
<!-- Display error message if direct-linked annotation fetch failed. -->
...
...
src/sidebar/test/build-thread-test.js
View file @
21ecaa76
'use strict'
;
const
buildThread
=
require
(
'../build-thread'
);
const
metadata
=
require
(
'../annotation-metadata'
);
const
metadata
=
require
(
'../
util/
annotation-metadata'
);
// Fixture with two top level annotations, one note and one reply
const
SIMPLE_FIXTURE
=
[
...
...
src/sidebar/annotation-metadata.js
→
src/sidebar/
util/
annotation-metadata.js
View file @
21ecaa76
File moved
src/sidebar/tabs.js
→
src/sidebar/
util/
tabs.js
View file @
21ecaa76
'use strict'
;
// Selectors that calculate the annotation counts displayed in tab headings
// and determine which tab an annotation should be displayed in.
// Functions that determine which tab an annotation should be displayed in.
const
countIf
=
require
(
'./util/array-util'
).
countIf
;
const
metadata
=
require
(
'./annotation-metadata'
);
const
uiConstants
=
require
(
'./ui-constants'
);
const
uiConstants
=
require
(
'.
.
/ui-constants'
);
/**
* Return the tab in which an annotation should be displayed.
...
...
@@ -37,24 +35,7 @@ function shouldShowInTab(ann, tab) {
return
tabForAnnotation
(
ann
)
===
tab
;
}
/**
* Return the counts for the headings of different tabs.
*
* @param {Annotation[]} annotations - List of annotations to display
*/
function
counts
(
annotations
)
{
const
counts
=
{
notes
:
countIf
(
annotations
,
metadata
.
isPageNote
),
annotations
:
countIf
(
annotations
,
metadata
.
isAnnotation
),
orphans
:
countIf
(
annotations
,
metadata
.
isOrphan
),
anchoring
:
countIf
(
annotations
,
metadata
.
isWaitingToAnchor
),
};
return
counts
;
}
module
.
exports
=
{
counts
:
counts
,
shouldShowInTab
:
shouldShowInTab
,
tabForAnnotation
:
tabForAnnotation
,
};
src/sidebar/test/annotation-metadata-test.js
→
src/sidebar/
util/
test/annotation-metadata-test.js
View file @
21ecaa76
'use strict'
;
const
annotationMetadata
=
require
(
'../annotation-metadata'
);
const
fixtures
=
require
(
'./annotation-fixtures'
);
const
fixtures
=
require
(
'.
./../test
/annotation-fixtures'
);
const
unroll
=
require
(
'../../shared/test/util'
).
unroll
;
const
unroll
=
require
(
'../../
../
shared/test/util'
).
unroll
;
const
documentMetadata
=
annotationMetadata
.
documentMetadata
;
const
domainAndTitle
=
annotationMetadata
.
domainAndTitle
;
...
...
src/sidebar/test/tabs-test.js
→
src/sidebar/
util/
test/tabs-test.js
View file @
21ecaa76
'use strict'
;
const
fixtures
=
require
(
'./annotation-fixtures'
);
const
uiConstants
=
require
(
'../ui-constants'
);
const
fixtures
=
require
(
'.
./../test
/annotation-fixtures'
);
const
uiConstants
=
require
(
'../
../
ui-constants'
);
const
tabs
=
require
(
'../tabs'
);
const
unroll
=
require
(
'../../shared/test/util'
).
unroll
;
const
unroll
=
require
(
'../../
../
shared/test/util'
).
unroll
;
describe
(
'tabs'
,
function
()
{
describe
(
'tabForAnnotation'
,
function
()
{
...
...
@@ -83,22 +83,4 @@ describe('tabs', function() {
]
);
});
describe
(
'counts'
,
function
()
{
const
annotation
=
Object
.
assign
(
fixtures
.
defaultAnnotation
(),
{
$orphan
:
false
,
});
const
orphan
=
Object
.
assign
(
fixtures
.
defaultAnnotation
(),
{
$orphan
:
true
,
});
it
(
'counts Annotations and Orphans separately'
,
function
()
{
assert
.
deepEqual
(
tabs
.
counts
([
annotation
,
orphan
],
true
),
{
anchoring
:
0
,
annotations
:
1
,
notes
:
0
,
orphans
:
1
,
});
});
});
});
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