Skip to content

Commit c2a3f7a

Browse files
authored
1.11 (#71)
* Remove access to backing gsheet and fix submitter name capture. * update read.me
1 parent eb9a5dd commit c2a3f7a

File tree

8 files changed

+351
-477
lines changed

8 files changed

+351
-477
lines changed

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,24 @@ The chrome extension is used by the ClinGen curation workflow (link) ...
88
This "main" branch is for the v2.x which split from v1.x after 1.9.6. The latest changes to v1.x can be found in the 1.10 branch.
99

1010
## Release Notes
11-
### v1.10 changes (see branch 1.10 for code)
11+
### v1.11 changes
12+
* Changed data repository google sheet to prevent user direct access in order to prevent user's from changing data after capture.
13+
* Fixed bug in capturing submitter name introduced in v1.10.
14+
15+
### v1.10 changes
1216
This version required some considerable modifications to deal with the html changes to the ClinVar HTML in handling the new section at the bottom called "Flagged Submissions".
1317
* Chrome extension broke due to new "Flagged Submission" UI. [#69](https://github.com/clingen-data-model/clinvar-curation-input-tool/issues/69)
1418
* In the chrome extension change 'non-contributory' to 'flagging candidate' [#68](https://github.com/clingen-data-model/clinvar-curation-input-tool/issues/68)
1519

20+
### v1.9.8 changes
21+
* Update Non-contributory category headings (missed in 1.9.7) [#57](https://github.com/clingen-data-model/clinvar-scv-curator-ext/issues/57)
22+
23+
### v1.9.7 changes
24+
* Modify text of several Non-contributory reasons (and update historical data to match modified text) [#58](https://github.com/clingen-data-model/clinvar-scv-curator-ext/issues/58)
25+
* Update Non-contributory action reasons (remove some, modify text of others) [#57](https://github.com/clingen-data-model/clinvar-scv-curator-ext/issues/57)
26+
* Remove Follow Up option [#57](https://github.com/clingen-data-model/clinvar-scv-curator-ext/issues/57)
27+
* Remove ability to annotate a VCV [#57](https://github.com/clingen-data-model/clinvar-scv-curator-ext/issues/57)
28+
1629
### v2.0.2 changes
1730
* Updated category headings that were missed in the 2.0.1 release [#57](https://github.com/clingen-data-model/clinvar-scv-curator-ext/issues/57)
1831

scvc/background.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<html>
2+
<head>
3+
<title></title>
4+
<script src="background.js"></script>
5+
</head>
6+
<body></body>
7+
<script src="https://apis.google.com/js/client.js?onload=onGAPILoad"></script>
8+
</html>

scvc/background.js

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
const API_KEY = 'AIzaSyADs3YruA9LTaRjc7hS94SQvKbQXJSpMp0';
2+
const DISCOVERY_DOCS = ["https://sheets.googleapis.com/$discovery/rest?version=v4"];
3+
4+
// Create a rule that will show the page action when the conditions are met.
5+
const kMatchRule = {
6+
// Declare the rule conditions.
7+
conditions: [new chrome.declarativeContent.PageStateMatcher({
8+
pageUrl: {hostEquals: 'www.ncbi.nlm.nih.gov',
9+
pathContains: 'variation'}})],
10+
// Shows the page action when the condition is met.
11+
actions: [new chrome.declarativeContent.ShowPageAction()]
12+
}
13+
14+
// Register the runtime.onInstalled event listener.
15+
chrome.runtime.onInstalled.addListener(function() {
16+
// Overrride the rules to replace them with kMatchRule.
17+
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
18+
chrome.declarativeContent.onPageChanged.addRules([kMatchRule]);
19+
});
20+
});
21+
22+
function onGAPILoad() {
23+
gapi.client.init({
24+
apiKey: API_KEY,
25+
discoveryDocs: DISCOVERY_DOCS,
26+
}).then(function () {
27+
console.log('gapi initialized');
28+
}, function(error) {
29+
console.log('error on initialize', error);
30+
alert('error on initialize...'+error);
31+
});
32+
}
33+
34+
// Listen for messages from popup.js
35+
chrome.extension.onMessage.addListener(
36+
function(request, sender, sendResponse) {
37+
38+
// verify that the request originated from the chrome-extension popup.html form
39+
if (!sender.url.includes("chrome-extension")) return false;
40+
41+
// Get the users email
42+
chrome.identity.getProfileUserInfo(function(userinfo){
43+
if (!userinfo.email) {
44+
alert("No email captured. Please set your browser profile to sync with your google account to bypass this message in the future.");
45+
}
46+
else {
47+
request.user_email=userinfo.email;
48+
}
49+
});
50+
51+
// Get the token
52+
chrome.identity.getAuthToken({interactive: true}, function(token) {
53+
54+
// Set scvc auth token
55+
gapi.auth.setToken({
56+
'access_token': token,
57+
});
58+
59+
let body = {};
60+
let range = "";
61+
62+
if (request.scv) {
63+
range = request.scv_range;
64+
body = {values: [[
65+
request.vcv,
66+
request.name,
67+
request.scv,
68+
request.submitter,
69+
request.interp,
70+
request.action,
71+
request.reason,
72+
request.notes,
73+
new Date(), // Timestamp
74+
request.submitter_id,
75+
request.variation_id,
76+
request.user_email
77+
]]};
78+
}
79+
80+
// Append values to the spreadsheet
81+
gapi.client.sheets.spreadsheets.values.append({
82+
spreadsheetId: request.spreadsheet,
83+
range: range,
84+
valueInputOption: 'USER_ENTERED',
85+
resource: body
86+
}).then((response) => {
87+
// On success
88+
console.log(`${response.result.updates.updatedCells} cells appended.`)
89+
sendResponse({success: true});
90+
}, function(error) {
91+
// On error
92+
console.log('error appending values', error)
93+
alert("Error appending values to google sheet...\n"+JSON.stringify(error));
94+
});
95+
})
96+
97+
// Wait for response
98+
return true;
99+
}
100+
);

scvc/content.js

Lines changed: 58 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
const SPREADSHEET_ID = '1pzuWR409vSmoFX9inmoU6el6vjG0SniB1KrxWLeVpaA'; // production
2-
// const SPREADSHEET_ID = '1W1rbALtDt9CmhoTsLUYJEYKOeakzWAlZrtIhGSUl5II'; // dev copy
1+
//const SPREADSHEET_ID = '1pzuWR409vSmoFX9inmoU6el6vjG0SniB1KrxWLeVpaA';
2+
const SPREADSHEET_ID = '1dUnmBZSnz3aeB948b7pIq0iT7_FuCDvtv6FXaVsNcOo';
33
const SCV_RANGE = 'SCVs';
44
const VCV_RANGE = 'VCVs';
55

@@ -13,30 +13,30 @@ chrome.runtime.sendMessage({
1313
// Listen for messages from the popup.
1414
chrome.runtime.onMessage.addListener((msg, sender, response) => {
1515

16-
// console.log('===== CONTENT.js event recieved: msg:', msg, new Date().getTime())
17-
// First, validate the message's structure.
18-
if ((msg.from === 'popup') && (msg.subject === 'DOMInfo')) {
19-
function getMatch(text, re, grp) {
20-
var result;
21-
result = text.match(re);
22-
if (result === null) {
23-
return "";
24-
}
25-
return result[grp];
26-
}
27-
// Collect the necessary data.
28-
var cond_origin_re = /(.*)\nAllele origin: (.*)/i;
29-
var review_method_re = /(.*)\n.*\n*Method: (.*)/i;
30-
var subm_scv_re = /(.*)(\n.*)*\nAccession: (.*)\nFirst in ClinVar: (.*)\nLast updated: (.*)/i;
31-
var interp_re = /(.*)\n\((.*)\)/i;
32-
var subm_id_re = /\/clinvar\/submitters\/([0-9]*)\//i;
16+
// First, validate the message's structure.
17+
if ((msg.from === 'popup') && (msg.subject === 'DOMInfo')) {
3318

34-
var vcv_interp_re = /<dt>Interpretation:<\/dt>\s*<dd.*>\s*(.*)[\x200B]*\s*<p>/i
35-
var vcv_revstat_re = /<dt>Review status:<\/dt>\s*<dd>.*(practice guideline|reviewed by expert panel|no assertion provided|no interpretation for the single variant|criteria provided, multiple submitters, no conflicts|criteria provided, single submitter|criteria provided, conflicting interpretations|no assertion criteria provided).*\<\/dd>\s*/is
36-
var vcv_most_recent_re = /<dt>Most recent Submission:<\/dt>\s*<dd>\s*(\w{3} \d+\, \d{4})\s*<\/dd>/i
37-
var vcv_last_eval_re = /<dt>Last evaluated:<\/dt>\s*<dd>\s*(\w{3} \d+\,\d{4})\s*<\/dd>\s*/i
38-
var vcv_accession_re = /<dt>Accession:<\/dt>\s*<dd>\s*(VCV[0-9]*\.[0-9]*)\s*<\/dd>\s*/i
39-
var vcv_variation_id_re = /<dt>Variation ID:<\/dt>\s*<dd>\s*(\d+)\s*<\/dd>\s*/i
19+
function getMatch(text, re, grp) {
20+
var result;
21+
result = text.match(re);
22+
if (result === null) {
23+
return "";
24+
}
25+
return result[grp];
26+
}
27+
28+
// Collect the necessary data.
29+
var cond_origin_re = /\W*Allele origin:.*?(\w+([\,\s]+\w+)*)/is;
30+
var review_method_re = /(practice guideline|reviewed by expert panel|no assertion provided|no interpretation for the single variant|criteria provided, multiple submitters, no conflicts|criteria provided, single submitter|criteria provided, conflicting interpretations|no assertion criteria provided|Flagged submission)\s(Method:\s([\w\,\s]+))*/is;
31+
var subm_scv_re = /\W*"https:\/\/www\.ncbi\.nlm\.nih\.gov\/\/clinvar\/submitters\/(\d+)\/">(.+)<\/a>.*?Accession:.*?(SCV\d+\.\d+).*?First in ClinVar:\W(\w+\s\d+\,\s\d+).*?Last updated:.*?(\w+\s\d+\,\s\d+)/is;
32+
var interp_re = /\W*(\w+([\s\/\-\,]*\w+)*).*?\(([\w\s\,\-]+)\)/is;
33+
34+
var vcv_interp_re = /Interpretation:.*?<dd.*?>.*?(\w+([\s\/\-\,]*\w+)*)/is;
35+
var vcv_revstat_re = /Review status:.*?(<[^>]+>[^<]*?)*?(\w+([\,\s]+\w+)*)/is;
36+
var vcv_most_recent_re = /Most recent Submission:.*?(\w+\s\d+\,\s\d+)/is;
37+
var vcv_last_eval_re = /Last evaluated:.*?(\w+\s\d+\,\s\d+)/is;
38+
var vcv_accession_re = /Accession:.*?(VCV\d+\.\d+)/is;
39+
var vcv_variation_id_re = /Variation ID:.*?(\d+)/is;
4040

4141
var domInfo = {
4242
spreadsheet: SPREADSHEET_ID,
@@ -52,44 +52,41 @@ chrome.runtime.onMessage.addListener((msg, sender, response) => {
5252
row: []
5353
};
5454

55-
var variantBox = document.evaluate(".//div[contains(concat(' ', @class, ' '),' variant-box ')]/dl", document, null, XPathResult.ANY_TYPE, null);
56-
var variantBoxHTML = variantBox.iterateNext().innerHTML;
57-
domInfo.vcv = getMatch(variantBoxHTML, vcv_accession_re, 1);
58-
domInfo.vcv_review = getMatch(variantBoxHTML, vcv_revstat_re, 1);
59-
domInfo.vcv_most_recent = getMatch(variantBoxHTML, vcv_most_recent_re, 1);
60-
domInfo.vcv_eval_date = getMatch(variantBoxHTML, vcv_last_eval_re, 1);
61-
domInfo.variation_id = getMatch(variantBoxHTML, vcv_variation_id_re, 1);
62-
domInfo.vcv_interp = getMatch(variantBoxHTML, vcv_interp_re, 1);
55+
var variantBox = document.evaluate(".//div[contains(concat(' ', @class, ' '),' variant-box ')]/dl", document, null, XPathResult.ANY_TYPE, null );
56+
var variantBoxHTML = variantBox.iterateNext().innerHTML;
6357

64-
domInfo.name = document.querySelectorAll('#id_first h4')[0].innerText;
65-
var scvarray = document.querySelectorAll('#assertion-list tbody tr');
66-
scvarray.forEach(myFunction);
58+
domInfo.vcv = getMatch(variantBoxHTML, vcv_accession_re, 1);
59+
domInfo.vcv_review = getMatch(variantBoxHTML, vcv_revstat_re, 2);
60+
domInfo.vcv_most_recent = getMatch(variantBoxHTML, vcv_most_recent_re, 1);
61+
domInfo.vcv_eval_date = getMatch(variantBoxHTML, vcv_last_eval_re, 1);
62+
domInfo.variation_id = getMatch(variantBoxHTML, vcv_variation_id_re, 1);
63+
domInfo.vcv_interp = getMatch(variantBoxHTML, vcv_interp_re, 1);
6764

68-
function myFunction(value, index, array) {
69-
var interp_match = value.cells[0].innerText.match(interp_re);
70-
var review_method_match = value.cells[1].innerText.match(review_method_re);
71-
var cond_origin_match = value.cells[2].innerText.match(cond_origin_re);
72-
var subm_scv_match = value.cells[3].innerText.match(subm_scv_re);
73-
var subm_id = value.cells[3].innerHTML.match(subm_id_re)[1];
65+
domInfo.name = document.querySelectorAll('#id_first h4')[0].innerText;
66+
var scvarray = document.querySelectorAll('#assertion-list tbody tr');
67+
68+
scvarray.forEach(myFunction);
7469

75-
domInfo.row.push({
76-
submitter: subm_scv_match[1],
77-
scv: subm_scv_match[3],
78-
submitter_id: subm_id,
79-
subm_date: subm_scv_match[5],
80-
condition: cond_origin_match[1],
81-
origin: cond_origin_match[2],
82-
review: review_method_match[1],
83-
method: review_method_match[2],
84-
interp: interp_match[1],
85-
eval_date: interp_match[2]
86-
});
87-
}
88-
// Directly respond to the sender (popup),
89-
// through the specified callback.
90-
response(domInfo);
91-
}
92-
93-
return true;
70+
function myFunction(value, index, array) {
71+
var interp_match = value.cells[0].innerHTML.match(interp_re);
72+
var review_method_match = value.cells[1].innerText.match(review_method_re);
73+
var cond_origin_match = value.cells[2].innerHTML.match(cond_origin_re);
74+
var subm_scv_match = value.cells[3].innerHTML.match(subm_scv_re);
9475

76+
domInfo.row.push({
77+
submitter_id: subm_scv_match[1],
78+
submitter: subm_scv_match[2],
79+
scv: subm_scv_match[3],
80+
subm_date: subm_scv_match[5],
81+
origin: cond_origin_match[1],
82+
review: review_method_match[1],
83+
method: review_method_match[3] == undefined ? "" : review_method_match[3],
84+
interp: interp_match[1],
85+
eval_date: interp_match[3]
86+
});
87+
}
88+
// Directly respond to the sender (popup),
89+
// through the specified callback.
90+
response(domInfo);
91+
}
9592
});

scvc/manifest.json

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,29 @@
11
{
2-
"name": "ClinVar Curator",
3-
"version": "2.0.2",
4-
"description": "Capture SCV notes from ClinVar variant screen in a google sheet.",
5-
"manifest_version": 3,
6-
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwC5g4vkDlMPFTsByPnG9WI9lY+IPWddES8SK3cxCuBQE5qSdgEgtDhrRLhXSvcIdUUCDwD7JzEPdQ0IhC3APwsKQJPQlDRweZvyFaTJOm6r5Blp3HvLphDuKZQwUoEzMuXK7IAby05kXPZTMSHas+0m00hHoR8ls//tqKoYt7N/lVj6Mry6nSpr5wFU17HPO8MksyxFlNDhu5OYcgOdTNjUiWthjZ8Xxd0ajdaR1QRoqVCQduUTSAzeptQ1+zYZtEX7+HF8jfZqc5BQDa5GoCuDyTvFvQAHl3Phz3zMWpvcGWR3jCMHD5zthiO8NKX+h2fXbGGrYhuwtQmHLWmTAsQIDAQAB",
7-
"oauth2": {
8-
"client_id": "974091131481-ffhgjpl8vh91e5qber2486eikrhf42ec.apps.googleusercontent.com",
9-
"scopes": ["https://www.googleapis.com/auth/spreadsheets"]
10-
},
11-
"content_security_policy": {
12-
"extension_pages": "script-src 'self'; object-src 'self'"
13-
},
14-
"action": {
15-
"default_title": "Clinvar Curator",
16-
"default_popup": "popup.html"
17-
},
18-
"background": {
19-
"service_worker": "service-worker.js",
20-
"type": "module"
21-
},
22-
"permissions": [
23-
"identity", "identity.email", "storage", "declarativeContent", "tabs"
24-
],
25-
"host_permissions": ["https://www.ncbi.nlm.nih.gov/clinvar/variation/*"],
26-
"content_scripts": [{
27-
"matches": ["https://www.ncbi.nlm.nih.gov/clinvar/variation/*"],
28-
"js": ["content.js"],
29-
"run_at": "document_end",
30-
"all_frames": false
31-
}]
2+
"name": "ClinVar Curator",
3+
"version": "1.11",
4+
"description": "Capture SCV notes from ClinVar variant screen in a google sheet.",
5+
"manifest_version": 2,
6+
"key" : "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwC5g4vkDlMPFTsByPnG9WI9lY+IPWddES8SK3cxCuBQE5qSdgEgtDhrRLhXSvcIdUUCDwD7JzEPdQ0IhC3APwsKQJPQlDRweZvyFaTJOm6r5Blp3HvLphDuKZQwUoEzMuXK7IAby05kXPZTMSHas+0m00hHoR8ls//tqKoYt7N/lVj6Mry6nSpr5wFU17HPO8MksyxFlNDhu5OYcgOdTNjUiWthjZ8Xxd0ajdaR1QRoqVCQduUTSAzeptQ1+zYZtEX7+HF8jfZqc5BQDa5GoCuDyTvFvQAHl3Phz3zMWpvcGWR3jCMHD5zthiO8NKX+h2fXbGGrYhuwtQmHLWmTAsQIDAQAB",
7+
"oauth2": {
8+
"client_id": "974091131481-ffhgjpl8vh91e5qber2486eikrhf42ec.apps.googleusercontent.com",
9+
"scopes":["https://www.googleapis.com/auth/spreadsheets"]
10+
},
11+
"content_security_policy": "script-src 'self' https://apis.google.com/; object-src 'self'",
12+
"page_action": {
13+
"default_title": "Clinvar Curator",
14+
"default_popup": "popup.html"
15+
},
16+
"background": {
17+
"page": "background.html",
18+
"persistent": true
19+
},
20+
"permissions": [
21+
"https://www.ncbi.nlm.nih.gov/clinvar/variation/*","identity", "identity.email", "storage", "declarativeContent"
22+
],
23+
"content_scripts": [{
24+
"matches": ["https://www.ncbi.nlm.nih.gov/clinvar/variation/*"],
25+
"js": ["content.js"],
26+
"run_at": "document_end",
27+
"all_frames": false
28+
}]
3229
}

scvc/popup.html

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
<body class="p-2" style="width:600px;">
1313

1414
<div class="container">
15-
<div class="row bg-primary text-white">
15+
<!-- <div class="row bg-primary text-white">
1616
<div class="col"><a href="#" id="gsheetlink" class="text-white">Google Sheet</a></div>
1717
<div class="col small text-right text-white">(right click to open in a new window)</div>
18-
</div>
18+
</div> -->
1919
<div class="row bg-primary text-white px-2">
2020
<h4 id="vcvid">VCV ID</h4>
2121
</div>
@@ -25,6 +25,7 @@ <h6 id="name">Variant Name</h6>
2525

2626
<div class="row p-2 border border-primary border-bottom-0">
2727
<div class="form-group">
28+
<label for="scvselect">Select an SCV</label>
2829
<label for="scvselect">Select an SCV</label>
2930
<select id="scvselect" name="scvselect" class="form-control" >
3031
<option selected value="">Choose...</option>
@@ -71,7 +72,6 @@ <h6 id="name">Variant Name</h6>
7172
<input type="hidden" id="submitter" name="submitter"/>
7273
<input type="hidden" id="submitter_id" name="submitter_id"/>
7374
<input type="hidden" id="subm_date" name="subm_date"/>
74-
<input type="hidden" id="condition" name="condition"/>
7575
<input type="hidden" id="origin" name="origin"/>
7676
<input type="hidden" id="review" name="review"/>
7777
<input type="hidden" id="method" name="method"/>
@@ -95,33 +95,9 @@ <h6 id="name">Variant Name</h6>
9595
<select id="action" name="action" class="form-control" disabled>
9696
<option selected value="">Choose...</option>
9797
<option id="no-chg-opt" value="No Change">No Change</option>
98-
<!-- <option id="follow-up-opt" value="Follow Up">Follow Up</option> -->
99-
<option id="non-contrib-opt" value="Non-contributory">Non-contributory</option>
100-
<!-- <option id="override-opt" value="Override">Override</option> -->
98+
<option id="non-contrib-opt" value="Flagging Candidate">Flagging Candidate</option>
10199
</select>
102100
</div>
103-
104-
<!-- NOTE: commenting out the Override option since rel 1.9.6
105-
<div id="override" class="col-sm">
106-
<div class="row">
107-
<label for="override-field">Override Field</label>
108-
<select id="override-field" name="override-field" class="form-control" disabled>
109-
<option selected value="">Choose...</option>
110-
<option value="Allele Origin">Allele Origin</option>
111-
<option value="Collection Method">Collection Method</option>
112-
<option value="Condition">Condition</option>
113-
<option value="Inheritance">Inheritance</option>
114-
<option value="Review Status">Review Status</option>
115-
<option value="Significance">Significance</option>
116-
<option value="Other">Other (see notes)...</option>
117-
</select>
118-
</div>
119-
<div class="row">
120-
<label for="override-value">New Value</label>
121-
<input id="override-value" name="override-value" class="form-control" disabled>
122-
</div>
123-
</div>
124-
-->
125101
</div>
126102
</div>
127103

0 commit comments

Comments
 (0)