Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Atlas Cohort Definition Validation Feature #2593

Draft
wants to merge 50 commits into
base: master
Choose a base branch
from
Draft
Changes from 1 commit
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
3d9cea1
Merge Annotation V2 changes
charhart Feb 1, 2021
a2261d1
Merge pull request #1 from cahilton/annotation-v2
charhart Feb 9, 2021
d5a2b3a
adding validation files, Also added Validation tab back to cohort-def…
Mar 8, 2021
45a2e06
adding more files that needed merged in
Mar 8, 2021
07cf6ab
small fixes for validationTool creation
Mar 8, 2021
8b91a5a
fixed indentation, removed unecessary tags
Mar 9, 2021
f5c95c2
adding lines to gitignore to ignore resultant files when building bro…
Mar 23, 2021
9602001
Cleanup JS errors on validationtool; call validationTool as observable
charhart Mar 24, 2021
10ceb01
revert canEdit change
charhart Mar 24, 2021
45928f8
Add annotation linking to sample UI
charhart May 18, 2021
7971ed1
rename annotationSetId
charhart May 18, 2021
4f249df
on validation page, go directly to question set screen
charhart May 19, 2021
570820b
progress on validate page - add list
charhart May 20, 2021
277e651
progress on validate page - improvements to question set UI
charhart May 21, 2021
ed475c9
annotations - check for results.
charhart May 21, 2021
d6eac91
annotations - fix toggle issue on annotations
charhart May 21, 2021
0f1d8b0
annotations - fix resize issue on annotation widget
charhart May 24, 2021
083e319
annotations - fix observable display issue
charhart May 24, 2021
4995883
annotations - fix observable display issue
charhart May 24, 2021
32a5790
annotations - fix observable init issue
charhart May 24, 2021
a9cc5e6
annotations - fix saving question set
charhart May 25, 2021
8b8ac5d
annotations - fix creating study behavior; show annotation window by …
charhart May 28, 2021
19730fd
fix next / last validation annotation
charhart Jun 7, 2021
0ecc46b
add view to show annotation study results
charhart Aug 5, 2021
644804c
updates to profile annotation buttons
charhart Aug 5, 2021
3291c6b
add loading of previously saved items
charhart Aug 13, 2021
a985a46
update sampleName to cohortSampleId
charhart Aug 13, 2021
207da60
add launch study window from sample window
charhart Aug 14, 2021
c74f72a
fix question form
charhart Aug 15, 2021
4dd8583
make case questions false by default
charhart Aug 15, 2021
ce6b86a
fix annotation set launching
charhart Aug 15, 2021
76788a2
view for question sets
charhart Aug 16, 2021
43c9d6e
disabled delete for now
charhart Aug 16, 2021
51066d6
add create study window on validation window from question sets
charhart Aug 16, 2021
1d65d57
fix linking samples from question sets on validation
charhart Aug 16, 2021
360d00f
fix profile launching with question set id route
charhart Aug 17, 2021
37b7090
add answer value and answer text on study results
charhart Aug 17, 2021
5d911ea
add date and numeric types
charhart Aug 18, 2021
cba5283
fix number annotation type
charhart Aug 18, 2021
284406f
add button/functionality for deleting question sets
charhart Aug 20, 2021
d40b879
Updated alert wording
jduke99 Aug 20, 2021
e1beb24
rename case status to case question on annotation tool
charhart Aug 20, 2021
6b85ce1
Merge branch 'master' of https://github.com/cahilton/Atlas
charhart Aug 20, 2021
925cc6d
fix route issue
charhart Aug 21, 2021
dc8b177
merge latest from OHDSI Atlas master; fix conflicts in cohort-definit…
charhart Aug 22, 2021
ed91892
fixes / testing after updates to corresponding WebAPI feature
charhart Aug 23, 2021
e442811
minor code cleanup on feature specific JS files
charhart Aug 23, 2021
dad58ca
Merge remote-tracking branch 'remotes/upstream/master' into annotatio…
chrisknoll Nov 8, 2021
290d805
Updated end points to 'annotation'.
chrisknoll Nov 10, 2021
70f116b
Merge pull request #2 from cahilton/annotation-cknoll
charhart Nov 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add launch study window from sample window
charhart committed Aug 14, 2021
commit 207da600abd4e7629b5b92ef100523a826db23d1
2 changes: 1 addition & 1 deletion js/pages/characterizations/routes.js
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ define(
router.setCurrentView('characterizations-list');
});
}),
'cc/characterizations/:id:': characterizationViewEdit,
'c/:id:': characterizationViewEdit,
'cc/characterizations/:id:/:section:': characterizationViewEdit,
'cc/characterizations/:id:/:section:/:subId:': characterizationViewEdit, // for executions
'cc/feature-analyses': new AuthorizedRoute(() => {
142 changes: 105 additions & 37 deletions js/pages/cohort-definitions/cohort-definition-manager.js
Original file line number Diff line number Diff line change
@@ -194,6 +194,7 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html',
class CohortDefinitionManager extends AutoBind(Clipboard(Page)) {
constructor(params) {
super(params);
const self = this;
this.pollTimeoutId = null;
this.authApi = authApi;
this.config = config;
@@ -237,7 +238,7 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html',
this.isFeMaleSample=ko.observable(false);
this.isOtherGenderSample=ko.observable(false);
//error state
this.sampleNameError=ko.pureComputed(() => this.sampleName().trim() == "");
this.sampleNameError=ko.pureComputed(() => this.sampleName().trim() === "");
this.patientCountError=ko.pureComputed(() => !(this.patientCount() > 0)); // this works because null == 0
this.isAgeRange =ko.pureComputed(() => ['between','notBetween'].includes(this.sampleAgeType()));
this.firstAgeError = ko.pureComputed(() => this.firstAge() != null && this.firstAge() < 0);
@@ -256,6 +257,21 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html',

//validation input value

this.selectedSampleId = ko.observable('');
this.selectedSampleName = ko.observable('');
this.sampleDataLoading = ko.observable(false);
this.sampleData =ko.observableArray([]);
this.sampleList = ko.observableArray();

// validation samples

this.annotationSets = ko.observableArray([]);
this.annotationLinkShown = ko.observable(false);
this.annotationSetsLoading = ko.observable(false);
this.isAnnotationSetLinking = ko.observable(false);
this.isAnnotationSetLoading = ko.observable(false);
this.annotationSampleId = ko.observable('');

//sample list
this.sampleListCols = [
{
@@ -294,7 +310,7 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html',
}
}
];
this.sampleList = ko.observableArray();


// Sample data table
this.sampleCols = [
@@ -315,19 +331,6 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html',
}
];

this.selectedSampleId = ko.observable('');
this.selectedSampleName = ko.observable('');
this.sampleDataLoading = ko.observable(false);
this.sampleData =ko.observableArray([]);

// validation samples

this.annotationSets = ko.observableArray([]);
this.annotationLinkShown = ko.observable(false);
this.annotationSetsLoading = ko.observable(false);
this.isAnnotationSetLinking = ko.observable(false);
this.annotationSampleId = ko.observable('');

this.annotationSetCols = [
{
title: 'ID',
@@ -344,8 +347,11 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html',
{
title: 'Actions',
sortable: false,
render: function() {
return `<button class="btn btn-primary btn-sm annotation-link-btn" title="Link annotation set">Create Study</button><span class="annotation-link-status"></span>`
data: 'id',
render: (d) => {
return `<button class="btn btn-primary btn-sm annotation-link-btn" title="View annotation set">Launch Study</button><span class="annotation-link-status"></span>`;


}
}
];
@@ -1715,13 +1721,16 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html',
this.annotationLinkShown(true);
this.annotationSetsLoading(true);
this.annotationSampleId(sampleId);

this.loadAnnotationSets(cohortDefinitionId)
.then(res => {
this.showAnnotationDataTable(res);
})
.finally(() => {
this.annotationSetsLoading(false);
});


} else {
this.fetchSampleData({sampleId, sourceKey, cohortDefinitionId});
}
@@ -1775,29 +1784,88 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html',
this.isAnnotationSetLinking(true);
const btn = e.target;
const status = btn.nextSibling;
status.textContent = "Retrieving study information...";
btn.disabled = true;
status.textContent = "Creating study...";
annotationService.linkAnnotationToSamples({
'sampleId': sampleId,
'cohortDefinitionId': cohortDefinitionId,
'sourceKey': sourceKey,
'annotationSetId': d.id
})
.then(res => {
status.textContent = "Study successfully created!";
console.log('posted annotation sample link');
console.log(res);
annotationService.getSetsBySampleId(sampleId)
.then((items) => {
return items.includes(d['id']);
})
.catch(error=>{
console.error(error);
status.textContent = "Error creating study!";
btn.disabled = false;
alert('Error linking sample to annotations. Please try again later.');
})
.finally(() => {
this.isAnnotationSetLinking(false);
this.annotationLinkShown(false);
.then((linked) => {
if (linked) {
status.textContent = "Launching study...";
annotationService.getAnnotationsBySampleIdSetId(sampleId, d.id)
.then((items) => {
if (items.length > 0) {
window.location = `#/profiles/${sourceKey}/${items[0].subjectId}/${cohortDefinitionId}/${sampleId}`;
location.reload();
} else {
console.error(error);
status.textContent = "Error launching study!";
btn.disabled = false;
alert('Error launching sample to annotations. Please try again later.');
}
})
.catch(error=>{
console.error(error);
status.textContent = "Error launching study!";
btn.disabled = false;
alert('Error launching sample to annotations. Please try again later.');
})
.finally(() => {
this.isAnnotationSetLinking(false);
this.annotationLinkShown(false);
})
}
else {
status.textContent = "Creating study...";
annotationService.linkAnnotationToSamples({
'sampleId': sampleId,
'cohortDefinitionId': cohortDefinitionId,
'sourceKey': sourceKey,
'annotationSetId': d.id
})
.then(res => {
status.textContent = "Launching Study...";
console.log('posted annotation sample link');
console.log(res);
annotationService.getAnnotationsBySampleIdSetId(sampleId, d.id)
.then((items) => {
if (items.length > 0) {
window.location = `#/profiles/${sourceKey}/${items[0].subjectId}/${cohortDefinitionId}/${sampleId}`;
location.reload();
} else {
console.error(error);
status.textContent = "Error launching study!";
btn.disabled = false;
alert('Error launching sample to annotations. Please try again later.');
}
})
.catch(error=>{
console.error(error);
status.textContent = "Error launching study!";
btn.disabled = false;
alert('Error launching sample to annotations. Please try again later.');
})
.finally(() => {
this.isAnnotationSetLinking(false);
this.annotationLinkShown(false);
})
})
.catch(error=>{
console.error(error);
status.textContent = "Error creating study!";
btn.disabled = false;
alert('Error linking sample to annotations. Please try again later.');
})
.finally(() => {
this.isAnnotationSetLinking(false);
this.annotationLinkShown(false);
});
}
});



}
}

4 changes: 3 additions & 1 deletion js/pages/profiles/annotation/view-models/Annotation.js
Original file line number Diff line number Diff line change
@@ -120,9 +120,11 @@ define(['knockout', './Set', './Result', 'services/Annotation'], function (ko, S
if (sampleName.indexOf(' ') >=0) {
sampleName = sampleName.split(" ").join('_');
}
self.annotationSaving(false );
self.annotationSaving(false);
//window.location = `#/profiles/${sourceKey}/${ko.toJS(annotationView).navigation.nextSubjectId}/${cohortId}/${sampleName}`;
self.nav.nextLink();
}).catch((error) => {
self.annotationSaving(false);
});
}
}
2 changes: 1 addition & 1 deletion js/pages/profiles/annotation/view-models/Content.js
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ define(['knockout', './Annotation', 'services/Annotation'], function (ko, Annota
});
} else {
self.annotation = new Annotation(set, personId, cohortId, sourceKey, [], null, annotationView, sampleName);
self.annotationLoaded(false);
self.annotationLoaded(true);
}
});
};
26 changes: 10 additions & 16 deletions js/pages/profiles/annotation/view-models/Navigation.js
Original file line number Diff line number Diff line change
@@ -8,11 +8,13 @@ define(['knockout', './Navigation', 'services/Annotation'], function (ko, Naviga
self.numProfileSamples = ko.observable();
self.numAnnotations = ko.observable();
self.navigationLoaded = ko.observable(false);
self.sampleId = ko.observable();
self.sourceKey = ko.observable(sourceKey);
self.cohortId = ko.observable(cohortId);
self.personId = ko.observable(personId);

this.prevLink = function() {
if (sampleName.indexOf(' ') >= 0) {
sampleName= sampleName.split(" ").join('_');
}

window.location = `#/profiles/${sourceKey}/${self.prevSubjectId()}/${cohortId}/${sampleName}`;
location.reload();
};
@@ -24,19 +26,6 @@ define(['knockout', './Navigation', 'services/Annotation'], function (ko, Naviga
location.reload();
};

// this.prevLink = ko.computed(function() {
// if (sampleName.indexOf(' ') >=0) {
// sampleName = sampleName.split(" ").join('_');
// }
// return `#/profiles/${sourceKey}/${self.prevSubjectId()}/${cohortId}/${sampleName}`;
// }, self);

// this.nextLink = ko.computed(function() {
// if (sampleName.indexOf(' ') >=0) {
// sampleName = sampleName.split(" ").join('_');
// }
// return `#/profiles/${sourceKey}/${self.nextSubjectId()}/${cohortId}/${sampleName}`;
// }, self);

this.completionPercent = ko.computed(function() {
return Math.ceil((self.numAnnotations()/self.numProfileSamples())*100);
@@ -45,6 +34,11 @@ define(['knockout', './Navigation', 'services/Annotation'], function (ko, Naviga
self.initialize = function(sampleName, cohortId, personId, sourceKey) {
annotationService.getAnnotationNavigation(sampleName, cohortId, personId, sourceKey)
.then((navigation) => {
if (sampleName.indexOf(' ') >= 0) {
sampleName= sampleName.split(" ").join('_');
}
self.sampleId(sampleName);

// const { prevSubjectId, nextSubjectId, nextUnannotatedSubjectId, numProfileSamples, numAnnotations } = navigation;
const samples = navigation.elements;

1 change: 1 addition & 0 deletions js/pages/profiles/const.js
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ define(
const paths = {
source: sourceKey => `#/profiles/${sourceKey}`,
person: (sourceKey, personId) => `#/profiles/${sourceKey}/${personId}`,
sample: (sourceKey, personId, cohortDefinitionId, sampleId) => `#/profiles/${sourceKey}/${personId}/${cohortDefinitionId}/${sampleId}`,
};

return {
4 changes: 2 additions & 2 deletions js/pages/profiles/profile-manager.html
Original file line number Diff line number Diff line change
@@ -145,10 +145,10 @@
<div data-bind="with: navigation">
<div class="btn-group btn-group-justified annotation-next-prev" disable role="group">
<div class="btn-group" role="group">
<a class="btn btn-default" data-bind="click: prevLink, attr: {disabled: !navigationLoaded() }, html: !navigationLoaded() ? 'Loading': '<span>Prev</span>'" role="button"></a>
<a class="btn btn-default btn-prf-annotation-prev" data-bind="click: prevLink, attr: { href: '#/profiles/' + sourceKey() + '/' + prevSubjectId() + '/' + cohortId() + '/' + sampleId(), disabled: !navigationLoaded() }, html: !navigationLoaded() ? 'Loading': '<span>Prev</span>'" role="button"></a>
</div>
<div class="btn-group" role="group">
<a class="btn btn-default" data-bind="click: nextLink, attr: {disabled: !navigationLoaded() }, html: !navigationLoaded() ? 'Loading': '<span>Next</span>'" role="button"></a>
<a class="btn btn-default btn-prf-annotation-next" data-bind="click: nextLink, attr: {href: '#/profiles/' + sourceKey() + '/' + nextSubjectId() + '/' + cohortId() + '/' + sampleId(), disabled: !navigationLoaded() }, html: !navigationLoaded() ? 'Loading': '<span>Next</span>'" role="button"></a>
</div>
</div>
<!-- <div class="annotation-progress">-->
1 change: 1 addition & 0 deletions js/pages/profiles/routes.js
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ define(
params.sourceKey = (path[0] || null);
params.personId = (path[1] || null);
params.cohortDefinitionId = (path[2] || null);
params.cohortSampleId = (path[3] || null);

router.setCurrentView('profile-manager', params);
});
30 changes: 30 additions & 0 deletions js/services/Annotation.js
Original file line number Diff line number Diff line change
@@ -81,6 +81,34 @@ define(function (require, exports) {

return response;
};

const getSetsBySampleId = function(sampleId) {
// http://localhost:8080/WebAPI/annotations?cohortSampleId=6
return httpService.doGet(`${config.webAPIRoot}annotations?cohortSampleId=${sampleId}`)
.then((resp) => {
const sets = new Set();
resp.data.forEach((x, i) => {
sets.add(x.questionSetId);
});
return Array.from(sets);
})
.catch(er => {
console.error("unable to load sets");
console.log(er);
});
};

const getAnnotationsBySampleIdSetId = function(sampleId, setId) {
// http://localhost:8080/WebAPI/annotations?cohortSampleId=6
return httpService.doGet(`${config.webAPIRoot}annotations?cohortSampleId=${sampleId}&setId=${setId}`)
.then((res) => {
return res.data;
})
.catch(er => {
console.error("unable to load sets");
console.log(er);
});
};

const getAnnotationNavigation = function(sampleName, cohort, subject, source) {
const data = {
@@ -112,6 +140,8 @@ define(function (require, exports) {

return {
getAnnotationSets,
getSetsBySampleId,
getAnnotationsBySampleIdSetId,
getStudySets,
getSuperTable,
getStudyResults,