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
59e8b4f6
Unverified
Commit
59e8b4f6
authored
Apr 22, 2020
by
Robert Knight
Committed by
GitHub
Apr 22, 2020
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2038 from hypothesis/remove-frame-connected
Remove `FRAME_CONNECTED` event
parents
389d6aa4
2a6f50bd
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
122 additions
and
110 deletions
+122
-110
events.js
src/sidebar/events.js
+0
-3
features.js
src/sidebar/services/features.js
+15
-17
frame-sync.js
src/sidebar/services/frame-sync.js
+0
-1
groups.js
src/sidebar/services/groups.js
+26
-22
features-test.js
src/sidebar/services/test/features-test.js
+50
-40
groups-test.js
src/sidebar/services/test/groups-test.js
+31
-27
No files found.
src/sidebar/events.js
View file @
59e8b4f6
...
@@ -3,9 +3,6 @@
...
@@ -3,9 +3,6 @@
* on $rootScope
* on $rootScope
*/
*/
export
default
{
export
default
{
// Internal state changes
FRAME_CONNECTED
:
'frameConnected'
,
// Session state changes
// Session state changes
/** The logged-in user changed */
/** The logged-in user changed */
...
...
src/sidebar/services/features.js
View file @
59e8b4f6
...
@@ -12,23 +12,20 @@
...
@@ -12,23 +12,20 @@
import
bridgeEvents
from
'../../shared/bridge-events'
;
import
bridgeEvents
from
'../../shared/bridge-events'
;
import
warnOnce
from
'../../shared/warn-once'
;
import
warnOnce
from
'../../shared/warn-once'
;
import
events
from
'../events
'
;
import
{
watch
}
from
'../util/watch
'
;
// @ngInject
// @ngInject
export
default
function
features
(
$rootScope
,
bridge
,
session
)
{
export
default
function
features
(
bridge
,
session
,
store
)
{
const
_sendFeatureFlags
=
function
()
{
const
currentFlags
=
()
=>
store
.
profile
().
features
;
const
userFeatures
=
session
.
state
.
features
;
const
sendFeatureFlags
=
()
=>
{
bridge
.
call
(
bridgeEvents
.
FEATURE_FLAGS_UPDATED
,
userFeatures
||
{});
bridge
.
call
(
bridgeEvents
.
FEATURE_FLAGS_UPDATED
,
currentFlags
()
||
{});
};
};
// user changed is currently called when we initially load
// Re-send feature flags to connected frames when flags change or a new
// the sidebar and when the user actually logs out/in.
// frame connects.
$rootScope
.
$on
(
events
.
USER_CHANGED
,
_sendFeatureFlags
);
watch
(
store
.
subscribe
,
[
currentFlags
,
()
=>
store
.
frames
()],
()
=>
sendFeatureFlags
()
// send on frame connected as well because the user_changed event
);
// alone might run before the frames ever connected. This will
// provide us the follow up to make sure that the frames get the flags
$rootScope
.
$on
(
events
.
FRAME_CONNECTED
,
_sendFeatureFlags
);
/**
/**
* Returns true if the flag with the given name is enabled for the current
* Returns true if the flag with the given name is enabled for the current
...
@@ -43,17 +40,18 @@ export default function features($rootScope, bridge, session) {
...
@@ -43,17 +40,18 @@ export default function features($rootScope, bridge, session) {
// (see CACHE_TTL in session.js)
// (see CACHE_TTL in session.js)
session
.
load
();
session
.
load
();
if
(
!
session
.
state
.
features
)
{
const
flags
=
currentFlags
();
if
(
!
flags
)
{
// features data has not yet been fetched
// features data has not yet been fetched
return
false
;
return
false
;
}
}
const
features
=
session
.
state
.
features
;
if
(
!
(
flag
in
flags
))
{
if
(
!
(
flag
in
features
))
{
warnOnce
(
'looked up unknown feature'
,
flag
);
warnOnce
(
'looked up unknown feature'
,
flag
);
return
false
;
return
false
;
}
}
return
f
eature
s
[
flag
];
return
f
lag
s
[
flag
];
}
}
return
{
return
{
...
...
src/sidebar/services/frame-sync.js
View file @
59e8b4f6
...
@@ -203,7 +203,6 @@ export default function FrameSync($rootScope, $window, store, bridge) {
...
@@ -203,7 +203,6 @@ export default function FrameSync($rootScope, $window, store, bridge) {
return
;
return
;
}
}
$rootScope
.
$broadcast
(
events
.
FRAME_CONNECTED
);
store
.
connectFrame
({
store
.
connectFrame
({
id
:
info
.
frameIdentifier
,
id
:
info
.
frameIdentifier
,
metadata
:
info
.
metadata
,
metadata
:
info
.
metadata
,
...
...
src/sidebar/services/groups.js
View file @
59e8b4f6
...
@@ -3,6 +3,7 @@ import serviceConfig from '../service-config';
...
@@ -3,6 +3,7 @@ import serviceConfig from '../service-config';
import
{
isReply
}
from
'../util/annotation-metadata'
;
import
{
isReply
}
from
'../util/annotation-metadata'
;
import
{
combineGroups
}
from
'../util/groups'
;
import
{
combineGroups
}
from
'../util/groups'
;
import
{
awaitStateChange
}
from
'../util/state'
;
import
{
awaitStateChange
}
from
'../util/state'
;
import
{
watch
}
from
'../util/watch'
;
const
DEFAULT_ORG_ID
=
'__default__'
;
const
DEFAULT_ORG_ID
=
'__default__'
;
...
@@ -31,7 +32,10 @@ export default function groups(
...
@@ -31,7 +32,10 @@ export default function groups(
const
svc
=
serviceConfig
(
settings
);
const
svc
=
serviceConfig
(
settings
);
const
authority
=
svc
?
svc
.
authority
:
null
;
const
authority
=
svc
?
svc
.
authority
:
null
;
function
getDocumentUriForGroupSearch
()
{
/**
* Return the main document URI that is used to fetch groups associated with
* the site that the user is on.
*/
function
mainUri
()
{
function
mainUri
()
{
const
mainFrame
=
store
.
mainFrame
();
const
mainFrame
=
store
.
mainFrame
();
if
(
!
mainFrame
)
{
if
(
!
mainFrame
)
{
...
@@ -39,6 +43,8 @@ export default function groups(
...
@@ -39,6 +43,8 @@ export default function groups(
}
}
return
mainFrame
.
uri
;
return
mainFrame
.
uri
;
}
}
function
getDocumentUriForGroupSearch
()
{
return
awaitStateChange
(
store
,
mainUri
);
return
awaitStateChange
(
store
,
mainUri
);
}
}
...
@@ -167,11 +173,7 @@ export default function groups(
...
@@ -167,11 +173,7 @@ export default function groups(
});
});
}
}
// The document URI passed to the most recent `GET /api/groups` call in order
let
didSubscribeToUriChanges
=
false
;
// to include groups associated with this page. This is retained to determine
// whether we need to re-fetch groups if the URLs of frames connected to the
// sidebar app changes.
let
documentUri
=
null
;
/*
/*
* Fetch an individual group.
* Fetch an individual group.
...
@@ -193,15 +195,27 @@ export default function groups(
...
@@ -193,15 +195,27 @@ export default function groups(
* The groups that are fetched depend on the current user, the URI of
* The groups that are fetched depend on the current user, the URI of
* the current document, and the direct-linked group and/or annotation.
* the current document, and the direct-linked group and/or annotation.
*
*
* On startup, `load()` must be called to trigger the initial groups fetch.
* Subsequently groups are automatically reloaded if the logged-in user or
* main document URI changes.
*
* @return {Promise<Group[]>}
* @return {Promise<Group[]>}
*/
*/
async
function
load
()
{
async
function
load
()
{
// Step 1: Get the URI of the active document, so we can fetch groups
// Step 1: Get the URI of the active document, so we can fetch groups
// associated with that document.
// associated with that document.
let
documentUri
;
if
(
isSidebar
)
{
if
(
isSidebar
)
{
documentUri
=
await
getDocumentUriForGroupSearch
();
documentUri
=
await
getDocumentUriForGroupSearch
();
}
}
if
(
!
didSubscribeToUriChanges
)
{
didSubscribeToUriChanges
=
true
;
watch
(
store
.
subscribe
,
mainUri
,
()
=>
{
load
();
});
}
// Step 2: Concurrently fetch the groups the user is a member of,
// Step 2: Concurrently fetch the groups the user is a member of,
// the groups associated with the current document and the annotation
// the groups associated with the current document and the annotation
// and/or group that was direct-linked (if any).
// and/or group that was direct-linked (if any).
...
@@ -362,16 +376,6 @@ export default function groups(
...
@@ -362,16 +376,6 @@ export default function groups(
return
load
();
return
load
();
});
});
// refetch the list of groups when document url changes
$rootScope
.
$on
(
events
.
FRAME_CONNECTED
,
()
=>
{
return
getDocumentUriForGroupSearch
().
then
(
uri
=>
{
if
(
documentUri
!==
uri
)
{
documentUri
=
uri
;
load
();
}
});
});
return
{
return
{
all
:
all
,
all
:
all
,
get
:
get
,
get
:
get
,
...
...
src/sidebar/services/test/features-test.js
View file @
59e8b4f6
import
bridgeEvents
from
'../../../shared/bridge-events'
;
import
bridgeEvents
from
'../../../shared/bridge-events'
;
import
events
from
'../../events'
;
import
features
from
'../features'
;
import
features
from
'../features'
;
import
{
$imports
}
from
'../features'
;
import
{
$imports
}
from
'../features'
;
describe
(
'
h:features - sidebar layer
'
,
function
()
{
describe
(
'
sidebar/services/features
'
,
function
()
{
let
fakeBridge
;
let
fakeBridge
;
let
fakeWarnOnce
;
let
fakeWarnOnce
;
let
fakeRootScope
;
let
fakeSession
;
let
fakeSession
;
let
sandbox
;
let
fakeStore
;
beforeEach
(
function
()
{
beforeEach
(
function
()
{
sandbox
=
sinon
.
createSandbox
();
fakeBridge
=
{
fakeBridge
=
{
call
:
sinon
.
stub
(),
call
:
sinon
.
stub
(),
};
};
fakeWarnOnce
=
sinon
.
stub
();
fakeWarnOnce
=
sinon
.
stub
();
fakeRootScope
=
{
eventCallbacks
:
{},
$broadcast
:
sandbox
.
stub
(),
$on
:
function
(
event
,
callback
)
{
this
.
eventCallbacks
[
event
]
=
callback
;
},
};
fakeSession
=
{
fakeSession
=
{
load
:
sinon
.
stub
(),
load
:
sinon
.
stub
(),
state
:
{
};
fakeStore
=
{
subscribe
:
sinon
.
stub
(),
frames
:
sinon
.
stub
().
returns
([]),
profile
:
sinon
.
stub
().
returns
({
features
:
{
features
:
{
feature_on
:
true
,
feature_on
:
true
,
feature_off
:
false
,
feature_off
:
false
,
},
},
},
}
)
,
};
};
$imports
.
$mock
({
$imports
.
$mock
({
...
@@ -46,64 +37,83 @@ describe('h:features - sidebar layer', function () {
...
@@ -46,64 +37,83 @@ describe('h:features - sidebar layer', function () {
afterEach
(
function
()
{
afterEach
(
function
()
{
$imports
.
$restore
();
$imports
.
$restore
();
sandbox
.
restore
();
});
});
function
createService
()
{
return
features
(
fakeBridge
,
fakeSession
,
fakeStore
);
}
describe
(
'flagEnabled'
,
function
()
{
describe
(
'flagEnabled'
,
function
()
{
it
(
'should retrieve features data'
,
function
()
{
it
(
'should retrieve features data'
,
function
()
{
const
features_
=
features
(
fakeRootScope
,
fakeBridge
,
fakeSession
);
const
features_
=
createService
(
);
assert
.
equal
(
features_
.
flagEnabled
(
'feature_on'
),
true
);
assert
.
equal
(
features_
.
flagEnabled
(
'feature_on'
),
true
);
assert
.
equal
(
features_
.
flagEnabled
(
'feature_off'
),
false
);
assert
.
equal
(
features_
.
flagEnabled
(
'feature_off'
),
false
);
});
});
it
(
'should return false if features have not been loaded'
,
function
()
{
it
(
'should return false if features have not been loaded'
,
function
()
{
const
features_
=
features
(
fakeRootScope
,
fakeBridge
,
fakeSession
);
const
features_
=
createService
(
);
//
s
imulate feature data not having been loaded yet
//
S
imulate feature data not having been loaded yet
fakeS
ession
.
state
=
{}
;
fakeS
tore
.
profile
.
returns
({})
;
assert
.
equal
(
features_
.
flagEnabled
(
'feature_on'
),
false
);
assert
.
equal
(
features_
.
flagEnabled
(
'feature_on'
),
false
);
});
});
it
(
'should trigger a refresh of session data'
,
function
()
{
it
(
'should trigger a refresh of session data'
,
function
()
{
const
features_
=
features
(
fakeRootScope
,
fakeBridge
,
fakeSession
);
const
features_
=
createService
(
);
features_
.
flagEnabled
(
'feature_on'
);
features_
.
flagEnabled
(
'feature_on'
);
assert
.
calledOnce
(
fakeSession
.
load
);
assert
.
calledOnce
(
fakeSession
.
load
);
});
});
it
(
'should return false for unknown flags'
,
function
()
{
it
(
'should return false for unknown flags'
,
function
()
{
const
features_
=
features
(
fakeRootScope
,
fakeBridge
,
fakeSession
);
const
features_
=
createService
(
);
assert
.
isFalse
(
features_
.
flagEnabled
(
'unknown_feature'
));
assert
.
isFalse
(
features_
.
flagEnabled
(
'unknown_feature'
));
});
});
});
});
it
(
'should broadcast feature flags to annotation layer based on load/user changes'
,
function
()
{
function
notifyStoreSubscribers
()
{
assert
.
notProperty
(
fakeRootScope
.
eventCallbacks
,
events
.
USER_CHANGED
);
const
subscribers
=
fakeStore
.
subscribe
.
args
.
map
(
args
=>
args
[
0
]);
assert
.
notProperty
(
fakeRootScope
.
eventCallbacks
,
events
.
FRAME_CONNECTED
);
subscribers
.
forEach
(
s
=>
s
());
}
features
(
fakeRootScope
,
fakeBridge
,
fakeSession
);
assert
.
property
(
fakeRootScope
.
eventCallbacks
,
events
.
USER_CHANGED
);
it
(
'should broadcast feature flags to annotator if flags change'
,
()
=>
{
assert
.
property
(
fakeRootScope
.
eventCallbacks
,
events
.
FRAME_CONNECTED
);
createService
(
);
// respond to user changing by broadcasting the feature flags
// First update, with no changes to feature flags.
notifyStoreSubscribers
();
assert
.
notCalled
(
fakeBridge
.
call
);
assert
.
notCalled
(
fakeBridge
.
call
);
fakeRootScope
.
eventCallbacks
[
events
.
USER_CHANGED
]();
// Second update, with changes to feature flags.
fakeStore
.
profile
.
returns
({
features
:
{
feature_on
:
true
,
feature_off
:
true
,
},
});
notifyStoreSubscribers
();
assert
.
calledOnce
(
fakeBridge
.
call
);
assert
.
calledWith
(
assert
.
calledWith
(
fakeBridge
.
call
,
fakeBridge
.
call
,
bridgeEvents
.
FEATURE_FLAGS_UPDATED
,
bridgeEvents
.
FEATURE_FLAGS_UPDATED
,
fakeS
ession
.
state
.
features
fakeS
tore
.
profile
()
.
features
);
);
});
it
(
'should broadcast feature flags to annotator if a new frame connects'
,
()
=>
{
createService
();
// First update, with no changes to frames.
notifyStoreSubscribers
();
assert
.
notCalled
(
fakeBridge
.
call
);
// Second update, with changes to frames.
fakeStore
.
frames
.
returns
([{
uri
:
'https://example.com'
}]);
// respond to frame connections by broadcasting the feature flags
notifyStoreSubscribers
();
fakeRootScope
.
eventCallbacks
[
events
.
FRAME_CONNECTED
]();
assert
.
calledTwice
(
fakeBridge
.
call
);
assert
.
calledWith
(
assert
.
calledWith
(
fakeBridge
.
call
,
fakeBridge
.
call
,
bridgeEvents
.
FEATURE_FLAGS_UPDATED
,
bridgeEvents
.
FEATURE_FLAGS_UPDATED
,
fakeS
ession
.
state
.
features
fakeS
tore
.
profile
()
.
features
);
);
});
});
});
});
src/sidebar/services/test/groups-test.js
View file @
59e8b4f6
import
events
from
'../../events'
;
import
events
from
'../../events'
;
import
fakeReduxStore
from
'../../test/fake-redux-store'
;
import
fakeReduxStore
from
'../../test/fake-redux-store'
;
import
groups
,
{
$imports
}
from
'../groups'
;
import
groups
,
{
$imports
}
from
'../groups'
;
import
{
waitFor
}
from
'../../../test-util/wait'
;
/**
/**
* Generate a truth table containing every possible combination of a set of
* Generate a truth table containing every possible combination of a set of
...
@@ -108,7 +109,7 @@ describe('groups', function () {
...
@@ -108,7 +109,7 @@ describe('groups', function () {
},
},
$on
:
function
(
event
,
callback
)
{
$on
:
function
(
event
,
callback
)
{
if
(
event
===
events
.
USER_CHANGED
||
event
===
events
.
FRAME_CONNECTED
)
{
if
(
event
===
events
.
USER_CHANGED
)
{
this
.
eventCallbacks
[
event
]
=
callback
;
this
.
eventCallbacks
[
event
]
=
callback
;
}
}
},
},
...
@@ -809,7 +810,7 @@ describe('groups', function () {
...
@@ -809,7 +810,7 @@ describe('groups', function () {
});
});
});
});
describe
(
'
calls load on various events
'
,
function
()
{
describe
(
'
automatic re-fetching
'
,
function
()
{
it
(
'refetches groups when the logged-in user changes'
,
()
=>
{
it
(
'refetches groups when the logged-in user changes'
,
()
=>
{
service
();
service
();
...
@@ -819,15 +820,14 @@ describe('groups', function () {
...
@@ -819,15 +820,14 @@ describe('groups', function () {
});
});
context
(
'when a new frame connects'
,
()
=>
{
context
(
'when a new frame connects'
,
()
=>
{
it
(
'should refetch groups if main frame URL has changed'
,
()
=>
{
it
(
'should refetch groups if main frame URL has changed'
,
async
()
=>
{
const
svc
=
service
();
const
svc
=
service
();
fakeStore
.
setState
({
fakeStore
.
setState
({
frames
:
[{
uri
:
'https://domain.com/page-a'
}],
frames
:
[{
uri
:
'https://domain.com/page-a'
}],
});
});
return
svc
await
svc
.
load
();
.
load
()
.
then
(()
=>
{
// Simulate main frame URL change, eg. due to client-side navigation in
// Simulate main frame URL change, eg. due to client-side navigation in
// a single page application.
// a single page application.
fakeApi
.
groups
.
list
.
resetHistory
();
fakeApi
.
groups
.
list
.
resetHistory
();
...
@@ -835,27 +835,31 @@ describe('groups', function () {
...
@@ -835,27 +835,31 @@ describe('groups', function () {
frames
:
[{
uri
:
'https://domain.com/page-b'
}],
frames
:
[{
uri
:
'https://domain.com/page-b'
}],
});
});
return
fakeRootScope
.
eventCallbacks
[
events
.
FRAME_CONNECTED
]();
await
waitFor
(()
=>
fakeApi
.
groups
.
list
.
callCount
>
0
);
})
.
then
(()
=>
{
assert
.
calledOnce
(
fakeApi
.
groups
.
list
);
assert
.
calledOnce
(
fakeApi
.
groups
.
list
);
});
});
});
it
(
'should not refetch groups if main frame URL has not changed'
,
()
=>
{
it
(
'should not refetch groups if main frame URL has not changed'
,
async
()
=>
{
const
svc
=
service
();
const
svc
=
service
();
fakeStore
.
setState
({
fakeStore
.
setState
({
frames
:
[{
uri
:
'https://domain.com/page-a'
}],
frames
:
[{
uri
:
'https://domain.com/page-a'
}],
});
});
return
svc
.
load
()
await
svc
.
load
();
.
then
(()
=>
{
return
fakeRootScope
.
eventCallbacks
[
events
.
FRAME_CONNECTED
]();
})
.
then
(()
=>
{
assert
.
calledOnce
(
fakeApi
.
groups
.
list
);
assert
.
calledOnce
(
fakeApi
.
groups
.
list
);
// A new frame connects, but the main frame URI remains the same.
fakeApi
.
groups
.
list
.
resetHistory
();
fakeStore
.
setState
({
frames
:
[
{
uri
:
'https://domain.com/page-a'
},
{
uri
:
'https://domain.com/iframe-b'
},
],
});
});
await
new
Promise
(
resolve
=>
setTimeout
(
resolve
,
1
));
assert
.
notCalled
(
fakeApi
.
groups
.
list
);
});
});
});
});
});
});
...
...
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