From 231c86c1abc0ad87e49961bf9c63cfda5dfdd7c2 Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Mon, 16 Mar 2026 00:38:24 -0400 Subject: [PATCH 01/21] Update permission checks to handle WebAPI 3.0 changes. Modified user/pass authentication to use basic authentication. --- js/components/ac-access-denied.html | 1 + js/components/ac-access-denied.js | 1 + js/components/atlas-state.js | 2 +- .../circe/components/ConceptSetBrowser.js | 4 +- js/components/welcome.js | 13 +- js/config/app.js | 2 +- js/pages/concept-sets/conceptset-browser.html | 4 +- js/pages/concept-sets/conceptset-browser.js | 3 - js/pages/concept-sets/conceptset-manager.js | 20 +- js/pages/vocabulary/PermissionService.js | 12 +- js/pages/vocabulary/components/search.html | 2 +- js/services/AuthAPI.js | 238 +++++++----------- 12 files changed, 126 insertions(+), 176 deletions(-) diff --git a/js/components/ac-access-denied.html b/js/components/ac-access-denied.html index 74c919a40..5c48db6bb 100644 --- a/js/components/ac-access-denied.html +++ b/js/components/ac-access-denied.html @@ -1,4 +1,5 @@
+ diff --git a/js/components/ac-access-denied.js b/js/components/ac-access-denied.js index 3f5640318..fad47ee3a 100644 --- a/js/components/ac-access-denied.js +++ b/js/components/ac-access-denied.js @@ -15,6 +15,7 @@ define([ class AccessDenied extends Component { constructor(params) { super(params); + this.message = params.message; this.isAuthenticated = params.isAuthenticated; this.isPermitted = params.isPermitted || (() => false); } diff --git a/js/components/atlas-state.js b/js/components/atlas-state.js index 88042e3bf..3fb2f998f 100644 --- a/js/components/atlas-state.js +++ b/js/components/atlas-state.js @@ -37,7 +37,7 @@ define(['knockout', 'lscache', 'services/job/jobDetail', 'assets/ohdsi.util', 'c state.currentVocabularyVersion(state.defaultVocabularyVersion()); } - state.sourceKeyOfVocabUrl = ko.computed(() => { + state.sourceKeyOfVocabUrl = ko.pureComputed(() => { return state.vocabularyUrl() ? state.vocabularyUrl().replace(/\/$/, '').split('/').pop() : null; }); diff --git a/js/components/circe/components/ConceptSetBrowser.js b/js/components/circe/components/ConceptSetBrowser.js index 6ac03a981..0580200cc 100644 --- a/js/components/circe/components/ConceptSetBrowser.js +++ b/js/components/circe/components/ConceptSetBrowser.js @@ -88,10 +88,10 @@ define([ self.isAuthenticated = authApi.isAuthenticated; self.canReadConceptsets = ko.pureComputed(function () { - return (appConfig.userAuthenticationEnabled && self.isAuthenticated() && authApi.isPermittedReadConceptsets()) || !appConfig.userAuthenticationEnabled; + return true; // TODO: do not need permission to list entities }); self.canReadCohorts = ko.pureComputed(function () { - return (config.userAuthenticationEnabled && self.isAuthenticated() && authApi.isPermittedReadCohorts()) || !config.userAuthenticationEnabled; + return true; // TODO: do not need permissions to list entities }); self.loadConceptSetsFromRepository = function (url) { diff --git a/js/components/welcome.js b/js/components/welcome.js index 8a1360c15..8d8ed0237 100644 --- a/js/components/welcome.js +++ b/js/components/welcome.js @@ -80,7 +80,7 @@ define([ self.onLoginSuccessful = function(data, textStatus, jqXHR) { sharedState.resetCurrentDataSourceScope(); - self.setAuthParams(jqXHR.getResponseHeader(authApi.TOKEN_HEADER), data.permissions); + self.setAuthParams(data.jwt); self.loadUserInfo().then(() => { self.errorMsg(null); self.isBadCredentials(null); @@ -98,12 +98,15 @@ define([ self.signinWithLoginPass = function(data) { self.isInProgress(true); + const username = data.elements.lg_username.value; + const password = data.elements.lg_password.value; + const authHeader = 'Basic ' + btoa(username + ':' + password); + $.ajax({ - method: 'POST', + method: 'GET', url: appConfig.webAPIRoot + self.authUrl(), - data: { - login: data.elements.lg_username.value, - password: data.elements.lg_password.value + headers: { + 'Authorization': authHeader }, success: self.onLoginSuccessful, error: (jqXHR, textStatus, errorThrown) => self.onLoginFailed(jqXHR, ko.i18n('components.welcome.messages.badCredentials', 'Bad credentials')()), diff --git a/js/config/app.js b/js/config/app.js index ec896db1d..49ddae271 100644 --- a/js/config/app.js +++ b/js/config/app.js @@ -166,7 +166,7 @@ define(function () { // "Tagging" section is hidden by default appConfig.enableTaggingSection = false; - appConfig.refreshTokenThreshold = 1000 * 60 * 60 * 4; // refresh auth token if it will expire within 4 hours + appConfig.refreshTokenThreshold = 1000 * 60 * 15; // refresh auth token if it will expire within 15 minutes. return appConfig; }); diff --git a/js/pages/concept-sets/conceptset-browser.html b/js/pages/concept-sets/conceptset-browser.html index c70550b2b..437e92271 100644 --- a/js/pages/concept-sets/conceptset-browser.html +++ b/js/pages/concept-sets/conceptset-browser.html @@ -1,6 +1,6 @@ -
+
- - \ No newline at end of file diff --git a/js/pages/concept-sets/conceptset-browser.js b/js/pages/concept-sets/conceptset-browser.js index b52bd04f5..9f530f3e1 100644 --- a/js/pages/concept-sets/conceptset-browser.js +++ b/js/pages/concept-sets/conceptset-browser.js @@ -22,9 +22,6 @@ define([ constructor(params) { super(params); this.componentParams = params; - - this.isAuthenticated = authAPI.isAuthenticated; - this.hasAccess = authAPI.isPermittedReadConceptsets; } } diff --git a/js/pages/concept-sets/conceptset-manager.js b/js/pages/concept-sets/conceptset-manager.js index d371fcdf6..f1ff5f38d 100644 --- a/js/pages/concept-sets/conceptset-manager.js +++ b/js/pages/concept-sets/conceptset-manager.js @@ -90,16 +90,11 @@ define([ this.fade = ko.observable(false); this.canEdit = ko.pureComputed(() => { - if (!authApi.isAuthenticated()) { - return false; - } - if (this.currentConceptSet() && (this.currentConceptSet() .id !== 0)) { - return authApi.isPermittedUpdateConceptset(this.currentConceptSet() - .id) || !config.userAuthenticationEnabled; + return authApi.isPermittedUpdateConceptset(this.currentConceptSet().id); } else { - return authApi.isPermittedCreateConceptset() || !config.userAuthenticationEnabled; + return authApi.isPermittedCreateConceptset(); } }); this.isNameFilled = ko.computed(() => { @@ -129,7 +124,11 @@ define([ this.canCreate = ko.computed(() => { return authApi.isPermittedCreateConceptset(); }); - this.hasAccess = authApi.isPermittedReadConceptsets; + this.hasAccess = () => { + return this.currentConceptSet() && + this.currentConceptSet().id !== 0 && + authApi.isPermittedReadConceptset(this.currentConceptSet().id); + }; this.hasPrioritySourceAccess = ko.observable(true); this.isAuthenticated = authApi.isAuthenticated; this.conceptSetCaption = ko.computed(() => { @@ -144,9 +143,6 @@ define([ } }); this.canDelete = ko.pureComputed(() => { - if (!config.userAuthenticationEnabled) { - return true; - } return this.conceptSetStore.current() && authApi.isPermittedDeleteConceptset(this.conceptSetStore.current().id); }); @@ -182,7 +178,7 @@ define([ }); this.saveConceptSetShow = ko.observable(false); this.canCopy = ko.computed(() => { - return this.currentConceptSet() && this.currentConceptSet().id > 0; + return this.currentConceptSet() && this.currentConceptSet().id > 0 && this.canCreate(); }); this.enablePermissionManagement = config.enablePermissionManagement; this.isSaving = ko.observable(false); diff --git a/js/pages/vocabulary/PermissionService.js b/js/pages/vocabulary/PermissionService.js index 48c6ef9bf..928b40c0c 100644 --- a/js/pages/vocabulary/PermissionService.js +++ b/js/pages/vocabulary/PermissionService.js @@ -1,15 +1,15 @@ define([ 'services/AuthAPI', - 'atlas-state', + 'atlas-state', ], function ( AuthAPI, sharedState, ) { const isPermittedSearch = () => { - return sharedState.vocabularyUrl() !== undefined && AuthAPI.isPermitted(`vocabulary:${sharedState.sourceKeyOfVocabUrl()}:search:*:get`); - }; + return sharedState.vocabularyUrl() !== undefined && AuthAPI.hasSourceAccess(sharedState.sourceKeyOfVocabUrl()); + }; - return { - isPermittedSearch, - } + return { + isPermittedSearch, + } }); \ No newline at end of file diff --git a/js/pages/vocabulary/components/search.html b/js/pages/vocabulary/components/search.html index 1eb8ba5d1..3c927b081 100644 --- a/js/pages/vocabulary/components/search.html +++ b/js/pages/vocabulary/components/search.html @@ -121,4 +121,4 @@ canSelectSource: true, }"> - + diff --git a/js/services/AuthAPI.js b/js/services/AuthAPI.js index 082377ba2..c222c082e 100644 --- a/js/services/AuthAPI.js +++ b/js/services/AuthAPI.js @@ -7,6 +7,8 @@ define(function(require, exports) { var TOKEN_HEADER = 'Bearer'; var LOCAL_STORAGE_PERMISSIONS_KEY = "permissions"; const httpService = require('services/http'); + const NONE_ENTITY_GRANT = {accessTypes: [], isOwner: false}; + const sharedState = require('atlas-state'); const AUTH_PROVIDERS = { IAP: 'AtlasGoogleSecurity', @@ -78,10 +80,10 @@ define(function(require, exports) { url: config.api.url + 'user/me', method: 'GET', success: function (info, textStatus, jqXHR) { - permissions(info.permissionIdx); // read from permission index of User info - subject(info.login); + permissions(info.authz); // Store user authroizations in permissions observable + subject(info.user.login); authProvider(jqXHR.getResponseHeader('x-auth-provider')); - fullName(info.name ? info.name : info.login); + fullName(info.user.name ? info.user.name : info.user.login); resolve(); }, error: function (err) { @@ -158,11 +160,7 @@ define(function(require, exports) { }); var isAuthenticated = ko.computed(() => { - if (!config.userAuthenticationEnabled) { - return true; - } - - return !!subject(); + return !!token(); }); var handleAccessDenied = function(xhr) { @@ -218,27 +216,19 @@ define(function(require, exports) { }; var isPermitted = function (permission) { - if (!config.userAuthenticationEnabled) { - return true; - } - - if (!permissions()) return false; - - firstPerm = permission.split(":")[0]; - - var etalons = [...(permissions()["*"] || []), ...(permissions()[firstPerm]||[])]; - if (!etalons) { - return false; - } + // TODO: we have a more complex object now: UserAuthorizations containing permissions and AccessGrants + // TODO: so maybe replace references to permissions() with authz() + var etalons = permissions() && permissions().permissions || []; + return etalons.some(e => checkPermission(permission, e)); + }; - for (var i = 0; i < etalons.length; i++) { - if (checkPermission(permission, etalons[i])) { - return true; - } + // this function will handle 'write implies read' when checking an access type against a set of granted access + var checkAccess = function (check, granted) { + if (check == "READ") { + return (["READ", "WRITE"]).some(c => granted.includes(c)); } - - return false; - }; + return granted.includes(check); + } function base64urldecode(arg) { var s = arg; @@ -269,15 +259,10 @@ define(function(require, exports) { return p && typeof p === 'object' && typeof p.status === 'function' && p.status() === 'pending'; } var refreshToken = function() { - - if (!config.userAuthenticationEnabled) { - return Promise.resolve(true); // no-op if userAuthenticationEnabled == false - } - if (!isPromisePending(refreshTokenPromise)) { refreshTokenPromise = httpService.doGet(getServiceUrl() + "user/refresh"); - refreshTokenPromise.then(({ data, headers }) => { - setAuthParams(headers.get(TOKEN_HEADER), data.permissions); + refreshTokenPromise.then(({data}) => { + setAuthParams(data.jwt); }); refreshTokenPromise.catch(() => { resetAuthParams(); @@ -287,84 +272,48 @@ define(function(require, exports) { return refreshTokenPromise; } - var isPermittedCreateConceptset = function() { - return isPermitted('conceptset:post'); + var isPermittedReadConceptset = function(conceptsetId) { + var id = +conceptsetId; // force to numeric + var authz = permissions().conceptSetAccess; + var grant = authz[id] || NONE_ENTITY_GRANT; // assign a falsy entity grant if not found + return grant.isOwner || + isPermitted("read:conceptset") || + isPermitted("write:conceptset") || + checkAccess("READ", grant.accessTypes); } - var isPermittedReadConceptsets = function () { - return isPermitted('conceptset:get'); - }; + var isPermittedCreateConceptset = function() { + return isPermitted('create:conceptset'); + } var isPermittedUpdateConceptset = function(conceptsetId) { - return (isPermitted('conceptset:' + conceptsetId + ':put') && isPermitted('conceptset:' + conceptsetId + ':items:put')) || (isPermitted('conceptset:*:put') && isPermitted('conceptset:*:items:put')); + var id = +conceptsetId; // force to numeric + var authz = permissions().conceptSetAccess; + var grant = authz[id] || NONE_ENTITY_GRANT; // assign a falsy entity grant if not found + return grant.isOwner || + isPermitted("write:conceptset") || + checkAccess("WRITE", grant.accessTypes); }; var isPermittedDeleteConceptset = function(id) { - return isPermitted('conceptset:' + id + ':delete'); + return isPermittedUpdateConceptset(id); }; + // TODO: we don't need perms to list incidence rates var isPermittedReadIRs = function () { - return isPermitted('ir:get'); - }; - - var isPermittedEditIR = function (id) { - return isPermitted('ir:' + id + ':put'); + return true; }; var isPermittedCreateIR = function () { - return isPermitted('ir:post'); - }; - - var isPermittedDeleteIR = function(id) { - return isPermitted('ir:' + id + ':delete'); + return isPermitted('create:incidence'); }; var isPermittedCopyIR = function(id) { - return isPermitted('ir:' + id + ':copy:get'); - }; - - var isPermittedReadEstimations = function () { - return isPermitted('comparativecohortanalysis:get'); + return isPermittedCreateIR(); }; var isPermittedEditSourcePriortiy = function() { - return isPermitted('source:*:daimons:*:set-priority:post') - }; - - var isPermittedReadEstimation = function (id) { - return isPermitted('comparativecohortanalysis:' + id + ':get'); - }; - - var isPermittedCreateEstimation = function() { - return isPermitted('comparativecohortanalysis:post'); - }; - - const isPermittedDeleteEstimation = function(id) { - return isPermitted(`comparativecohortanalysis:${id}:delete`); - } - - var isPermittedReadPlps = function() { - return isPermitted('plp:get'); - }; - - var isPermittedCreatePlp = function () { - return isPermitted('plp:post'); - }; - - var isPermittedReadPlp = function(id) { - return isPermitted('plp:' + id + ':get'); - }; - - var isPermittedDeletePlp = function(id) { - return isPermitted('plp:' + id + ':delete'); - }; - - var isPermittedCopyPlp = function(id) { - return isPermitted(`plp:${id}:copy:get`); - } - - var isPermittedSearch = function() { - return isPermitted('vocabulary:*:search:*:get'); + return isPermitted('admin:source') }; var isPermittedViewCdmResults = function () { @@ -379,60 +328,67 @@ define(function(require, exports) { return isPermitted('*:person:*:get:dates'); }; - var isPermittedReadCohort = function(id) { - return isPermitted('cohortdefinition:' + id + ':get') && isPermitted('cohortdefinition:sql:post'); - } - var isPermittedReadCohorts = function() { - return isPermitted('cohortdefinition:get'); + return true; // TODO: remove list perm checks + } + + var isPermittedReadCohort = function(id) { + var cohortId = +id; // force to numeric + var authz = permissions().cohortDefinitionAccess; + var grant = authz[cohortId] || NONE_ENTITY_GRANT; // assign a falsy entity grant if not found + return grant.isOwner || + isPermitted("read:cohort") || + isPermitted("write:cohort") || + checkAccess("READ", grant.accessTypes); } var isPermittedCreateCohort = function() { - return isPermitted('cohortdefinition:post'); + return isPermitted('create:cohort-definition'); } var isPermittedCopyCohort = function(id) { - return isPermitted('cohortdefinition:' + id + ':copy:get'); + return isPermittedCreateCohort(); } var isPermittedUpdateCohort = function(id) { - var permission = 'cohortdefinition:' + id + ':put'; - return isPermitted(permission); + var cohortId = +id; // force to numeric + var authz = permissions().cohortDefinitionAccess; + var grant = authz[cohortId] || NONE_ENTITY_GRANT; // assign a falsy entity grant if not found + return grant.isOwner || + isPermitted("write:cohort") || + checkAccess("WRITE", grant.accessTypes); } var isPermittedDeleteCohort = function(id) { - var permission = 'cohortdefinition:' + id + ':delete'; - var allPermissions = 'cohortdefinition:delete'; - return isPermitted(permission) || isPermitted(allPermissions); + return isPermittedUpdateCohort(id); } var isPermittedGenerateCohort = function(cohortId, sourceKey) { - return isPermitted('cohortdefinition:' + cohortId + ':generate:' + sourceKey + ':get') && - isPermitted('cohortdefinition:' + cohortId + ':info:get'); + return true; // TODO: check source canWrite() } var isPermittedReadCohortReport = function(cohortId, sourceKey) { - return isPermitted('cohortdefinition:' + cohortId + ':report:' + sourceKey + ':get'); + return true; // TODO: check source canRead || canWrite } var isPermittedReadJobs = function() { - return isPermitted('job:execution:get'); + return true; } var isPermittedEditConfiguration = function() { - return isPermitted('configuration:edit:ui') + return isPermitted('admin'); //TODO: everyone can view config, just need specific perms to make specific changes. } var isPermittedCreateSource = function() { - return isPermitted('source:post'); + return isPermitted('admin:source'); } var isPermittedAccessSource = function(key) { - return isPermitted('source:' + key + ':access'); + return true; // TODO: check source canRead || canWrite; } var isPermittedReadSource = function(key) { - return isPermitted('source:' + key + ':get'); + return true; // TODO: check source canRead } var isPermittedCheckSourceConnection = function(key) { @@ -440,15 +396,15 @@ define(function(require, exports) { } var isPermittedEditSource = function(key) { - return isPermitted('source:' + key + ':put'); + return isPermitted('admin:source'); } var isPermittedDeleteSource = function(key) { - return isPermitted('source:' + key + ':delete'); + return isPermitted('admin:source'); } var isPermittedReadRoles = function() { - return isPermitted('role:get'); + return true; // TODO: anyone should be able to list roles } var isPermittedReadRole = function (roleId) { var permitted = @@ -469,7 +425,7 @@ define(function(require, exports) { return isPermitted('role:' + roleId + ':delete'); } var isPermittedEditRoleUsers = function(roleId) { - return isPermitted('role:' + roleId + ':users:*:put') && isPermitted('role:' + roleId + ':users:*:delete'); + return isPermitted('admin:security') && isPermitted('role:' + roleId + ':users:*:delete'); } var isPermittedEditRolePermissions = function(roleId) { return isPermitted('role:' + roleId + ':permissions:*:put') && isPermitted('role:' + roleId + ':permissions:*:delete'); @@ -487,15 +443,28 @@ define(function(require, exports) { return isPermitted('executionservice:*:get'); }; const isPermittedGetSourceDaimonPriority = function() { - return isPermitted('source:daimon:priority:get'); + return true; // isPermitted('source:daimon:priority:get'); //TODO: shouldn't everyone be able to lookup source daimon priority? }; - const isPermittedImportUsers = function() { - return isPermitted('user:import:post') && isPermitted('user:import:*:post'); - } + const isPermittedImportUsers = function() { + return isPermitted('user:import:post') && isPermitted('user:import:*:post'); + } + + const hasSourceAccess = function (sourceKey, accessType = "READ") { + var sourceKey = sharedState.sourceKeyOfVocabUrl(); + var sourceId = (sharedState.sources().find(s => s.sourceKey == sourceKey) || {}).sourceId; + + if (!sourceId) return false; // source not found + + var authz = permissions().sourceAccess; + var accessTypes = authz[sourceId] || []; // default to no access + if (accessType == "READ") { + return isPermitted("read:source") || isPermitted("write:source") || checkAccess("READ", accessTypes); + } else if (accessType == "WRITE") { + return isPermitted("write:source") || checkAccess("WRITE", accessTypes); + } - const hasSourceAccess = function (sourceKey) { - return isPermitted(`source:${sourceKey}:access`) || /* For 2.5.* and below */ isPermitted(`cohortdefinition:*:generate:${sourceKey}:get`); + return false; } const isPermittedClearServerCache = function (sourceKey) { @@ -503,7 +472,7 @@ define(function(require, exports) { }; const isPermittedTagsManagement = function () { - return isPermitted(`tag:management`); + return isPermitted("admin:tags"); }; const isPermittedConceptSetAnnotationsDelete = function (conceptSetId) { @@ -516,9 +485,8 @@ define(function(require, exports) { const isPermittedViewDataSourceReportDetails = sourceKey => isPermitted(`cdmresults:${sourceKey}:*:*:get`); - const setAuthParams = (tokenHeader, permissionsStr = '') => { - !!tokenHeader && token(tokenHeader); - !!permissionsStr && permissions(permissionsStr); + const setAuthParams = (jwt) => { + !!jwt && token(jwt); }; var resetAuthParams = function () { @@ -572,9 +540,9 @@ define(function(require, exports) { isPermittedPostViewedNotifications: isPermittedPostViewedNotifications, isPermittedCreateConceptset: isPermittedCreateConceptset, + isPermittedReadConceptset: isPermittedReadConceptset, isPermittedUpdateConceptset: isPermittedUpdateConceptset, isPermittedDeleteConceptset: isPermittedDeleteConceptset, - isPermittedReadConceptsets: isPermittedReadConceptsets, isPermittedReadCohorts: isPermittedReadCohorts, isPermittedReadCohort: isPermittedReadCohort, @@ -600,22 +568,8 @@ define(function(require, exports) { isPermittedReadIRs: isPermittedReadIRs, isPermittedCreateIR: isPermittedCreateIR, - isPermittedEditIR: isPermittedEditIR, - isPermittedDeleteIR: isPermittedDeleteIR, isPermittedCopyIR, - isPermittedReadEstimations: isPermittedReadEstimations, - isPermittedReadEstimation: isPermittedReadEstimation, - isPermittedCreateEstimation: isPermittedCreateEstimation, - isPermittedDeleteEstimation, - - isPermittedReadPlps: isPermittedReadPlps, - isPermittedReadPlp: isPermittedReadPlp, - isPermittedCreatePlp: isPermittedCreatePlp, - isPermittedDeletePlp: isPermittedDeletePlp, - isPermittedCopyPlp: isPermittedCopyPlp, - - isPermittedSearch: isPermittedSearch, isPermittedViewCdmResults: isPermittedViewCdmResults, isPermittedViewProfiles: isPermittedViewProfiles, isPermittedViewProfileDates: isPermittedViewProfileDates, From cf1a863a696675d0e82aacfe90034a1bd3bc3e8f Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Wed, 25 Mar 2026 09:54:55 -0400 Subject: [PATCH 02/21] Modified authentication calls to handle anonymous users. Updated permission checks to use the permission structure. --- js/Application.js | 36 +++--------------- js/components/ac-access-denied.html | 7 +--- js/components/ac-access-denied.js | 1 - js/components/atlas.cohort-editor.html | 2 +- .../cohort-definition-manager.html | 2 +- .../cohort-definition-manager.js | 37 +++++-------------- .../cohort-definitions/cohort-definitions.js | 4 +- js/services/AuthAPI.js | 8 ++-- 8 files changed, 25 insertions(+), 72 deletions(-) diff --git a/js/Application.js b/js/Application.js index 66decffb6..ee77a8e25 100644 --- a/js/Application.js +++ b/js/Application.js @@ -198,39 +198,15 @@ define( initServiceInformation() { console.info('Initializing service information'); return new Promise((resolve, reject) => { - const serviceCacheKey = 'ATLAS|' + config.api.url; - const cachedService = lscache.get(serviceCacheKey); - - if (cachedService && cachedService.sources) { - console.info('cached service'); - config.api.sources = cachedService; - sourceApi.setSharedStateSources(cachedService.sources); - resolve(); - } else { - sharedState.sources([]); - - if (config.userAuthenticationEnabled && !authApi.isAuthenticated()) { - this.authSubscription = authApi.isAuthenticated.subscribe(async (isAuthed) => { - if (isAuthed) { - sharedState.appInitializationStatus(await sourceApi.initSourcesConfig()); - this.authSubscription.dispose(); - console.info('Re-initialized service information'); - } - }); - sharedState.appInitializationStatus(constants.applicationStatuses.running); + sourceApi.initSourcesConfig() + .then(function (appStatus) { + sharedState.appInitializationStatus(appStatus); + console.info('Init sources from server'); resolve(); - return; - } else { - sourceApi.initSourcesConfig() - .then(function (appStatus) { - sharedState.appInitializationStatus(appStatus); - console.info('Init sources from server'); - resolve(); - }); - } - } + }); }); } + checkOAuthError() { let hash = window.location.hash; if (hash && hash.includes("oauth_error_email")) { diff --git a/js/components/ac-access-denied.html b/js/components/ac-access-denied.html index 5c48db6bb..75b77c744 100644 --- a/js/components/ac-access-denied.html +++ b/js/components/ac-access-denied.html @@ -1,9 +1,6 @@ -
+
- + - - -
diff --git a/js/components/ac-access-denied.js b/js/components/ac-access-denied.js index fad47ee3a..756690e0a 100644 --- a/js/components/ac-access-denied.js +++ b/js/components/ac-access-denied.js @@ -16,7 +16,6 @@ define([ constructor(params) { super(params); this.message = params.message; - this.isAuthenticated = params.isAuthenticated; this.isPermitted = params.isPermitted || (() => false); } } diff --git a/js/components/atlas.cohort-editor.html b/js/components/atlas.cohort-editor.html index dc3f2bc90..4bad7eccc 100644 --- a/js/components/atlas.cohort-editor.html +++ b/js/components/atlas.cohort-editor.html @@ -1,4 +1,4 @@ -
+
- +
diff --git a/js/pages/cohort-definitions/cohort-definition-manager.js b/js/pages/cohort-definitions/cohort-definition-manager.js index 57cdae1ee..5af4cf57e 100644 --- a/js/pages/cohort-definitions/cohort-definition-manager.js +++ b/js/pages/cohort-definitions/cohort-definition-manager.js @@ -365,23 +365,14 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html', this.isNameCorrect = ko.pureComputed(() => { return this.isNameFilled() && !this.isDefaultName() && this.isNameCharactersValid() && this.isNameLengthValid(); }); - this.isAuthenticated = ko.pureComputed(() => { - return this.authApi.isAuthenticated(); - }); this.isNew = ko.pureComputed(() => { return !this.currentCohortDefinition() || (this.currentCohortDefinition().id() === 0); }); this.canEdit = ko.pureComputed(() => { - if (!authApi.isAuthenticated()) { - return false; - } - - if (this.currentCohortDefinition() && (this.currentCohortDefinition() - .id() != 0)) { - return authApi.isPermittedUpdateCohort(this.currentCohortDefinition() - .id()) || !config.userAuthenticationEnabled; + if (this.currentCohortDefinition() && (this.currentCohortDefinition().id() != 0)) { + return authApi.isPermittedUpdateCohort(this.currentCohortDefinition().id()); } else { - return authApi.isPermittedCreateCohort() || !config.userAuthenticationEnabled; + return authApi.isPermittedCreateCohort(); } }); this.isSaving = ko.observable(false); @@ -391,28 +382,18 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html', return this.isSaving() || this.isCopying() || this.isDeleting(); }); this.canCopy = ko.pureComputed(() => { - return !this.dirtyFlag().isDirty() && !this.isNew() && - (this.isAuthenticated() && this.authApi.isPermittedCopyCohort(this.currentCohortDefinition().id()) || !config.userAuthenticationEnabled); + return !this.dirtyFlag().isDirty() + && !this.isNew() + && this.authApi.isPermittedCopyCohort(this.currentCohortDefinition().id()); }); this.canDelete = ko.pureComputed(() => { if (this.isNew()) { return false; } - return ((this.isAuthenticated() && this.authApi.isPermittedDeleteCohort(this.currentCohortDefinition().id()) || !config.userAuthenticationEnabled)); + return (this.authApi.isPermittedDeleteCohort(this.currentCohortDefinition().id())); }); this.hasAccess = ko.pureComputed(() => { - if (!config.userAuthenticationEnabled) { - return true; - } - if (!this.isAuthenticated()) { - return false; - } - if (this.currentCohortDefinition() && this.isNew()) { - return this.authApi.isPermittedCreateCohort(); - } - - return this.authApi.isPermittedReadCohorts() || - (this.currentCohortDefinition() && this.authApi.isPermittedReadCohort(this.currentCohortDefinition().id())); + return this.isNew() || (this.currentCohortDefinition() && this.authApi.isPermittedReadCohort(this.currentCohortDefinition().id())); }); this.hasAccessToGenerate = (sourceKey) => { @@ -423,7 +404,7 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html', return this.authApi.isPermittedGenerateCohort(this.currentCohortDefinition().id(), sourceKey); } this.hasAccessToReadCohortReport = (sourceKey) => { - return this.isAuthenticated() && this.authApi.isPermittedReadCohortReport(this.currentCohortDefinition().id(), sourceKey); + return this.authApi.isPermittedReadCohortReport(this.currentCohortDefinition().id(), sourceKey); } this.renderCountColumn = datatableUtils.renderCountColumn; diff --git a/js/pages/cohort-definitions/cohort-definitions.js b/js/pages/cohort-definitions/cohort-definitions.js index c3da8163a..201ec9691 100644 --- a/js/pages/cohort-definitions/cohort-definitions.js +++ b/js/pages/cohort-definitions/cohort-definitions.js @@ -42,8 +42,8 @@ define([ }); this.isAuthenticated = authApi.isAuthenticated; - this.canReadCohorts = ko.pureComputed(() => (config.userAuthenticationEnabled && this.isAuthenticated() && authApi.isPermittedReadCohorts()) || !config.userAuthenticationEnabled); - this.canCreateCohort = ko.pureComputed(() => (config.userAuthenticationEnabled && this.isAuthenticated() && authApi.isPermittedCreateCohort()) || !config.userAuthenticationEnabled); + this.canReadCohorts = ko.pureComputed(() => authApi.isPermittedReadCohorts()); + this.canCreateCohort = ko.pureComputed(() => authApi.isPermittedCreateCohort()); this.tableOptions = commonUtils.getTableOptions('L'); } diff --git a/js/services/AuthAPI.js b/js/services/AuthAPI.js index c222c082e..00a19cf1b 100644 --- a/js/services/AuthAPI.js +++ b/js/services/AuthAPI.js @@ -337,8 +337,8 @@ define(function(require, exports) { var authz = permissions().cohortDefinitionAccess; var grant = authz[cohortId] || NONE_ENTITY_GRANT; // assign a falsy entity grant if not found return grant.isOwner || - isPermitted("read:cohort") || - isPermitted("write:cohort") || + isPermitted("read:cohort-definition") || + isPermitted("write:cohort-definition") || checkAccess("READ", grant.accessTypes); } @@ -355,7 +355,7 @@ define(function(require, exports) { var authz = permissions().cohortDefinitionAccess; var grant = authz[cohortId] || NONE_ENTITY_GRANT; // assign a falsy entity grant if not found return grant.isOwner || - isPermitted("write:cohort") || + isPermitted("write:cohort-definition") || checkAccess("WRITE", grant.accessTypes); } @@ -509,7 +509,7 @@ define(function(require, exports) { const executeWithRefresh = async function(httpPromise) { const result = await httpPromise; - await refreshToken(); + await loadUserInfo(); return result; } From 997d4e49ae5b32ae98a1cf6012053ee83d3aa40c Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Thu, 2 Apr 2026 14:07:00 -0400 Subject: [PATCH 03/21] Fixed permission checks for characterization and feature analysis. --- .../services/PermissionService.js | 59 +++++++++++-------- js/services/AuthAPI.js | 19 +++++- 2 files changed, 54 insertions(+), 24 deletions(-) diff --git a/js/pages/characterizations/services/PermissionService.js b/js/pages/characterizations/services/PermissionService.js index 9a9ff22c2..c5814517e 100644 --- a/js/pages/characterizations/services/PermissionService.js +++ b/js/pages/characterizations/services/PermissionService.js @@ -5,78 +5,91 @@ define([ ) { function isPermittedCreateCC() { - return AuthAPI.isPermitted(`cohort-characterization:post`); + return AuthAPI.isPermitted(`create:cohort-characterization`); } function isPermittedImportCC() { - return AuthAPI.isPermitted(`cohort-characterization:import:post`); + return AuthAPI.isPermitted(`create:cohort-characterization`); } function isPermittedGetCCList() { - return AuthAPI.isPermitted(`cohort-characterization:get`); + return true; // we do not need to restrict list opertions } - function isPermittedGetCC(id) { - return AuthAPI.isPermitted(`cohort-characterization:${id}:get`); + var isPermittedGetCC = function(id) { + var grant = AuthAPI.getCCGrant(id); + return grant.isOwner || + AuthAPI.isPermitted("read:cohort-characterization") || + AuthAPI.isPermitted("write:cohort-characterization") || + AuthAPI.checkAccess("READ", grant.accessTypes); } - function isPermittedUpdateCC(id) { - return AuthAPI.isPermitted(`cohort-characterization:${id}:put`); - } + var isPermittedUpdateCC = function(id) { + var grant = AuthAPI.getCCGrant(id); + return grant.isOwner || + AuthAPI.isPermitted("write:cohort-characterization") || + AuthAPI.checkAccess("WRITE", grant.accessTypes); + } function isPermittedDeleteCC(id) { - return AuthAPI.isPermitted(`cohort-characterization:${id}:delete`); + return isPermittedUpdateCC(id); } function isPermittedListGenerations(id) { - return AuthAPI.isPermitted(`cohort-characterization:${id}:generation:get`); + return true; // TODO: do we need to restrict listing generations? } function isPermittedGenerate(id, sourceKey) { - return AuthAPI.isPermitted(`cohort-characterization:${id}:generation:${sourceKey}:post`); + return AuthAPI.hasSourceAccess(sourceKey, "WRITE"); // TODO: Do we need read/write checks on the design? } function isPermittedResults(sourceKey) { - return (AuthAPI.isPermitted(`cohort-characterization:generation:*:result:post`)) - && AuthAPI.isPermitted(`source:${sourceKey}:access`); + return AuthAPI.hasSourceAccess(sourceKey, "READ"); } function isPermittedExportGenerationDesign(id) { - return AuthAPI.isPermitted(`cohort-characterization:generation:${id}:design:get`); + return isPermittedGetCC(id); } function isPermittedExportCC(id) { - return AuthAPI.isPermitted(`cohort-characterization:${id}:export:get`); + return isPermittedGetCC(id); } function isPermittedCopyCC(id) { - return AuthAPI.isPermitted(`cohort-characterization:${id}:post`); + return isPermittedGetCC(id) && isPermittedCreateCC(); } - // + // FA Permissions function isPermittedGetFaList() { - return AuthAPI.isPermitted(`feature-analysis:get`); + return true; // TODO: do we need perms to list assets? } function isPermittedCreateFa() { - return AuthAPI.isPermitted(`feature-analysis:post`); + return AuthAPI.isPermitted(`create:feature-analysis`); } function isPermittedGetFa(id) { - return AuthAPI.isPermitted(`feature-analysis:${id}:get`); + var grant = AuthAPI.getFAGrant(id); + return grant.isOwner || + AuthAPI.isPermitted("read:feature-analysis") || + AuthAPI.isPermitted("write:feature-analysis") || + AuthAPI.checkAccess("READ", grant.accessTypes); } function isPermittedUpdateFa(id) { - return AuthAPI.isPermitted(`feature-analysis:${id}:put`); + var grant = AuthAPI.getFAGrant(id); + return grant.isOwner || + AuthAPI.isPermitted("write:feature-analysis") || + AuthAPI.checkAccess("WRITE", grant.accessTypes); } function isPermittedDeleteFa(id) { - return AuthAPI.isPermitted(`feature-analysis:${id}:delete`); + return isPermittedUpdateFa(id); } function isPermittedCopyFa(id) { - return AuthAPI.isPermitted(`feature-analysis:${id}:copy:get`); + return isPermittedGetFa(id) && isPermittedCreateFa(); } return { diff --git a/js/services/AuthAPI.js b/js/services/AuthAPI.js index 00a19cf1b..fe6f98909 100644 --- a/js/services/AuthAPI.js +++ b/js/services/AuthAPI.js @@ -230,6 +230,18 @@ define(function(require, exports) { return granted.includes(check); } + var getCCGrant = function(id) { + var ccId = +id; // force to numeric + var authz = permissions().cohortCharacterizationAccess; + return authz[ccId] || NONE_ENTITY_GRANT; // assign a falsy entity grant if not found + } + + var getFAGrant = function(id) { + var faId = +id; // force to numeric + var authz = permissions().feAnalysisAccess; + return authz[faId] || NONE_ENTITY_GRANT; // assign a falsy entity grant if not found + } + function base64urldecode(arg) { var s = arg; s = s.replace(/-/g, '+'); // 62nd char of encoding @@ -451,7 +463,6 @@ define(function(require, exports) { } const hasSourceAccess = function (sourceKey, accessType = "READ") { - var sourceKey = sharedState.sourceKeyOfVocabUrl(); var sourceId = (sharedState.sources().find(s => s.sourceKey == sourceKey) || {}).sourceId; if (!sourceId) return false; // source not found @@ -516,6 +527,7 @@ define(function(require, exports) { var api = { AUTH_PROVIDERS: AUTH_PROVIDERS, AUTH_CLIENTS: AUTH_CLIENTS, + NONE_ENTITY_GRANT: NONE_ENTITY_GRANT, token: token, authClient: authClient, @@ -534,11 +546,16 @@ define(function(require, exports) { isAuthenticated: isAuthenticated, signInOpened: signInOpened, isPermitted: isPermitted, + checkAccess: checkAccess, isPermittedGetAllNotifications: isPermittedGetAllNotifications, isPermittedGetViewedNotifications: isPermittedGetViewedNotifications, isPermittedPostViewedNotifications: isPermittedPostViewedNotifications, + // will add the various get{entity} grants here + getCCGrant: getCCGrant, + getFAGrant: getFAGrant, + isPermittedCreateConceptset: isPermittedCreateConceptset, isPermittedReadConceptset: isPermittedReadConceptset, isPermittedUpdateConceptset: isPermittedUpdateConceptset, From f708db2cafa6a89c5e89a145e52718d2e67ad086 Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Mon, 6 Apr 2026 11:36:45 -0400 Subject: [PATCH 04/21] Update permission checks for IR. --- js/pages/incidence-rates/PermissionService.js | 50 +++++++++++++++- .../iranalysis/components/editor.html | 2 +- .../iranalysis/components/editor.js | 2 +- js/pages/incidence-rates/ir-browser.html | 2 +- js/pages/incidence-rates/ir-browser.js | 15 ++--- js/pages/incidence-rates/ir-manager.html | 8 +-- js/pages/incidence-rates/ir-manager.js | 60 ++++--------------- js/services/AuthAPI.js | 24 +++----- js/services/IRAnalysis.js | 4 +- 9 files changed, 83 insertions(+), 84 deletions(-) diff --git a/js/pages/incidence-rates/PermissionService.js b/js/pages/incidence-rates/PermissionService.js index c27dde970..6c4aeb45b 100644 --- a/js/pages/incidence-rates/PermissionService.js +++ b/js/pages/incidence-rates/PermissionService.js @@ -4,11 +4,59 @@ define([ AuthAPI ) { + // TODO: we don't need perms to list incidence rates + function isPermittedReadIRs() { + return true; + }; + + function isPermittedReadIR(id) { + var grant = AuthAPI.getIRGrant(id); + return grant.isOwner || + AuthAPI.isPermitted("read:incidence") || + AuthAPI.isPermitted("write:incidence") || + AuthAPI.checkAccess("READ", grant.accessTypes); + }; + + function isPermittedExport(id) { + return isPermittedReadIR(id); + }; + + function isPermittedCreateIR() { + return AuthAPI.isPermitted('create:incidence'); + }; + + function isPermittedImport() { + return isPermittedCreateIR(); + }; + + function isPermittedEditIR(id) { + var grant = AuthAPI.getIRGrant(id); + return grant.isOwner || + AuthAPI.isPermitted("write:incidence") || + AuthAPI.checkAccess("WRITE", grant.accessTypes); + } + + function isPermittedCopyIR(id) { + return isPermittedReadIR(id) && isPermittedCreateIR(); + }; + + function isPermittedDeleteIR(id) { + return isPermittedEditIR(id); + }; + function isPermittedExportSQL() { - return AuthAPI.isPermitted('ir:sql:post'); + return true; // TODO: no permissions required } return { + isPermittedReadIRs, + isPermittedReadIR, + isPermittedExport, + isPermittedCreateIR, + isPermittedImport, + isPermittedCopyIR, + isPermittedDeleteIR, + isPermittedEditIR, isPermittedExportSQL, }; diff --git a/js/pages/incidence-rates/components/iranalysis/components/editor.html b/js/pages/incidence-rates/components/iranalysis/components/editor.html index 4d72744ef..6aad9514c 100644 --- a/js/pages/incidence-rates/components/iranalysis/components/editor.html +++ b/js/pages/incidence-rates/components/iranalysis/components/editor.html @@ -1,4 +1,4 @@ -
+
diff --git a/js/pages/incidence-rates/components/iranalysis/components/editor.js b/js/pages/incidence-rates/components/iranalysis/components/editor.js index 1c46f8c22..d7e960dd4 100644 --- a/js/pages/incidence-rates/components/iranalysis/components/editor.js +++ b/js/pages/incidence-rates/components/iranalysis/components/editor.js @@ -49,7 +49,7 @@ define([ // Subscriptions this.subscriptions.push(this.analysis.subscribe((newVal) => { //console.log("New analysis set."); - this.selectedStrataRule(params.analysis().strata()[this.selectedStrataRuleIndex]); + this.selectedStrataRule(this.analysis()?.strata()[this.selectedStrataRuleIndex]); })); } diff --git a/js/pages/incidence-rates/ir-browser.html b/js/pages/incidence-rates/ir-browser.html index 1dd93a2a6..089b811ce 100644 --- a/js/pages/incidence-rates/ir-browser.html +++ b/js/pages/incidence-rates/ir-browser.html @@ -18,4 +18,4 @@
- + diff --git a/js/pages/incidence-rates/ir-browser.js b/js/pages/incidence-rates/ir-browser.js index 4827cfa88..a2efc3a56 100644 --- a/js/pages/incidence-rates/ir-browser.js +++ b/js/pages/incidence-rates/ir-browser.js @@ -3,7 +3,7 @@ define([ 'text!./ir-browser.html', 'appConfig', 'services/IRAnalysis', - 'services/AuthAPI', + './PermissionService', 'pages/Page', 'utils/CommonUtils', 'utils/DatatableUtils', @@ -17,7 +17,7 @@ define([ view, config, IRAnalysisService, - authApi, + PermissionService, Page, commonUtils, datatableUtils, @@ -29,12 +29,9 @@ define([ this.loading = ko.observable(false); this.config = config; this.analysisList = ko.observableArray(); - this.isAuthenticated = authApi.isAuthenticated; - this.canReadIRs = ko.pureComputed(() => { - return (config.userAuthenticationEnabled && this.isAuthenticated() && authApi.isPermittedReadIRs()) || !config.userAuthenticationEnabled; - }); + this.canReadIRs = ko.pureComputed(() => true); // TODO: list operations should be unrestricted? this.canCreateIR = ko.pureComputed(() => { - return (config.userAuthenticationEnabled && this.isAuthenticated() && authApi.isPermittedCreateIR()) || !config.userAuthenticationEnabled; + return PermissionService.isPermittedCreateIR(); }); this.tableOptions = commonUtils.getTableOptions('L'); @@ -86,9 +83,7 @@ define([ ]); // startup actions - if (this.isAuthenticated() && this.canReadIRs()) { - this.refresh(); - } + this.refresh(); } refresh() { diff --git a/js/pages/incidence-rates/ir-manager.html b/js/pages/incidence-rates/ir-manager.html index ab7f76a96..64a299a04 100644 --- a/js/pages/incidence-rates/ir-manager.html +++ b/js/pages/incidence-rates/ir-manager.html @@ -7,7 +7,7 @@
- +
@@ -71,7 +71,7 @@
- +
@@ -80,7 +80,7 @@
@@ -158,7 +158,7 @@
diff --git a/js/pages/incidence-rates/ir-manager.js b/js/pages/incidence-rates/ir-manager.js index 77db6bb0d..98ee4aa4d 100644 --- a/js/pages/incidence-rates/ir-manager.js +++ b/js/pages/incidence-rates/ir-manager.js @@ -58,7 +58,7 @@ define([ authAPI, FileService, JobPollService, - { isPermittedExportSQL }, + PermissionService, GlobalPermissionService, TagsService, { entityType }, @@ -87,54 +87,27 @@ define([ this.dirtyFlag = sharedState.IRAnalysis.dirtyFlag; this.enablePermissionManagement = config.enablePermissionManagement; this.exporting = ko.observable(); - this.isAuthenticated = ko.pureComputed(() => { - return authAPI.isAuthenticated(); - }); this.defaultName = ko.unwrap(globalConstants.newEntityNames.incidenceRate); this.conceptSetStore = ConceptSetStore.getStore(ConceptSetStore.sourceKeys().incidenceRates); this.isViewPermitted = ko.pureComputed(() => { - return !config.userAuthenticationEnabled - || ( - config.userAuthenticationEnabled - && authAPI.isPermittedReadIRs() - ) + return PermissionService.isPermittedReadIR(this.selectedAnalysisId()); }); this.canCreate = ko.pureComputed(() => { - return !config.userAuthenticationEnabled - || ( - config.userAuthenticationEnabled - && authAPI.isPermittedCreateIR() - ) - }); - this.isDeletable = ko.pureComputed(() => { - return !config.userAuthenticationEnabled - || ( - config.userAuthenticationEnabled - && authAPI.isPermittedDeleteIR(this.selectedAnalysisId()) - ) + return PermissionService.isPermittedCreateIR(); }); this.isEditable = ko.pureComputed(() => { - return this.selectedAnalysisId() === null || this.selectedAnalysisId() === 0 - || !config.userAuthenticationEnabled - || ( - config.userAuthenticationEnabled - && authAPI.isPermittedEditIR(this.selectedAnalysisId()) - ) + return this.selectedAnalysisId() === null + || this.selectedAnalysisId() === 0 + || PermissionService.isPermittedEditIR(this.selectedAnalysisId()) }); + this.isDeletable = this.isEditable; // if you can edit, you can delete this.canCopy = ko.pureComputed(() => { - return !config.userAuthenticationEnabled - || ( - config.userAuthenticationEnabled - && authAPI.isPermittedCopyIR(this.selectedAnalysisId()) - && !this.dirtyFlag().isDirty() - ) - }); - this.isPermittedExportSQL = isPermittedExportSQL; - this.selectedAnalysisId.subscribe((id) => { - if (config.userAuthenticationEnabled && authAPI.isAuthenticated) { - authAPI.loadUserInfo(); - } + return PermissionService.isPermittedCopyIR(this.selectedAnalysisId()) + && !this.dirtyFlag().isDirty(); }); + this.isPermittedImport = PermissionService.isPermittedImport; + this.isPermittedExport = PermissionService.isPermittedExport; + this.isPermittedExportSQL = PermissionService.isPermittedExportSQL; this.isRunning = ko.observable(false); this.activeTab = ko.observable(params.activeTab || this.tabs.DEFINITION); @@ -155,6 +128,7 @@ define([ } return analysisCohorts; }); + this.showConceptSetBrowser = ko.observable(false); this.criteriaContext = ko.observable(); this.generateActionsSettings = { @@ -300,14 +274,6 @@ define([ this.init(); } - isPermittedImport() { - return authAPI.isPermitted(`ir:design:post`); - } - - isPermittedExport(id) { - return authAPI.isPermitted(`ir:${id}:design:get`); - } - diagnose() { if (this.selectedAnalysis()) { return IRAnalysisService.runDiagnostics(this.selectedAnalysis()); diff --git a/js/services/AuthAPI.js b/js/services/AuthAPI.js index fe6f98909..58ea675e7 100644 --- a/js/services/AuthAPI.js +++ b/js/services/AuthAPI.js @@ -242,6 +242,12 @@ define(function(require, exports) { return authz[faId] || NONE_ENTITY_GRANT; // assign a falsy entity grant if not found } + var getIRGrant = function(id) { + var irId = +id; // force to numeric + var authz = permissions().incidenceRateAccess; + return authz[irId] || NONE_ENTITY_GRANT; // assign a falsy entity grant if not found + } + function base64urldecode(arg) { var s = arg; s = s.replace(/-/g, '+'); // 62nd char of encoding @@ -311,19 +317,6 @@ define(function(require, exports) { return isPermittedUpdateConceptset(id); }; - // TODO: we don't need perms to list incidence rates - var isPermittedReadIRs = function () { - return true; - }; - - var isPermittedCreateIR = function () { - return isPermitted('create:incidence'); - }; - - var isPermittedCopyIR = function(id) { - return isPermittedCreateIR(); - }; - var isPermittedEditSourcePriortiy = function() { return isPermitted('admin:source') }; @@ -555,6 +548,7 @@ define(function(require, exports) { // will add the various get{entity} grants here getCCGrant: getCCGrant, getFAGrant: getFAGrant, + getIRGrant: getIRGrant, isPermittedCreateConceptset: isPermittedCreateConceptset, isPermittedReadConceptset: isPermittedReadConceptset, @@ -583,10 +577,6 @@ define(function(require, exports) { isPermittedEditRoleUsers: isPermittedEditRoleUsers, isPermittedEditRolePermissions: isPermittedEditRolePermissions, - isPermittedReadIRs: isPermittedReadIRs, - isPermittedCreateIR: isPermittedCreateIR, - isPermittedCopyIR, - isPermittedViewCdmResults: isPermittedViewCdmResults, isPermittedViewProfiles: isPermittedViewProfiles, isPermittedViewProfileDates: isPermittedViewProfileDates, diff --git a/js/services/IRAnalysis.js b/js/services/IRAnalysis.js index 19daf1088..63d9179a4 100644 --- a/js/services/IRAnalysis.js +++ b/js/services/IRAnalysis.js @@ -50,13 +50,13 @@ define(function (require, exports) { const url = `${config.webAPIRoot}ir/${definitionCopy.id || ""}`; let result; if (definitionCopy.id) { - result = await httpService + result = authApi.executeWithRefresh(httpService .doPut(url, definitionCopy) .catch(response => { authApi.handleAccessDenied(response); return response; }) - .then(parse); + .then(parse)); } else { result = authApi.executeWithRefresh(httpService .doPost(url, definitionCopy) From a160217c9836a45231d982640b9c8bab5c30c5fc Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Tue, 7 Apr 2026 17:02:14 -0400 Subject: [PATCH 05/21] Fixed permissions for data-sources. --- js/pages/data-sources/data-sources.js | 2 +- js/pages/pathways/PermissionService.js | 43 +++++++++++++++++++------- js/services/AuthAPI.js | 12 +++++-- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/js/pages/data-sources/data-sources.js b/js/pages/data-sources/data-sources.js index 95206ccc4..325292a04 100644 --- a/js/pages/data-sources/data-sources.js +++ b/js/pages/data-sources/data-sources.js @@ -119,7 +119,7 @@ define([ this.isAuthenticated = authApi.isAuthenticated; this.canViewCdmResults = ko.pureComputed(() => { - return (config.userAuthenticationEnabled && this.isAuthenticated() && authApi.isPermittedViewCdmResults()) || !config.userAuthenticationEnabled; + return authApi.isPermittedViewCdmResults(); }); this.showSelectionArea = params.showSelectionArea == undefined ? true : params.showSelectionArea; diff --git a/js/pages/pathways/PermissionService.js b/js/pages/pathways/PermissionService.js index fa36f600b..cc44ce9b5 100644 --- a/js/pages/pathways/PermissionService.js +++ b/js/pages/pathways/PermissionService.js @@ -3,53 +3,72 @@ define([ ], function ( AuthAPI, ) { + function canCreate() { + return AuthAPI.isPermitted('create:pathway'); + } + + function canRead(id) { + var grant = AuthAPI.getPathwayGrant(id); + return grant.isOwner || + AuthAPI.isPermitted('read:pathway') || + AuthAPI.isPermitted('write:pathway') || + AuthAPI.checkAccess('READ', grant.accessTypes); + } + + function canWrite(id) { + var grant = AuthAPI.getPathwayGrant(id); + return grant.isOwner || + AuthAPI.isPermitted('write:pathway') || + AuthAPI.checkAccess('WRITE', grant.accessTypes); + } function isPermittedCreate() { - return AuthAPI.isPermitted(`pathway-analysis:post`); + return canCreate(); } function isPermittedImport() { - return AuthAPI.isPermitted(`pathway-analysis:import:post`); + return isPermittedCreate(); } function isPermittedList() { - return AuthAPI.isPermitted(`pathway-analysis:get`); + return AuthAPI.isPermitted('read:pathway'); } function isPermittedLoad(id) { - return AuthAPI.isPermitted(`pathway-analysis:${id}:get`); + return canRead(id); } function isPermittedUpdate(id) { - return AuthAPI.isPermitted(`pathway-analysis:${id}:put`); + return canWrite(id); } function isPermittedDelete(id) { - return AuthAPI.isPermitted(`pathway-analysis:${id}:delete`); + return isPermittedUpdate(id); } function isPermittedListGenerations(id) { - return AuthAPI.isPermitted(`pathway-analysis:${id}:generation:get`); + return isPermittedLoad(id); } function isPermittedGenerate(id, sourceKey) { - return AuthAPI.isPermitted(`pathway-analysis:${id}:generation:${sourceKey}:post`); + // allow generate only if user has write access to the source + return AuthAPI.hasSourceAccess(sourceKey, 'WRITE'); } function isPermittedResults(sourceKey) { - return AuthAPI.isPermitted(`pathway-analysis:generation:*:result:get`) && AuthAPI.isPermitted(`source:${sourceKey}:access`); + return AuthAPI.hasSourceAccess(sourceKey, 'READ'); } function isPermittedExportGenerationDesign(id) { - return AuthAPI.isPermitted(`pathway-analysis:generation:${id}:design:get`); + return isPermittedLoad(id); } function isPermittedExport(id) { - return AuthAPI.isPermitted(`pathway-analysis:${id}:export:get`); + return isPermittedLoad(id); } function isPermittedCopy(id) { - return AuthAPI.isPermitted(`pathway-analysis:${id}:post`); + return isPermittedCreate() && isPermittedLoad(id); } diff --git a/js/services/AuthAPI.js b/js/services/AuthAPI.js index 58ea675e7..49129de27 100644 --- a/js/services/AuthAPI.js +++ b/js/services/AuthAPI.js @@ -248,6 +248,11 @@ define(function(require, exports) { return authz[irId] || NONE_ENTITY_GRANT; // assign a falsy entity grant if not found } + var getPathwayGrant = function(id) { + var pathwayId = +id; // force to numeric + var authz = permissions().pathwayAccess; + return authz[pathwayId] || NONE_ENTITY_GRANT; // assign a falsy entity grant if not found + } function base64urldecode(arg) { var s = arg; s = s.replace(/-/g, '+'); // 62nd char of encoding @@ -322,7 +327,7 @@ define(function(require, exports) { }; var isPermittedViewCdmResults = function () { - return isPermitted('cdmresults:*:get'); + return true; // TODO: Do we need general view permission + source?? }; var isPermittedViewProfiles = function (sourceKey) { @@ -485,9 +490,9 @@ define(function(require, exports) { const isPermittedRunAs = () => isPermitted('user:runas:post'); - const isPermittedViewDataSourceReport = sourceKey => isPermitted(`cdmresults:${sourceKey}:*:get`); + const isPermittedViewDataSourceReport = sourceKey => hasSourceAccess(sourceKey); - const isPermittedViewDataSourceReportDetails = sourceKey => isPermitted(`cdmresults:${sourceKey}:*:*:get`); + const isPermittedViewDataSourceReportDetails = sourceKey => hasSourceAccess(sourceKey); const setAuthParams = (jwt) => { !!jwt && token(jwt); @@ -549,6 +554,7 @@ define(function(require, exports) { getCCGrant: getCCGrant, getFAGrant: getFAGrant, getIRGrant: getIRGrant, + getPathwayGrant: getPathwayGrant, isPermittedCreateConceptset: isPermittedCreateConceptset, isPermittedReadConceptset: isPermittedReadConceptset, From e0f9a9b6f749e2a8d1b713da106b30e869a3203e Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Tue, 7 Apr 2026 17:39:47 -0400 Subject: [PATCH 06/21] Remove preduction and estimation UI elements. --- js/Application.js | 2 - js/components/atlas-state.js | 18 - js/components/security/access/const.js | 2 - js/const.js | 2 - js/pages/estimation/PermissionService.js | 56 -- js/pages/estimation/cca-manager.html | 80 --- js/pages/estimation/cca-manager.js | 596 ------------------ js/pages/estimation/cca-manager.less | 134 ---- .../cca-specification-view-edit.html | 141 ----- .../components/cca-specification-view-edit.js | 153 ----- .../cca-specification-view-edit.less | 3 - .../estimation/components/cca-utilities.html | 92 --- .../estimation/components/cca-utilities.js | 142 ----- .../cohort-method-analysis-editor.html | 280 -------- .../editors/cohort-method-analysis-editor.js | 174 ----- .../editors/cohort-method-analysis.less | 9 - .../components/editors/comparison-editor.html | 94 --- .../components/editors/comparison-editor.js | 88 --- .../components/editors/match-args-editor.html | 24 - .../components/editors/match-args-editor.js | 34 - ...ontrol-outcome-cohort-settings-editor.html | 20 - ...-control-outcome-cohort-settings-editor.js | 26 - .../editors/outcome-model-args-editor.html | 55 -- .../editors/outcome-model-args-editor.js | 61 -- ...tive-control-sythesis-settings-editor.html | 107 ---- ...sitive-control-sythesis-settings-editor.js | 44 -- .../editors/stratify-args-editor.html | 18 - .../editors/stratify-args-editor.js | 34 - js/pages/estimation/const.js | 446 ------------- js/pages/estimation/estimation-browser.html | 24 - js/pages/estimation/estimation-browser.js | 115 ---- js/pages/estimation/estimation-browser.less | 13 - js/pages/estimation/index.js | 34 - js/pages/estimation/inputTypes/Analysis.js | 17 - .../CohortMethodAnalysis.js | 56 -- .../ComparativeCohortAnalysis.js | 18 - .../ComparativeCohortAnalysis/CreatePsArgs.js | 27 - .../CreateStudyPopulationArgs.js | 28 - .../FitOutcomeModelArgs.js | 28 - .../ComparativeCohortAnalysis/FullAnalysis.js | 14 - .../GetDbCohortMethodDataArgs.js | 27 - .../MatchOnPsAndCovariateArgs.js | 20 - .../MatchOnPsArgs.js | 20 - .../StratifyByPsAndCovariatesArgs.js | 19 - .../StratifyByPsArgs.js | 19 - .../ComparativeCohortAnalysis/TrimByPsArgs.js | 17 - .../TrimByPsToEquipoiseArgs.js | 17 - js/pages/estimation/inputTypes/Comparison.js | 22 - .../inputTypes/EstimationAnalysis.js | 48 -- .../inputTypes/EstimationAnalysisSettings.js | 24 - .../inputTypes/EstimationCovariateSettings.js | 18 - .../estimation/inputTypes/NegativeControl.js | 12 - ...NegativeControlExposureCohortDefinition.js | 12 - .../NegativeControlOutcomeCohortDefinition.js | 15 - .../PositiveControlSynthesisArgs.js | 36 -- .../inputTypes/TargetComparatorOutcome.js | 15 - .../inputTypes/TargetComparatorOutcomes.js | 17 - .../estimation/inputTypes/TargetOutcomes.js | 14 - js/pages/estimation/routes.js | 31 - js/pages/main.js | 4 - js/pages/prediction/PermissionService.js | 56 -- .../editors/evaluation-settings-editor.html | 26 - .../editors/evaluation-settings-editor.js | 47 -- .../editors/execution-settings-editor.html | 24 - .../editors/execution-settings-editor.js | 37 -- .../editors/model-settings-editor.html | 5 - .../editors/model-settings-editor.js | 30 - .../ModelSettingsEditorComponent.js | 48 -- .../modelSettings/ada-boost-settings.html | 8 - .../modelSettings/ada-boost-settings.js | 39 -- .../modelSettings/decision-tree-settings.html | 31 - .../modelSettings/decision-tree-settings.js | 61 -- .../modelSettings/decision-tree-settings.less | 5 - .../gradient-boosting-machine-settings.html | 29 - .../gradient-boosting-machine-settings.js | 60 -- .../editors/modelSettings/knn-settings.html | 11 - .../editors/modelSettings/knn-settings.js | 25 - .../lasso-logistic-regression-settings.html | 11 - .../lasso-logistic-regression-settings.js | 24 - .../editors/modelSettings/mlp-settings.html | 8 - .../editors/modelSettings/mlp-settings.js | 40 -- .../modelSettings/naive-bayes-settings.html | 1 - .../modelSettings/naive-bayes-settings.js | 19 - .../modelSettings/random-forest-settings.html | 34 - .../modelSettings/random-forest-settings.js | 54 -- .../editors/population-settings-editor.html | 66 -- .../editors/population-settings-editor.js | 30 - .../editors/population-settings-editor.less | 5 - .../prediction-covariate-settings-editor.html | 65 -- .../prediction-covariate-settings-editor.js | 63 -- .../prediction-specification-view-edit.html | 244 ------- .../prediction-specification-view-edit.js | 220 ------- .../prediction-specification-view-edit.less | 6 - .../components/prediction-utilities.html | 183 ------ .../components/prediction-utilities.js | 163 ----- js/pages/prediction/const.js | 404 ------------ js/pages/prediction/index.js | 35 - .../inputTypes/CreateStudyPopulationArgs.js | 28 - .../prediction/inputTypes/FullAnalysis.js | 23 - .../prediction/inputTypes/GetDbPlpDataArgs.js | 15 - .../inputTypes/ModelCovarPopTuple.js | 17 - .../prediction/inputTypes/ModelSettings.js | 396 ------------ .../PatientLevelPredictionAnalysis.js | 52 -- .../inputTypes/PredictionCovariateSettings.js | 18 - js/pages/prediction/inputTypes/RunPlpArgs.js | 19 - .../prediction/inputTypes/TargetOutcome.js | 16 - .../modelSettings/AdaBoostSettings.js | 16 - .../modelSettings/DecisionTreeSettings.js | 19 - .../GradientBoostingMachineSettings.js | 19 - .../inputTypes/modelSettings/KNNSettings.js | 14 - .../LassoLogisticRegressionSettings.js | 15 - .../inputTypes/modelSettings/MLPSettings.js | 16 - .../modelSettings/NaiveBayesSettings.js | 12 - .../modelSettings/RandomForestSettings.js | 18 - js/pages/prediction/prediction-browser.html | 22 - js/pages/prediction/prediction-browser.js | 116 ---- js/pages/prediction/prediction-browser.less | 9 - js/pages/prediction/prediction-manager.html | 94 --- js/pages/prediction/prediction-manager.js | 495 --------------- js/pages/prediction/prediction-manager.less | 112 ---- js/pages/prediction/routes.js | 39 -- js/pages/prediction/utils.js | 48 -- js/services/Estimation.js | 116 ---- js/services/JobDetailsService.js | 11 - js/services/Prediction.js | 111 ---- js/services/Tags.js | 2 - 126 files changed, 7821 deletions(-) delete mode 100644 js/pages/estimation/PermissionService.js delete mode 100644 js/pages/estimation/cca-manager.html delete mode 100644 js/pages/estimation/cca-manager.js delete mode 100644 js/pages/estimation/cca-manager.less delete mode 100644 js/pages/estimation/components/cca-specification-view-edit.html delete mode 100644 js/pages/estimation/components/cca-specification-view-edit.js delete mode 100644 js/pages/estimation/components/cca-specification-view-edit.less delete mode 100644 js/pages/estimation/components/cca-utilities.html delete mode 100644 js/pages/estimation/components/cca-utilities.js delete mode 100644 js/pages/estimation/components/editors/cohort-method-analysis-editor.html delete mode 100644 js/pages/estimation/components/editors/cohort-method-analysis-editor.js delete mode 100644 js/pages/estimation/components/editors/cohort-method-analysis.less delete mode 100644 js/pages/estimation/components/editors/comparison-editor.html delete mode 100644 js/pages/estimation/components/editors/comparison-editor.js delete mode 100644 js/pages/estimation/components/editors/match-args-editor.html delete mode 100644 js/pages/estimation/components/editors/match-args-editor.js delete mode 100644 js/pages/estimation/components/editors/negative-control-outcome-cohort-settings-editor.html delete mode 100644 js/pages/estimation/components/editors/negative-control-outcome-cohort-settings-editor.js delete mode 100644 js/pages/estimation/components/editors/outcome-model-args-editor.html delete mode 100644 js/pages/estimation/components/editors/outcome-model-args-editor.js delete mode 100644 js/pages/estimation/components/editors/positive-control-sythesis-settings-editor.html delete mode 100644 js/pages/estimation/components/editors/positive-control-sythesis-settings-editor.js delete mode 100644 js/pages/estimation/components/editors/stratify-args-editor.html delete mode 100644 js/pages/estimation/components/editors/stratify-args-editor.js delete mode 100644 js/pages/estimation/const.js delete mode 100644 js/pages/estimation/estimation-browser.html delete mode 100644 js/pages/estimation/estimation-browser.js delete mode 100644 js/pages/estimation/estimation-browser.less delete mode 100644 js/pages/estimation/index.js delete mode 100644 js/pages/estimation/inputTypes/Analysis.js delete mode 100644 js/pages/estimation/inputTypes/ComparativeCohortAnalysis/CohortMethodAnalysis.js delete mode 100644 js/pages/estimation/inputTypes/ComparativeCohortAnalysis/ComparativeCohortAnalysis.js delete mode 100644 js/pages/estimation/inputTypes/ComparativeCohortAnalysis/CreatePsArgs.js delete mode 100644 js/pages/estimation/inputTypes/ComparativeCohortAnalysis/CreateStudyPopulationArgs.js delete mode 100644 js/pages/estimation/inputTypes/ComparativeCohortAnalysis/FitOutcomeModelArgs.js delete mode 100644 js/pages/estimation/inputTypes/ComparativeCohortAnalysis/FullAnalysis.js delete mode 100644 js/pages/estimation/inputTypes/ComparativeCohortAnalysis/GetDbCohortMethodDataArgs.js delete mode 100644 js/pages/estimation/inputTypes/ComparativeCohortAnalysis/MatchOnPsAndCovariateArgs.js delete mode 100644 js/pages/estimation/inputTypes/ComparativeCohortAnalysis/MatchOnPsArgs.js delete mode 100644 js/pages/estimation/inputTypes/ComparativeCohortAnalysis/StratifyByPsAndCovariatesArgs.js delete mode 100644 js/pages/estimation/inputTypes/ComparativeCohortAnalysis/StratifyByPsArgs.js delete mode 100644 js/pages/estimation/inputTypes/ComparativeCohortAnalysis/TrimByPsArgs.js delete mode 100644 js/pages/estimation/inputTypes/ComparativeCohortAnalysis/TrimByPsToEquipoiseArgs.js delete mode 100644 js/pages/estimation/inputTypes/Comparison.js delete mode 100644 js/pages/estimation/inputTypes/EstimationAnalysis.js delete mode 100644 js/pages/estimation/inputTypes/EstimationAnalysisSettings.js delete mode 100644 js/pages/estimation/inputTypes/EstimationCovariateSettings.js delete mode 100644 js/pages/estimation/inputTypes/NegativeControl.js delete mode 100644 js/pages/estimation/inputTypes/NegativeControlExposureCohortDefinition.js delete mode 100644 js/pages/estimation/inputTypes/NegativeControlOutcomeCohortDefinition.js delete mode 100644 js/pages/estimation/inputTypes/PositiveControlSynthesisArgs.js delete mode 100644 js/pages/estimation/inputTypes/TargetComparatorOutcome.js delete mode 100644 js/pages/estimation/inputTypes/TargetComparatorOutcomes.js delete mode 100644 js/pages/estimation/inputTypes/TargetOutcomes.js delete mode 100644 js/pages/estimation/routes.js delete mode 100644 js/pages/prediction/PermissionService.js delete mode 100644 js/pages/prediction/components/editors/evaluation-settings-editor.html delete mode 100644 js/pages/prediction/components/editors/evaluation-settings-editor.js delete mode 100644 js/pages/prediction/components/editors/execution-settings-editor.html delete mode 100644 js/pages/prediction/components/editors/execution-settings-editor.js delete mode 100644 js/pages/prediction/components/editors/model-settings-editor.html delete mode 100644 js/pages/prediction/components/editors/model-settings-editor.js delete mode 100644 js/pages/prediction/components/editors/modelSettings/ModelSettingsEditorComponent.js delete mode 100644 js/pages/prediction/components/editors/modelSettings/ada-boost-settings.html delete mode 100644 js/pages/prediction/components/editors/modelSettings/ada-boost-settings.js delete mode 100644 js/pages/prediction/components/editors/modelSettings/decision-tree-settings.html delete mode 100644 js/pages/prediction/components/editors/modelSettings/decision-tree-settings.js delete mode 100644 js/pages/prediction/components/editors/modelSettings/decision-tree-settings.less delete mode 100644 js/pages/prediction/components/editors/modelSettings/gradient-boosting-machine-settings.html delete mode 100644 js/pages/prediction/components/editors/modelSettings/gradient-boosting-machine-settings.js delete mode 100644 js/pages/prediction/components/editors/modelSettings/knn-settings.html delete mode 100644 js/pages/prediction/components/editors/modelSettings/knn-settings.js delete mode 100644 js/pages/prediction/components/editors/modelSettings/lasso-logistic-regression-settings.html delete mode 100644 js/pages/prediction/components/editors/modelSettings/lasso-logistic-regression-settings.js delete mode 100644 js/pages/prediction/components/editors/modelSettings/mlp-settings.html delete mode 100644 js/pages/prediction/components/editors/modelSettings/mlp-settings.js delete mode 100644 js/pages/prediction/components/editors/modelSettings/naive-bayes-settings.html delete mode 100644 js/pages/prediction/components/editors/modelSettings/naive-bayes-settings.js delete mode 100644 js/pages/prediction/components/editors/modelSettings/random-forest-settings.html delete mode 100644 js/pages/prediction/components/editors/modelSettings/random-forest-settings.js delete mode 100644 js/pages/prediction/components/editors/population-settings-editor.html delete mode 100644 js/pages/prediction/components/editors/population-settings-editor.js delete mode 100644 js/pages/prediction/components/editors/population-settings-editor.less delete mode 100644 js/pages/prediction/components/editors/prediction-covariate-settings-editor.html delete mode 100644 js/pages/prediction/components/editors/prediction-covariate-settings-editor.js delete mode 100644 js/pages/prediction/components/prediction-specification-view-edit.html delete mode 100644 js/pages/prediction/components/prediction-specification-view-edit.js delete mode 100644 js/pages/prediction/components/prediction-specification-view-edit.less delete mode 100644 js/pages/prediction/components/prediction-utilities.html delete mode 100644 js/pages/prediction/components/prediction-utilities.js delete mode 100644 js/pages/prediction/const.js delete mode 100644 js/pages/prediction/index.js delete mode 100644 js/pages/prediction/inputTypes/CreateStudyPopulationArgs.js delete mode 100644 js/pages/prediction/inputTypes/FullAnalysis.js delete mode 100644 js/pages/prediction/inputTypes/GetDbPlpDataArgs.js delete mode 100644 js/pages/prediction/inputTypes/ModelCovarPopTuple.js delete mode 100644 js/pages/prediction/inputTypes/ModelSettings.js delete mode 100644 js/pages/prediction/inputTypes/PatientLevelPredictionAnalysis.js delete mode 100644 js/pages/prediction/inputTypes/PredictionCovariateSettings.js delete mode 100644 js/pages/prediction/inputTypes/RunPlpArgs.js delete mode 100644 js/pages/prediction/inputTypes/TargetOutcome.js delete mode 100644 js/pages/prediction/inputTypes/modelSettings/AdaBoostSettings.js delete mode 100644 js/pages/prediction/inputTypes/modelSettings/DecisionTreeSettings.js delete mode 100644 js/pages/prediction/inputTypes/modelSettings/GradientBoostingMachineSettings.js delete mode 100644 js/pages/prediction/inputTypes/modelSettings/KNNSettings.js delete mode 100644 js/pages/prediction/inputTypes/modelSettings/LassoLogisticRegressionSettings.js delete mode 100644 js/pages/prediction/inputTypes/modelSettings/MLPSettings.js delete mode 100644 js/pages/prediction/inputTypes/modelSettings/NaiveBayesSettings.js delete mode 100644 js/pages/prediction/inputTypes/modelSettings/RandomForestSettings.js delete mode 100644 js/pages/prediction/prediction-browser.html delete mode 100644 js/pages/prediction/prediction-browser.js delete mode 100644 js/pages/prediction/prediction-browser.less delete mode 100644 js/pages/prediction/prediction-manager.html delete mode 100644 js/pages/prediction/prediction-manager.js delete mode 100644 js/pages/prediction/prediction-manager.less delete mode 100644 js/pages/prediction/routes.js delete mode 100644 js/pages/prediction/utils.js delete mode 100644 js/services/Estimation.js delete mode 100644 js/services/Prediction.js diff --git a/js/Application.js b/js/Application.js index ee77a8e25..dd6a5612d 100644 --- a/js/Application.js +++ b/js/Application.js @@ -51,8 +51,6 @@ define( || sharedState.CohortDefinition.dirtyFlag().isDirty() || sharedState.IRAnalysis.dirtyFlag().isDirty() || sharedState.CohortPathways.dirtyFlag().isDirty() - || sharedState.estimationAnalysis.dirtyFlag().isDirty() - || sharedState.predictionAnalysis.dirtyFlag().isDirty() || sharedState.CohortCharacterization.dirtyFlag().isDirty() ); }); diff --git a/js/components/atlas-state.js b/js/components/atlas-state.js index 3fb2f998f..57dd36fe2 100644 --- a/js/components/atlas-state.js +++ b/js/components/atlas-state.js @@ -84,24 +84,6 @@ define(['knockout', 'lscache', 'services/job/jobDetail', 'assets/ohdsi.util', 'c }; state.CohortPathways.dirtyFlag = ko.observable(new ohdsiUtil.dirtyFlag(state.CohortPathways.current())); - - state.estimationAnalysis = { - current: ko.observable(null), - analysisPath: null, - selectedId: ko.observable(null), - comparisons: ko.observableArray(), - } - state.estimationAnalysis.dirtyFlag = ko.observable(new ohdsiUtil.dirtyFlag(state.estimationAnalysis.current())); - - state.predictionAnalysis = { - current: ko.observable(null), - analysisPath: null, - selectedId: ko.observable(null), - targetCohorts: ko.observableArray(), - outcomeCohorts: ko.observableArray(), - } - state.predictionAnalysis.dirtyFlag = ko.observable(new ohdsiUtil.dirtyFlag(state.predictionAnalysis.current())); - state.availableLocales = ko.observableArray(); state.locale = ko.observable(); state.localeSettings = ko.observable(); diff --git a/js/components/security/access/const.js b/js/components/security/access/const.js index f305e8ccc..6aa3d93a6 100644 --- a/js/components/security/access/const.js +++ b/js/components/security/access/const.js @@ -8,8 +8,6 @@ define([], function () { FE_ANALYSIS: 'FE_ANALYSIS', INCIDENCE_RATE: 'INCIDENCE_RATE', SOURCE: 'SOURCE', - ESTIMATION: 'ESTIMATION', - PREDICTION: 'PREDICTION', REUSABLE: 'REUSABLE' }; diff --git a/js/const.js b/js/const.js index b8a4ded79..8dbbd5195 100644 --- a/js/const.js +++ b/js/const.js @@ -248,9 +248,7 @@ define([ cohortDefinition: ko.i18n('const.newEntityNames.cohortDefinition', 'New Cohort Definition'), incidenceRate: ko.i18n('const.newEntityNames.incidenceRate', 'New Incidence Rate Analysis'), pathway: ko.i18n('const.newEntityNames.pathway', 'New Cohort Pathway'), - ple: ko.i18n('const.newEntityNames.ple', 'New Population Level Estimation Analysis'), conceptSet: ko.i18n('const.newEntityNames.conceptSet', 'New Concept Set'), - plp: ko.i18n('const.newEntityNames.plp', 'New Patient Level Prediction Analysis'), reusable: ko.i18n('const.newEntityNames.reusable', 'New Reusable'), }; diff --git a/js/pages/estimation/PermissionService.js b/js/pages/estimation/PermissionService.js deleted file mode 100644 index 0d365fbd4..000000000 --- a/js/pages/estimation/PermissionService.js +++ /dev/null @@ -1,56 +0,0 @@ -define([ - 'services/AuthAPI', -], function ( - AuthAPI, -) { - return class PermissionService { - - static isPermittedCreate() { - return AuthAPI.isPermitted(`estimation:post`); - } - - static isPermittedList() { - return AuthAPI.isPermitted(`estimation:get`); - } - - static isPermittedLoad(id) { - return AuthAPI.isPermitted(`estimation:${id}:get`); - } - - static isPermittedUpdate(id) { - return AuthAPI.isPermitted(`estimation:${id}:put`); - } - - static isPermittedDelete(id) { - return AuthAPI.isPermitted(`estimation:${id}:delete`); - } - - static isPermittedCopy(id) { - return AuthAPI.isPermitted(`estimation:${id}:copy:get`); - } - - static isPermittedDownload(id) { - return AuthAPI.isPermitted(`estimation:${id}:download:get`); - } - - static isPermittedExport(id) { - return AuthAPI.isPermitted(`estimation:${id}:export:get`); - } - - static isPermittedGenerate(id, sourceKey) { - return AuthAPI.isPermitted(`estimation:${id}:generation:*:post`) && AuthAPI.isPermitted(`source:${sourceKey}:access`); - } - - static isPermittedListGenerations(id) { - return AuthAPI.isPermitted(`estimation:${id}:generation:get`); - } - - static isPermittedResults(id) { - return AuthAPI.isPermitted(`estimation:generation:${id}:result:get`); - } - - static isPermittedImport() { - return AuthAPI.isPermitted(`estimation:import:post`); - } - } -}); diff --git a/js/pages/estimation/cca-manager.html b/js/pages/estimation/cca-manager.html deleted file mode 100644 index 05b1d6a02..000000000 --- a/js/pages/estimation/cca-manager.html +++ /dev/null @@ -1,80 +0,0 @@ - - - - - -
- - - - -
-
- -
- - - - - - - - - -
-
- -
- - - -
- - - - diff --git a/js/pages/estimation/cca-manager.js b/js/pages/estimation/cca-manager.js deleted file mode 100644 index 55ddf0d4c..000000000 --- a/js/pages/estimation/cca-manager.js +++ /dev/null @@ -1,596 +0,0 @@ -define([ - 'knockout', - 'text!./cca-manager.html', - 'pages/Page', - 'utils/CommonUtils', - 'assets/ohdsi.util', - 'appConfig', - './const', - 'const', - 'atlas-state', - 'pages/Router', - 'services/AuthAPI', - './PermissionService', - 'services/Permission', - 'components/security/access/const', - 'services/Estimation', - './inputTypes/EstimationAnalysis', - './inputTypes/Comparison', - 'services/analysis/ConceptSet', - './inputTypes/TargetComparatorOutcomes', - 'services/analysis/ConceptSetCrossReference', - 'featureextraction/InputTypes/CovariateSettings', - 'services/FeatureExtraction', - 'services/Poll', - 'lodash', - 'faceted-datatable', - 'components/tabs', - './components/cca-specification-view-edit', - './components/cca-utilities', - 'less!./cca-manager.less', - 'databindings', - 'components/security/access/configure-access-modal', - 'components/checks/warnings', - 'components/heading', - 'components/authorship', - 'components/name-validation', -], function ( - ko, - view, - Page, - commonUtils, - ohdsiUtil, - config, - constants, - globalConstants, - sharedState, - router, - authApi, - PermissionService, - GlobalPermissionService, - { entityType }, - EstimationService, - EstimationAnalysis, - Comparison, - ConceptSet, - TargetComparatorOutcomes, - ConceptSetCrossReference, - CovariateSettings, - FeatureExtractionService, - {PollService}, - lodash -) { - class ComparativeCohortAnalysisManager extends Page { - constructor(params) { - super(params); - sharedState.estimationAnalysis.analysisPath = constants.paths.ccaAnalysisDash; - - this.selectTab = this.selectTab.bind(this); - this.defaultLoadingMessage = ko.i18n('common.loadingWithDots', 'Loading...'); - this.estimationType = 'ComparativeCohortAnalysis'; - this.cohortMethodAnalysisList = null; - this.defaultCovariateSettings = ko.observable(); - this.options = constants.options; - this.config = config; - this.enablePermissionManagement = config.enablePermissionManagement; - this.loading = ko.observable(true); - this.isAuthenticated = ko.pureComputed(() => { - return authApi.isAuthenticated(); - }); - this.estimationAnalysis = sharedState.estimationAnalysis.current; - this.selectedAnalysisId = sharedState.estimationAnalysis.selectedId; - this.dirtyFlag = sharedState.estimationAnalysis.dirtyFlag; - this.tabMode = ko.observable('specification'); - this.comparisons = sharedState.estimationAnalysis.comparisons; - this.fullAnalysisList = ko.observableArray(); - this.fullSpecification = ko.observable(null); - this.isExporting = ko.observable(false); - this.loadingMessage = ko.observable(this.defaultLoadingMessage); - this.packageName = ko.observable().extend({alphaNumeric: null}); - this.selectedTabKey = ko.observable(router.routerParams().section); - this.isSaving = ko.observable(false); - this.isCopying = ko.observable(false); - this.isDeleting = ko.observable(false); - this.defaultName = ko.unwrap(globalConstants.newEntityNames.ple); - this.executionTabTitle = config.useExecutionEngine ? ko.i18n('ple.tabs.executions', 'Executions') : ""; - this.isProcessing = ko.computed(() => { - return this.isSaving() || this.isCopying() || this.isDeleting(); - }); - - this.isNameFilled = ko.computed(() => { - return this.estimationAnalysis() && this.estimationAnalysis().name() && this.estimationAnalysis().name().trim(); - }); - this.isNameCharactersValid = ko.computed(() => { - return this.isNameFilled() && commonUtils.isNameCharactersValid(this.estimationAnalysis().name()); - }); - this.isNameLengthValid = ko.computed(() => { - return this.isNameFilled() && commonUtils.isNameLengthValid(this.estimationAnalysis().name()); - }); - this.isDefaultName = ko.computed(() => { - return this.isNameFilled() && this.estimationAnalysis().name().trim() === this.defaultName; - }); - this.isNameCorrect = ko.computed(() => { - return this.isNameFilled() && !this.isDefaultName() && this.isNameCharactersValid() && this.isNameLengthValid(); - }); - - this.isViewPermitted = ko.pureComputed(() => { - return PermissionService.isPermittedLoad(this.selectedAnalysisId()); - }); - - this.canDelete = ko.pureComputed(() => { - return PermissionService.isPermittedDelete(this.selectedAnalysisId()); - }); - - this.canCopy = ko.pureComputed(() => { - return PermissionService.isPermittedCopy(this.selectedAnalysisId()); - }); - - this.canEdit = ko.pureComputed(() => parseInt(this.selectedAnalysisId()) ? PermissionService.isPermittedUpdate(this.selectedAnalysisId()) : PermissionService.isPermittedCreate()); - - this.canSave = ko.pureComputed(() => { - return this.dirtyFlag().isDirty() && this.isNameCorrect() && this.canEdit(); - }); - - this.selectedSourceId = ko.observable(router.routerParams().sourceId); - - this.criticalCount = ko.observable(0); - this.isDiagnosticsRunning = ko.observable(false); - - const extraExecutionPermissions = ko.computed(() => !this.dirtyFlag().isDirty() - && config.api.isExecutionEngineAvailable() - && this.canEdit() - && this.criticalCount() <= 0); - - const generationDisableReason = ko.computed(() => { - if (this.dirtyFlag().isDirty()) return ko.unwrap(globalConstants.disabledReasons.DIRTY); - if (this.criticalCount() > 0) return ko.unwrap(globalConstants.disabledReasons.INVALID_DESIGN); - if (!config.api.isExecutionEngineAvailable()) return ko.unwrap(globalConstants.disabledReasons.ENGINE_NOT_AVAILABLE); - return ko.unwrap(globalConstants.disabledReasons.ACCESS_DENIED); - }); - - this.componentParams = ko.observable({ - comparisons: sharedState.estimationAnalysis.comparisons, - defaultCovariateSettings: this.defaultCovariateSettings, - dirtyFlag: sharedState.estimationAnalysis.dirtyFlag, - estimationAnalysis: sharedState.estimationAnalysis.current, - estimationId: sharedState.estimationAnalysis.selectedId, - fullAnalysisList: this.fullAnalysisList, - fullSpecification: this.fullSpecification, - loading: this.loading, - loadingMessage: this.loadingMessage, - packageName: this.packageName, - subscriptions: this.subscriptions, - criticalCount: this.criticalCount, - analysisId: sharedState.estimationAnalysis.selectedId, - PermissionService, - ExecutionService: EstimationService, - extraExecutionPermissions, - tableColumns: ['Date', 'Status', 'Duration', 'Results'], - executionResultMode: globalConstants.executionResultModes.DOWNLOAD, - downloadFileName: 'estimation-analysis-results', - downloadApiPaths: constants.apiPaths, - runExecutionInParallel: true, - isEditPermitted: this.canEdit, - PollService: PollService, - selectedSourceId: this.selectedSourceId, - generationDisableReason, - resultsPathPrefix: '/estimation/cca/', - afterImportSuccess: this.afterImportSuccess.bind(this), - }); - - this.isNewEntity = this.isNewEntityResolver(); - - this.populationCaption = ko.computed(() => { - if (this.estimationAnalysis()) { - if (this.selectedAnalysisId() === '0') { - return ko.i18n('const.newEntityNames.ple', 'New Population Level Effect Estimation')() + ' - ' + - ko.i18n('ple.caption', 'Comparative Cohort Analysis')(); - } else { - return ko.i18n('ple.title', 'Population Level Effect Estimation')() + ' - ' + - ko.i18nformat('ple.captionNumber', 'Comparative Cohort Analysis #<%=id%>', {id: this.selectedAnalysisId()})(); - } - } - }); - - this.warningParams = ko.observable({ - current: sharedState.estimationAnalysis.current, - warningsTotal: ko.observable(0), - warningCount: ko.observable(0), - infoCount: ko.observable(0), - criticalCount: this.criticalCount, - changeFlag: ko.pureComputed(() => this.dirtyFlag().isChanged()), - isDiagnosticsRunning: this.isDiagnosticsRunning, - onDiagnoseCallback: this.diagnose.bind(this), - checkChangesOnly: true, - }); - - GlobalPermissionService.decorateComponent(this, { - entityTypeGetter: () => entityType.ESTIMATION, - entityIdGetter: () => this.selectedAnalysisId(), - createdByUsernameGetter: () => this.estimationAnalysis() && lodash.get(this.estimationAnalysis(), 'createdBy.login') - }); - } - - selectTab(index, { key }) { - this.selectedTabKey(key); - return commonUtils.routeTo('/estimation/cca/' + this.componentParams().estimationId() + '/' + key); - } - - isNewEntityResolver() { - return ko.computed(() => this.estimationAnalysis() && this.estimationAnalysis().id() < 1); - } - - async delete() { - if (!confirm(ko.i18n('ple.deleteConfirmation', 'Delete estimation specification? Warning: deletion can not be undone!')())) - return; - - this.isDeleting(true); - const analysis = await EstimationService.deleteEstimation(this.selectedAnalysisId()); - - this.loading(true); - this.estimationAnalysis(null); - this.selectedAnalysisId(null); - this.comparisons.removeAll(); - this.dirtyFlag(new ohdsiUtil.dirtyFlag(this.estimationAnalysis())); - document.location = constants.paths.browser() - } - - async save() { - this.isSaving(true); - this.loading(true); - - let estimationName = this.estimationAnalysis().name(); - this.estimationAnalysis().name(estimationName.trim()); - - // Next check to see that an estimation analysis with this name does not already exist - // in the database. Also pass the id so we can make sure that the current estimation analysis is excluded in this check. - try{ - const results = await EstimationService.exists(this.estimationAnalysis().name(), this.estimationAnalysis().id() == undefined ? 0 : this.estimationAnalysis().id()); - if (results > 0) { - alert(ko.i18n('ple.analysisExistsAlert', 'An estimation analysis with this name already exists. Please choose a different name.')()); - } else { - this.fullAnalysisList.removeAll(); - const payload = this.prepForSave(); - const savedEstimation = await EstimationService.saveEstimation(payload); - this.setAnalysis(savedEstimation); - commonUtils.routeTo(constants.paths.ccaAnalysis(this.estimationAnalysis().id())); - } - } catch (e) { - alert(ko.i18n('ple.analysisSaveErrorAlert', 'An error occurred while attempting to save an estimation analysis.')()); - } finally { - this.isSaving(false); - this.loading(false); - } - } - - prepForSave() { - const specification = ko.toJS(this.estimationAnalysis()); - - // createdBy/modifiedBy INSIDE the spec should not be objects, just a string - specification.createdBy = this.estimationAnalysis().createdBy ? this.estimationAnalysis().createdBy.login : null; - specification.modifiedBy = this.estimationAnalysis().modifiedBy ? this.estimationAnalysis().modifiedBy.login : null; - - specification.cohortDefinitions = []; - specification.conceptSets = []; - specification.conceptSetCrossReference = []; - specification.estimationAnalysisSettings.analysisSpecification.targetComparatorOutcomes = []; - specification.packageName = this.packageName(); - - this.comparisons().forEach((comp, index) => { - const tco = new TargetComparatorOutcomes({ - targetId: comp.target().id, - comparatorId: comp.comparator().id, - outcomeIds: comp.outcomes().map(d => {return d.id}), - }); - specification.estimationAnalysisSettings.analysisSpecification.targetComparatorOutcomes.push(tco); - this.addCohortToEstimation(specification, comp.target); - this.addCohortToEstimation(specification, comp.comparator); - comp.outcomes().map(o => this.addCohortToEstimation(specification, o)); - - if (comp.negativeControlOutcomesConceptSet() !== null && comp.negativeControlOutcomesConceptSet().id > 0) { - this.addConceptSetToEstimation(specification, ko.toJS(comp.negativeControlOutcomesConceptSet), - constants.conceptSetCrossReference.negativeControlOutcomes.targetName, - index, - constants.conceptSetCrossReference.negativeControlOutcomes.propertyName); - } - if (comp.includedCovariateConceptSet() !== null && comp.includedCovariateConceptSet().id > 0) { - this.addConceptSetToEstimation(specification, ko.toJS(comp.includedCovariateConceptSet), - constants.conceptSetCrossReference.targetComparatorOutcome.targetName, - index, - constants.conceptSetCrossReference.targetComparatorOutcome.propertyName.includedCovariateConcepts); - } - if (comp.excludedCovariateConceptSet() !== null && comp.excludedCovariateConceptSet().id > 0) { - this.addConceptSetToEstimation(specification, ko.toJS(comp.excludedCovariateConceptSet), - constants.conceptSetCrossReference.targetComparatorOutcome.targetName, - index, - constants.conceptSetCrossReference.targetComparatorOutcome.propertyName.excludedCovariateConcepts); - } - }); - specification.estimationAnalysisSettings.analysisSpecification.cohortMethodAnalysisList.forEach((a, index) => { - // Set the analysisId on each analysis - a.analysisId = index + 1; - - const covarSettings = a.getDbCohortMethodDataArgs.covariateSettings; - if (covarSettings.includedCovariateConceptSet !== null && covarSettings.includedCovariateConceptSet.id > 0) { - this.addConceptSetToEstimation(specification, covarSettings.includedCovariateConceptSet, - constants.conceptSetCrossReference.analysisCovariateSettings.targetName, - index, - constants.conceptSetCrossReference.analysisCovariateSettings.propertyName.includedCovariateConcepts); - } - if (covarSettings.excludedCovariateConceptSet !== null && covarSettings.excludedCovariateConceptSet.id > 0) { - this.addConceptSetToEstimation(specification, covarSettings.excludedCovariateConceptSet, - constants.conceptSetCrossReference.analysisCovariateSettings.targetName, - index, - constants.conceptSetCrossReference.analysisCovariateSettings.propertyName.excludedCovariateConcepts); - } - - // Remove the concept set references by setting it to the base class - specification.estimationAnalysisSettings.analysisSpecification.cohortMethodAnalysisList[index].getDbCohortMethodDataArgs.covariateSettings = ko.toJS(new CovariateSettings(covarSettings)); - }); - let pcsaCovarSettings = specification.positiveControlSynthesisArgs.covariateSettings; - if (pcsaCovarSettings != null) { - if (pcsaCovarSettings.includedCovariateConceptSet !== null && pcsaCovarSettings.includedCovariateConceptSet.id > 0) { - this.addConceptSetToEstimation(specification, pcsaCovarSettings.includedCovariateConceptSet, - constants.conceptSetCrossReference.positiveControlCovariateSettings.targetName, - index, - constants.conceptSetCrossReference.positiveControlCovariateSettings.targetName.includedCovariateConcepts); - } - if (pcsaCovarSettings.excludedCovariateConceptSet !== null && pcsaCovarSettings.excludedCovariateConceptSet.id > 0) { - this.addConceptSetToEstimation(specification, pcsaCovarSettings.excludedCovariateConceptSet, - constants.conceptSetCrossReference.positiveControlCovariateSettings.targetName, - index, - constants.conceptSetCrossReference.positiveControlCovariateSettings.targetName.includedCovariateConcepts); - } - - // Remove the concept set references by setting it to the base class - specification.positiveControlSynthesisArgs.covariateSettings = ko.toJS(new CovariateSettings(pcsaCovarSettings)); - } - - return { - id: this.estimationAnalysis().id(), - name: this.estimationAnalysis().name(), - type: this.estimationType, - description: this.estimationAnalysis().description(), - specification: ko.toJSON(specification), - }; - } - - close() { - if (this.dirtyFlag().isDirty() && !confirm(ko.i18n('ple.changesNotSavedConfirmation', 'Estimation Analysis changes are not saved. Would you like to continue?')())) { - return; - } - this.loading(true); - this.estimationAnalysis(null); - this.selectedAnalysisId(null); - this.comparisons.removeAll(); - this.dirtyFlag(new ohdsiUtil.dirtyFlag(this.estimationAnalysis())); - document.location = constants.paths.browser(); - } - - copy() { - this.isCopying(true); - this.loading(true); - EstimationService.copyEstimation(this.selectedAnalysisId()).then((analysis) => { - this.setAnalysis(analysis); - this.isCopying(false); - this.loading(false); - commonUtils.routeTo(constants.paths.ccaAnalysis(this.estimationAnalysis().id())); - }); - } - - diagnose() { - if (this.estimationAnalysis()) { - // do not pass modifiedBy and createdBy parameters to check - const modifiedBy = this.estimationAnalysis().modifiedBy; - this.estimationAnalysis().modifiedBy = null; - const createdBy = this.estimationAnalysis().createdBy; - this.estimationAnalysis().createdBy = null; - const payload = this.prepForSave(); - this.estimationAnalysis().modifiedBy = modifiedBy; - this.estimationAnalysis().createdBy = createdBy; - return EstimationService.runDiagnostics(payload); - - } - } - - loadAnalysisFromServer() { - this.loading(true); - EstimationService.getEstimation(this.selectedAnalysisId()).then((analysis) => { - this.setAnalysis(analysis); - this.loading(false); - }); - }; - - setAnalysis(analysis) { - const header = analysis.json; - const specification = JSON.parse(analysis.data.specification); - this.setParsedAnalysis(header, specification); - } - - setParsedAnalysis(header, specification) { - this.selectedAnalysisId(header.id); - this.estimationAnalysis(new EstimationAnalysis({ - ...specification, - ...header, - }, this.estimationType, this.defaultCovariateSettings())); - this.estimationAnalysis().id(header.id); - this.estimationAnalysis().name(header.name); - this.estimationAnalysis().description(header.description); - this.packageName(header.packageName); - this.setCohortMethodAnalysisList(); - this.setUserInterfaceDependencies(); - this.fullSpecification(null); - this.resetDirtyFlag(); - } - - setUserInterfaceDependencies() { - this.comparisons.removeAll(); - const cohortDefinitions = this.estimationAnalysis().cohortDefinitions(); - const conceptSets = this.estimationAnalysis().conceptSets(); - const csXref =this.estimationAnalysis().conceptSetCrossReference(); - this.estimationAnalysis().estimationAnalysisSettings.analysisSpecification.targetComparatorOutcomes().forEach((tco, index) => { - let target = null; - let comparator = null; - const outcomes = []; - - if (tco.targetId() !== null) { - const tCohortDefinitionList = cohortDefinitions.filter(d => d.id() === tco.targetId()); - if (tCohortDefinitionList.length > 0) { - target = {id: tco.targetId(), name: tCohortDefinitionList[0].name()}; - } else { - console.error("Target cohort id: " + tco.comparatorId() + " not found in cohort definition collection"); - } - } - if (tco.comparatorId() !== null) { - const cCohortDefinitionList = cohortDefinitions.filter(d => d.id() === tco.comparatorId()); - if (cCohortDefinitionList.length > 0) { - comparator = {id: tco.comparatorId(), name: cCohortDefinitionList[0].name()}; - } else { - console.error("Comparator cohort id: " + tco.comparatorId() + " not found in cohort definition collection"); - } - } - tco.outcomeIds().forEach(outcomeId => { - const oCohortDefinitionList = cohortDefinitions.filter(d => d.id() === outcomeId); - if (oCohortDefinitionList.length > 0) { - outcomes.push({id: outcomeId, name: oCohortDefinitionList[0].name()}); - } else { - console.error("Outcome cohort id: " + outcomeId + " not found in cohort definition collection"); - } - }); - - const comp = new Comparison({ - target: target, - comparator: comparator, - outcomes: outcomes, - }); - this.comparisons.push(comp); - }); - csXref.forEach((xref) => { - // Find the concept set each item - const selectedConceptSetList = conceptSets.filter((cs) => { return cs.id === xref.conceptSetId}); - if (selectedConceptSetList.length === 0) { - console.error("Concept Set: " + xref.conceptSetId + " not found in specification."); - } - const selectedConceptSet = new ConceptSet({id: selectedConceptSetList[0].id, name: selectedConceptSetList[0].name()}); - if (xref.targetName === constants.conceptSetCrossReference.targetComparatorOutcome.targetName) { - if (xref.propertyName === constants.conceptSetCrossReference.targetComparatorOutcome.propertyName.includedCovariateConcepts) { - this.comparisons()[xref.targetIndex].includedCovariateConceptSet(selectedConceptSet); - } - if (xref.propertyName === constants.conceptSetCrossReference.targetComparatorOutcome.propertyName.excludedCovariateConcepts) { - this.comparisons()[xref.targetIndex].excludedCovariateConceptSet(selectedConceptSet); - } - } else if (xref.targetName === constants.conceptSetCrossReference.negativeControlOutcomes.targetName) { - this.comparisons()[xref.targetIndex].negativeControlOutcomesConceptSet(selectedConceptSet); - } else if (xref.targetName === constants.conceptSetCrossReference.analysisCovariateSettings.targetName) { - const targetAnalysis = this.estimationAnalysis().estimationAnalysisSettings.analysisSpecification.cohortMethodAnalysisList()[xref.targetIndex]; - if (xref.propertyName === constants.conceptSetCrossReference.analysisCovariateSettings.propertyName.includedCovariateConcepts) { - targetAnalysis.getDbCohortMethodDataArgs.covariateSettings.includedCovariateConceptSet(selectedConceptSet); - } - if (xref.propertyName === constants.conceptSetCrossReference.analysisCovariateSettings.propertyName.excludedCovariateConcepts) { - targetAnalysis.getDbCohortMethodDataArgs.covariateSettings.excludedCovariateConceptSet(selectedConceptSet); - } - } else if (xref.targetName === constants.conceptSetCrossReference.positiveControlCovariateSettings.targetName) { - const targetPcsCovariateSettings = this.estimationAnalysis().positiveControlSynthesisArgs().covariateSettings; - if (xref.propertyName === constants.conceptSetCrossReference.positiveControlCovariateSettings.propertyName.includedCovariateConcepts) { - targetPcsCovariateSettings.includedCovariateConceptSet(selectedConceptSet); - } - if (xref.propertyName === constants.conceptSetCrossReference.positiveControlCovariateSettings.propertyName.excludedCovariateConcepts) { - targetPcsCovariateSettings.excludedCovariateConceptSet(selectedConceptSet); - } - } - }); - } - - setCohortMethodAnalysisList() { - this.cohortMethodAnalysisList = this.estimationAnalysis().estimationAnalysisSettings.analysisSpecification.cohortMethodAnalysisList; - } - - resetDirtyFlag() { - this.dirtyFlag(new ohdsiUtil.dirtyFlag({analysis: this.estimationAnalysis(), comparisons: this.comparisons})); - } - - newAnalysis() { - this.loading(true); - this.estimationAnalysis(new EstimationAnalysis({id: 0, name: this.defaultName}, this.estimationType, this.defaultCovariateSettings())); - return new Promise(async (resolve, reject) => { - this.setCohortMethodAnalysisList(); - this.resetDirtyFlag(); - this.loading(false); - - resolve(); - }); - } - - onPageCreated() { - FeatureExtractionService.getDefaultCovariateSettings().then(({ data }) => { - const selectedAnalysisId = parseInt(this.selectedAnalysisId()); - this.defaultCovariateSettings(data); - if (selectedAnalysisId === 0 && !this.dirtyFlag().isDirty()) { - this.newAnalysis(); - } else if (selectedAnalysisId > 0 && selectedAnalysisId !== (this.estimationAnalysis() && this.estimationAnalysis().id())) { - this.loadAnalysisFromServer(); - } else { - this.setCohortMethodAnalysisList(); - this.loading(false); - } - }).catch(() => this.loading(false)); - } - - onRouterParamsChanged({ id, section, sourceId }) { - if (section !== undefined) { - this.selectedTabKey(section); - } - if (sourceId !== undefined) { - this.selectedSourceId(sourceId); - } - if (id !== undefined && id !== parseInt(this.selectedAnalysisId())) { - this.onPageCreated(); - } - } - - addCohortToEstimation(specification, cohort) { - cohort = ko.isObservable(cohort) ? ko.utils.unwrapObservable(cohort) : cohort; - if (specification.cohortDefinitions.filter(element => element.id === cohort.id).length === 0) { - // Server expects createdBy and modifiedBy as string - if (cohort.createdBy && typeof cohort.createdBy === 'object') { - cohort.createdBy = cohort.createdBy.login; - } - if (cohort.modifiedBy && typeof cohort.modifiedBy === 'object') { - cohort.modifiedBy = cohort.modifiedBy.login; - } - specification.cohortDefinitions.push(cohort); - } - } - - addConceptSetToEstimation(specification, conceptSet, targetName, targetIndex, propertyName) { - if (specification.conceptSets.filter(element => element.id === conceptSet.id).length === 0) { - specification.conceptSets.push(conceptSet); - } - specification.conceptSetCrossReference.push( - new ConceptSetCrossReference({ - conceptSetId: conceptSet.id, - targetName: targetName, - targetIndex: targetIndex, - propertyName: propertyName - }) - ); - } - - async afterImportSuccess(res) { - commonUtils.routeTo('/estimation/cca/' + res.id); - }; - - getAuthorship() { - const createdDate = commonUtils.formatDateForAuthorship(this.estimationAnalysis().createdDate); - const modifiedDate = commonUtils.formatDateForAuthorship(this.estimationAnalysis().modifiedDate); - return { - createdBy: lodash.get(this.estimationAnalysis(), 'createdBy.name'), - createdDate, - modifiedBy: lodash.get(this.estimationAnalysis(), 'modifiedBy.name'), - modifiedDate, - } - } - } - - return commonUtils.build('cca-manager', ComparativeCohortAnalysisManager, view); -}); diff --git a/js/pages/estimation/cca-manager.less b/js/pages/estimation/cca-manager.less deleted file mode 100644 index af4179698..000000000 --- a/js/pages/estimation/cca-manager.less +++ /dev/null @@ -1,134 +0,0 @@ -.comparative-cohort-analysis-specification-view-edit, .cohort-method-analysis-editor, .comparison-editor { - &__analysis-name { - font-size: 14px; - } - &__analysis-name-input { - width: 500px; - } - &__analysis-name-container { - width: 10%; - float: left; - margin-right: 5px; - padding-top: 7px; - } - &__description-entry { - width: 100%; - } - &__panel-buffer { - margin-top: 15px; - } - &__panel-buffer-left { - margin-left: 5px; - } - .panel-default, .panel-primary { - .panel-heading { - line-height: 30px; - font-size: 14px; - } - .panel-heading span:before { - font-family: 'Glyphicons Halflings'; - float: right; - transition: all 0.5s; - } - .panel-heading.active span:before { - -webkit-transform: rotate(180deg); - -moz-transform: rotate(180deg); - transform: rotate(180deg); - } - .panel-subheading { - padding-top: 2px; - padding-bottom: 2px; - font-size: 12px; - } - .panel-heading-collapsible { - cursor: pointer; - } - } - .input-group { - padding-top: 2px; - padding-bottom: 5px; - } - input.dateField { - width: 90px; - padding: 0px; - line-height: .9em; - } - &__filter-group-bordered { - margin-top: 5px; - padding-top: 15px; - margin-bottom: 10px; - border-top: #CCC 1px solid; - } - &__filter-view { - padding-left: 5px; - padding-right: 10px; - font-weight: 700; - font-size: 12px; - color: #959595; - text-transform: uppercase; - letter-spacing: 1px; - line-height: 25px; - vertical-align: middle; - } - &__info-message { - padding: 5px; - margin: 5px; - font-style: italic; - font-size: 12px; - } - &__subsection { - padding-top: 10px; - } - .col-remove { - width: 50px; - text-align: center; - } - - .col-copy { - width: 80px; - text-align: center; - } - /* Tooltip container */ - .tool-tip { - cursor: help; - position: relative; - display: inline-block; - border-bottom: 1px dotted #ccc; - color: #006080; - /* Tooltip text */ - .tooltiptext { - visibility: hidden; - position: absolute; - width: 400px; - background-color: #333; - color: #fff; - text-align: center; - padding: 5px; - margin: 5px; - border-radius: 6px; - z-index: 1; - opacity: 0; - transition: opacity .6s; - - top: 105%; - left: 50%; - margin-left: -200px; - .tooltipitem { - text-align: left; - display: list-item; - list-style-type: disc; - list-style-position: inside; - margin-top: 2px; - padding-bottom: 2px; - } - } - } - - /* Show the tooltip text when you mouse over the tooltip container */ - .tool-tip:hover { - .tooltiptext { - visibility: visible; - opacity: 1; - } - } -} \ No newline at end of file diff --git a/js/pages/estimation/components/cca-specification-view-edit.html b/js/pages/estimation/components/cca-specification-view-edit.html deleted file mode 100644 index a53080633..000000000 --- a/js/pages/estimation/components/cca-specification-view-edit.html +++ /dev/null @@ -1,141 +0,0 @@ -
-
-
- -
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
- - -
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
- - -
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
- -
-
- - -
-
-
-
- -
-
-
- -
- -
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/js/pages/estimation/components/cca-specification-view-edit.js b/js/pages/estimation/components/cca-specification-view-edit.js deleted file mode 100644 index 9776ee694..000000000 --- a/js/pages/estimation/components/cca-specification-view-edit.js +++ /dev/null @@ -1,153 +0,0 @@ -define([ - 'knockout', - 'text!./cca-specification-view-edit.html', - 'utils/AutoBind', - 'components/Component', - 'utils/CommonUtils', - '../inputTypes/ComparativeCohortAnalysis/CohortMethodAnalysis', - '../inputTypes/Comparison', - '../const', - './editors/comparison-editor', - './editors/cohort-method-analysis-editor', - './editors/negative-control-outcome-cohort-settings-editor', - './editors/positive-control-sythesis-settings-editor', - 'less!./cca-specification-view-edit.less', -], function ( - ko, - view, - AutoBind, - Component, - commonUtils, - CohortMethodAnalysis, - Comparison, - constants, -) { - class ComparativeCohortAnalysisSpecificationViewEdit extends AutoBind(Component) { - constructor(params) { - super(params); - this.specificationPillMode = ko.observable('all'); - this.comparisons = params.comparisons; - this.cohortMethodAnalysisList = params.estimationAnalysis().estimationAnalysisSettings.analysisSpecification.cohortMethodAnalysisList; - this.subscriptions = params.subscriptions; - this.editorComponentName = ko.observable(null); - this.editorComponentParams = ko.observable({}); - this.editorDescription = ko.observable(); - this.editorHeading = ko.observable(); - this.editorArray = ko.observableArray(); - this.estimationAnalysis = params.estimationAnalysis; - this.options = constants.options; - this.isEditPermitted = params.isEditPermitted; - this.cca = constants.getCca(this.isEditPermitted())[0]; - this.loading = params.loading; - this.managerMode = ko.observable('summary'); - this.defaultCovariateSettings = params.defaultCovariateSettings; - } - - comparisonTableRowClickHandler(data, obj, tableRow, rowIndex) { - if ( - obj.target.className.indexOf("btn-remove") >= 0 || - obj.target.className.indexOf("fa-times") >= 0 - ) { - this.deleteFromTable(this.comparisons, obj, rowIndex); - } else if ( - obj.target.className.indexOf("btn-copy") >= 0 || - obj.target.className.indexOf("fa-clone") >= 0 - ) { - this.copyComparison(obj, rowIndex); - } else { - this.editComparison(data); - } - } - - analysisSettingsTableRowClickHandler(data, obj, tableRow, rowIndex) { - if ( - obj.target.className.indexOf("btn-remove") >= 0 || - obj.target.className.indexOf("fa-times") >= 0 - ) { - this.deleteFromTable(this.cohortMethodAnalysisList, obj, rowIndex); - } else if ( - obj.target.className.indexOf("btn-copy") >= 0 || - obj.target.parentElement.className.indexOf("btn-copy") >= 0 - ) { - this.copyAnalysisSettings(obj, rowIndex); - } else { - this.editAnalysis(data); - } - } - - addAnalysis() { - this.cohortMethodAnalysisList.push( - new CohortMethodAnalysis({description: ko.i18n('ple.spec.newAnalysis', 'New analysis')() + ' ' + (this.cohortMethodAnalysisList().length + 1)}, this.defaultCovariateSettings()) - ); - // Get the index - const index = this.cohortMethodAnalysisList().length - 1; - this.editAnalysis(this.cohortMethodAnalysisList()[index]); - } - - editAnalysis(analysis) { - this.editorArray = this.cohortMethodAnalysisList; - this.editorHeading(ko.i18n('ple.spec.analysisSettings', 'Analysis Settings')); - this.editorDescription(ko.i18n('ple.spec.analysisSettingsDescription', 'Add or update the analysis settings')); - this.editorComponentName('cohort-method-analysis-editor'); - this.editorComponentParams({ - analysis: analysis, - subscriptions: this.subscriptions, - isEditPermitted: this.isEditPermitted - }); - this.managerMode('editor') - } - - copyAnalysisSettings(obj, index) { - const newAnalysis = ko.toJS(this.cohortMethodAnalysisList()[index]); - newAnalysis.analysisId = this.cohortMethodAnalysisList().length + 1; - newAnalysis.description = ko.i18nformat('common.copyOf', 'Copy of <%=name%>', {name: newAnalysis.description})(); - this.cohortMethodAnalysisList.push(new CohortMethodAnalysis(newAnalysis)); - } - - addComparison() { - this.comparisons.push( - new Comparison() - ); - // Get the index - var index = this.comparisons().length - 1; - this.editComparison(this.comparisons()[index]); - } - - editComparison(comparison) { - this.editorArray = this.comparisons; - this.editorHeading(ko.i18n('ple.spec.comparison', 'Comparison')); - this.editorDescription(ko.i18n('ple.spec.comparisonDescription', 'Add or update the target, comparator, outcome(s) cohorts and negative control outcomes')); - this.editorComponentName('comparison-editor'); - this.editorComponentParams({ - comparison: comparison, - subscriptions: this.subscriptions, - isEditPermitted: this.isEditPermitted - }); - this.managerMode('editor') - } - - copyComparison(obj, index) { - const newComparison = ko.toJS(this.comparisons()[index]); - newComparison.target = null; - newComparison.comparator = null; - this.comparisons.push(new Comparison(newComparison)); - } - - deleteFromTable(list, obj, index) { - // Check if the button or inner element were clicked - if ( - obj.target.className.indexOf("btn-remove") >= 0 || - obj.target.className.indexOf("fa-times") >= 0 - ) { - list.splice(index, 1); - } - } - - closeEditor() { - this.editorArray.valueHasMutated(); - this.managerMode('summary'); - } - } - - return commonUtils.build('comparative-cohort-analysis-specification-view-edit', ComparativeCohortAnalysisSpecificationViewEdit, view); -}); \ No newline at end of file diff --git a/js/pages/estimation/components/cca-specification-view-edit.less b/js/pages/estimation/components/cca-specification-view-edit.less deleted file mode 100644 index 0098a4784..000000000 --- a/js/pages/estimation/components/cca-specification-view-edit.less +++ /dev/null @@ -1,3 +0,0 @@ -.settings-disabled { - pointer-events: none; -} \ No newline at end of file diff --git a/js/pages/estimation/components/cca-utilities.html b/js/pages/estimation/components/cca-utilities.html deleted file mode 100644 index fd37359f6..000000000 --- a/js/pages/estimation/components/cca-utilities.html +++ /dev/null @@ -1,92 +0,0 @@ -
-
- -
-
-
- Your study has invalid design that prevent you from reviewing the full specification details and downloading the study package. Please check "Messages" tab -
-
- -
-
- -
-
-
-
- -
-
-
-
- -
-
- -
-
-
-
- -
-
-
- -
- -
- -
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
- -
-
- -
-
-
-
-
\ No newline at end of file diff --git a/js/pages/estimation/components/cca-utilities.js b/js/pages/estimation/components/cca-utilities.js deleted file mode 100644 index 9cbd94726..000000000 --- a/js/pages/estimation/components/cca-utilities.js +++ /dev/null @@ -1,142 +0,0 @@ -define([ - 'knockout', - 'text!./cca-utilities.html', - 'components/Component', - 'utils/CommonUtils', - 'services/file', - 'appConfig', - 'services/Estimation', - '../PermissionService', - '../const', - 'clipboard', - '../inputTypes/ComparativeCohortAnalysis/FullAnalysis', - 'services/analysis/Cohort', - '../inputTypes/TargetComparatorOutcome', - 'faceted-datatable', - 'utilities/import', - 'utilities/export', -], function ( - ko, - view, - Component, - commonUtils, - fileService, - config, - EstimationService, - PermissionService, - constants, - clipboard, - FullAnalysis, - Cohort, - TargetComparatorOutcome, -) { - class ComparativeCohortAnalysisUtilities extends Component { - constructor(params) { - super(params); - - this.utilityPillMode = ko.observable('download'); - this.defaultLoadingMessage = ko.i18n('common.loadingWithDots', 'Loading...')(); - this.constants = constants; - this.options = constants.options; - this.cohortMethodAnalysisList = params.estimationAnalysis().estimationAnalysisSettings.analysisSpecification.cohortMethodAnalysisList; - this.comparisons = params.comparisons; - this.dirtyFlag = params.dirtyFlag; - this.isExporting = ko.observable(false); - this.fullAnalysisList = params.fullAnalysisList; - this.fullSpecification = params.fullSpecification; - this.loading = params.loading; - this.subscriptions = params.subscriptions; - this.loadingDownload = ko.observable(false); - this.loadingMessage = params.loadingMessage; - this.packageName = params.packageName; - this.selectedAnalysisId = params.estimationId; - this.criticalCount = params.criticalCount; - this.exportService = EstimationService.exportEstimation; - this.importService = EstimationService.importEstimation; - this.isPermittedExport = PermissionService.isPermittedExport; - this.isPermittedImport = PermissionService.isPermittedImport; - this.isEditPermitted = params.isEditPermitted; - this.afterImportSuccess = params.afterImportSuccess; - this.cca = constants.getCca(this.isEditPermitted())[0]; - - this.specificationValid = ko.pureComputed(() => this.criticalCount() <= 0); - - this.validPackageName = ko.pureComputed(() => { - return (this.packageName() && this.packageName().length > 0) - }); - - this.subscriptions.push(this.utilityPillMode.subscribe(() => { - if (this.utilityPillMode() == 'download') { - this.computeCartesian(); - } - })); - - // Fire the subscription upon load. - this.utilityPillMode.valueHasMutated(); - } - - computeCartesian() { - // Init - this.loadingDownload(true); - this.fullAnalysisList.removeAll(); - - // Explode T+C for all O's - var fullComparisonList = []; - this.comparisons().forEach((tcos) => { - tcos.outcomes().forEach((outcome) => { - fullComparisonList.push(new TargetComparatorOutcome({ - target: tcos.target(), - comparator: tcos.comparator(), - outcome: new Cohort(outcome), - })) - }); - }) - - // Full Analysis - var fullAnalysisCartesian = commonUtils.cartesian( - fullComparisonList, - this.cohortMethodAnalysisList(), - ); - fullAnalysisCartesian.forEach(element => { - if (element.length != 2) { - console.error("Expecting array with index 0: TargetComparatorOutcome, 1: CohortMethodAnalysis"); - } else { - this.fullAnalysisList().push( - new FullAnalysis(element[0],element[1]) - ); - } - }); - this.fullAnalysisList.valueHasMutated(); - this.loadingDownload(false); - } - - downloadPackage() { - this.loadingMessage("Starting download..."); - this.loading(true); - fileService.loadZip( - config.api.url + constants.apiPaths.downloadCcaAnalysisPackage(this.selectedAnalysisId(), this.packageName()), - `estimation_study_${this.selectedAnalysisId()}_export.zip` - ) - .catch((e) => console.error("error when downloading: " + e)) - .finally(() => this.loading(false)); - } - - copyFullSpecificationToClipboard() { - var currentClipboard = new clipboard('#btnCopyFullSpecificationClipboard'); - - currentClipboard.on('success', function (e) { - e.clearSelection(); - $('#copyFullSpecificationToClipboardMessage').fadeIn(); - setTimeout(function () { - $('#copyFullSpecificationToClipboardMessage').fadeOut(); - }, 1500); - }); - - currentClipboard.on('error', function (e) { - console.error('Error copying to clipboard'); - }); - } - } - - return commonUtils.build('comparative-cohort-analysis-utilities', ComparativeCohortAnalysisUtilities, view); -}); \ No newline at end of file diff --git a/js/pages/estimation/components/editors/cohort-method-analysis-editor.html b/js/pages/estimation/components/editors/cohort-method-analysis-editor.html deleted file mode 100644 index 7166894ae..000000000 --- a/js/pages/estimation/components/editors/cohort-method-analysis-editor.html +++ /dev/null @@ -1,280 +0,0 @@ -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
-
-
-
-
-
- -
-
-
- -
-
- -
- - - - - -
- -
-
-
- -
- - - - - -
- -
-
-
-
-
-
-
- -
-
-
- -
-    -
-
-
- -
-    -
-
-
- -
- -
-
-
-
-
-
-
-
- -
-
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
-
- -
-
- -
-
- -
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
-
-
-
-
- -
-
- -
-
-
-
-
-
- -
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
- -
-
-
-
-
- - - - - - \ No newline at end of file diff --git a/js/pages/estimation/components/editors/cohort-method-analysis-editor.js b/js/pages/estimation/components/editors/cohort-method-analysis-editor.js deleted file mode 100644 index efe49d591..000000000 --- a/js/pages/estimation/components/editors/cohort-method-analysis-editor.js +++ /dev/null @@ -1,174 +0,0 @@ -define([ - 'knockout', - 'text!./cohort-method-analysis-editor.html', - 'components/Component', - 'utils/CommonUtils', - 'const', - '../../const', - 'utils/DataTypeConverterUtils', - 'services/analysis/ConceptSet', - 'databindings', - 'cyclops', - './match-args-editor', - './stratify-args-editor', - './outcome-model-args-editor', - 'featureextraction/components/covariate-settings-editor', - 'components/entityBrowsers/cohort-definition-browser', - 'less!./cohort-method-analysis.less', -], function ( - ko, - view, - Component, - commonUtils, - constants, - estimationConstants, - dataTypeConverterUtils, - ConceptSet, -) { - class CohortMethodAnalysisEditor extends Component { - constructor(params) { - super(params); - - this.analysis = params.analysis; - this.constants = constants; - this.options = estimationConstants.options; - this.subscriptions = params.subscriptions; - this.editorMode = ko.observable('all'); - this.isEditPermitted = params.isEditPermitted; - this.showCovariateSelector = ko.observable(false); - this.showControlDisplay = ko.observable(false); - this.showPriorDisplay = ko.observable(false); - this.showConceptSetSelector = ko.observable(false); - this.currentConceptSet = ko.observable(null); - this.trimSelection = ko.observable(); - this.matchStratifySelection = ko.observable(); - this.excludeCovariateIds = ko.observable(this.analysis.createPsArgs.excludeCovariateIds() && this.analysis.createPsArgs.excludeCovariateIds().length > 0 ? this.analysis.createPsArgs.excludeCovariateIds().join() : ''); - this.includeCovariateIds = ko.observable(this.analysis.createPsArgs.includeCovariateIds() && this.analysis.createPsArgs.includeCovariateIds().length > 0 ? this.analysis.createPsArgs.includeCovariateIds().join() : ''); - this.cvIncludeCovariateIds = ko.observable(this.analysis.getDbCohortMethodDataArgs.covariateSettings.includedCovariateIds() && this.analysis.getDbCohortMethodDataArgs.covariateSettings.includedCovariateIds().length > 0 ? this.analysis.getDbCohortMethodDataArgs.covariateSettings.includedCovariateIds().join() : ''); - this.trimFraction = ko.observable(this.analysis.trimByPsArgs.trimFraction() ? dataTypeConverterUtils.convertFromPercent(this.analysis.trimByPsArgs.trimFraction()) : ''); - this.bounds = ko.observable(this.analysis.trimByPsToEquipoiseArgs.bounds() && this.analysis.trimByPsToEquipoiseArgs.bounds().length > 0 ? dataTypeConverterUtils.percentArrayToCommaDelimitedList(this.analysis.trimByPsToEquipoiseArgs.bounds()) : ''); - this.studyStartDate = ko.observable(this.analysis.getDbCohortMethodDataArgs.studyStartDate() !== null ? dataTypeConverterUtils.convertFromRDateToDate(this.analysis.getDbCohortMethodDataArgs.studyStartDate()) : null); - this.studyEndDate = ko.observable(this.analysis.getDbCohortMethodDataArgs.studyEndDate() !== null ? dataTypeConverterUtils.convertFromRDateToDate(this.analysis.getDbCohortMethodDataArgs.studyEndDate()) : null); - this.useRegularization = ko.observable(estimationConstants.isUsingRegularization(this.analysis.createPsArgs.prior) ? true : false); - - this.subscriptions.push(this.includeCovariateIds.subscribe(newValue => { - this.analysis.createPsArgs.includeCovariateIds(dataTypeConverterUtils.commaDelimitedListToNumericArray(newValue)); - })); - - this.subscriptions.push(this.excludeCovariateIds.subscribe(newValue => { - this.analysis.createPsArgs.excludeCovariateIds(dataTypeConverterUtils.commaDelimitedListToNumericArray(newValue)); - })); - - this.subscriptions.push(this.cvIncludeCovariateIds.subscribe(newValue => { - this.analysis.getDbCohortMethodDataArgs.covariateSettings.includedCovariateIds(dataTypeConverterUtils.commaDelimitedListToNumericArray(newValue)); - })); - - this.subscriptions.push(this.trimFraction.subscribe(newValue => { - this.analysis.trimByPsArgs.trimFraction(dataTypeConverterUtils.convertToPercent(newValue)); - })); - - this.subscriptions.push(this.bounds.subscribe(newValue => { - this.analysis.trimByPsToEquipoiseArgs.bounds(dataTypeConverterUtils.commaDelimitedListToPercentArray(newValue)); - })); - - this.subscriptions.push(this.studyStartDate.subscribe(newValue => { - this.analysis.getDbCohortMethodDataArgs.studyStartDate(dataTypeConverterUtils.convertToDateForR(newValue)); - })); - - this.subscriptions.push(this.studyEndDate.subscribe(newValue => { - this.analysis.getDbCohortMethodDataArgs.studyEndDate(dataTypeConverterUtils.convertToDateForR(newValue)); - })); - - this.subscriptions.push(this.trimSelection.subscribe(newValue => { - this.analysis.trimByPs(this.trimSelection() === "byPercent"); - this.analysis.trimByPsToEquipoise(this.trimSelection() === "toEquipoise"); - this.setCreatePs(); - })); - - this.subscriptions.push(this.useRegularization.subscribe(newValue => { - estimationConstants.setRegularization(newValue, this.analysis.createPsArgs.prior); - })); - - // Initialize trimSelection - if (this.analysis.trimByPs()) { - this.trimSelection("byPercent") - } else if (this.analysis.trimByPsToEquipoise()) { - this.trimSelection("toEquipoise") - } else { - this.trimSelection("none") - } - - // Initialize matchStratifySelection - if (this.analysis.matchOnPs()) { - this.matchStratifySelection("matchOnPs") - } else if (this.analysis.matchOnPsAndCovariates()) { - this.matchStratifySelection("matchOnPsAndCovariates") - } else if (this.analysis.stratifyByPs()) { - this.matchStratifySelection("stratifyByPs") - } else if (this.analysis.stratifyByPsAndCovariates()) { - this.matchStratifySelection("stratifyOnPsAndCovariates") - } else { - this.matchStratifySelection("none") - } - - // Set the subscription - this.subscriptions.push(this.matchStratifySelection.subscribe(newValue => { - this.analysis.matchOnPs(this.matchStratifySelection() === "matchOnPs"); - this.analysis.matchOnPsAndCovariates(this.matchStratifySelection() === "matchOnPsAndCovariates"); - this.analysis.stratifyByPs(this.matchStratifySelection() === "stratifyByPs"); - this.analysis.stratifyByPsAndCovariates(this.matchStratifySelection() === "stratifyOnPsAndCovariates"); - this.setCreatePs(); - })); - - - this.subscriptions.push(this.analysis.fitOutcomeModelArgs.inversePtWeighting.subscribe(newValue => { - this.setCreatePs(); - })); - } - - toggleControlDisplay() { - this.showControlDisplay(!this.showControlDisplay()); - } - - togglePriorDisplay() { - this.showPriorDisplay(!this.showPriorDisplay()); - } - - conceptsetSelected(d) { - this.currentConceptSet()(new ConceptSet({id: d.id, name: d.name})); - this.showConceptSetSelector(false); - } - - chooseIncludedCovariates() { - this.showConceptSetSelector(true); - this.currentConceptSet(this.analysis.getDbCohortMethodDataArgs.covariateSettings.includedCovariateConceptSet); - } - - clearIncludedCovariates () { - this.analysis.getDbCohortMethodDataArgs.covariateSettings.includedCovariateConceptSet(new ConceptSet()); - } - - chooseExcludedCovariates() { - this.showConceptSetSelector(true); - this.currentConceptSet(this.analysis.getDbCohortMethodDataArgs.covariateSettings.excludedCovariateConceptSet); - } - - clearExcludedCovariates () { - this.analysis.getDbCohortMethodDataArgs.covariateSettings.excludedCovariateConceptSet(new ConceptSet()); - } - - setCreatePs() { - if (this.matchStratifySelection() && this.trimSelection()) { - this.analysis.createPs( - !(this.matchStratifySelection() === "none" && this.trimSelection() === "none") - ); - } - if (this.analysis.fitOutcomeModelArgs.inversePtWeighting()) { - this.analysis.createPs(true); - } - } - - } - - return commonUtils.build('cohort-method-analysis-editor', CohortMethodAnalysisEditor, view); -}); \ No newline at end of file diff --git a/js/pages/estimation/components/editors/cohort-method-analysis.less b/js/pages/estimation/components/editors/cohort-method-analysis.less deleted file mode 100644 index 4adfa896a..000000000 --- a/js/pages/estimation/components/editors/cohort-method-analysis.less +++ /dev/null @@ -1,9 +0,0 @@ -.div-disabled { - pointer-events: none; - .btn { - opacity: 0.7; - } -} -.div-enabled { - pointer-events: all; -} \ No newline at end of file diff --git a/js/pages/estimation/components/editors/comparison-editor.html b/js/pages/estimation/components/editors/comparison-editor.html deleted file mode 100644 index a22f26449..000000000 --- a/js/pages/estimation/components/editors/comparison-editor.html +++ /dev/null @@ -1,94 +0,0 @@ -
-
- -
- - - - - -
-
-
- -
- - - - - -
-
-
- -
-
- -
-
- -
- - - - - -
-
-
-
- Covariate selection -
-
-
- -
- - - - - -
- -
-
-
- -
- - - - - -
- -
-
-
-
- - - - - - \ No newline at end of file diff --git a/js/pages/estimation/components/editors/comparison-editor.js b/js/pages/estimation/components/editors/comparison-editor.js deleted file mode 100644 index 779ef6bdd..000000000 --- a/js/pages/estimation/components/editors/comparison-editor.js +++ /dev/null @@ -1,88 +0,0 @@ -define([ - 'knockout', - 'text!./comparison-editor.html', - 'components/Component', - 'utils/CommonUtils', - 'services/analysis/Cohort', - 'services/analysis/ConceptSet', - 'components/entityBrowsers/cohort-definition-browser', - 'components/cohort/linked-cohort-list', - 'circe', -], function ( - ko, - view, - Component, - commonUtils, - Cohort, - ConceptSet, -) { - class ComparisonEditor extends Component { - constructor(params) { - super(params); - - this.comparison = params.comparison; - this.isEditPermitted = params.isEditPermitted; - this.currentCohort = ko.observable(null); - this.showCohortSelector = ko.observable(false); - this.showConceptSetSelector = ko.observable(false); - this.currentConceptSet = ko.observable(null); - } - - cohortSelected(id, name) { - this.currentCohort()(new Cohort({id: id, name: name})); - this.showCohortSelector(false); - } - - chooseTarget() { - this.showCohortSelector(true); - this.currentCohort(this.comparison.target); - } - - chooseComparator() { - this.showCohortSelector(true); - this.currentCohort(this.comparison.comparator); - } - - clearTarget() { - this.comparison.target(new Cohort()); - } - - clearComparator() { - this.comparison.comparator(new Cohort()); - } - - chooseNegativeControlOutcomesConceptSet() { - this.currentConceptSet(this.comparison.negativeControlOutcomesConceptSet); - this.showConceptSetSelector(true); - } - - clearNegativeControlOutcomesConceptSet() { - this.comparison.negativeControlOutcomesConceptSet(new ConceptSet()); - } - - chooseIncludedCovariateConceptSet() { - this.currentConceptSet(this.comparison.includedCovariateConceptSet); - this.showConceptSetSelector(true); - } - - clearIncludedCovariateConceptSet() { - this.comparison.includedCovariateConceptSet(new ConceptSet()); - } - - chooseExcludedCovariateConceptSet() { - this.currentConceptSet(this.comparison.excludedCovariateConceptSet); - this.showConceptSetSelector(true); - } - - clearExcludedCovariateConceptSet() { - this.comparison.excludedCovariateConceptSet(new ConceptSet()); - } - - conceptsetSelected(d) { - this.currentConceptSet()(new ConceptSet({id: d.id, name: d.name})); - this.showConceptSetSelector(false); - } - } - - return commonUtils.build('comparison-editor', ComparisonEditor, view); -}); \ No newline at end of file diff --git a/js/pages/estimation/components/editors/match-args-editor.html b/js/pages/estimation/components/editors/match-args-editor.html deleted file mode 100644 index bd160eae6..000000000 --- a/js/pages/estimation/components/editors/match-args-editor.html +++ /dev/null @@ -1,24 +0,0 @@ -
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
diff --git a/js/pages/estimation/components/editors/match-args-editor.js b/js/pages/estimation/components/editors/match-args-editor.js deleted file mode 100644 index c7cd96143..000000000 --- a/js/pages/estimation/components/editors/match-args-editor.js +++ /dev/null @@ -1,34 +0,0 @@ -define([ - 'knockout', - 'text!./match-args-editor.html', - 'components/Component', - 'utils/CommonUtils', - '../../const', - 'databindings', -], function ( - ko, - view, - Component, - commonUtils, - constants, -) { - class MatchArgsEditor extends Component { - constructor(params) { - super(params); - - this.matchArgs = params.matchArgs; - this.options = constants.options; - this.isEditPermitted = params.isEditPermitted; - - // TODO: At the moment, we do not expose the ability - // to edit Match/Stratify by covariate arguments - // and if we do, we need to format the covariate - // ID list as numbers - this.hasCovariateIds = ko.pureComputed(() => { - return (this.matchArgs.covariateIds !== undefined) - }); - } - } - - return commonUtils.build('match-args-editor', MatchArgsEditor, view); -}); \ No newline at end of file diff --git a/js/pages/estimation/components/editors/negative-control-outcome-cohort-settings-editor.html b/js/pages/estimation/components/editors/negative-control-outcome-cohort-settings-editor.html deleted file mode 100644 index eaca0a318..000000000 --- a/js/pages/estimation/components/editors/negative-control-outcome-cohort-settings-editor.html +++ /dev/null @@ -1,20 +0,0 @@ -
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
diff --git a/js/pages/estimation/components/editors/negative-control-outcome-cohort-settings-editor.js b/js/pages/estimation/components/editors/negative-control-outcome-cohort-settings-editor.js deleted file mode 100644 index 094c7ac7a..000000000 --- a/js/pages/estimation/components/editors/negative-control-outcome-cohort-settings-editor.js +++ /dev/null @@ -1,26 +0,0 @@ -define([ - 'knockout', - 'text!./negative-control-outcome-cohort-settings-editor.html', - 'components/Component', - 'utils/CommonUtils', - '../../const', - 'databindings', -], function ( - ko, - view, - Component, - commonUtils, - constants, -) { - class NegativeControlOutcomeCohortSettingsEditor extends Component { - constructor(params) { - super(params); - this.isEditPermitted = params.isEditPermitted; - - this.negativeControlCohortSettings = params.negativeControlCohortSettings; - this.options = constants.options; - } - } - - return commonUtils.build('nc-outcome-cohort-settings-editor', NegativeControlOutcomeCohortSettingsEditor, view); -}); \ No newline at end of file diff --git a/js/pages/estimation/components/editors/outcome-model-args-editor.html b/js/pages/estimation/components/editors/outcome-model-args-editor.html deleted file mode 100644 index da736aa00..000000000 --- a/js/pages/estimation/components/editors/outcome-model-args-editor.html +++ /dev/null @@ -1,55 +0,0 @@ -
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
- -
-
-
-
-
-
- -
-
- -
-
-
-
-
-
- -
-
- -
-
-
-
\ No newline at end of file diff --git a/js/pages/estimation/components/editors/outcome-model-args-editor.js b/js/pages/estimation/components/editors/outcome-model-args-editor.js deleted file mode 100644 index 8da818f10..000000000 --- a/js/pages/estimation/components/editors/outcome-model-args-editor.js +++ /dev/null @@ -1,61 +0,0 @@ -define([ - 'knockout', - 'text!./outcome-model-args-editor.html', - 'components/Component', - 'utils/CommonUtils', - '../../const', - 'utils/DataTypeConverterUtils', - 'databindings', - 'cyclops', -], function ( - ko, - view, - Component, - commonUtils, - constants, - dataTypeConverterUtils -) { - class OutcomeModelArgsEditor extends Component { - constructor(params) { - super(params); - - this.outcomeModelArgs = params.outcomeModelArgs; - this.matchStratifySelection = params.matchStratifySelection; - this.options = constants.options; - this.isEditPermitted = params.isEditPermitted; - this.subscriptions = params.subscriptions; - this.showControlDisplay = ko.observable(false); - this.showPriorDisplay = ko.observable(false); - this.excludeCovariateIds = ko.observable(this.outcomeModelArgs.excludeCovariateIds() && this.outcomeModelArgs.excludeCovariateIds().length > 0 ? this.outcomeModelArgs.excludeCovariateIds().join() : ''); - this.includeCovariateIds = ko.observable(this.outcomeModelArgs.includeCovariateIds() && this.outcomeModelArgs.includeCovariateIds().length > 0 ? this.outcomeModelArgs.includeCovariateIds().join() : ''); - this.interactionCovariateIds = ko.observable(this.outcomeModelArgs.interactionCovariateIds() && this.outcomeModelArgs.interactionCovariateIds().length > 0 ? this.outcomeModelArgs.interactionCovariateIds().join() : ''); - this.useRegularization = ko.observable(constants.isUsingRegularization(this.outcomeModelArgs.prior) ? true : false); - - this.subscriptions.push(this.includeCovariateIds.subscribe(newValue => { - this.outcomeModelArgs.includeCovariateIds(dataTypeConverterUtils.commaDelimitedListToNumericArray(newValue)); - })); - - this.subscriptions.push(this.excludeCovariateIds.subscribe(newValue => { - this.outcomeModelArgs.excludeCovariateIds(dataTypeConverterUtils.commaDelimitedListToNumericArray(newValue)); - })); - - this.subscriptions.push(this.interactionCovariateIds.subscribe(newValue => { - this.outcomeModelArgs.interactionCovariateIds(dataTypeConverterUtils.commaDelimitedListToNumericArray(newValue)); - })); - - this.subscriptions.push(this.useRegularization.subscribe(newValue => { - constants.setRegularization(newValue, this.outcomeModelArgs.prior); - })); - } - - toggleControlDisplay() { - this.showControlDisplay(!this.showControlDisplay()); - } - - togglePriorDisplay() { - this.showPriorDisplay(!this.showPriorDisplay()); - } - } - - return commonUtils.build('outcome-model-args-editor', OutcomeModelArgsEditor, view); -}); \ No newline at end of file diff --git a/js/pages/estimation/components/editors/positive-control-sythesis-settings-editor.html b/js/pages/estimation/components/editors/positive-control-sythesis-settings-editor.html deleted file mode 100644 index c790bb8fe..000000000 --- a/js/pages/estimation/components/editors/positive-control-sythesis-settings-editor.html +++ /dev/null @@ -1,107 +0,0 @@ -
-
- -
- -
-
-
- -
-
- -
-    -
-
-
- -
-    -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
-
-
-
- - - \ No newline at end of file diff --git a/js/pages/estimation/components/editors/positive-control-sythesis-settings-editor.js b/js/pages/estimation/components/editors/positive-control-sythesis-settings-editor.js deleted file mode 100644 index 8853c3779..000000000 --- a/js/pages/estimation/components/editors/positive-control-sythesis-settings-editor.js +++ /dev/null @@ -1,44 +0,0 @@ -define([ - 'knockout', - 'text!./positive-control-sythesis-settings-editor.html', - 'components/Component', - 'utils/CommonUtils', - 'const', - '../../const', - 'utils/DataTypeConverterUtils', - 'databindings', - 'cyclops', -], function ( - ko, - view, - Component, - commonUtils, - constants, - estimationConstants, - dataTypeConverterUtils -) { - class PositiveControlSythesisSettingsEditor extends Component { - constructor(params) { - super(params); - - this.settings = params.settings; - this.constants = constants; - this.options = estimationConstants.options.positiveControlSynthesisArgs; - this.subscriptions = params.subscriptions; - this.showCovariateSelector = ko.observable(false); - this.showAdditionalSettings = ko.observable(false); - this.effectSizes = ko.observable(this.settings().effectSizes() && this.settings().effectSizes().length > 0 ? this.settings().effectSizes().join() : ''); - this.isEditPermitted = params.isEditPermitted; - - this.subscriptions.push(this.effectSizes.subscribe(newValue => { - this.settings().effectSizes(dataTypeConverterUtils.commaDelimitedListToNumericArray(newValue)); - })); - } - - toggleAdditionalSettings() { - this.showAdditionalSettings(!this.showAdditionalSettings()); - } - } - - return commonUtils.build('positive-control-synthesis-settings-editor', PositiveControlSythesisSettingsEditor, view); -}); \ No newline at end of file diff --git a/js/pages/estimation/components/editors/stratify-args-editor.html b/js/pages/estimation/components/editors/stratify-args-editor.html deleted file mode 100644 index 8eaf51f3e..000000000 --- a/js/pages/estimation/components/editors/stratify-args-editor.html +++ /dev/null @@ -1,18 +0,0 @@ -
- -
- -
-
-
- -
- -
-
-
- -
- -
-
diff --git a/js/pages/estimation/components/editors/stratify-args-editor.js b/js/pages/estimation/components/editors/stratify-args-editor.js deleted file mode 100644 index 853479169..000000000 --- a/js/pages/estimation/components/editors/stratify-args-editor.js +++ /dev/null @@ -1,34 +0,0 @@ -define([ - 'knockout', - 'text!./stratify-args-editor.html', - 'components/Component', - 'utils/CommonUtils', - '../../const', - 'databindings', -], function ( - ko, - view, - Component, - commonUtils, - constants, -) { - class StratifyArgsEditor extends Component { - constructor(params) { - super(params); - - this.stratifyArgs = params.stratifyArgs; - this.options = constants.options; - this.isEditPermitted = params.isEditPermitted; - - // TODO: At the moment, we do not expose the ability - // to edit Match/Stratify by covariate arguments - // and if we do, we need to format the covariate - // ID list as numbers - this.hasCovariateIds = ko.pureComputed(() => { - return (this.stratifyArgs.covariateIds !== undefined) - }); - } - } - - return commonUtils.build('stratify-args-editor', StratifyArgsEditor, view); -}); \ No newline at end of file diff --git a/js/pages/estimation/const.js b/js/pages/estimation/const.js deleted file mode 100644 index e90e1be9b..000000000 --- a/js/pages/estimation/const.js +++ /dev/null @@ -1,446 +0,0 @@ -define( - (require, exports) => { - const pageTitle = 'Estimation'; - const ko = require('knockout'); - const config = require('appConfig'); - const _ = require('lodash'); - const consts = require('const'); - const commonUtils = require('utils/CommonUtils'); - - const apiPaths = { - downloadCcaAnalysisPackage: (id, name) => `estimation/${id}/download?packageName=${name}`, - downloadResults: id => `estimation/generation/${id}/result`, - }; - - const paths = { - root: '/estimation/cca/', - ccaAnalysis: id => `/estimation/cca/${id}`, - ccaAnalysisDash: id => `#${paths.ccaAnalysis(id)}`, - createCcaAnalysis: () => '#/estimation/cca/0', - browser: () => '#/estimation', - }; - - - const conceptSetCrossReference = { - targetComparatorOutcome: { - targetName: "estimationAnalysisSettings.analysisSpecification.targetComparatorOutcomes", - propertyName: { - includedCovariateConcepts: "includedCovariateConceptIds", - excludedCovariateConcepts: "excludedCovariateConceptIds", - }, - }, - negativeControlOutcomes: { - targetName: "negativeControlOutcomes", - propertyName: "outcomeId", - }, - analysisCovariateSettings: { - targetName: "estimationAnalysisSettings.analysisSpecification.cohortMethodAnalysisList.getDbCohortMethodDataArgs.covariateSettings", - propertyName: { - includedCovariateConcepts: "includedCovariateConceptIds", - excludedCovariateConcepts: "excludedCovariateConceptIds", - }, - }, - positiveControlCovariateSettings: { - targetName: "positiveControlSynthesisArgs.covariateSettings", - propertyName: { - includedCovariateConcepts: "includedCovariateConceptIds", - excludedCovariateConcepts: "excludedCovariateConceptIds", - }, - } - }; - - const isUsingRegularization = (prior) => { - return !(prior.priorType() === "none" && prior.useCrossValidation() === false); - } - - const setRegularization = (enable, prior) => { - if (enable === true) { - prior.priorType("laplace"); - prior.useCrossValidation(true); - } else { - prior.priorType("none"); - prior.useCrossValidation(false); - } - } - - const getTimeAtRisk = (createStudyPopArgs) => { - return (createStudyPopArgs.riskWindowStart() + "-" + createStudyPopArgs.riskWindowEnd() + ko.i18n('common.daysAbbr', 'd')() + - " (" + ko.i18n('common.min', 'min')() + ": " + createStudyPopArgs.minDaysAtRisk() + - ko.i18n('common.daysAbbr', 'd')() + ")"); - }; - - const options = { - removeButton: ``, - copyButton: ``, - numberOfStrataOptions: _.range(1,11).map(v => '' + v), - maxRatioOptions: _.range(0,11).map(v => '' + v), - dayOptions: ['0', '1', '7', '14', '21', '30', '60', '90', '120', '180', '365', '548', '730', '1095'], - maxCohortSizeOptions: ['0', '1000', '5000', '10000', '50000', '100000'], - maxCohortSizeForFittingOptions: ['250000', '150000', '100000', '50000', '10000', '5000', '0'], - yesNoOptions: [{ - name: ko.i18n('options.yes', 'Yes'), - id: true, - }, { - name: ko.i18n('options.no', 'No'), - id: false - }], - removeDuplicateSubjectOptions: [{ - name: ko.i18n('ple.spec.options.keepAll', 'Keep All'), - id: 'keep all', - }, { - name: ko.i18n('ple.spec.options.keepFirst', 'Keep First'), - id: 'keep first' - }, { - name: ko.i18n('ple.spec.options.removeAll', 'Remove All'), - id: 'remove all' - }], - trimOptions: [{ - name: ko.i18n('ple.spec.options.none', 'None'), - id: 'none', - }, { - name: ko.i18n('ple.spec.options.byPercent', 'By Percent'), - id: 'byPercent' - }, { - name: ko.i18n('ple.spec.options.toEquipoise', 'To Equipoise'), - id: 'toEquipoise' - }], - matchStratifyOptions: [{ - name: ko.i18n('ple.spec.options.none', 'None'), - id: 'none', - }, { - name: ko.i18n('ple.spec.options.matchOnPropensityScore', 'Match on propensity score'), - id: 'matchOnPs' - }, { - name: ko.i18n('ple.spec.options.stratifyOnPropensityScore', 'Stratify on propensity score'), - id: 'stratifyByPs' - }], - caliperScaleOptions: [{ - name: ko.i18n('ple.spec.options.standardizedLogit', 'Standardized Logit'), - id: 'standardized logit', - }, { - name: ko.i18n('ple.spec.options.standardized', 'Standardized'), - id: 'standardized' - }, { - name: ko.i18n('ple.spec.options.propensityScore', 'Propensity score'), - id: 'propensity score' - }], - stratificationBaseSelectionOptions: [{ - name: ko.i18n('ple.spec.options.all', 'All'), - id: 'all', - }, { - name: ko.i18n('ple.spec.options.target', 'Target'), - id: 'target' - }, { - name: ko.i18n('ple.spec.options.comparator', 'Comparator'), - id: 'comparator' - }], - outcomeModelTypeOptions: [{ - name: ko.i18n('ple.spec.options.logisticRegression', 'Logistic regression'), - id: 'logistic', - }, { - name: ko.i18n('ple.spec.options.poissonRegression', 'Poisson regression'), - id: 'poisson' - }, { - name: ko.i18n('ple.spec.options.coxProportionalHazards', 'Cox proportional hazards'), - id: 'cox' - }], - occurrenceTypeOptions: [{ - name: ko.i18n('ple.spec.options.allOccurrences', 'All occurrences'), - id: 'all', - }, { - name: ko.i18n('ple.spec.options.firstOccurrence', 'First occurrence'), - id: 'first' - }], - domains: [{ - name: ko.i18n('ple.spec.options.condition', 'Condition'), - id: 'condition', - }, { - name: ko.i18n('ple.spec.options.drug', 'Drug'), - id: 'drug' - }, { - name: ko.i18n('ple.spec.options.device', 'Device'), - id: 'device' - }, { - name: ko.i18n('ple.spec.options.measurement', 'Measurement'), - id: 'measurement' - }, { - name: ko.i18n('ple.spec.options.observation', 'Observation'), - id: 'observation' - }, { - name: ko.i18n('ple.spec.options.procedure', 'Procedure'), - id: 'procedure' - }, { - name: ko.i18n('ple.spec.options.visit', 'Visit'), - id: 'visit' - }], - positiveControlSynthesisArgs: { - modelType: [{ - name: ko.i18n('ple.spec.options.poisson', 'Poisson'), - id: 'poisson', - }, { - name: ko.i18n('ple.spec.options.survival', 'Survival'), - id: 'survival' - }], - minOutcomeCountForModelOptions: ['100', '75', '50', '25', '10'], - minOutcomeCountForInjectionOptions: ['100', '75', '50', '25', '10'], - washoutPeriodOptions: ['0', '1', '7', '14', '21', '30', '60', '90', '120', '180', '183', '365', '548', '730', '1095'], - dayOptions: ['0', '1', '7', '14', '21', '30', '60', '90', '120', '180', '365', '548', '730', '1095'], - maxSubjectsForModelOptions: ['0', '1000', '5000', '10000', '50000', '100000', '150000', '200000', '250000'], - yesNoOptions: [{ - name: ko.i18n('options.yes', 'Yes'), - id: true, - }, { - name: ko.i18n('options.no', 'No'), - id: false - }], - } - }; - const getCca = (canEdit) => [{ - comparisonTableColumns: [ - { - title: ko.i18n('columns.remove', 'Remove'), - render: (s, p, d) => { - return options.removeButton; - }, - orderable: false, - searchable: false, - className: 'col-remove', - visible: canEdit, - }, - { - title: ko.i18n('columns.targetId', 'Target Id'), - data: d => d.target().id, - visible: false, - }, - { - title: ko.i18n('columns.target', 'Target'), - data: d => d.target().name, - }, - { - title: ko.i18n('columns.comparatorId', 'Comparator Id'), - data: d => d.comparator().id, - visible: false, - }, - { - title: ko.i18n('columns.comparator', 'Comparator'), - data: d => d.comparator().name, - }, - { - title: ko.i18n('columns.outcomes', 'Outcomes'), - render: (s, p, d, a, b, c) => { - if (d.outcomes().length > 1) { - let tooltipText = ""; - d.outcomes().forEach((element, index) => { - element = ko.toJS(element); - if (index > 0) { - tooltipText += ("" + element.name + ""); - } - }); - const outcomeDisplay = d.outcomes().length === 2 ? "outcome" : "outcomes"; - return ko.toJS(d.outcomes()[0]).name + "
(" + (d.outcomes().length - 1) + "+ more " + outcomeDisplay + "" + tooltipText + ")
"; - } else if (d.outcomes().length === 1) { - return ko.toJS(d.outcomes()[0]).name; - } else { - return 0; - } - } - }, - { - title: ko.i18n('columns.ncOutcomes', 'NC Outcomes'), - data: d => d.negativeControlOutcomesConceptSet().name, - }, - { - title: ko.i18n('columns.inclCovariates', 'Incl Covariates'), - data: d => d.includedCovariateConceptSet().length, - visible: false, - }, - { - title: ko.i18n('columns.exclCovariates', 'Excl Covariates'), - data: d => d.excludedCovariateConceptSet().length, - visible: false, - }, - { - title: ko.i18n('columns.copy', 'Copy'), - render: (s, p, d) => { - return options.copyButton; - }, - orderable: false, - searchable: false, - className: 'col-copy', - visible: canEdit, - }, - ], - comparisonTableOptions: { - ...commonUtils.getTableOptions('S'), - dom: '<<"row vertical-align"<"col-xs-6"l><"col-xs-6 search"f>><"row vertical-align"><"row vertical-align"<"col-xs-3"i><"col-xs-9"p>>>', - }, - analysisSettingsTableColumns: [ - { - title: ko.i18n('columns.remove', 'Remove'), - render: (s, p, d) => { - return options.removeButton; - }, - orderable: false, - searchable: false, - className: 'col-remove', - visible: canEdit - }, - { - title: ko.i18n('columns.description', 'Description'), - data: d => d.description(), - }, - { - title: ko.i18n('columns.timeAtRiskStart', 'Time At Risk Start'), - render: (s, p, d) => { - if (d.createStudyPopArgs != null) { - return d.createStudyPopArgs.riskWindowStart() + - " " + - "
" + - ko.unwrap(consts.timeAtRiskCohortDate.find(f => f.id === d.createStudyPopArgs.addExposureDaysToStart()).name); - } else { - return ''; - } - } - }, - { - title: ko.i18n('columns.timeAtRiskEnd', 'Time At Risk End'), - render: (s, p, d) => { - if (d.createStudyPopArgs != null) { - return d.createStudyPopArgs.riskWindowEnd() + - " " + - "
" + - ko.unwrap(consts.timeAtRiskCohortDate.find(f => f.id === d.createStudyPopArgs.addExposureDaysToEnd()).name); - } else { - return ''; - } - } - }, - { - title: ko.i18n('columns.minimumTimeAtRisk', 'Minimum Time At Risk'), - render: (s, p, d) => { - if (d.createStudyPopArgs != null) { - return d.createStudyPopArgs.minDaysAtRisk() + ""; - } else { - return ''; - } - } - }, - { - title: ko.i18n('columns.adjustmentStrategy', 'Adjustment Strategy'), - render: (s, p, d) => { - if (d.matchOnPs()) { - return ko.i18nformat('ple.spec.options.matching', '<%=ratio%>:1 matching', {ratio: d.matchOnPsArgs.maxRatio()})(); - } else if (d.stratifyByPs()) { - return ko.i18nformat('ple.spec.options.stratification', 'Stratification (stratum: <%=stratum%>)', {stratum: d.stratifyByPsArgs.numberOfStrata()})(); - } else { - return ko.i18n('ple.spec.options.none', 'None')(); - } - } - }, - { - title: ko.i18n('columns.outcomeModel', 'Outcome Model'), - render: (s, p, d) => { - if (d.fitOutcomeModelArgs != null) { - return d.fitOutcomeModelArgs.modelType(); - } else { - return ''; - } - } - }, - { - title: ko.i18n('columns.copy', 'Copy'), - render: (s, p, d) => { - return options.copyButton; - }, - orderable: false, - searchable: false, - className: 'col-copy', - visible: canEdit - }, - ], - analysisSettingsTableOptions: { - ...commonUtils.getTableOptions('S'), - dom: '<<"row vertical-align"<"col-xs-6"l><"col-xs-6 search"f>><"row vertical-align"><"row vertical-align"<"col-xs-3"i><"col-xs-9"p>>>', - }, - fullAnalysisTableColumns: [ - { - title: ko.i18n('columns.targetId', 'Target Id'), - data: d => d.targetComparatorOutcome.target.id, - visible: false, - }, - { - title: ko.i18n('columns.targetCohortName', 'Target Cohort Name'), - data: d => d.targetComparatorOutcome.target.name, - }, - { - title: ko.i18n('columns.comparatorId', 'Comparator Id'), - data: d => d.targetComparatorOutcome.comparator.id, - visible: false, - }, - { - title: ko.i18n('columns.comparatorCohortName', 'Comparator Cohort Name'), - data: d => d.targetComparatorOutcome.comparator.name, - }, - { - title: ko.i18n('columns.outcomes', 'Outcomes'), - data: d => d.targetComparatorOutcome.outcome.id, - visible: false, - }, - { - title: ko.i18n('columns.outcomeCohortName', 'Outcome Cohort Name'), - data: d => d.targetComparatorOutcome.outcome.name, - }, - { - title: ko.i18n('columns.analysisName', 'Analysis Name'), - data: d => d.cohortMethodAnalysis.description(), - }, - { - title: ko.i18n('columns.timeAtRisk', 'Time At Risk'), - data: d => { - //return (d.cohortMethodAnalysis.createStudyPopArgs.riskWindowStart() + "-" + d.cohortMethodAnalysis.createStudyPopArgs.riskWindowEnd() + "d
(min: " + d.cohortMethodAnalysis.createStudyPopArgs.minDaysAtRisk() + "d)"); - return getTimeAtRisk(d.cohortMethodAnalysis.createStudyPopArgs); - } - }, - { - title: ko.i18n('columns.outcomeModel', 'Outcome Model'), - data: d => { - return d.cohortMethodAnalysis.fitOutcomeModelArgs.modelType(); - }, - } - ], - fullAnalysisTableOptions: { - ...commonUtils.getTableOptions('S'), - dom: '<<"row vertical-align"<"col-xs-6"<"dt-btn"B>l><"col-xs-6 search"f>><"row vertical-align"><"row vertical-align"<"col-xs-3"i><"col-xs-9"p>>>', - domNoButtons: '<<"row vertical-align"<"col-xs-6"l><"col-xs-6 search"f>><"row vertical-align"><"row vertical-align"<"col-xs-3"i><"col-xs-9"p>>>', - Facets: [{ - 'caption': ko.i18n('facets.caption.targetCohorts', 'Target Cohorts'), - 'binding': d => d.targetComparatorOutcome.target.name, - }, - { - 'caption': ko.i18n('facets.caption.comparatorCohorts', 'Comparator Cohorts'), - 'binding': d => d.targetComparatorOutcome.comparator.name, - }, - { - 'caption': ko.i18n('facets.caption.outcomeCohorts', 'Outcome Cohorts'), - 'binding': d => d.targetComparatorOutcome.outcome.name, - }, - { - 'caption': ko.i18n('facets.caption.analysisName', 'Analysis Name'), - 'binding': d => d.cohortMethodAnalysis.description(), - }, - ] - } - }]; - - return { - pageTitle, - apiPaths, - paths: paths, - conceptSetCrossReference, - isUsingRegularization, - setRegularization, - options, - getCca, - }; - } -); \ No newline at end of file diff --git a/js/pages/estimation/estimation-browser.html b/js/pages/estimation/estimation-browser.html deleted file mode 100644 index 68178e5cf..000000000 --- a/js/pages/estimation/estimation-browser.html +++ /dev/null @@ -1,24 +0,0 @@ - - -
- - - - - -
- - \ No newline at end of file diff --git a/js/pages/estimation/estimation-browser.js b/js/pages/estimation/estimation-browser.js deleted file mode 100644 index be4cff3a4..000000000 --- a/js/pages/estimation/estimation-browser.js +++ /dev/null @@ -1,115 +0,0 @@ -define([ - 'knockout', - 'text!./estimation-browser.html', - 'appConfig', - './const', - 'services/MomentAPI', - './PermissionService', - 'pages/Page', - 'utils/CommonUtils', - 'utils/DatatableUtils', - 'services/Estimation', - 'services/AuthAPI', - 'faceted-datatable', - 'components/ac-access-denied', - 'components/heading', - 'components/empty-state', - 'less!./estimation-browser.less' -], function( - ko, - view, - config, - constants, - momentApi, - PermissionService, - Page, - commonUtils, - datatableUtils, - EstimationService, - authAPI -) { - class EstimationBrowser extends Page { - constructor(params) { - super(params); - this.reference = ko.observableArray(); - this.loading = ko.observable(false); - this.config = config; - - this.canReadEstimations = PermissionService.isPermittedList; - this.canCreateEstimation = PermissionService.isPermittedCreate; - - this.isAuthenticated = authAPI.isAuthenticated; - this.hasAccess = authAPI.isPermittedReadEstimations; - this.tableOptions = commonUtils.getTableOptions('L'); - this.options = { - Facets: [ - { - 'caption': ko.i18n('facets.caption.created', 'Created'), - 'binding': (o) => datatableUtils.getFacetForDate(o.createdDate) - }, - { - 'caption': ko.i18n('facets.caption.updated', 'Updated'), - 'binding': (o) => datatableUtils.getFacetForDate(o.modifiedDate) - }, - { - 'caption': ko.i18n('facets.caption.author', 'Author'), - 'binding': datatableUtils.getFacetForCreatedBy, - }, - { - 'caption': 'Designs', - 'binding': datatableUtils.getFacetForDesign, - }, - ] - }; - - this.columns = [ - { - title: ko.i18n('columns.id', 'Id'), - data: 'id' - }, - { - title: ko.i18n('columns.type', 'Type'), - data: d => d.type, - visible: false, - }, - { - title: ko.i18n('columns.name', 'Name'), - render: datatableUtils.getLinkFormatter(d => ({ - link: constants.paths.ccaAnalysisDash(d.id), - label: d['name'] - })), - }, - { - title: ko.i18n('columns.created', 'Created'), - render: datatableUtils.getDateFieldFormatter('createdDate'), - }, - { - title: ko.i18n('columns.updated', 'Updated'), - render: datatableUtils.getDateFieldFormatter('modifiedDate'), - }, - { - title: ko.i18n('columns.author', 'Author'), - render: datatableUtils.getCreatedByFormatter(), - } - ]; - } - - onPageCreated() { - if (this.canReadEstimations()) { - this.loading(true); - EstimationService.getEstimationList() - .then(({data}) => { - datatableUtils.coalesceField(data, 'modifiedDate', 'createdDate'); - this.loading(false); - this.reference(data); - }); - } - } - - newEstimation() { - document.location = constants.paths.createCcaAnalysis(); - } - } - - return commonUtils.build('estimation-browser', EstimationBrowser, view); -}); \ No newline at end of file diff --git a/js/pages/estimation/estimation-browser.less b/js/pages/estimation/estimation-browser.less deleted file mode 100644 index 0e878fc89..000000000 --- a/js/pages/estimation/estimation-browser.less +++ /dev/null @@ -1,13 +0,0 @@ -.estimation-browser { - &__new-btn { - align-self: flex-end; - } - - &__toggle-estimation-browser { - padding-top: 20px; - } - - &__empty-state { - justify-content: center; - } - } \ No newline at end of file diff --git a/js/pages/estimation/index.js b/js/pages/estimation/index.js deleted file mode 100644 index b8c0c9a6c..000000000 --- a/js/pages/estimation/index.js +++ /dev/null @@ -1,34 +0,0 @@ -define( - (require, exports) => { - const ko = require('knockout'); - const buildRoutes = require('./routes'); - const appState = require('atlas-state'); - const constants = require('./const'); - - const statusCss = ko.pureComputed(function () { - if (appState.estimationAnalysis.current()) - return appState.estimationAnalysis.dirtyFlag().isDirty() ? "unsaved" : "open"; - return ""; - }); - - const navUrl = ko.pureComputed(function () { - let url = constants.paths.browser(); - if (appState.estimationAnalysis.current()) { - if (appState.estimationAnalysis.current().id() != null && appState.estimationAnalysis.current().id() > 0) { - url = appState.estimationAnalysis.analysisPath(appState.estimationAnalysis.current().id()); - } else { - url = constants.paths.createCcaAnalysis(); - } - } - return url; - }); - - return { - title: ko.i18n('navigation.estimation', 'Estimation'), - buildRoutes, - navUrl: navUrl, - icon: 'balance-scale', - statusCss: statusCss - }; - } -); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/Analysis.js b/js/pages/estimation/inputTypes/Analysis.js deleted file mode 100644 index bc384193e..000000000 --- a/js/pages/estimation/inputTypes/Analysis.js +++ /dev/null @@ -1,17 +0,0 @@ -define([ - 'knockout', - 'services/analysis/RLangClass', -], function ( - ko, - RLangClass -) { - class Analysis extends RLangClass { - constructor(data = {}) { - super(data); - this.analysisId = ko.observable(data.analysisId === 0 ? 0 : data.analysisId || null); - this.description = ko.observable(data.description || null); - } - } - - return Analysis; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/CohortMethodAnalysis.js b/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/CohortMethodAnalysis.js deleted file mode 100644 index d89a2cdc2..000000000 --- a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/CohortMethodAnalysis.js +++ /dev/null @@ -1,56 +0,0 @@ -define([ - 'knockout', - '../Analysis', - './GetDbCohortMethodDataArgs', - './CreateStudyPopulationArgs', - './CreatePsArgs', - './TrimByPsArgs', - './TrimByPsToEquipoiseArgs', - './MatchOnPsArgs', - './MatchOnPsAndCovariateArgs', - './StratifyByPsArgs', - './StratifyByPsAndCovariatesArgs', - './FitOutcomeModelArgs' - ], function ( - ko, - Analysis, - GetDbCohortMethodDataArgs, - CreateStudyPopulationArgs, - CreatePsArgs, - TrimByPsArgs, - TrimByPsToEquipoiseArgs, - MatchOnPsArgs, - MatchOnPsAndCovariatesArgs, - StratifyByPsArgs, - StratifyByPsAndCovariatesArgs, - FitOutcomeModelArgs - ) { - class CohortMethodAnalysis extends Analysis { - constructor(data = {}, defaultCovariateSettings) { - data.attr_class = "cmAnalysis"; - super(data); - this.targetType = ko.observable(data.targetType || null); - this.comparatorType = ko.observable(data.comparatorType || null); - this.getDbCohortMethodDataArgs = new GetDbCohortMethodDataArgs(data.getDbCohortMethodDataArgs, defaultCovariateSettings); - this.createStudyPopArgs = new CreateStudyPopulationArgs(data.createStudyPopArgs); - this.createPs = ko.observable(data.createPs === undefined ? true : data.createPs); - this.createPsArgs = new CreatePsArgs(data.createPsArgs); - this.trimByPs = ko.observable(data.trimByPs === undefined ? false : data.trimByPs); - this.trimByPsArgs = new TrimByPsArgs(data.trimByPsArgs); - this.trimByPsToEquipoise = ko.observable(data.trimByPsToEquipoise === undefined ? false : data.trimByPsToEquipoise); - this.trimByPsToEquipoiseArgs = new TrimByPsToEquipoiseArgs(data.trimByPsToEquipoiseArgs); - this.matchOnPs = ko.observable(data.matchOnPs === undefined ? false : data.matchOnPs); - this.matchOnPsArgs = new MatchOnPsArgs(data.matchOnPsArgs); - this.matchOnPsAndCovariates = ko.observable(data.matchOnPsAndCovariates === undefined ? false : data.matchOnPsAndCovariates); - this.matchOnPsAndCovariatesArgs = new MatchOnPsAndCovariatesArgs(data.matchOnPsAndCovariatesArgs); - this.stratifyByPs = ko.observable(data.stratifyByPs === undefined ? true : data.stratifyByPs); - this.stratifyByPsArgs = new StratifyByPsArgs(data.stratifyByPsArgs); - this.stratifyByPsAndCovariates = ko.observable(data.stratifyByPsAndCovariates === undefined ? false : data.stratifyByPsAndCovariates); - this.stratifyByPsAndCovariatesArgs = new StratifyByPsAndCovariatesArgs(data.stratifyByPsAndCovariatesArgs); - this.fitOutcomeModel = ko.observable(data.fitOutcomeModel === undefined ? true : data.fitOutcomeModel); - this.fitOutcomeModelArgs = new FitOutcomeModelArgs(data.fitOutcomeModelArgs); - } - } - - return CohortMethodAnalysis; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/ComparativeCohortAnalysis.js b/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/ComparativeCohortAnalysis.js deleted file mode 100644 index 0ec73c216..000000000 --- a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/ComparativeCohortAnalysis.js +++ /dev/null @@ -1,18 +0,0 @@ -define([ - 'knockout', - '../TargetComparatorOutcomes', - './CohortMethodAnalysis' - ], function ( - ko, - TargetComparatorOutcomes, - CohortMethodAnalysis - ) { - class ComparativeCohortAnalysis { - constructor(data = {}, defaultCovariateSettings) { - this.targetComparatorOutcomes = ko.observableArray(data.targetComparatorOutcomes && data.targetComparatorOutcomes.map(function(d) { return new TargetComparatorOutcomes(d) })); - this.cohortMethodAnalysisList = ko.observableArray(data.cohortMethodAnalysisList && data.cohortMethodAnalysisList.map(function(d) { return new CohortMethodAnalysis(d, defaultCovariateSettings) })); - } - } - - return ComparativeCohortAnalysis; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/CreatePsArgs.js b/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/CreatePsArgs.js deleted file mode 100644 index 7e0e2fc7b..000000000 --- a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/CreatePsArgs.js +++ /dev/null @@ -1,27 +0,0 @@ -define([ - 'knockout', - 'services/analysis/RLangClass', - 'cyclops/InputTypes/Prior', - 'cyclops/InputTypes/Control', - 'databindings', -], function ( - ko, - RLangClass, - Prior, - Control -) { - class CreatePsArgs extends RLangClass { - constructor(data = {}) { - super(); - this.excludeCovariateIds = ko.observableArray((data.excludeCovariateIds && Array.isArray(data.excludeCovariateIds)) ? data.excludeCovariateIds : []); - this.includeCovariateIds = ko.observableArray((data.includeCovariateIds && Array.isArray(data.includeCovariateIds)) ? data.includeCovariateIds : []); - this.maxCohortSizeForFitting = ko.observable(data.maxCohortSizeForFitting || 250000).extend({ numeric: 0}); - this.errorOnHighCorrelation = ko.observable(data.errorOnHighCorrelation === undefined ? true : data.errorOnHighCorrelation); - this.stopOnError = true; - this.prior = data.prior === undefined ? new Prior({priorType: "laplace", exclude: 0, useCrossValidation: true}) : new Prior(data.prior); - this.control = data.control === undefined ? new Control({cvType: "auto", startingVariance: 0.01, tolerance: .0000002, cvRepetitions: 10, noiseLevel: "silent", seed: 1}) : new Control(data.control); - } - } - - return CreatePsArgs; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/CreateStudyPopulationArgs.js b/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/CreateStudyPopulationArgs.js deleted file mode 100644 index 49f2e9cab..000000000 --- a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/CreateStudyPopulationArgs.js +++ /dev/null @@ -1,28 +0,0 @@ -define([ - 'knockout', - 'services/analysis/RLangClass', - 'databindings', -], function ( - ko, - RLangClass -) { - class CreateStudyPopulationArgs extends RLangClass { - constructor(data = {}) { - super(); - this.firstExposureOnly = ko.observable(data.firstExposureOnly === undefined ? false : data.firstExposureOnly); - this.restrictToCommonPeriod = ko.observable(data.restrictToCommonPeriod === undefined ? false : data.restrictToCommonPeriod); - this.washoutPeriod = ko.observable(data.washoutPeriod === 0 ? 0 : data.washoutPeriod || 0).extend({ numeric: 0}); - this.removeDuplicateSubjects = ko.observable(data.removeDuplicateSubjects || "keep all"); - this.removeSubjectsWithPriorOutcome = ko.observable(data.removeSubjectsWithPriorOutcome === 0 ? false : data.removeSubjectsWithPriorOutcome || false); - this.priorOutcomeLookback = ko.observable(data.priorOutcomeLookback === 0 ? 0 : data.priorOutcomeLookback || 99999).extend({ numeric: 0}); - this.minDaysAtRisk = ko.observable(data.minDaysAtRisk === 0 ? 0 : data.minDaysAtRisk || 1).extend({ numeric: 0}); - this.riskWindowStart = ko.observable(data.riskWindowStart === 0 ? 0 : data.riskWindowStart || 0).extend({ numeric: 0}); - this.addExposureDaysToStart = ko.observable(data.addExposureDaysToStart === undefined ? false : data.addExposureDaysToStart); - this.riskWindowEnd = ko.observable(data.riskWindowEnd === 0 ? 0 : data.riskWindowEnd || 0).extend({ numeric: 0}); - this.addExposureDaysToEnd = ko.observable(data.addExposureDaysToEnd === undefined ? true : data.addExposureDaysToEnd); - this.censorAtNewRiskWindow = ko.observable(data.censorAtNewRiskWindow === undefined ? false : data.censorAtNewRiskWindow); - } - } - - return CreateStudyPopulationArgs; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/FitOutcomeModelArgs.js b/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/FitOutcomeModelArgs.js deleted file mode 100644 index ec31268b2..000000000 --- a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/FitOutcomeModelArgs.js +++ /dev/null @@ -1,28 +0,0 @@ -define([ - 'knockout', - 'services/analysis/RLangClass', - 'cyclops/InputTypes/Prior', - 'cyclops/InputTypes/Control' - ], function ( - ko, - RLangClass, - Prior, - Control - ) { - class FitOutcomeModelArgs extends RLangClass { - constructor(data = {}) { - super(); - this.modelType = ko.observable(data.modelType || "cox"); - this.stratified = ko.observable(data.stratified === undefined ? true : data.stratified); - this.useCovariates = ko.observable(data.useCovariates === undefined ? false : data.useCovariates); - this.inversePtWeighting = ko.observable(data.inversePtWeighting === undefined ? false : data.inversePtWeighting); - this.interactionCovariateIds = ko.observableArray((data.interactionCovariateIds && Array.isArray(data.interactionCovariateIds)) ? data.interactionCovariateIds : []); - this.excludeCovariateIds = ko.observableArray((data.excludeCovariateIds && Array.isArray(data.excludeCovariateIds)) ? data.excludeCovariateIds : []); - this.includeCovariateIds = ko.observableArray((data.includeCovariateIds && Array.isArray(data.includeCovariateIds)) ? data.includeCovariateIds : []); - this.prior = data.prior === undefined ? new Prior({priorType: "laplace", useCrossValidation: true}) : new Prior(data.prior); - this.control = data.control === undefined ? new Control({cvType: "auto", startingVariance: 0.01, tolerance: .0000002, cvRepetitions: 10, noiseLevel: "quiet", seed: 1}) : new Control(data.control); - } - } - - return FitOutcomeModelArgs; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/FullAnalysis.js b/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/FullAnalysis.js deleted file mode 100644 index 53c625560..000000000 --- a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/FullAnalysis.js +++ /dev/null @@ -1,14 +0,0 @@ -define([ - 'knockout', -], function ( - ko -) { - class FullAnalysis { - constructor(targetComparatorOutcome, cohortMethodAnalysis) { - this.targetComparatorOutcome = targetComparatorOutcome || null; - this.cohortMethodAnalysis = cohortMethodAnalysis || null; - } - } - - return FullAnalysis; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/GetDbCohortMethodDataArgs.js b/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/GetDbCohortMethodDataArgs.js deleted file mode 100644 index 181fa4e9d..000000000 --- a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/GetDbCohortMethodDataArgs.js +++ /dev/null @@ -1,27 +0,0 @@ -define([ - 'knockout', - 'services/analysis/RLangClass', - '../EstimationCovariateSettings', - 'databindings', -], function ( - ko, - RLangClass, - CovariateSettings -) { - class GetDbCohortMethodDataArgs extends RLangClass { - constructor(data = {}, defaultCovariateSettings) { - super(); - this.studyStartDate = ko.observable(data.studyStartDate || null); - this.studyEndDate = ko.observable(data.studyEndDate || null); - this.excludeDrugsFromCovariates = ko.observable(data.excludeDrugsFromCovariates === undefined ? false : data.excludeDrugsFromCovariates); - this.firstExposureOnly = ko.observable(data.firstExposureOnly === undefined ? false : data.firstExposureOnly); - this.removeDuplicateSubjects = ko.observable(data.removeDuplicateSubjects || "keep all"); - this.restrictToCommonPeriod = ko.observable(data.restrictToCommonPeriod === undefined ? false : data.restrictToCommonPeriod); - this.washoutPeriod = ko.observable(data.washoutPeriod === 0 ? 0 : data.washoutPeriod || 0).extend({ numeric: 0}); - this.maxCohortSize = ko.observable(data.maxCohortSize === 0 ? 0 : data.maxCohortSize || 0).extend({ numeric: 0}); - this.covariateSettings = new CovariateSettings(data.covariateSettings || defaultCovariateSettings); - } - } - - return GetDbCohortMethodDataArgs; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/MatchOnPsAndCovariateArgs.js b/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/MatchOnPsAndCovariateArgs.js deleted file mode 100644 index 3e45c57f3..000000000 --- a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/MatchOnPsAndCovariateArgs.js +++ /dev/null @@ -1,20 +0,0 @@ -define([ - 'knockout', - 'services/analysis/RLangClass', - 'databindings', -], function ( - ko, - RLangClass -) { - class MatchOnPsAndCovariateArgs extends RLangClass { - constructor(data = {}) { - super(); - this.caliper = ko.observable(data.caliper === 0 ? 0 : data.caliper || 0.2).extend({ numeric: 2}); - this.caliperScale = ko.observable(data.caliperScale || "standardized logit"); - this.maxRatio = ko.observable(data.maxRatio === 0 ? 0 : data.maxRatio || 1).extend({ numeric: 0}); - this.covariateIds = (data.covariateIds && Array.isArray(data.covariateIds)) ? data.covariateIds : []; - } - } - - return MatchOnPsAndCovariateArgs; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/MatchOnPsArgs.js b/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/MatchOnPsArgs.js deleted file mode 100644 index b34c053a8..000000000 --- a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/MatchOnPsArgs.js +++ /dev/null @@ -1,20 +0,0 @@ -define([ - 'knockout', - 'services/analysis/RLangClass', - 'databindings', -], function ( - ko, - RLangClass -) { - class MatchOnPsArgs extends RLangClass { - constructor(data = {}) { - super(); - this.caliper = ko.observable(data.caliper === 0 ? 0 : data.caliper || 0.2).extend({ numeric: 2}); - this.caliperScale = ko.observable(data.caliperScale || "standardized logit"); - this.maxRatio = ko.observable(data.maxRatio === 0 ? 0 : data.maxRatio || 1).extend({ numeric: 0}); - this.stratificationColumns = (data.stratificationColumns && Array.isArray(data.stratificationColumns)) ? data.stratificationColumns : []; - } - } - - return MatchOnPsArgs; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/StratifyByPsAndCovariatesArgs.js b/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/StratifyByPsAndCovariatesArgs.js deleted file mode 100644 index 8afcf6a48..000000000 --- a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/StratifyByPsAndCovariatesArgs.js +++ /dev/null @@ -1,19 +0,0 @@ -define([ - 'knockout', - 'services/analysis/RLangClass', - 'databindings', -], function ( - ko, - RLangClass -) { - class StratifyByPsAndCovariatesArgs extends RLangClass { - constructor(data = {}) { - super(); - this.numberOfStrata = ko.observable(data.numberOfStrata === 0 ? 0 : data.numberOfStrata || 5).extend({ numeric: 0}); - this.baseSelection = ko.observable(data.baseSelection || "all"); - this.covariateIds = (data.covariateIds && Array.isArray(data.covariateIds)) ? data.covariateIds : []; - } - } - - return StratifyByPsAndCovariatesArgs; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/StratifyByPsArgs.js b/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/StratifyByPsArgs.js deleted file mode 100644 index 9acad5290..000000000 --- a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/StratifyByPsArgs.js +++ /dev/null @@ -1,19 +0,0 @@ -define([ - 'knockout', - 'services/analysis/RLangClass', - 'databindings', -], function ( - ko, - RLangClass -) { - class StratifyByPsArgs extends RLangClass { - constructor(data = {}) { - super(); - this.numberOfStrata = ko.observable(data.numberOfStrata === 0 ? 0 : data.numberOfStrata || 5).extend({ numeric: 0}); - this.baseSelection = ko.observable(data.baseSelection || "all"); - this.stratificationColumns = (data.stratificationColumns && Array.isArray(data.stratificationColumns)) ? data.stratificationColumns : []; - } - } - - return StratifyByPsArgs; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/TrimByPsArgs.js b/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/TrimByPsArgs.js deleted file mode 100644 index 5cb999d06..000000000 --- a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/TrimByPsArgs.js +++ /dev/null @@ -1,17 +0,0 @@ -define([ - 'knockout', - 'services/analysis/RLangClass', - 'databindings', -], function ( - ko, - RLangClass -) { - class TrimByPsArgs extends RLangClass { - constructor(data = {}) { - super(); - this.trimFraction = ko.observable(data.trimFraction === 0 ? 0 : data.trimFraction || 0.05).extend({ numeric: 2}); - } - } - - return TrimByPsArgs; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/TrimByPsToEquipoiseArgs.js b/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/TrimByPsToEquipoiseArgs.js deleted file mode 100644 index a0cb94de8..000000000 --- a/js/pages/estimation/inputTypes/ComparativeCohortAnalysis/TrimByPsToEquipoiseArgs.js +++ /dev/null @@ -1,17 +0,0 @@ -define([ - 'knockout', - 'services/analysis/RLangClass', - 'databindings', -], function ( - ko, - RLangClass -) { - class TrimByPsToEquipoiseArgs extends RLangClass { - constructor(data = {}) { - super(); - this.bounds = ko.observableArray(data.bounds || [0.25, 0.75]); - } - } - - return TrimByPsToEquipoiseArgs; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/Comparison.js b/js/pages/estimation/inputTypes/Comparison.js deleted file mode 100644 index 1d5996be0..000000000 --- a/js/pages/estimation/inputTypes/Comparison.js +++ /dev/null @@ -1,22 +0,0 @@ -define([ - 'knockout', - 'services/analysis/Cohort', - 'services/analysis/ConceptSet' -], function ( - ko, - Cohort, - ConceptSet -) { - class Comparison { - constructor(data = {}) { - this.target = ko.observable(data.target !== null ? new Cohort(data.target) : new Cohort()); - this.comparator = ko.observable(data.comparator !== null ? new Cohort(data.comparator) : new Cohort()); - this.outcomes = ko.observableArray(data.outcomes && data.outcomes.map(function(d) { return new Cohort(d) })); - this.negativeControlOutcomesConceptSet = ko.observable(data.negativeControlOutcomesConceptSet !== null ? new ConceptSet(data.negativeControlOutcomesConceptSet) : new ConceptSet()); - this.includedCovariateConceptSet = ko.observable(data.includedCovariateConceptSet !== null ? new ConceptSet(data.includedCovariateConceptSet) : new ConceptSet()); - this.excludedCovariateConceptSet = ko.observable(data.excludedCovariateConceptSet !== null ? new ConceptSet(data.excludedCovariateConceptSet) : new ConceptSet()); - } - } - - return Comparison; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/EstimationAnalysis.js b/js/pages/estimation/inputTypes/EstimationAnalysis.js deleted file mode 100644 index d5a832bba..000000000 --- a/js/pages/estimation/inputTypes/EstimationAnalysis.js +++ /dev/null @@ -1,48 +0,0 @@ -define([ - 'knockout', - '../../../components/cohortbuilder/CohortDefinition', - 'components/conceptset/InputTypes/ConceptSet', - 'services/analysis/ConceptSetCrossReference', - "./PositiveControlSynthesisArgs", - './NegativeControl', - './NegativeControlExposureCohortDefinition', - './NegativeControlOutcomeCohortDefinition', - './EstimationAnalysisSettings' -], function ( - ko, - CohortDefinition, - ConceptSet, - ConceptSetCrossReference, - PositiveControlSynthesisArgs, - NegativeControl, - NegativeControlExposureCohortDefinition, - NegativeControlOutcomeCohortDefinition, - EstimationAnalysisSettings -) { - class EstimationAnalysis { - constructor(data = {}, estimationType, defaultCovariateSettings) { - this.id = ko.observable(data && data.id || null); - this.name = ko.observable(data && data.name || null); - this.description = ko.observable(data && data.description || null); - this.version = ko.observable(data && data.version || "v2.7.0"); - this.packageName = ko.observable(data && data.packageName || null); - this.skeletonType = data.skeletonType || "ComparativeEffectStudy"; - this.skeletonVersion = data.skeletonVersion || "v0.0.1"; - this.createdBy = data.createdBy; - this.createdDate = data.createdDate; - this.modifiedBy = data.modifiedBy; - this.modifiedDate = data.modifiedDate; - this.cohortDefinitions = ko.observableArray(data && data.cohortDefinitions && data.cohortDefinitions.map(function(d) { return new CohortDefinition(d) })); - this.conceptSets = ko.observableArray(data && data.conceptSets && data.conceptSets.map(function(d) { return new ConceptSet(d) })); - this.conceptSetCrossReference = ko.observableArray(data && data.conceptSetCrossReference && data.conceptSetCrossReference.map(function(d) { return new ConceptSetCrossReference(d) })); - this.negativeControls = ko.observableArray(data && data.negativeControls && data.negativeControls.map(function(d) { return new NegativeControl(d) })); - this.doPositiveControlSynthesis = ko.observable(data && data.doPositiveControlSynthesis || false); - this.positiveControlSynthesisArgs = ko.observable(new PositiveControlSynthesisArgs(data && data.positiveControlSynthesisArgs, defaultCovariateSettings)); - this.negativeControlOutcomeCohortDefinition = ko.observable(new NegativeControlOutcomeCohortDefinition(data && data.negativeControlOutcomeCohortDefinition)); - this.negativeControlExposureCohortDefinition = ko.observable(new NegativeControlExposureCohortDefinition(data && data.negativeControlExposureCohortDefinition)); - this.estimationAnalysisSettings = new EstimationAnalysisSettings(data && data.estimationAnalysisSettings, estimationType, defaultCovariateSettings); - } - } - - return EstimationAnalysis; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/EstimationAnalysisSettings.js b/js/pages/estimation/inputTypes/EstimationAnalysisSettings.js deleted file mode 100644 index e2dcd7142..000000000 --- a/js/pages/estimation/inputTypes/EstimationAnalysisSettings.js +++ /dev/null @@ -1,24 +0,0 @@ -define([ - 'knockout', - './ComparativeCohortAnalysis/ComparativeCohortAnalysis' -], function ( - ko, - ComparativeCohortAnalysis -) { - class EstimationAnalysisSettings { - constructor(data = {}, estimationType, defaultCovariateSettings) { - this.estimationType = (data.estimationType || estimationType); - this.analysisSpecification = this.getAnalysisObject(this.estimationType, data.analysisSpecification, defaultCovariateSettings); - } - - getAnalysisObject(estimationType, analysisSpecification, defaultCovariateSettings) { - if (estimationType === "ComparativeCohortAnalysis") { - return new ComparativeCohortAnalysis(analysisSpecification, defaultCovariateSettings); - } else { - console.error("estimationType property not set on Estimation Analysis and cannot initialize properly.") - } - } - } - - return EstimationAnalysisSettings; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/EstimationCovariateSettings.js b/js/pages/estimation/inputTypes/EstimationCovariateSettings.js deleted file mode 100644 index bf86a2913..000000000 --- a/js/pages/estimation/inputTypes/EstimationCovariateSettings.js +++ /dev/null @@ -1,18 +0,0 @@ -define([ - 'knockout', - 'featureextraction/InputTypes/CovariateSettings', - 'services/analysis/ConceptSet', -], function ( - ko, - CovariateSettings, - ConceptSet -){ - class EstimationCovariateSettings extends CovariateSettings { - constructor(data) { - super(data); - this.includedCovariateConceptSet = ko.observable(data.includedCovariateConceptSet !== null ? new ConceptSet(data.includedCovariateConceptSet) : new ConceptSet()); - this.excludedCovariateConceptSet = ko.observable(data.excludedCovariateConceptSet !== null ? new ConceptSet(data.excludedCovariateConceptSet) : new ConceptSet()); - } - } - return EstimationCovariateSettings; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/NegativeControl.js b/js/pages/estimation/inputTypes/NegativeControl.js deleted file mode 100644 index f178fa495..000000000 --- a/js/pages/estimation/inputTypes/NegativeControl.js +++ /dev/null @@ -1,12 +0,0 @@ -define([ - 'knockout', -], function ( - ko -) { - class NegativeControl { - constructor(data = {}) { - } - } - - return NegativeControl; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/NegativeControlExposureCohortDefinition.js b/js/pages/estimation/inputTypes/NegativeControlExposureCohortDefinition.js deleted file mode 100644 index d7beb7017..000000000 --- a/js/pages/estimation/inputTypes/NegativeControlExposureCohortDefinition.js +++ /dev/null @@ -1,12 +0,0 @@ -define([ - 'knockout', -], function ( - ko -) { - class NegativeControlExposureCohortDefinition { - constructor(data = {}) { - } - } - - return NegativeControlExposureCohortDefinition; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/NegativeControlOutcomeCohortDefinition.js b/js/pages/estimation/inputTypes/NegativeControlOutcomeCohortDefinition.js deleted file mode 100644 index 625a2f739..000000000 --- a/js/pages/estimation/inputTypes/NegativeControlOutcomeCohortDefinition.js +++ /dev/null @@ -1,15 +0,0 @@ -define([ - 'knockout', -], function ( - ko -) { - class NegativeControlOutcomeCohortDefinition { - constructor(data = {}) { - this.occurrenceType = ko.observable(data.occurrenceType || "all"); - this.detectOnDescendants = ko.observable(data.detectOnDescendants || true); - this.domains = ko.observableArray(data.domains && data.domains.map(function(d) { return d }) || ['condition','procedure']); - } - } - - return NegativeControlOutcomeCohortDefinition; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/PositiveControlSynthesisArgs.js b/js/pages/estimation/inputTypes/PositiveControlSynthesisArgs.js deleted file mode 100644 index bc7622fb7..000000000 --- a/js/pages/estimation/inputTypes/PositiveControlSynthesisArgs.js +++ /dev/null @@ -1,36 +0,0 @@ -define([ - 'knockout', - 'cyclops/InputTypes/Control', - './EstimationCovariateSettings', - 'cyclops/InputTypes/Prior', - 'databindings', -], function ( - ko, - Control, - CovariateSettings, - Prior -) { - class PositiveControlSynthesisArgs { - constructor(data = {}, defaultCovariateSettings) { - this.modelType = ko.observable(data.modelType || "survival"); - this.minOutcomeCountForModel = ko.observable(data.minOutcomeCountForModel === 0 ? 0 : data.minOutcomeCountForModel || 50).extend({ numeric: 0}); - this.minOutcomeCountForInjection = ko.observable(data.minOutcomeCountForInjection === 0 ? 0 : data.minOutcomeCountForInjection || 25).extend({ numeric: 0}); - this.covariateSettings = new CovariateSettings(data.covariateSettings || defaultCovariateSettings); - this.prior = data.prior === undefined ? new Prior({priorType: "laplace", exclude: 0, useCrossValidation: true}) : new Prior(data.prior); - this.control = data.control === undefined ? new Control({cvType: "auto", startingVariance: 0.01, noiseLevel: "quiet", seed: 1}) : new Control(data.control); - this.firstExposureOnly = ko.observable(data.firstExposureOnly === undefined ? true : data.firstExposureOnly); - this.washoutPeriod = ko.observable(data.washoutPeriod === 0 ? 0 : data.washoutPeriod || 365).extend({ numeric: 0}); - this.riskWindowStart = ko.observable(data.riskWindowStart === 0 ? 0 : data.riskWindowStart || 0).extend({ numeric: 0}); - this.riskWindowEnd = ko.observable(data.riskWindowEnd === 0 ? 0 : data.riskWindowEnd || 30).extend({ numeric: 0}); - this.addExposureDaysToEnd = ko.observable(data.addExposureDaysToEnd === undefined ? true : data.addExposureDaysToEnd); - this.firstOutcomeOnly = ko.observable(data.firstOutcomeOnly === undefined ? true : data.firstOutcomeOnly); - this.removePeopleWithPriorOutcomes = ko.observable(data.removePeopleWithPriorOutcomes === undefined ? true : data.removePeopleWithPriorOutcomes); - this.maxSubjectsForModel = ko.observable(data.maxSubjectsForModel === 0 ? 0 : data.maxSubjectsForModel || 250000).extend({ numeric: 0}); - this.effectSizes = ko.observableArray(data.effectSizes || [1.5, 2, 4]); - this.precision = ko.observable(data.precision === 0 ? 0.00 : data.precision || 0.01).extend({ numeric: 2}); - this.outputIdOffset = ko.observable(data.outputIdOffset === 0 ? 0 : data.outputIdOffset || 10000).extend({ numeric: 0}); - } - } - - return PositiveControlSynthesisArgs; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/TargetComparatorOutcome.js b/js/pages/estimation/inputTypes/TargetComparatorOutcome.js deleted file mode 100644 index c2d2b3b4d..000000000 --- a/js/pages/estimation/inputTypes/TargetComparatorOutcome.js +++ /dev/null @@ -1,15 +0,0 @@ -define([ - 'services/analysis/Cohort' -], function ( - Cohort -) { - class TargetComparatorOutcome { - constructor(data = {}) { - this.target = data.target || new Cohort(); - this.comparator = data.comparator || new Cohort(); - this.outcome = data.outcome || new Cohort(); - } - } - - return TargetComparatorOutcome; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/TargetComparatorOutcomes.js b/js/pages/estimation/inputTypes/TargetComparatorOutcomes.js deleted file mode 100644 index d4a607fba..000000000 --- a/js/pages/estimation/inputTypes/TargetComparatorOutcomes.js +++ /dev/null @@ -1,17 +0,0 @@ -define([ - 'knockout', -], function ( - ko -) { - class TargetComparatorOutcomes { - constructor(data = {}) { - this.targetId = ko.observable(data.targetId || null); - this.comparatorId = ko.observable(data.comparatorId || null); - this.outcomeIds = ko.observableArray((data.outcomeIds && Array.isArray(data.outcomeIds)) ? data.outcomeIds : []); - this.excludedCovariateConceptIds = ko.observableArray((data.excludedCovariateConceptIds && Array.isArray(data.excludedCovariateConceptIds)) ? data.excludedCovariateConceptIds : []); - this.includedCovariateConceptIds = ko.observableArray((data.includedCovariateConceptIds && Array.isArray(data.includedCovariateConceptIds)) ? data.includedCovariateConceptIds : []); - } - } - - return TargetComparatorOutcomes; -}); \ No newline at end of file diff --git a/js/pages/estimation/inputTypes/TargetOutcomes.js b/js/pages/estimation/inputTypes/TargetOutcomes.js deleted file mode 100644 index ec92c035e..000000000 --- a/js/pages/estimation/inputTypes/TargetOutcomes.js +++ /dev/null @@ -1,14 +0,0 @@ -define([ - 'knockout', -], function ( - ko -) { - class TargetOutcomes { - constructor(data = {}) { - this.targetId = ko.observable(data.targetId || null); - this.outcomeIds = ko.observableArray((data.outcomeIds && Array.isArray(data.outcomeIds)) ? data.outcomeIds : []); - } - } - - return TargetOutcomes; -}); \ No newline at end of file diff --git a/js/pages/estimation/routes.js b/js/pages/estimation/routes.js deleted file mode 100644 index 9eba4b501..000000000 --- a/js/pages/estimation/routes.js +++ /dev/null @@ -1,31 +0,0 @@ -define((require, factory) => { - const { AuthorizedRoute } = require('pages/Route'); - const atlasState = require('atlas-state'); - function routes(router) { - - const ccaViewEdit = new AuthorizedRoute((estimationId, section, sourceId) => { - require(['./cca-manager'], function () { - atlasState.estimationAnalysis.selectedId(estimationId); - router.setCurrentView('cca-manager', { - id: estimationId, - section: section || 'specification', - sourceId: section === 'executions' ? sourceId : null, - }); - }); - }); - - return { - '/estimation': new AuthorizedRoute(() => { - require(['./estimation-browser'], function () { - router.setCurrentView('estimation-browser'); - }); - }), - '/estimation/cca/:estimationId:': ccaViewEdit, - '/estimation/cca/:estimationId:/:section:': ccaViewEdit, - '/estimation/cca/:estimationId:/:section:/:sourceId:': ccaViewEdit, - }; - } - - return routes; - } -); \ No newline at end of file diff --git a/js/pages/main.js b/js/pages/main.js index d53917389..561de0216 100644 --- a/js/pages/main.js +++ b/js/pages/main.js @@ -9,8 +9,6 @@ define( const incidenceRates = require('./incidence-rates/index'); const profiles = require('./profiles/index'); const pathways = require('./pathways/index'); - const estimation = require('./estimation/index'); - const prediction = require('./prediction/index'); const reusables = require('./reusables/index'); const tagging = require('./tagging/index'); const jobs = require('./jobs/index'); @@ -29,8 +27,6 @@ define( pathways, incidenceRates, profiles, - estimation, - prediction, reusables, tagging, jobs, diff --git a/js/pages/prediction/PermissionService.js b/js/pages/prediction/PermissionService.js deleted file mode 100644 index 4315fd663..000000000 --- a/js/pages/prediction/PermissionService.js +++ /dev/null @@ -1,56 +0,0 @@ -define([ - 'services/AuthAPI', -], function ( - AuthAPI, -) { - return class PermissionService { - - static isPermittedCreate() { - return AuthAPI.isPermitted(`prediction:post`); - } - - static isPermittedList() { - return AuthAPI.isPermitted(`prediction:get`); - } - - static isPermittedLoad(id) { - return AuthAPI.isPermitted(`prediction:${id}:get`); - } - - static isPermittedUpdate(id) { - return AuthAPI.isPermitted(`prediction:${id}:put`); - } - - static isPermittedDelete(id) { - return AuthAPI.isPermitted(`prediction:${id}:delete`); - } - - static isPermittedCopy(id) { - return AuthAPI.isPermitted(`prediction:${id}:copy:get`); - } - - static isPermittedDownload(id) { - return AuthAPI.isPermitted(`prediction:${id}:download:get`); - } - - static isPermittedExport(id) { - return AuthAPI.isPermitted(`prediction:${id}:export:get`); - } - - static isPermittedGenerate(id, sourceKey) { - return AuthAPI.isPermitted(`prediction:${id}:generation:*:post`) && AuthAPI.isPermitted(`source:${sourceKey}:access`); - } - - static isPermittedListGenerations(id) { - return AuthAPI.isPermitted(`prediction:${id}:generation:get`); - } - - static isPermittedResults(id) { - return AuthAPI.isPermitted(`prediction:generation:${id}:result:get`); - } - - static isPermittedImport() { - return AuthAPI.isPermitted(`prediction:import:post`); - } - } -}); diff --git a/js/pages/prediction/components/editors/evaluation-settings-editor.html b/js/pages/prediction/components/editors/evaluation-settings-editor.html deleted file mode 100644 index 216074015..000000000 --- a/js/pages/prediction/components/editors/evaluation-settings-editor.html +++ /dev/null @@ -1,26 +0,0 @@ -
- -
- -
-
-
- -
- -
-
-
- -
- - -
-
-
- -
- -
-
\ No newline at end of file diff --git a/js/pages/prediction/components/editors/evaluation-settings-editor.js b/js/pages/prediction/components/editors/evaluation-settings-editor.js deleted file mode 100644 index 1ed3a810e..000000000 --- a/js/pages/prediction/components/editors/evaluation-settings-editor.js +++ /dev/null @@ -1,47 +0,0 @@ -define([ - 'knockout', - 'text!./evaluation-settings-editor.html', - 'components/Component', - 'utils/CommonUtils', - 'utils/DataTypeConverterUtils', - '../../const', - 'databindings' -], function ( - ko, - view, - Component, - commonUtils, - dataTypeConverterUtils, - constants, -) { - class EvaluationSettingsEditor extends Component { - constructor(params) { - super(params); - - this.isInteger = RegExp('^[1-9][0-9]*$'); - this.runPlpArgs = params.runPlpArgs(); - this.options = constants.options; - this.subscriptions = params.subscriptions; - this.splitSeed = ko.observable(this.runPlpArgs.splitSeed() !== null && this.runPlpArgs.splitSeed() !== 0 ? this.runPlpArgs.splitSeed() : ''); - this.testFraction = ko.observable(dataTypeConverterUtils.convertFromPercent(this.runPlpArgs.testFraction())); - this.isEditPermitted = params.isEditPermitted; - - this.subscriptions.push(this.splitSeed.subscribe(newValue => { - if (newValue === '' || !this.isInteger.test(newValue)) { - this.runPlpArgs.splitSeed(null); - this.splitSeed(''); - } else { - this.runPlpArgs.splitSeed(newValue); - } - })); - - this.subscriptions.push(this.testFraction.subscribe(newValue => { - const val = dataTypeConverterUtils.convertToPercent(newValue); - this.runPlpArgs.testFraction(val); - this.testFraction(dataTypeConverterUtils.convertFromPercent(val)); - })); - } - } - - return commonUtils.build('evaluation-settings-editor', EvaluationSettingsEditor, view); -}); \ No newline at end of file diff --git a/js/pages/prediction/components/editors/execution-settings-editor.html b/js/pages/prediction/components/editors/execution-settings-editor.html deleted file mode 100644 index 898c29944..000000000 --- a/js/pages/prediction/components/editors/execution-settings-editor.html +++ /dev/null @@ -1,24 +0,0 @@ -
- -
- -
-
-
- - patients -
-
-
-
- -
- -
-
-
- -
- -
-
\ No newline at end of file diff --git a/js/pages/prediction/components/editors/execution-settings-editor.js b/js/pages/prediction/components/editors/execution-settings-editor.js deleted file mode 100644 index cca36df7c..000000000 --- a/js/pages/prediction/components/editors/execution-settings-editor.js +++ /dev/null @@ -1,37 +0,0 @@ -define([ - 'knockout', - 'text!./execution-settings-editor.html', - 'components/Component', - 'utils/CommonUtils', - '../../const', - 'databindings' -], function ( - ko, - view, - Component, - commonUtils, - constants, -) { - class ExecutionSettingsEditor extends Component { - constructor(params) { - super(params); - - this.getPlpDataArgs = params.getPlpDataArgs(); - this.runPlpArgs = params.runPlpArgs(); - this.options = constants.options; - this.subscriptions = params.subscriptions; - this.isEditPermitted = params.isEditPermitted; - - this.maxSampleSizeToggle = ko.observable(this.getPlpDataArgs.maxSampleSize() != null || false); - this.subscriptions.push(this.maxSampleSizeToggle.subscribe(optionVal => { - if (optionVal == false) { - this.getPlpDataArgs.maxSampleSize(null); - } else { - this.getPlpDataArgs.maxSampleSize(10000); - } - })); - } - } - - return commonUtils.build('execution-settings-editor', ExecutionSettingsEditor, view); -}); \ No newline at end of file diff --git a/js/pages/prediction/components/editors/model-settings-editor.html b/js/pages/prediction/components/editors/model-settings-editor.html deleted file mode 100644 index 4bde4a97b..000000000 --- a/js/pages/prediction/components/editors/model-settings-editor.html +++ /dev/null @@ -1,5 +0,0 @@ -
-
-
- - diff --git a/js/pages/prediction/components/editors/model-settings-editor.js b/js/pages/prediction/components/editors/model-settings-editor.js deleted file mode 100644 index 8a97d78a4..000000000 --- a/js/pages/prediction/components/editors/model-settings-editor.js +++ /dev/null @@ -1,30 +0,0 @@ -define([ - 'knockout', - 'text!./model-settings-editor.html', - 'components/Component', - 'utils/CommonUtils', - './modelSettings/naive-bayes-settings', - './modelSettings/random-forest-settings', - './modelSettings/mlp-settings', - './modelSettings/knn-settings', - './modelSettings/gradient-boosting-machine-settings', - './modelSettings/decision-tree-settings', - './modelSettings/ada-boost-settings', - './modelSettings/lasso-logistic-regression-settings', -], function ( - ko, - view, - Component, - commonUtils, -) { - class ModelSettingsEditor extends Component { - constructor(params) { - super(params); - - this.editor = params.editor; - this.editorSettings = params; - } - } - - return commonUtils.build('model-settings-editor', ModelSettingsEditor, view); -}); \ No newline at end of file diff --git a/js/pages/prediction/components/editors/modelSettings/ModelSettingsEditorComponent.js b/js/pages/prediction/components/editors/modelSettings/ModelSettingsEditorComponent.js deleted file mode 100644 index 004df5cb3..000000000 --- a/js/pages/prediction/components/editors/modelSettings/ModelSettingsEditorComponent.js +++ /dev/null @@ -1,48 +0,0 @@ -define([ - 'knockout', - 'components/Component', - '../../../utils', - '../../../const', - 'components/multi-select', - 'components/multi-input/multi-input', -], function ( - ko, - Component, - utils, - constants -) { - class ModelSettingsEditorComponent extends Component { - constructor(params) { - super(params); - this.modelSettings = params.modelSettings[this.constructor.name]; - this.defaultModelSettings = utils.getDefaultModelSettings(this.constructor.name); - this.utils = utils; - this.constants = constants; - this.options = constants.options; - this.trueFalseOptions = ko.observable(this.options.trueFalseOptions); - this.classWeightOptions = ko.observable(this.options.classWeightOptions); - this.extenders = constants.extenders; - this.subscriptions = params.subscriptions; - } - - modelSettingDescription(settingName) { - return utils.getDefaultModelSettingDescriptionTranslate(this.defaultModelSettings, settingName); - } - getModelSettingByName(settingName) { - if (!Object.keys(this.modelSettings).indexOf(settingName) < 0) { - console.error("Setting: " + settingName + " not found in modelSettings"); - } - return Object.values(this.modelSettings)[Object.keys(this.modelSettings).indexOf(settingName)]; - } - isDefault(settingName) { - const setting = this.getModelSettingByName(settingName); - return JSON.stringify(setting()) === JSON.stringify(utils.getDefaultModelSettingValue(this.defaultModelSettings, settingName)); - } - setToDefault(settingName) { - const setting = this.getModelSettingByName(settingName); - setting(utils.getDefaultModelSettingValue(this.defaultModelSettings, settingName)); - } - } - - return ModelSettingsEditorComponent; -}); \ No newline at end of file diff --git a/js/pages/prediction/components/editors/modelSettings/ada-boost-settings.html b/js/pages/prediction/components/editors/modelSettings/ada-boost-settings.html deleted file mode 100644 index d806bb47e..000000000 --- a/js/pages/prediction/components/editors/modelSettings/ada-boost-settings.html +++ /dev/null @@ -1,8 +0,0 @@ -
- - -
-
- - -
\ No newline at end of file diff --git a/js/pages/prediction/components/editors/modelSettings/ada-boost-settings.js b/js/pages/prediction/components/editors/modelSettings/ada-boost-settings.js deleted file mode 100644 index cb4083746..000000000 --- a/js/pages/prediction/components/editors/modelSettings/ada-boost-settings.js +++ /dev/null @@ -1,39 +0,0 @@ -define([ - 'knockout', - 'text!./ada-boost-settings.html', - './ModelSettingsEditorComponent', - 'utils/CommonUtils', - 'utils/DataTypeConverterUtils', -], function ( - ko, - view, - ModelSettingsEditorComponent, - commonUtils, - dataTypeConverterUtils, -) { - const settings = { - learningRate: 'learningRate', - nEstimators: 'nEstimators' - }; - - class AdaBoostSettings extends ModelSettingsEditorComponent { - constructor(params) { - super(params); - - this.learningRate = { - name: settings.learningRate, - value: this.modelSettings.learningRate, - valueLabel: this.utils.getDefaultModelSettingName(this.defaultModelSettings, settings.learningRate), - default: this.utils.getDefaultModelSettingValue(this.defaultModelSettings, settings.learningRate), - }; - this.nEstimators = { - name: settings.nEstimators, - value: this.modelSettings.nEstimators, - valueLabel: this.utils.getDefaultModelSettingName(this.defaultModelSettings, settings.nEstimators), - default: this.utils.getDefaultModelSettingValue(this.defaultModelSettings, settings.nEstimators), - }; - } - } - - return commonUtils.build('ada-boost-settings', AdaBoostSettings, view); -}); \ No newline at end of file diff --git a/js/pages/prediction/components/editors/modelSettings/decision-tree-settings.html b/js/pages/prediction/components/editors/modelSettings/decision-tree-settings.html deleted file mode 100644 index f543c943a..000000000 --- a/js/pages/prediction/components/editors/modelSettings/decision-tree-settings.html +++ /dev/null @@ -1,31 +0,0 @@ -
-
- -
- - - - -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
\ No newline at end of file diff --git a/js/pages/prediction/components/editors/modelSettings/decision-tree-settings.js b/js/pages/prediction/components/editors/modelSettings/decision-tree-settings.js deleted file mode 100644 index 78ef85ac8..000000000 --- a/js/pages/prediction/components/editors/modelSettings/decision-tree-settings.js +++ /dev/null @@ -1,61 +0,0 @@ -define([ - 'knockout', - 'text!./decision-tree-settings.html', - './ModelSettingsEditorComponent', - 'utils/CommonUtils', - 'utils/DataTypeConverterUtils', - 'less!./decision-tree-settings.less', -], function ( - ko, - view, - ModelSettingsEditorComponent, - commonUtils, - dataTypeConverterUtils -) { - const settings = { - maxDepth: 'maxDepth', - minSamplesSplit: 'minSamplesSplit', - minSamplesLeaf: 'minSamplesLeaf', - minImpurityDecrease: 'minImpurityDecrease', - classWeight: 'classWeight', - }; - - class DecisionTreeSettings extends ModelSettingsEditorComponent { - constructor(params) { - super(params); - - this.maxDepth = { - name: settings.maxDepth, - value: this.modelSettings.maxDepth, - valueLabel: this.utils.getDefaultModelSettingName(this.defaultModelSettings, settings.maxDepth), - default: this.utils.getDefaultModelSettingValue(this.defaultModelSettings, settings.maxDepth), - }; - this.minSamplesSplit = { - name: settings.minSamplesSplit, - value: this.modelSettings.minSamplesSplit, - valueLabel: this.utils.getDefaultModelSettingName(this.defaultModelSettings, settings.minSamplesSplit), - default: this.utils.getDefaultModelSettingValue(this.defaultModelSettings, settings.minSamplesSplit), - }; - this.minSamplesLeaf = { - name: settings.minSamplesLeaf, - value: this.modelSettings.minSamplesLeaf, - valueLabel: this.utils.getDefaultModelSettingName(this.defaultModelSettings, settings.minSamplesLeaf), - default: this.utils.getDefaultModelSettingValue(this.defaultModelSettings, settings.minSamplesLeaf), - }; - this.minImpurityDecrease = { - name: settings.minImpurityDecrease, - value: this.modelSettings.minImpurityDecrease, - valueLabel: this.utils.getDefaultModelSettingName(this.defaultModelSettings, settings.minImpurityDecrease), - default: this.utils.getDefaultModelSettingValue(this.defaultModelSettings, settings.minImpurityDecrease), - }; - this.classWeight = { - name: settings.classWeight, - value: this.modelSettings.classWeight, - valueLabel: this.utils.getDefaultModelSettingName(this.defaultModelSettings, settings.classWeight), - default: this.utils.getDefaultModelSettingValue(this.defaultModelSettings, settings.classWeight), - }; - } - } - - return commonUtils.build('decision-tree-settings', DecisionTreeSettings, view); -}); \ No newline at end of file diff --git a/js/pages/prediction/components/editors/modelSettings/decision-tree-settings.less b/js/pages/prediction/components/editors/modelSettings/decision-tree-settings.less deleted file mode 100644 index f059dc7e2..000000000 --- a/js/pages/prediction/components/editors/modelSettings/decision-tree-settings.less +++ /dev/null @@ -1,5 +0,0 @@ -.decision-tree-settings { - &__class-weight { - margin-bottom: 20px; - } -} \ No newline at end of file diff --git a/js/pages/prediction/components/editors/modelSettings/gradient-boosting-machine-settings.html b/js/pages/prediction/components/editors/modelSettings/gradient-boosting-machine-settings.html deleted file mode 100644 index 1fbc1e850..000000000 --- a/js/pages/prediction/components/editors/modelSettings/gradient-boosting-machine-settings.html +++ /dev/null @@ -1,29 +0,0 @@ -
- - -
-
- - -
-
- - -
-
- - -
-
- -
- - - - -
-
diff --git a/js/pages/prediction/components/editors/modelSettings/gradient-boosting-machine-settings.js b/js/pages/prediction/components/editors/modelSettings/gradient-boosting-machine-settings.js deleted file mode 100644 index 8088dc611..000000000 --- a/js/pages/prediction/components/editors/modelSettings/gradient-boosting-machine-settings.js +++ /dev/null @@ -1,60 +0,0 @@ -define([ - 'knockout', - 'text!./gradient-boosting-machine-settings.html', - './ModelSettingsEditorComponent', - 'utils/CommonUtils', - 'utils/DataTypeConverterUtils', -], function ( - ko, - view, - ModelSettingsEditorComponent, - commonUtils, - dataTypeConverterUtils, -) { - const settings = { - ntrees: 'ntrees', - nthread: 'nthread', - maxDepth: 'maxDepth', - minRows: 'minRows', - learnRate: 'learnRate' - }; - - class GradientBoostingMachineSettings extends ModelSettingsEditorComponent { - constructor(params) { - super(params); - - this.ntrees = { - name: settings.ntrees, - value: this.modelSettings.ntrees, - valueLabel: this.utils.getDefaultModelSettingName(this.defaultModelSettings, settings.ntrees), - default: this.utils.getDefaultModelSettingValue(this.defaultModelSettings, settings.ntrees), - }; - this.nthread = { - name: settings.nthread, - value: this.modelSettings.nthread, - valueLabel: this.utils.getDefaultModelSettingName(this.defaultModelSettings, settings.nthread), - default: this.utils.getDefaultModelSettingValue(this.defaultModelSettings, settings.nthread), - }; - this.maxDepth = { - name: settings.maxDepth, - value: this.modelSettings.maxDepth, - valueLabel: this.utils.getDefaultModelSettingName(this.defaultModelSettings, settings.maxDepth), - default: this.utils.getDefaultModelSettingValue(this.defaultModelSettings, settings.maxDepth), - }; - this.minRows = { - name: settings.minRows, - value: this.modelSettings.minRows, - valueLabel: this.utils.getDefaultModelSettingName(this.defaultModelSettings, settings.minRows), - default: this.utils.getDefaultModelSettingValue(this.defaultModelSettings, settings.minRows), - }; - this.learnRate = { - name: settings.learnRate, - value: this.modelSettings.learnRate, - valueLabel: this.utils.getDefaultModelSettingName(this.defaultModelSettings, settings.learnRate), - default: this.utils.getDefaultModelSettingValue(this.defaultModelSettings, settings.learnRate), - }; - } - } - - return commonUtils.build('gradient-boosting-machine-settings', GradientBoostingMachineSettings, view); -}); \ No newline at end of file diff --git a/js/pages/prediction/components/editors/modelSettings/knn-settings.html b/js/pages/prediction/components/editors/modelSettings/knn-settings.html deleted file mode 100644 index cfe731a28..000000000 --- a/js/pages/prediction/components/editors/modelSettings/knn-settings.html +++ /dev/null @@ -1,11 +0,0 @@ - -
- - - - -
\ No newline at end of file diff --git a/js/pages/prediction/components/editors/modelSettings/knn-settings.js b/js/pages/prediction/components/editors/modelSettings/knn-settings.js deleted file mode 100644 index 252590ec0..000000000 --- a/js/pages/prediction/components/editors/modelSettings/knn-settings.js +++ /dev/null @@ -1,25 +0,0 @@ -define([ - 'knockout', - 'text!./knn-settings.html', - './ModelSettingsEditorComponent', - 'utils/CommonUtils', -], function ( - ko, - view, - ModelSettingsEditorComponent, - commonUtils, -) { - class KNNSettings extends ModelSettingsEditorComponent { - constructor(params) { - super(params); - - this.k = { - name: 'k', - value: this.modelSettings.k, - }; - - } - } - - return commonUtils.build('knn-settings', KNNSettings, view); -}); \ No newline at end of file diff --git a/js/pages/prediction/components/editors/modelSettings/lasso-logistic-regression-settings.html b/js/pages/prediction/components/editors/modelSettings/lasso-logistic-regression-settings.html deleted file mode 100644 index 1af1b79c6..000000000 --- a/js/pages/prediction/components/editors/modelSettings/lasso-logistic-regression-settings.html +++ /dev/null @@ -1,11 +0,0 @@ - -
- - - - -
\ No newline at end of file diff --git a/js/pages/prediction/components/editors/modelSettings/lasso-logistic-regression-settings.js b/js/pages/prediction/components/editors/modelSettings/lasso-logistic-regression-settings.js deleted file mode 100644 index d23146302..000000000 --- a/js/pages/prediction/components/editors/modelSettings/lasso-logistic-regression-settings.js +++ /dev/null @@ -1,24 +0,0 @@ -define([ - 'knockout', - 'text!./lasso-logistic-regression-settings.html', - './ModelSettingsEditorComponent', - 'utils/CommonUtils', -], function ( - ko, - view, - ModelSettingsEditorComponent, - commonUtils, -) { - class LassoLogisticRegressionSettings extends ModelSettingsEditorComponent { - constructor(params) { - super(params); - - this.variance = { - name: 'variance', - value: this.modelSettings.variance, - }; - } - } - - return commonUtils.build('lasso-logistic-regression-settings', LassoLogisticRegressionSettings, view); -}); \ No newline at end of file diff --git a/js/pages/prediction/components/editors/modelSettings/mlp-settings.html b/js/pages/prediction/components/editors/modelSettings/mlp-settings.html deleted file mode 100644 index 999f1f8f7..000000000 --- a/js/pages/prediction/components/editors/modelSettings/mlp-settings.html +++ /dev/null @@ -1,8 +0,0 @@ -
- - -
-
- - -
\ No newline at end of file diff --git a/js/pages/prediction/components/editors/modelSettings/mlp-settings.js b/js/pages/prediction/components/editors/modelSettings/mlp-settings.js deleted file mode 100644 index cb4905dd6..000000000 --- a/js/pages/prediction/components/editors/modelSettings/mlp-settings.js +++ /dev/null @@ -1,40 +0,0 @@ -define([ - 'knockout', - 'text!./mlp-settings.html', - './ModelSettingsEditorComponent', - 'utils/CommonUtils', - 'utils/DataTypeConverterUtils' -], function ( - ko, - view, - ModelSettingsEditorComponent, - commonUtils, - dataTypeConverterUtils, -) { - const settings = { - size: 'size', - alpha: 'alpha', - }; - - class MLPSettings extends ModelSettingsEditorComponent { - constructor(params) { - super(params); - - this.size = { - name: settings.size, - value: this.modelSettings.size, - valueLabel: this.utils.getDefaultModelSettingName(this.defaultModelSettings, settings.size), - default: this.utils.getDefaultModelSettingValue(this.defaultModelSettings, settings.size), - }; - - this.alpha = { - name: settings.alpha, - value: this.modelSettings.alpha, - valueLabel: this.utils.getDefaultModelSettingName(this.defaultModelSettings, settings.alpha), - default: this.utils.getDefaultModelSettingValue(this.defaultModelSettings, settings.alpha), - }; - } - } - - return commonUtils.build('mlp-settings', MLPSettings, view); -}); \ No newline at end of file diff --git a/js/pages/prediction/components/editors/modelSettings/naive-bayes-settings.html b/js/pages/prediction/components/editors/modelSettings/naive-bayes-settings.html deleted file mode 100644 index 479310b6c..000000000 --- a/js/pages/prediction/components/editors/modelSettings/naive-bayes-settings.html +++ /dev/null @@ -1 +0,0 @@ -
\ No newline at end of file diff --git a/js/pages/prediction/components/editors/modelSettings/naive-bayes-settings.js b/js/pages/prediction/components/editors/modelSettings/naive-bayes-settings.js deleted file mode 100644 index 42a946811..000000000 --- a/js/pages/prediction/components/editors/modelSettings/naive-bayes-settings.js +++ /dev/null @@ -1,19 +0,0 @@ -define([ - 'knockout', - 'text!./naive-bayes-settings.html', - './ModelSettingsEditorComponent', - 'utils/CommonUtils', -], function ( - ko, - view, - ModelSettingsEditorComponent, - commonUtils, -) { - class NaiveBayesSettings extends ModelSettingsEditorComponent { - constructor(params) { - super(params); - } - } - - return commonUtils.build('naive-bayes-settings', NaiveBayesSettings, view); -}); \ No newline at end of file diff --git a/js/pages/prediction/components/editors/modelSettings/random-forest-settings.html b/js/pages/prediction/components/editors/modelSettings/random-forest-settings.html deleted file mode 100644 index 821d54244..000000000 --- a/js/pages/prediction/components/editors/modelSettings/random-forest-settings.html +++ /dev/null @@ -1,34 +0,0 @@ -
-
- - - -
-
- - - -
-
- - - -
-
- -
- - - - - -
-
-
\ No newline at end of file diff --git a/js/pages/prediction/components/editors/modelSettings/random-forest-settings.js b/js/pages/prediction/components/editors/modelSettings/random-forest-settings.js deleted file mode 100644 index 1ed872435..000000000 --- a/js/pages/prediction/components/editors/modelSettings/random-forest-settings.js +++ /dev/null @@ -1,54 +0,0 @@ -define([ - 'knockout', - 'text!./random-forest-settings.html', - './ModelSettingsEditorComponent', - 'utils/CommonUtils', - 'utils/DataTypeConverterUtils', -], function ( - ko, - view, - ModelSettingsEditorComponent, - commonUtils, - dataTypeConverterUtils, -) { - - const settings = { - mtries: 'mtries', - ntrees: 'ntrees', - maxDepth: 'maxDepth', - varImp: 'varImp' - }; - - class RandomForestSettings extends ModelSettingsEditorComponent { - constructor(params) { - super(params); - - this.mtries = { - name: settings.mtries, - value: this.modelSettings.mtries, - valueLabel: this.utils.getDefaultModelSettingName(this.defaultModelSettings, settings.mtries), - default: this.utils.getDefaultModelSettingValue(this.defaultModelSettings, settings.mtries), - }; - this.ntrees = { - name: settings.ntrees, - value: this.modelSettings.ntrees, - valueLabel: this.utils.getDefaultModelSettingName(this.defaultModelSettings, settings.ntrees), - default: this.utils.getDefaultModelSettingValue(this.defaultModelSettings, settings.ntrees), - }; - this.maxDepth = { - name: settings.maxDepth, - value: this.modelSettings.maxDepth, - valueLabel: this.utils.getDefaultModelSettingName(this.defaultModelSettings, settings.maxDepth), - default: this.utils.getDefaultModelSettingValue(this.defaultModelSettings, settings.maxDepth), - }; - this.varImp = { - name: settings.varImp, - value: this.modelSettings.varImp, - valueLabel: this.utils.getDefaultModelSettingName(this.defaultModelSettings, settings.varImp), - default: this.utils.getDefaultModelSettingValue(this.defaultModelSettings, settings.varImp), - }; - } - } - - return commonUtils.build('random-forest-settings', RandomForestSettings, view); -}); \ No newline at end of file diff --git a/js/pages/prediction/components/editors/population-settings-editor.html b/js/pages/prediction/components/editors/population-settings-editor.html deleted file mode 100644 index d3b62dd20..000000000 --- a/js/pages/prediction/components/editors/population-settings-editor.html +++ /dev/null @@ -1,66 +0,0 @@ -
-
- -
-  days from -
-
-
- -
-  days from -
-
-
- -
- -
-
-
- -
-
-
- -
-
- -
-  days -
-
-
-
-
- -
- -
-
-
-
- -
- -
-
-
- -
- -
-
-
- -  days prior to cohort start -
-
-
-
diff --git a/js/pages/prediction/components/editors/population-settings-editor.js b/js/pages/prediction/components/editors/population-settings-editor.js deleted file mode 100644 index f1bd0b988..000000000 --- a/js/pages/prediction/components/editors/population-settings-editor.js +++ /dev/null @@ -1,30 +0,0 @@ -define([ - 'knockout', - 'text!./population-settings-editor.html', - 'components/Component', - 'utils/CommonUtils', - '../../const', - 'const', - 'databindings', - 'less!./population-settings-editor.less', -], function ( - ko, - view, - Component, - commonUtils, - predictionConstants, - constants, -) { - class PopulationSettingsEditor extends Component { - constructor(params) { - super(params); - - this.populationSettings = params.populationSettings; - this.options = predictionConstants.options; - this.constants = constants; - this.isEditPermitted = params.isEditPermitted; - } - } - - return commonUtils.build('population-settings-editor', PopulationSettingsEditor, view); -}); \ No newline at end of file diff --git a/js/pages/prediction/components/editors/population-settings-editor.less b/js/pages/prediction/components/editors/population-settings-editor.less deleted file mode 100644 index fed987452..000000000 --- a/js/pages/prediction/components/editors/population-settings-editor.less +++ /dev/null @@ -1,5 +0,0 @@ -.population-settings-editor { - &__form-sub-option { - padding-left: 10px; - } -} diff --git a/js/pages/prediction/components/editors/prediction-covariate-settings-editor.html b/js/pages/prediction/components/editors/prediction-covariate-settings-editor.html deleted file mode 100644 index 84d8e47da..000000000 --- a/js/pages/prediction/components/editors/prediction-covariate-settings-editor.html +++ /dev/null @@ -1,65 +0,0 @@ -
-
- -
- - - - - -
- -
-
- -
- -
-
-
- -
- - - - - -
-
-
- -
- -
-
-
- -
- -
-
-
-
-

- - - - \ No newline at end of file diff --git a/js/pages/prediction/components/editors/prediction-covariate-settings-editor.js b/js/pages/prediction/components/editors/prediction-covariate-settings-editor.js deleted file mode 100644 index 3cf270f19..000000000 --- a/js/pages/prediction/components/editors/prediction-covariate-settings-editor.js +++ /dev/null @@ -1,63 +0,0 @@ -define([ - 'knockout', - 'text!./prediction-covariate-settings-editor.html', - 'components/Component', - 'utils/CommonUtils', - 'utils/DataTypeConverterUtils', - '../../const', - 'services/analysis/ConceptSet', - 'databindings', - 'featureextraction/components/covariate-settings-editor', - 'circe', -], function ( - ko, - view, - Component, - commonUtils, - dataTypeConverterUtils, - constants, - ConceptSet, -) { - class PredictionCovariateSettingsEditor extends Component { - constructor(params) { - super(params); - - this.covariateSettings = params.covariateSettings; - this.options = constants.options; - this.subscriptions = params.subscriptions; - this.currentConceptSet = ko.observable(null); - this.showConceptSetSelector = ko.observable(false); - this.includedCovariateIds = ko.observable(this.covariateSettings.includedCovariateIds() && this.covariateSettings.includedCovariateIds().length > 0 ? this.analysis.getDbCohortMethodDataArgs.covariateSettings.includedCovariateIds().join() : ''); - this.isEditPermitted = params.isEditPermitted; - this.subscriptions.push(this.includedCovariateIds.subscribe(newValue => { - this.covariateSettings.includedCovariateIds(dataTypeConverterUtils.commaDelimitedListToNumericArray(newValue)); - })); - } - - conceptsetSelected(d) { - this.currentConceptSet()(new ConceptSet({id: d.id, name: d.name})); - this.showConceptSetSelector(false); - } - - chooseIncludedCovariates() { - this.showConceptSetSelector(true); - this.currentConceptSet(this.covariateSettings.includedCovariateConceptSet); - } - - clearIncludedCovariates () { - this.covariateSettings.includedCovariateConceptSet(new ConceptSet()); - } - - chooseExcludedCovariates() { - this.showConceptSetSelector(true); - this.currentConceptSet(this.covariateSettings.excludedCovariateConceptSet); - } - - clearExcludedCovariates () { - this.covariateSettings.excludedCovariateConceptSet(new ConceptSet()); - } - - } - - return commonUtils.build('prediction-covar-settings-editor', PredictionCovariateSettingsEditor, view); -}); \ No newline at end of file diff --git a/js/pages/prediction/components/prediction-specification-view-edit.html b/js/pages/prediction/components/prediction-specification-view-edit.html deleted file mode 100644 index d38fd60cf..000000000 --- a/js/pages/prediction/components/prediction-specification-view-edit.html +++ /dev/null @@ -1,244 +0,0 @@ -
-
-
- -
-
-
-
- -
-
- -
-
-
-
-
-
-
- -
-
-
-
-
- - -
-
- -
-
-
-
- - - -
-
- -
-
-
-
-
-
-
-
-
-
-
- - -
-
-
-
-
- -
- - -
-
-
- -
-
-
-
- -
- -
-
-
- -
-
-
-
- - -
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
- -
-
-
-
-
-
-
-
- -
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - - \ No newline at end of file diff --git a/js/pages/prediction/components/prediction-specification-view-edit.js b/js/pages/prediction/components/prediction-specification-view-edit.js deleted file mode 100644 index cd37ba654..000000000 --- a/js/pages/prediction/components/prediction-specification-view-edit.js +++ /dev/null @@ -1,220 +0,0 @@ -define([ - 'knockout', - 'text!./prediction-specification-view-edit.html', - 'utils/AutoBind', - 'components/Component', - 'utils/CommonUtils', - '../const', - 'services/analysis/Cohort', - '../inputTypes/ModelSettings', - '../inputTypes/CreateStudyPopulationArgs', - '../inputTypes/PredictionCovariateSettings', - 'featureextraction/components/covariate-settings-editor', - 'featureextraction/components/temporal-covariate-settings-editor', - 'components/entityBrowsers/cohort-definition-browser', - 'faceted-datatable', - 'less!./prediction-specification-view-edit.less', -], function ( - ko, - view, - AutoBind, - Component, - commonUtils, - constants, - Cohort, - ModelSettings, - CreateStudyPopulationArgs, - PredictionCovariateSettings, -) { - class PredictionSpecificationViewEdit extends AutoBind(Component) { - constructor(params) { - super(params); - this.subscriptions = params.subscriptions; - this.editorComponentName = ko.observable(null); - this.editorComponentParams = ko.observable({}); - this.editorDescription = ko.observable(); - this.editorHeading = ko.observable(); - this.editorArray = ko.observableArray(); - this.options = constants.options; - this.managerMode = ko.observable('summary'); - this.patientLevelPredictionAnalysis = params.patientLevelPredictionAnalysis; - this.specificationPillMode = ko.observable('all'); - this.targetCohorts = params.targetCohorts; - this.outcomeCohorts = params.outcomeCohorts; - this.currentCohortList = ko.observable(null); - this.showCohortSelector = ko.observable(false); - this.covariateSettings = this.patientLevelPredictionAnalysis().covariateSettings; - this.modelSettings = this.patientLevelPredictionAnalysis().modelSettings; - this.populationSettings = this.patientLevelPredictionAnalysis().populationSettings; - this.modelSettingsOptions = ModelSettings.options; - this.defaultCovariateSettings = constants.defaultNontemporalCovariates; - this.isEditPermitted = params.isEditPermitted; - this.cohortTableColumns = constants.getCohortTableColumns(this.isEditPermitted()); - this.populationSettingsTableColumns = constants.getPopulationSettingsTableColumns(this.isEditPermitted()); - this.modelSettingsTableColumns = constants.getModelSettingsTableColumns(this.isEditPermitted()); - this.covariateSettingsTableColumns = constants.getCovariateSettingsTableColumns(this.isEditPermitted()); - this.language = ko.i18n('datatable.language'); - } - - removeTargetCohort(data, obj, tableRow, rowIndex) { - this.deleteFromTable(this.targetCohorts, obj, rowIndex); - } - - removeOutcomeCohort(data, obj, tableRow, rowIndex) { - this.deleteFromTable(this.outcomeCohorts, obj, rowIndex); - } - - modelSettingRowClickHandler(data, obj, tableRow, rowIndex) { - if ( - obj.target.className.indexOf("btn-remove") >= 0 || - obj.target.className.indexOf("fa-times") >= 0 - ) { - this.deleteFromTable(this.modelSettings, obj, rowIndex); - } else { - this.editModelSettings(data); - } - } - - covariateSettingRowClickHandler(data, obj, tableRow, rowIndex) { - if ( - obj.target.className.indexOf("btn-remove") >= 0 || - obj.target.className.indexOf("fa-times") >= 0 - ) { - this.deleteFromTable(this.patientLevelPredictionAnalysis().covariateSettings, obj, rowIndex); - } else { - this.editCovariateSettings(data); - } - } - - populationSettingRowClickHandler(data, obj, tableRow, rowIndex) { - if ( - obj.target.className.indexOf("btn-remove") >= 0 || - obj.target.className.indexOf("fa-times") >= 0 - ) { - this.deleteFromTable(this.patientLevelPredictionAnalysis().populationSettings, obj, rowIndex); - } else { - this.editPopulationSettings(data); - } - } - - addTarget() { - this.currentCohortList(this.targetCohorts); - this.showCohortSelector(true); - } - - addOutcome() { - this.currentCohortList(this.outcomeCohorts); - this.showCohortSelector(true); - } - - cohortSelected(items) { - const cohortList = items.map(({ id, name }) => new Cohort({ id, name })); - this.currentCohortList()(cohortList); - this.showCohortSelector(false); - } - - deleteFromTable(list, obj, index) { - // Check if the button or inner element were clicked - if ( - obj.target.className.indexOf("btn-remove") >= 0 || - obj.target.className.indexOf("fa-times") >= 0 - ) { - list.splice(index, 1); - } - } - - // For later when we support temporal and non-temporal covariate settings - /* - addCovariateSettings(setting) { - const covariateSettings = (setting == 'Temporal') ? new TemporalCovariateSettings(this.defaultTemporalCovariateSettings) : new PredictionCovariateSettings(this.defaultCovariateSettings); - const headingPrefix = (setting == 'Temporal') ? 'Temporal ' : ''; - const editorNamePrefix = (setting == 'Temporal') ? 'temporal-' : ''; - this.patientLevelPredictionAnalysis().covariateSettings.push( - covariateSettings - ); - var index = this.patientLevelPredictionAnalysis().covariateSettings().length - 1; - this.editorHeading(headingPrefix + 'Covariate Settings'); - this.editorDescription('Add or update the covariate settings'); - this.editorComponentName(editorNamePrefix + 'prediction-covar-settings-editor'); - this.editorComponentParams({ - covariateSettings: this.patientLevelPredictionAnalysis().covariateSettings()[index], - }); - this.managerMode('editor'); - } - */ - - addCovariateSettings() { - const covariateSettings = new PredictionCovariateSettings(this.defaultCovariateSettings); - this.patientLevelPredictionAnalysis().covariateSettings.push( - covariateSettings - ); - const index = this.patientLevelPredictionAnalysis().covariateSettings().length - 1; - this.editCovariateSettings(this.patientLevelPredictionAnalysis().covariateSettings()[index]); - } - - editCovariateSettings(settings) { - this.editorArray = this.covariateSettings; - this.editorHeading(ko.i18n('predictions.covariateSettingsTitle', 'Covariate Settings')); - this.editorDescription(ko.i18n('predictions.covariateSettingsDesc', 'Add or update the covariate settings')); - this.editorComponentName('prediction-covar-settings-editor'); - this.editorComponentParams({ - covariateSettings: settings, - subscriptions: this.subscriptions, - isEditPermitted: this.isEditPermitted - }); - this.managerMode('editor'); - } - - addModelSettings(d) { - this.modelSettings.push(d.action()); - const index = this.modelSettings().length - 1; - this.editModelSettings(this.modelSettings()[index], d.editor); - } - - editModelSettings(modelSettings, editor) { - const option = ModelSettings.GetOptionsFromObject(modelSettings); - if (editor === undefined) { - editor = option.editor; - } - this.editorArray = this.modelSettings; - this.editorHeading(ko.i18n(option.name, option.defaultName)); - this.editorDescription(ko.i18n('predictions.modelSettingsDesc', 'Use the options below to edit the model settings')); - this.editorComponentName('model-settings-editor'); - this.editorComponentParams({ - subscriptions: this.subscriptions, - modelSettings: modelSettings, - editor: editor, - }); - this.managerMode('editor'); - } - - addPopulationSettings() { - this.patientLevelPredictionAnalysis().populationSettings.push( - new CreateStudyPopulationArgs() - ); - const index = this.patientLevelPredictionAnalysis().populationSettings().length - 1; - this.editPopulationSettings(this.patientLevelPredictionAnalysis().populationSettings()[index]); - } - - editPopulationSettings(settings) { - this.editorArray = this.populationSettings; - this.editorHeading(ko.unwrap(ko.i18n('predictions.populationSettingsTitle', 'Population Settings'))); - this.editorDescription(ko.unwrap(ko.i18n('predictions.populationSettingsDesc', 'Add or update the population settings'))); - this.editorComponentName('population-settings-editor'); - this.editorComponentParams({ - populationSettings: settings, - subscriptions: this.subscriptions, - isEditPermitted: this.isEditPermitted - }); - this.managerMode('editor'); - } - - closeEditor() { - this.editorArray.valueHasMutated(); - this.managerMode('summary'); - } - - } - - return commonUtils.build('prediction-specification-view-edit', PredictionSpecificationViewEdit, view); -}); \ No newline at end of file diff --git a/js/pages/prediction/components/prediction-specification-view-edit.less b/js/pages/prediction/components/prediction-specification-view-edit.less deleted file mode 100644 index 96d7731fc..000000000 --- a/js/pages/prediction/components/prediction-specification-view-edit.less +++ /dev/null @@ -1,6 +0,0 @@ -.settings-disabled { - pointer-events: none; - .btn { - opacity: 0.7; - } -} \ No newline at end of file diff --git a/js/pages/prediction/components/prediction-utilities.html b/js/pages/prediction/components/prediction-utilities.html deleted file mode 100644 index 4bfb9f521..000000000 --- a/js/pages/prediction/components/prediction-utilities.html +++ /dev/null @@ -1,183 +0,0 @@ -
-
- -
-
-
- Your study has invalid design that prevent you from reviewing the full specification details and downloading the study package. Please check "Messages" tab -
-
- -
-
- -
-
-
-
- - -
-
-
-
- - -
-
-
- - - -
-
- -
-
- -
-
- -
-
- -
-
-
-
-
-
- - -
-
-
- -
- -
- -
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
- -
-
- -
-
-
-
-
\ No newline at end of file diff --git a/js/pages/prediction/components/prediction-utilities.js b/js/pages/prediction/components/prediction-utilities.js deleted file mode 100644 index 8e21594b1..000000000 --- a/js/pages/prediction/components/prediction-utilities.js +++ /dev/null @@ -1,163 +0,0 @@ -define([ - 'knockout', - 'text!./prediction-utilities.html', - 'components/Component', - 'utils/CommonUtils', - 'services/file', - 'appConfig', - '../const', - 'services/Prediction', - '../PermissionService', - '../inputTypes/TargetOutcome', - '../inputTypes/ModelCovarPopTuple', - '../inputTypes/FullAnalysis', - 'utilities/import', - 'utilities/export', -], function ( - ko, - view, - Component, - commonUtils, - fileService, - config, - constants, - PredictionService, - PermissionService, - TargetOutcome, - ModelCovarPopTuple, - FullAnalysis, -) { - class PredictionUtilities extends Component { - constructor(params) { - super(params); - this.utilityPillMode = ko.observable('download'); - this.constants = constants; - this.options = constants.options; - this.loading = params.loading; - this.subscriptions = params.subscriptions; - this.selectedAnalysisId = params.analysisId; - this.patientLevelPredictionAnalysis = params.patientLevelPredictionAnalysis; - this.fullAnalysisList = params.fullAnalysisList; - this.fullSpecification = params.fullSpecification; - this.dirtyFlag = params.dirtyFlag; - this.packageName = params.packageName; - this.targetCohorts = params.targetCohorts; - this.outcomeCohorts = params.outcomeCohorts; - this.criticalCount = params.criticalCount; - this.covariateSettings = this.patientLevelPredictionAnalysis().covariateSettings; - this.modelSettings = this.patientLevelPredictionAnalysis().modelSettings; - this.populationSettings = this.patientLevelPredictionAnalysis().populationSettings; - this.loadingDownload = ko.observable(false); - this.downloadTabMode = ko.observable('full'); - this.targetOutcomePairs = ko.observableArray(); - this.modelCovarPopTuple = ko.observableArray(); - this.loadingMessage = ko.observable(); - this.isExporting = ko.observable(false); - this.exportService = PredictionService.exportPrediction; - this.importService = PredictionService.importPrediction; - this.isPermittedExport = PermissionService.isPermittedExport; - this.isPermittedImport = PermissionService.isPermittedImport; - this.afterImportSuccess = params.afterImportSuccess; - this.language = ko.i18n('datatable.language'); - - this.specificationValid = ko.pureComputed(() => this.criticalCount() <= 0); - - this.validPackageName = ko.pureComputed(() => { - return (this.packageName() && this.packageName().length > 0) - }); - - this.subscriptions.push(this.utilityPillMode.subscribe(() => { - if (this.utilityPillMode() === 'download') { - this.computeCartesian(); - } - })); - - // Fire the subscription upon load. - this.utilityPillMode.valueHasMutated(); - } - - patientLevelPredictionAnalysisJson() { - return commonUtils.syntaxHighlight(ko.toJSON(this.patientLevelPredictionAnalysis)); - } - - downloadPackage() { - this.loadingMessage("Starting download..."); - this.loading(true); - fileService.loadZip( - config.api.url + constants.apiPaths.downloadPackage(this.selectedAnalysisId(), this.packageName()), - `prediction_study_${this.selectedAnalysisId()}_export.zip` - ) - .catch((e) => console.error("error when downloading: " + e)) - .finally(() => this.loading(false)); - } - - computeCartesian() { - // Init - this.loadingDownload(true); - this.targetOutcomePairs.removeAll(); - this.modelCovarPopTuple.removeAll(); - this.fullAnalysisList.removeAll(); - - // T*O Pairs - const targetOutcomeCartesian = commonUtils.cartesian(this.targetCohorts(), this.outcomeCohorts()); - targetOutcomeCartesian.forEach(element => { - if (element.length !== 2) { - console.error("Expecting array with index 0: treatments, 1: outcomes"); - } else { - this.targetOutcomePairs().push( - new TargetOutcome({ - targetId: element[0].id, - targetName: element[0].name, - outcomeId: element[1].id, - outcomeName: element[1].name, - }) - ); - } - }); - this.targetOutcomePairs.valueHasMutated(); - - // Analysis Settings - const modelCovarPopCartesian = commonUtils.cartesian( - this.patientLevelPredictionAnalysis().modelSettings(), - this.patientLevelPredictionAnalysis().covariateSettings(), - this.patientLevelPredictionAnalysis().populationSettings(), - ); - modelCovarPopCartesian.forEach(element => { - if (element.length !== 3) { - console.error("Expecting array with index 0: model, 1: covariate settings, 2: population settings"); - } else { - this.modelCovarPopTuple().push( - new ModelCovarPopTuple({ - modelName: Object.keys(element[0])[0], - modelSettings: ko.toJSON(element[0][Object.keys(element[0])[0]]), - covariateSettings: ko.toJSON(element[1]), - popRiskWindowStart: element[2].riskWindowStart(), - popRiskWindowEnd: element[2].riskWindowEnd(), - }) - ); - } - }); - this.modelCovarPopTuple.valueHasMutated(); - - // Full Analysis - const fullAnalysisCartesian = commonUtils.cartesian( - this.targetOutcomePairs(), - this.modelCovarPopTuple(), - ); - this.fullAnalysisList.removeAll(); - fullAnalysisCartesian.forEach(element => { - if (element.length !== 2) { - console.error("Expecting array with index 0: TargetOutcome, 1: ModelCovarPopTuple"); - } else { - this.fullAnalysisList().push( - new FullAnalysis(element[0],element[1]) - ); - } - }); - this.fullAnalysisList.valueHasMutated(); - this.loadingDownload(false); - } - } - - return commonUtils.build('prediction-utilities', PredictionUtilities, view); -}); \ No newline at end of file diff --git a/js/pages/prediction/const.js b/js/pages/prediction/const.js deleted file mode 100644 index 0a4896427..000000000 --- a/js/pages/prediction/const.js +++ /dev/null @@ -1,404 +0,0 @@ -define( - (require, exports) => { - const pageTitle = 'Prediction'; - const ko = require('knockout'); - const config = require('appConfig'); - const commonUtils = require('utils/CommonUtils'); - const _ = require('lodash'); - const consts = require('const'); - - const apiPaths = { - downloadPackage: (id, name) => `prediction/${id}/download?packageName=${name}`, - downloadResults: id => `prediction/generation/${id}/result`, - }; - - const paths = { - root: '/prediction/', - analysis: id => `#/prediction/${id}`, - createAnalysis: () => '#/prediction/0', - browser: () => '#/prediction', - }; - - const conceptSetCrossReference = { - covariateSettings: { - targetName: "covariateSettings", - propertyName: { - includedCovariateConcepts: "includedCovariateConceptIds", - excludedCovariateConcepts: "excludedCovariateConceptIds", - }, - }, - }; - - const predictionGenerationStatus = consts.generationStatuses; - - const defaultNontemporalCovariates = { - "temporal": false, - "DemographicsGender": true, - "DemographicsAgeGroup": true, - "DemographicsRace": true, - "DemographicsEthnicity": true, - "DemographicsIndexMonth": true, - "ConditionGroupEraLongTerm": true, - "ConditionGroupEraShortTerm": true, - "DrugGroupEraLongTerm": true, - "DrugGroupEraShortTerm": true, - "DrugGroupEraOverlapping": true, - "ProcedureOccurrenceLongTerm": true, - "ProcedureOccurrenceShortTerm": true, - "DeviceExposureLongTerm": true, - "DeviceExposureShortTerm": true, - "MeasurementLongTerm": true, - "MeasurementShortTerm": true, - "MeasurementRangeGroupLongTerm": true, - "ObservationLongTerm": true, - "ObservationShortTerm": true, - "CharlsonIndex": true, - "Dcsi": true, - "Chads2": true, - "Chads2Vasc": true, - "includedCovariateConceptIds": [], - "includedCovariateIds": [], - "addDescendantsToInclude": false, - "excludedCovariateConceptIds": [], - "addDescendantsToExclude": false, - "shortTermStartDays": -30, - "mediumTermStartDays": -180, - "endDays": 0, - "longTermStartDays": -365 - }; - - const options = { - removeButton: ``, - targetOutcomeTableColumns: [ - { - title: ko.i18n('columns.targetId', 'Target Id'), - data: d => d.targetId, - visible: false, - }, - { - title: ko.i18n('columns.targetName', 'Target Cohort Name'), - data: d => d.targetName, - }, - { - title: ko.i18n('columns.outcomeId', 'Outcome Id'), - data: d => d.outcomeId, - visible: false, - }, - { - title: ko.i18n('columns.outcomeName', 'Outcome Cohort Name'), - data: d => d.outcomeName, - }, - ], - modelCovarPopTupleTableColumns: [ - { - title: ko.i18n('columns.modelName', 'Model Name'), - data: d => d.modelName, - }, - { - title: ko.i18n('columns.modelSettings', 'Model Settings'), - data: d => d.modelSettings, - }, - { - title: ko.i18n('columns.covariateSettings', 'Covariate Settings'), - data: d => d.covariateSettings.substring(1,30) + "...", - }, - { - title: ko.i18n('columns.riskWindowStart', 'Risk Window Start'), - data: d => d.popRiskWindowStart, - }, - { - title: ko.i18n('columns.riskWindowEnd', 'Risk Window End'), - data: d => d.popRiskWindowEnd, - }, - ], - fullAnalysisTableColumns: [ - { - title: ko.i18n('columns.targetId', 'Target Id'), - data: d => d.targetOutcome.targetId, - visible: false, - }, - { - title: ko.i18n('columns.targetName', 'Target Cohort Name'), - data: d => d.targetOutcome.targetName, - }, - { - title: ko.i18n('columns.outcomeId', 'Outcome Id'), - data: d => d.targetOutcome.outcomeId, - visible: false, - }, - { - title: ko.i18n('columns.outcomeName', 'Outcome Cohort Name'), - data: d => d.targetOutcome.outcomeName, - }, - { - title: ko.i18n('columns.modelName', 'Model Name'), - data: d => d.modelCovarPopTuple.modelName, - }, - { - title: ko.i18n('columns.modelSettings', 'Model Settings'), - data: d => d.modelCovarPopTuple.modelSettings, - }, - { - title: ko.i18n('columns.covariateSettings', 'Covariate Settings'), - data: d => d.modelCovarPopTuple.covariateSettings.substring(1,30) + "...", - }, - { - title: ko.i18n('columns.riskWindowStart', 'Risk Window Start'), - data: d => d.modelCovarPopTuple.popRiskWindowStart, - }, - { - title: ko.i18n('columns.riskWindowEnd', 'Risk Window End'), - data: d => d.modelCovarPopTuple.popRiskWindowEnd, - }, - ], - fullAnalysisTableOptions: { - ...commonUtils.getTableOptions('S'), - dom: '<<"row vertical-align"<"col-xs-6"<"dt-btn"B>l><"col-xs-6 search"f>><"row vertical-align"><"row vertical-align"<"col-xs-3"i><"col-xs-9"p>>>', - domNoButtons: '<<"row vertical-align"<"col-xs-6"l><"col-xs-6 search"f>><"row vertical-align"><"row vertical-align"<"col-xs-3"i><"col-xs-9"p>>>', - Facets: [{ - 'caption': ko.i18n('facets.caption.targetCohorts', 'Target Cohorts'), - 'binding': d => d.targetOutcome.targetName, - }, - { - 'caption': ko.i18n('facets.caption.outcomeCohorts', 'Outcome Cohorts'), - 'binding': d => d.targetOutcome.outcomeName, - }, - { - 'caption': ko.i18n('facets.caption.modelName', 'Model Name'), - 'binding': d => d.modelCovarPopTuple.modelName, - }, - { - 'caption': ko.i18n('facets.caption.riskWindow', 'Risk Window'), - 'binding': d => { - return d.modelCovarPopTuple.popRiskWindowStart + "-" + d.modelCovarPopTuple.popRiskWindowEnd; - }, - }, - ] - }, - specificationSummaryTableOptions: { - ...commonUtils.getTableOptions('S'), - dom: '<<"row vertical-align"<"col-xs-6"<"dt-btn"B>l><"col-xs-6 search"f>><"row vertical-align"><"row vertical-align"<"col-xs-3"i><"col-xs-9"p>>>', - domNoButtons: '<<"row vertical-align"<"col-xs-6"l><"col-xs-6 search"f>><"row vertical-align"><"row vertical-align"<"col-xs-3"i><"col-xs-9"p>>>', - }, - covariateSettingsTableOptions: { - ...commonUtils.getTableOptions('S'), - dom: '<<"row vertical-align"<"col-xs-6"<"dt-btn"B>l><"col-xs-6 search"f>><"row vertical-align"><"row vertical-align"<"col-xs-3"i><"col-xs-9"p>>>', - domNoButtons: '<<"row vertical-align"<"col-xs-6"l><"col-xs-6 search"f>><"row vertical-align"><"row vertical-align"<"col-xs-3"i><"col-xs-9"p>>>', - //'<<"row vertical-align"<"col-xs-6"<"dt-btn"B>l><"col-xs-6 search"f>><"row vertical-align"<"col-xs-3"i><"col-xs-9"p>><"row vertical-align"<"col-xs-3"i><"col-xs-9"p>>>'; - }, - nfoldOptions: _.range(2,16).map(v => '' + v), - dayOptions: ['0', '1', '7', '14', '21', '30', '60', '90', '120', '180', '365', '548', '730', '1095'], - sampleSizeOptions: ['1000', '5000', '10000', '50000', '100000'], - delCovariatesSmallCount: ['5', '10', '15', '20', '25', '50', '75', '100', '150', '200', '500'], - yesNoOptions: [{ - name: ko.i18n('options.yes', 'Yes'), - id: true, - }, { - name: ko.i18n('options.no', 'No'), - id: false - }], - yesNoIntOptions: [{ - name: ko.i18n('options.yes', 'Yes'), - id: "1" - }, { - name: ko.i18n('options.no', 'No'), - id: "0" - }], - testSplit: [{ - name: 'time', - desc: ko.i18n('options.time', 'Time'), - }, { - name: 'person', - desc: ko.i18n('options.person', 'Person'), - }], - trueFalseOptions: [{label: ko.i18n('options.true', 'true'), value: true}, {label: ko.i18n('options.false', 'false'), value: false}], - classWeightOptions: [{label: ko.i18n('options.none', 'None'), value: 'None'},{label: ko.i18n('options.balanced', 'Balanced'), value: 'Balanced'}], - }; - - const getCohortTableColumns = (canEdit) => [ - { - title: ko.i18n('columns.remove', 'Remove'), - render: function (s, p, d) { - return options.removeButton; - }, - orderable: false, - searchable: false, - className: 'col-remove', - visible: canEdit, - }, - { - title: ko.i18n('columns.id', 'Id'), - data: d => d.id, - visible: false, - }, - { - title: ko.i18n('columns.name', 'Name'), - data: d => d.name, - }, - ]; - - const getPopulationSettingsTableColumns = (canEdit) => [ - { - title: ko.i18n('columns.remove', 'Remove'), - render: (s, p, d) => { - return options.removeButton; - }, - orderable: false, - searchable: false, - className: 'col-remove', - visible: canEdit, - }, - { - title: ko.i18n('columns.binary', 'Binary'), - data: d => d.binary().toString(), - visible: false, - }, - { - title: ko.i18n('columns.firstExposureOnly', 'First Exposure Only'), - data: d => d.firstExposureOnly().toString(), - visible: false, - }, - { - title: ko.i18n('columns.riskWindowStart', 'Risk Window Start'), - render: (s, p, d) => { - return d.riskWindowStart().toString() + - " " + - "
" + - ko.unwrap(consts.timeAtRiskCohortDate.find(f => f.id === d.addExposureDaysToStart()).name); - }, - }, - { - title: ko.i18n('columns.riskWindowEnd', 'Risk Window End'), - render: (s, p, d) => { - return d.riskWindowEnd().toString() + - " " + - "
" + - ko.unwrap(consts.timeAtRiskCohortDate.find(f => f.id === d.addExposureDaysToEnd()).name); - }, - }, - { - title: ko.i18n('columns.washoutPeriod', 'Washout Period'), - data: d => d.washoutPeriod().toString() + 'd', - }, - { - title: ko.i18n('columns.includeAllOutcomes', 'Include All Outcomes'), - data: d => d.includeAllOutcomes().toString(), - }, - { - title: ko.i18n('columns.removeSubjectsWithPriorOutcome', 'Remove Subjects With Prior Outcome'), - data: d => d.removeSubjectsWithPriorOutcome().toString(), - }, - { - title: ko.i18n('columns.priorOutcomeLookback', 'Prior Outcome Lookback'), - data: d => d.priorOutcomeLookback().toString() + 'd', - visible: false, - }, - { - title: ko.i18n('columns.requireTimeAtRisk', 'Require Time At Risk'), - data: d => d.requireTimeAtRisk().toString(), - visible: false, - }, - { - title: ko.i18n('columns.minimumTimeAtRisk', 'Minimum Time At Risk'), - data: d => d.minTimeAtRisk().toString() + 'd', - }, - ]; - - const getModelSettingsTableColumns = (canEdit) => [ - { - title: ko.i18n('columns.remove', 'Remove'), - render: (s, p, d) => { - return options.removeButton; - }, - orderable: false, - searchable: false, - className: 'col-remove', - visible: canEdit, - }, - { - title: ko.i18n('columns.model', 'Model'), - data: d => Object.keys(d)[0], - }, - { - title: ko.i18n('columns.options', 'Options'), - data: d => { - const key = Object.keys(d)[0]; - return ko.toJSON(d[key]); - }, - }, - ]; - - const getCovariateSettingsTableColumns = (canEdit) => [ - { - title: ko.i18n('columns.remove', 'Remove'), - render: (s, p, d) => { - return options.removeButton; - }, - orderable: false, - searchable: false, - className: 'col-remove', - visible: canEdit, - }, - { - title: ko.i18n('columns.temporal', 'Temporal'), - render: (s, p, d) => { - return Object.keys(d)[0] === 'temporal' ? 'Yes': 'No' - }, - visible: false, - }, - { - title: ko.i18n('columns.options', 'Options'), - render: (s, p, d, a, b, c) => { - const keys = Object.keys(d); - const vals = Object.values(d); - var settings = []; - const defaultDisplayLength = 5; - for (let i = 0; i < keys.length; i++) { - const currentVal = ko.isObservable(vals[i]) ? vals[i]() : vals[i]; - if (currentVal === true) { - settings.push(keys[i]); - } - } - if (settings.length > 1) { - let displayVal = ""; - settings.forEach((element, index) => { - if (index < defaultDisplayLength) { - if (index < settings.length - 1) { - displayVal += (element + ", "); - } else { - displayVal += element; - } - } else if (index === defaultDisplayLength) { - displayVal = displayVal + element + "  
(+" + (settings.length - defaultDisplayLength - 1) + " more covariate settings"; - } else if (index > defaultDisplayLength) { - displayVal += ("" + element + ""); - } - }); - if (settings.length > defaultDisplayLength) { - displayVal += ")
"; - } - return displayVal; - } else if (settings.length === 1) { - return settings[0]; - } else { - return 'No covariate settings selected'; - } - } - }, - ]; - - return { - apiPaths, - pageTitle, - paths: paths, - conceptSetCrossReference, - defaultNontemporalCovariates, - options, - predictionGenerationStatus, - getCohortTableColumns, - getPopulationSettingsTableColumns, - getModelSettingsTableColumns, - getCovariateSettingsTableColumns, - }; - } -); \ No newline at end of file diff --git a/js/pages/prediction/index.js b/js/pages/prediction/index.js deleted file mode 100644 index 9068e336c..000000000 --- a/js/pages/prediction/index.js +++ /dev/null @@ -1,35 +0,0 @@ -define( - (require, exports) => { - const ko = require('knockout'); - const buildRoutes = require('./routes'); - const appState = require('atlas-state'); - const constants = require('./const'); - - const statusCss = ko.pureComputed(function () { - if (appState.predictionAnalysis.current()) { - return appState.predictionAnalysis.dirtyFlag().isDirty() ? "unsaved" : "open"; - } - return ""; - }); - - const navUrl = ko.pureComputed(function () { - let url = constants.paths.browser(); - if (appState.predictionAnalysis.current()) { - if (appState.predictionAnalysis.current().id() != null && appState.predictionAnalysis.current().id() > 0) { - url = appState.predictionAnalysis.analysisPath(appState.predictionAnalysis.current().id()); - } else { - url = constants.paths.createAnalysis(); - } - } - return url; - }); - - return { - title: ko.i18n('navigation.prediction', 'Prediction'), - buildRoutes, - navUrl: navUrl, - icon: 'heartbeat', - statusCss: statusCss, - }; - } -); \ No newline at end of file diff --git a/js/pages/prediction/inputTypes/CreateStudyPopulationArgs.js b/js/pages/prediction/inputTypes/CreateStudyPopulationArgs.js deleted file mode 100644 index c0812d1cd..000000000 --- a/js/pages/prediction/inputTypes/CreateStudyPopulationArgs.js +++ /dev/null @@ -1,28 +0,0 @@ -define([ - 'knockout', - 'services/analysis/RLangClass', - 'databindings', -], function ( - ko, - RLangClass -) { - class CreateStudyPopulationArgs extends RLangClass { - constructor(data = {}) { - super({"attr_class": "populationSettings"}); - this.binary = ko.observable(data.binary === undefined ? true : data.binary); - this.includeAllOutcomes = ko.observable(data.includeAllOutcomes === undefined ? true : data.includeAllOutcomes); - this.firstExposureOnly = ko.observable(data.firstExposureOnly === undefined ? false : data.firstExposureOnly); - this.washoutPeriod = ko.observable(data.washoutPeriod === 0 ? 0 : data.washoutPeriod || 365).extend({ numeric: 0}); - this.removeSubjectsWithPriorOutcome = ko.observable(data.removeSubjectsWithPriorOutcome === undefined ? false : data.removeSubjectsWithPriorOutcome); - this.priorOutcomeLookback = ko.observable(data.priorOutcomeLookback === 0 ? 0 : data.priorOutcomeLookback || 99999); - this.requireTimeAtRisk = ko.observable(data.requireTimeAtRisk === undefined ? true : data.requireTimeAtRisk); - this.minTimeAtRisk = ko.observable(data.minTimeAtRisk === 0 ? 0 : data.minTimeAtRisk || 364).extend({ numeric: 0}); - this.riskWindowStart = ko.observable(data.riskWindowStart === 0 ? 0 : data.riskWindowStart || 1).extend({ numeric: 0}); - this.addExposureDaysToStart = ko.observable(data.addExposureDaysToStart === undefined ? false : data.addExposureDaysToStart); - this.riskWindowEnd = ko.observable(data.riskWindowEnd === 0 ? 0 : data.riskWindowEnd || 365).extend({ numeric: 0}); - this.addExposureDaysToEnd = ko.observable(data.addExposureDaysToEnd === undefined ? false : data.addExposureDaysToEnd); - } - } - - return CreateStudyPopulationArgs; -}); \ No newline at end of file diff --git a/js/pages/prediction/inputTypes/FullAnalysis.js b/js/pages/prediction/inputTypes/FullAnalysis.js deleted file mode 100644 index 384d88424..000000000 --- a/js/pages/prediction/inputTypes/FullAnalysis.js +++ /dev/null @@ -1,23 +0,0 @@ -define([ - './TargetOutcome', - './ModelCovarPopTuple' -], function ( - TargetOutcome, - ModelCovarPopTuple -) { - class FullAnalysis { - constructor(targetOutcome, modelCovarPopTuple) { - if (typeof targetOutcome !== TargetOutcome) { - targetOutcome = new TargetOutcome(targetOutcome); - } - if (typeof modelCovarPopTuple !== ModelCovarPopTuple) { - modelCovarPopTuple = new ModelCovarPopTuple(modelCovarPopTuple); - } - - this.targetOutcome = targetOutcome || null; - this.modelCovarPopTuple = modelCovarPopTuple || null; - } - } - - return FullAnalysis; -}); \ No newline at end of file diff --git a/js/pages/prediction/inputTypes/GetDbPlpDataArgs.js b/js/pages/prediction/inputTypes/GetDbPlpDataArgs.js deleted file mode 100644 index 503c6eb71..000000000 --- a/js/pages/prediction/inputTypes/GetDbPlpDataArgs.js +++ /dev/null @@ -1,15 +0,0 @@ -define([ - 'knockout', - 'databindings', -], function ( - ko -) { - class GetDbPLPDataArgs { - constructor(data = {}) { - this.washoutPeriod = ko.observable(data.washoutPeriod === 0 ? 0 : data.washoutPeriod || 0).extend({numeric: 0}); - this.maxSampleSize = ko.observable(data.maxSampleSize || null); - } - } - - return GetDbPLPDataArgs; -}); \ No newline at end of file diff --git a/js/pages/prediction/inputTypes/ModelCovarPopTuple.js b/js/pages/prediction/inputTypes/ModelCovarPopTuple.js deleted file mode 100644 index cd61f625f..000000000 --- a/js/pages/prediction/inputTypes/ModelCovarPopTuple.js +++ /dev/null @@ -1,17 +0,0 @@ -define([ - 'knockout', -], function ( - ko -) { - class ModelCovarPopTuple { - constructor(data = {}) { - this.modelName = data.modelName || null; - this.modelSettings = data.modelSettings || null; - this.covariateSettings = data.covariateSettings ||null; - this.popRiskWindowStart = data.popRiskWindowStart || null; - this.popRiskWindowEnd = data.popRiskWindowEnd || null; - } - } - - return ModelCovarPopTuple; -}); \ No newline at end of file diff --git a/js/pages/prediction/inputTypes/ModelSettings.js b/js/pages/prediction/inputTypes/ModelSettings.js deleted file mode 100644 index 5ea174ff8..000000000 --- a/js/pages/prediction/inputTypes/ModelSettings.js +++ /dev/null @@ -1,396 +0,0 @@ -define(function (require, exports) { - var NaiveBayesSettings = require("./modelSettings/NaiveBayesSettings"); - var RandomForestSettings = require("./modelSettings/RandomForestSettings"); - var MLPSettings = require("./modelSettings/MLPSettings"); - var KNNSettings = require("./modelSettings/KNNSettings"); - var GradientBoostingMachineSettings = require("./modelSettings/GradientBoostingMachineSettings"); - var DecisionTreeSettings = require("./modelSettings/DecisionTreeSettings"); - var AdaBoostSettings = require("./modelSettings/AdaBoostSettings"); - var LassoLogisticRegressionSettings = require("./modelSettings/LassoLogisticRegressionSettings"); - var utils = require("../utils"); - var ko = require("knockout"); - - function GetSettingNameFromObject(data) { - if (data.hasOwnProperty("NaiveBayesSettings")) { - return "NaiveBayesSettings"; - } else if (data.hasOwnProperty("RandomForestSettings")) { - return "RandomForestSettings"; - } else if (data.hasOwnProperty("MLPSettings")) { - return "MLPSettings"; - } else if (data.hasOwnProperty("KNNSettings")) { - return "KNNSettings"; - } else if (data.hasOwnProperty("GradientBoostingMachineSettings")) { - return "GradientBoostingMachineSettings"; - } else if (data.hasOwnProperty("DecisionTreeSettings")) { - return "DecisionTreeSettings"; - } else if (data.hasOwnProperty("AdaBoostSettings")) { - return "AdaBoostSettings"; - } else if (data.hasOwnProperty("LassoLogisticRegressionSettings")) { - return "LassoLogisticRegressionSettings"; - } - } - - function GetSettingsFromObject(data) { - switch (this.GetSettingNameFromObject(data)) { - case "NaiveBayesSettings": - return { - NaiveBayesSettings: new exports.NaiveBayesSettings( - data.NaiveBayesSettings - ), - }; - break; - case "RandomForestSettings": - return { - RandomForestSettings: new exports.RandomForestSettings( - data.RandomForestSettings - ), - }; - break; - case "MLPSettings": - return { - MLPSettings: new exports.MLPSettings(data.MLPSettings), - }; - break; - case "KNNSettings": - return { - KNNSettings: new exports.KNNSettings(data.KNNSettings), - }; - break; - case "GradientBoostingMachineSettings": - return { - GradientBoostingMachineSettings: new exports.GradientBoostingMachineSettings( - data.GradientBoostingMachineSettings - ), - }; - break; - case "DecisionTreeSettings": - return { - DecisionTreeSettings: new exports.DecisionTreeSettings( - data.DecisionTreeSettings - ), - }; - break; - case "AdaBoostSettings": - return { - AdaBoostSettings: new exports.AdaBoostSettings(data.AdaBoostSettings), - }; - break; - case "LassoLogisticRegressionSettings": - return { - LassoLogisticRegressionSettings: new exports.LassoLogisticRegressionSettings( - data.LassoLogisticRegressionSettings - ), - }; - break; - default: - console.error("Model Settings not found!"); - break; - } - } - - function GetOptionsFromObject(data) { - const settingName = this.GetSettingNameFromObject(data); - return exports.options.find((f) => f.key === settingName); - } - - exports.NaiveBayesSettings = NaiveBayesSettings; - exports.RandomForestSettings = RandomForestSettings; - exports.MLPSettings = MLPSettings; - exports.KNNSettings = KNNSettings; - exports.GradientBoostingMachineSettings = GradientBoostingMachineSettings; - exports.DecisionTreeSettings = DecisionTreeSettings; - exports.AdaBoostSettings = AdaBoostSettings; - exports.LassoLogisticRegressionSettings = LassoLogisticRegressionSettings; - - exports.GetSettingNameFromObject = GetSettingNameFromObject; - exports.GetSettingsFromObject = GetSettingsFromObject; - exports.GetOptionsFromObject = GetOptionsFromObject; - - exports.options = [ - { - key: "LassoLogisticRegressionSettings", - name: "predictions.inputTypes.lassoLogisticRegression", - defaultName: "Lasso Logistic Regression", - editor: "lasso-logistic-regression-settings", - action: () => { - const defaultValues = utils.getDefaultModelSettingsValueList( - "LassoLogisticRegressionSettings" - ); - return { - LassoLogisticRegressionSettings: new LassoLogisticRegressionSettings( - defaultValues - ), - }; - }, - }, - { - key: "RandomForestSettings", - name: "predictions.inputTypes.randomForest", - defaultName: "Random Forest", - editor: "random-forest-settings", - action: () => { - const defaultValues = utils.getDefaultModelSettingsValueList( - "RandomForestSettings" - ); - return { - RandomForestSettings: new RandomForestSettings(defaultValues), - }; - }, - }, - { - key: "GradientBoostingMachineSettings", - name: "predictions.inputTypes.gradientBoostingMachine", - defaultName: "Gradient Boosting Machine", - editor: "gradient-boosting-machine-settings", - action: () => { - const defaultValues = utils.getDefaultModelSettingsValueList( - "GradientBoostingMachineSettings" - ); - return { - GradientBoostingMachineSettings: new GradientBoostingMachineSettings( - defaultValues - ), - }; - }, - }, - { - key: "AdaBoostSettings", - name: "predictions.inputTypes.adaBoost", - defaultName: "Ada Boost", - editor: "ada-boost-settings", - action: () => { - const defaultValues = utils.getDefaultModelSettingsValueList( - "AdaBoostSettings" - ); - return { - AdaBoostSettings: new AdaBoostSettings(defaultValues), - }; - }, - }, - { - key: "DecisionTreeSettings", - name: "predictions.inputTypes.decisionTree", - defaultName: "Decision Tree", - editor: "decision-tree-settings", - action: () => { - const defaultValues = utils.getDefaultModelSettingsValueList( - "DecisionTreeSettings" - ); - return { - DecisionTreeSettings: new DecisionTreeSettings(defaultValues), - }; - }, - }, - { - key: "NaiveBayesSettings", - name: "predictions.inputTypes.naiveBayes", - defaultName: "Naive Bayes", - editor: "naive-bayes-settings", - action: () => { - var defaultValues = utils.getDefaultModelSettingsValueList( - "NaiveBayesSettings" - ); - return { - NaiveBayesSettings: new NaiveBayesSettings(defaultValues), - }; - }, - }, - { - key: "MLPSettings", - name: "predictions.inputTypes.multilayerPerceptionModel", - defaultName: "Multilayer Perception Model", - editor: "mlp-settings", - action: () => { - const defaultValues = utils.getDefaultModelSettingsValueList( - "MLPSettings" - ); - return { - MLPSettings: new MLPSettings(defaultValues), - }; - }, - }, - { - key: "KNNSettings", - name: "predictions.inputTypes.nearestNeighbors", - defaultName: "K Nearest Neighbors", - editor: "knn-settings", - action: () => { - const defaultValues = utils.getDefaultModelSettingsValueList( - "KNNSettings" - ); - return { - KNNSettings: new KNNSettings(defaultValues), - }; - }, - }, - ]; - - exports.defaultModelSettings = [ - { - name: 'RandomForestSettings', - modelSettings: [ - { - setting: 'maxDepth', - name: ko.i18n('predictions.inputTypes.randomForestSettings.name_maxDepth', 'Max depth'), - description: ko.i18n('predictions.inputTypes.randomForestSettings.desc_maxDepth', 'Maximum number of interactions - a large value will lead to slow model training'), - defaultValue: [4, 10, 17], - }, - { - setting: 'mtries', - name: ko.i18n('predictions.inputTypes.randomForestSettings.name_mtries', 'Number of tree features'), - description: ko.i18n('predictions.inputTypes.randomForestSettings.desc_mtries', 'The number of features to include in each tree (-1 defaults to square root of total features)'), - defaultValue: [-1], - }, - { - setting: 'ntrees', - name: ko.i18n('predictions.inputTypes.randomForestSettings.name_ntrees', 'Number of tress to build'), - description: ko.i18n('predictions.inputTypes.randomForestSettings.desc_ntrees', 'The number of trees to build'), - defaultValue: [500], - }, - { - setting: 'varImp', - name: ko.i18n('predictions.inputTypes.randomForestSettings.name_varImp', 'Perform an initial variable selection'), - description: ko.i18n('predictions.inputTypes.randomForestSettings.desc_varImp', 'Perform an initial variable selection prior to fitting the model to select the useful variables'), - defaultValue: [true], - }, - ], - }, - { - name: 'NaiveBayesSettings', - modelSettings: [], - }, - { - name: 'MLPSettings', - modelSettings: [ - { - setting: 'alpha', - name: ko.i18n('predictions.inputTypes.mlpSettings.name_alpha','Alpha'), - description: ko.i18n('predictions.inputTypes.mlpSettings.desc_alpha', 'The l2 regularisation'), - defaultValue: [0.00001], - }, - { - setting: 'size', - name: ko.i18n('predictions.inputTypes.mlpSettings.name_size', 'Number of hidden nodes'), - description: ko.i18n('predictions.inputTypes.mlpSettings.desc_size', 'The number of hidden nodes'), - defaultValue: [4], - }, - ], - }, - { - name: 'KNNSettings', - id: 4, - modelSettings: [ - { - setting: 'k', - name: ko.i18n('predictions.inputTypes.knnSettings.name_k', 'Number of neighbors'), - description: ko.i18n('predictions.inputTypes.knnSettings.desc_k', 'The number of neighbors to consider'), - defaultValue: 1000, - }, - ], - }, - { - name: 'GradientBoostingMachineSettings', - modelSettings: [ - { - setting: 'learnRate', - name: ko.i18n('predictions.inputTypes.gradientBoostingMachineSettings.name_learnRate', 'Boosting learn rate'), - description: ko.i18n('predictions.inputTypes.gradientBoostingMachineSettings.desc_learnRate', 'The boosting learn rate'), - defaultValue: [0.01, 0.1], - }, - { - setting: 'maxDepth', - name: ko.i18n('predictions.inputTypes.gradientBoostingMachineSettings.name_maxDepth', 'Maximum number of interactions'), - description: ko.i18n('predictions.inputTypes.gradientBoostingMachineSettings.desc_maxDepth', 'Maximum number of interactions - a large value will lead to slow model training'), - defaultValue: [4, 6, 17], - }, - { - setting: 'minRows', - name: ko.i18n('predictions.inputTypes.gradientBoostingMachineSettings.name_minRows', 'Minimum number of rows'), - description: ko.i18n('predictions.inputTypes.gradientBoostingMachineSettings.desc_minRows', 'The minimum number of rows required at each end node of the tree'), - defaultValue: [20], - }, - { - setting: 'nthread', - name: ko.i18n('predictions.inputTypes.gradientBoostingMachineSettings.name_nthread', 'Computer threads for computation'), - description: ko.i18n('predictions.inputTypes.gradientBoostingMachineSettings.desc_nthread', 'The number of computer threads to use (how many cores do you have?)'), - defaultValue: 20, - }, - { - setting: 'ntrees', - name: ko.i18n('predictions.inputTypes.gradientBoostingMachineSettings.name_ntrees', 'Trees to build'), - description: ko.i18n('predictions.inputTypes.gradientBoostingMachineSettings.desc_ntrees', 'The number of trees to build'), - defaultValue: [10, 100], - }, - ], - }, - { - name: 'DecisionTreeSettings', - modelSettings: [ - { - setting: 'classWeight', - name: ko.i18n('predictions.inputTypes.decisionTreeSettings.name_classWeight', 'Class weight'), - description: ko.i18n('predictions.inputTypes.decisionTreeSettings.desc_classWeight', 'Class weight'), - defaultValue: ['None'], - }, - { - setting: 'maxDepth', - name: ko.i18n('predictions.inputTypes.decisionTreeSettings.name_maxDepth', 'Max depth'), - description: ko.i18n('predictions.inputTypes.decisionTreeSettings.desc_maxDepth', 'Maximum number of interactions - a large value will lead to slow model training'), - defaultValue: [10], - }, - { - setting: 'minImpurityDecrease', - name: ko.i18n('predictions.inputTypes.decisionTreeSettings.name_minImpurityDecrease', 'Minimum impurity split'), - description: ko.i18n('predictions.inputTypes.decisionTreeSettings.desc_minImpurityDecrease', 'Threshold for early stopping in tree growth. A node will split if its impurity is above the threshold, otherwise it is a leaf.'), - defaultValue: [0.0000001], - }, - { - setting: 'minSamplesLeaf', - name: ko.i18n('predictions.inputTypes.decisionTreeSettings.name_minSamplesLeaf', 'Minimum samples per leaf'), - description: ko.i18n('predictions.inputTypes.decisionTreeSettings.desc_minSamplesLeaf', 'The minimum number of samples per leaf'), - defaultValue: [10], - }, - { - setting: 'minSamplesSplit', - name: ko.i18n('predictions.inputTypes.decisionTreeSettings.name_minSamplesSplit', 'Minimum samples per split'), - description: ko.i18n('predictions.inputTypes.decisionTreeSettings.desc_minSamplesSplit', 'The minimum samples per split'), - defaultValue: [2], - }, - { - setting: 'plot', - name: ko.i18n('predictions.inputTypes.decisionTreeSettings.name_plot', 'Minimum samples per split'), - description: ko.i18n('predictions.inputTypes.decisionTreeSettings.desc_plot', 'The minimum samples per split'), - defaultValue: false, - }, - ], - }, - { - name: 'AdaBoostSettings', - modelSettings: [ - { - setting: 'learningRate', - name: ko.i18n('predictions.inputTypes.adaBoostSettings.name_learningRate', 'Learning rate'), - description: ko.i18n('predictions.inputTypes.adaBoostSettings.desc_learningRate', 'Learning rate shrinks the contribution of each classifier. There is a trade-off between learning rate and nEstimators.'), - defaultValue: [1], - }, - { - setting: 'nEstimators', - name: ko.i18n('predictions.inputTypes.adaBoostSettings.name_nEstimators', 'Maximum number of estimators'), - description: ko.i18n('predictions.inputTypes.adaBoostSettings.desc_nEstimators', 'The maximum number of estimators at which boosting is terminated'), - defaultValue: [50], - }, - ], - }, - { - name: 'LassoLogisticRegressionSettings', - modelSettings: [ - { - setting: 'variance', - name: ko.i18n('predictions.inputTypes.lassoLogisticRegressionSettings.name', 'Starting value for the automatic lambda search'), - description: ko.i18n('predictions.inputTypes.lassoLogisticRegressionSettings.desc', 'A single value used as the starting value for the automatic lambda search'), - defaultValue: 0.01, - }, - ], - }, - ]; -}); diff --git a/js/pages/prediction/inputTypes/PatientLevelPredictionAnalysis.js b/js/pages/prediction/inputTypes/PatientLevelPredictionAnalysis.js deleted file mode 100644 index 8e26a8656..000000000 --- a/js/pages/prediction/inputTypes/PatientLevelPredictionAnalysis.js +++ /dev/null @@ -1,52 +0,0 @@ -define([ - 'knockout', - '../../../components/cohortbuilder/CohortDefinition', - 'components/conceptset/InputTypes/ConceptSet', - 'services/analysis/ConceptSetCrossReference', - './PredictionCovariateSettings', - "./CreateStudyPopulationArgs", - './GetDbPlpDataArgs', - './ModelSettings', - './RunPlpArgs', -], function ( - ko, - CohortDefinition, - ConceptSet, - ConceptSetCrossReference, - CovariateSettings, - CreateStudyPopulationArgs, - GetDbPlpDataArgs, - ModelSettings, - RunPlpArgs -) { - class PatientLevelPrediction { - constructor(data = {}) { - this.id = ko.observable(data.id || null); - this.name = ko.observable(data.name || null); - this.description = ko.observable(data.description || null); - this.version = ko.observable(data.version || "v2.7.0"); - this.description = ko.observable(data.description || null); - this.packageName = ko.observable(data.packageName || null); - this.skeletonType = data.skeletonType || "PatientLevelPredictionStudy"; - this.skeletonVersion = data.skeletonVersion || "v0.0.1"; - this.createdBy = data.createdBy || null; - this.createdDate = data.createdDate || null; - this.modifiedBy = data.modifiedBy || null; - this.modifiedDate = data.modifiedDate || null; - this.cohortDefinitions = ko.observableArray(data.cohortDefinitions && data.cohortDefinitions.map(function(d) { return new CohortDefinition(d) })); - this.conceptSets = ko.observableArray(data.conceptSets && data.conceptSets.map(function(d) { return new ConceptSet(d) })); - this.conceptSetCrossReference = ko.observableArray(data.conceptSetCrossReference && data.conceptSetCrossReference.map(function(d) { return new ConceptSetCrossReference(d) })); - this.targetIds = ko.observableArray(data.targetIds && data.targetIds.map(function(d) { return d })); - this.outcomeIds = ko.observableArray(data.outcomeIds && data.outcomeIds.map(function(d) { return d })); - this.covariateSettings = ko.observableArray(data.covariateSettings && data.covariateSettings.map(function(d) { return new CovariateSettings(d) })); - this.populationSettings = ko.observableArray(data.populationSettings && data.populationSettings.map(function(d) { return new CreateStudyPopulationArgs(d)})); - this.modelSettings = ko.observableArray(data.modelSettings && data.modelSettings.map(function (d) { - return ModelSettings.GetSettingsFromObject(d) - })); - this.getPlpDataArgs = new GetDbPlpDataArgs(data.getPlpDataArgs); - this.runPlpArgs = new RunPlpArgs(data.runPlpArgs); - } - } - - return PatientLevelPrediction; -}); \ No newline at end of file diff --git a/js/pages/prediction/inputTypes/PredictionCovariateSettings.js b/js/pages/prediction/inputTypes/PredictionCovariateSettings.js deleted file mode 100644 index ac562d5e8..000000000 --- a/js/pages/prediction/inputTypes/PredictionCovariateSettings.js +++ /dev/null @@ -1,18 +0,0 @@ -define([ - 'knockout', - 'featureextraction/InputTypes/CovariateSettings', - 'services/analysis/ConceptSet', -], function ( - ko, - CovariateSettings, - ConceptSet -){ - class PredictionCovariateSettings extends CovariateSettings { - constructor(data) { - super(data); - this.includedCovariateConceptSet = ko.observable(data.includedCovariateConceptSet !== null ? new ConceptSet(data.includedCovariateConceptSet) : new ConceptSet()); - this.excludedCovariateConceptSet = ko.observable(data.excludedCovariateConceptSet !== null ? new ConceptSet(data.excludedCovariateConceptSet) : new ConceptSet()); - } - } - return PredictionCovariateSettings; -}); \ No newline at end of file diff --git a/js/pages/prediction/inputTypes/RunPlpArgs.js b/js/pages/prediction/inputTypes/RunPlpArgs.js deleted file mode 100644 index d970c5116..000000000 --- a/js/pages/prediction/inputTypes/RunPlpArgs.js +++ /dev/null @@ -1,19 +0,0 @@ -define([ - 'knockout', - 'databindings', -], function ( - ko -) { - class RunPlpArgs { - constructor(data = {}) { - this.minCovariateFraction = ko.observable(data.minCovariateFraction === 0 ? 0 : data.minCovariateFraction || 0.001).extend({numeric: 5}); - this.normalizeData = ko.observable(data.normalizeData === undefined ? true : data.normalizeData); - this.testSplit = ko.observable(data.testSplit || "person"); - this.testFraction = ko.observable(data.testFraction === 0 ? 0 : data.testFraction || 0.25).extend({numeric: 2}); - this.splitSeed = ko.observable(data.splitSeed || null).extend({numeric: 0}); - this.nfold = ko.observable(data.nfold || 3); - } - } - - return RunPlpArgs; -}); \ No newline at end of file diff --git a/js/pages/prediction/inputTypes/TargetOutcome.js b/js/pages/prediction/inputTypes/TargetOutcome.js deleted file mode 100644 index f3cb2ab0b..000000000 --- a/js/pages/prediction/inputTypes/TargetOutcome.js +++ /dev/null @@ -1,16 +0,0 @@ -define([ - 'knockout', -], function ( - ko -) { - class TargetOutcome { - constructor(data = {}) { - this.targetId = data.targetId || null; - this.targetName = data.targetName || null; - this.outcomeId = data.outcomeId ||null; - this.outcomeName = data.outcomeName || null; - } - } - - return TargetOutcome; -}); \ No newline at end of file diff --git a/js/pages/prediction/inputTypes/modelSettings/AdaBoostSettings.js b/js/pages/prediction/inputTypes/modelSettings/AdaBoostSettings.js deleted file mode 100644 index f0ec59134..000000000 --- a/js/pages/prediction/inputTypes/modelSettings/AdaBoostSettings.js +++ /dev/null @@ -1,16 +0,0 @@ -define([ - 'knockout', - 'databindings', -], function ( - ko -) { - class AdaBoostSettings { - constructor(data = {}) { - this.nEstimators = ko.observableArray((data.nEstimators && Array.isArray(data.nEstimators)) ? data.nEstimators.slice() : [50]); - this.learningRate = ko.observableArray((data.learningRate && Array.isArray(data.learningRate)) ? data.learningRate.slice() : [1]); - this.seed = ko.observable(data.seed || null); - } - } - - return AdaBoostSettings; -}); \ No newline at end of file diff --git a/js/pages/prediction/inputTypes/modelSettings/DecisionTreeSettings.js b/js/pages/prediction/inputTypes/modelSettings/DecisionTreeSettings.js deleted file mode 100644 index 57af790f0..000000000 --- a/js/pages/prediction/inputTypes/modelSettings/DecisionTreeSettings.js +++ /dev/null @@ -1,19 +0,0 @@ -define([ - 'knockout', - 'databindings', -], function ( - ko -) { - class DecisionTreeSettings { - constructor(data = {}) { - this.maxDepth = ko.observableArray((data.maxDepth && Array.isArray(data.maxDepth)) ? data.maxDepth.slice() : [10]); - this.minSamplesSplit = ko.observableArray((data.minSamplesSplit && Array.isArray(data.minSamplesSplit)) ? data.minSamplesSplit.slice() : [2]); - this.minSamplesLeaf = ko.observableArray((data.minSamplesLeaf && Array.isArray(data.minSamplesLeaf)) ? data.minSamplesLeaf.slice() : [10]); - this.minImpurityDecrease = ko.observableArray((data.minImpurityDecrease && Array.isArray(data.minImpurityDecrease)) ? data.minImpurityDecrease.slice() : [0.0000001]); - this.classWeight = ko.observableArray((data.classWeight && Array.isArray(data.classWeight)) ? data.classWeight.slice() : ["None"]); - this.plot = ko.observable(data.plot === undefined ? false : data.plot); - } - } - - return DecisionTreeSettings; -}); \ No newline at end of file diff --git a/js/pages/prediction/inputTypes/modelSettings/GradientBoostingMachineSettings.js b/js/pages/prediction/inputTypes/modelSettings/GradientBoostingMachineSettings.js deleted file mode 100644 index 1545f9910..000000000 --- a/js/pages/prediction/inputTypes/modelSettings/GradientBoostingMachineSettings.js +++ /dev/null @@ -1,19 +0,0 @@ -define([ - 'knockout', - 'databindings', -], function ( - ko -) { - class GradientBoostingMachineSettings { - constructor(data = {}) { - this.ntrees = ko.observableArray((data.ntrees && Array.isArray(data.ntrees)) ? data.ntrees.slice() : []); - this.nthread = ko.observable(data.nthread === 0 ? 0 : data.nthread || 20); - this.maxDepth = ko.observableArray((data.maxDepth && Array.isArray(data.maxDepth)) ? data.maxDepth.slice() : []); - this.minRows = ko.observableArray(data.minRows && Array.isArray(data.minRows) ? data.minRows.slice() : [20]); - this.learnRate = ko.observableArray((data.learnRate && Array.isArray(data.learnRate)) ? data.learnRate.slice() : []); - this.seed = ko.observable(data.seed || null); - } - } - - return GradientBoostingMachineSettings; -}); \ No newline at end of file diff --git a/js/pages/prediction/inputTypes/modelSettings/KNNSettings.js b/js/pages/prediction/inputTypes/modelSettings/KNNSettings.js deleted file mode 100644 index 285e2c7cc..000000000 --- a/js/pages/prediction/inputTypes/modelSettings/KNNSettings.js +++ /dev/null @@ -1,14 +0,0 @@ -define([ - 'knockout', - 'databindings', -], function ( - ko -) { - class KNNSettings { - constructor(data = {}) { - this.k = ko.observable(data.k === 0 ? 0 : data.k || 1000).extend({numeric: 0}); - } - } - - return KNNSettings; -}); \ No newline at end of file diff --git a/js/pages/prediction/inputTypes/modelSettings/LassoLogisticRegressionSettings.js b/js/pages/prediction/inputTypes/modelSettings/LassoLogisticRegressionSettings.js deleted file mode 100644 index df678bcfb..000000000 --- a/js/pages/prediction/inputTypes/modelSettings/LassoLogisticRegressionSettings.js +++ /dev/null @@ -1,15 +0,0 @@ -define([ - 'knockout', - 'databindings', -], function ( - ko -) { - class LassoLogisticRegressionSettings { - constructor(data = {}) { - this.variance = ko.observable(data.variance === 0 ? 0 : data.variance || 0.01).extend({numeric: 9}); - this.seed = ko.observable(data.seed || null); - } - } - - return LassoLogisticRegressionSettings; -}); \ No newline at end of file diff --git a/js/pages/prediction/inputTypes/modelSettings/MLPSettings.js b/js/pages/prediction/inputTypes/modelSettings/MLPSettings.js deleted file mode 100644 index 6698a7b85..000000000 --- a/js/pages/prediction/inputTypes/modelSettings/MLPSettings.js +++ /dev/null @@ -1,16 +0,0 @@ -define([ - 'knockout', - 'databindings', -], function ( - ko -) { - class MLPSettings { - constructor(data = {}) { - this.size = ko.observableArray((data.size && Array.isArray(data.size)) ? data.size.slice() : [4]); - this.alpha = ko.observableArray((data.alpha && Array.isArray(data.alpha)) ? data.alpha.slice() : [0.00001]); - this.seed = ko.observable(data.seed || null); - } - } - - return MLPSettings; -}); \ No newline at end of file diff --git a/js/pages/prediction/inputTypes/modelSettings/NaiveBayesSettings.js b/js/pages/prediction/inputTypes/modelSettings/NaiveBayesSettings.js deleted file mode 100644 index ad4f8e9da..000000000 --- a/js/pages/prediction/inputTypes/modelSettings/NaiveBayesSettings.js +++ /dev/null @@ -1,12 +0,0 @@ -define([ - 'knockout', -], function ( - ko -) { - class NaiveBayesSettings { - constructor(data = {}) { - } - } - - return NaiveBayesSettings; -}); \ No newline at end of file diff --git a/js/pages/prediction/inputTypes/modelSettings/RandomForestSettings.js b/js/pages/prediction/inputTypes/modelSettings/RandomForestSettings.js deleted file mode 100644 index 6f7c4406f..000000000 --- a/js/pages/prediction/inputTypes/modelSettings/RandomForestSettings.js +++ /dev/null @@ -1,18 +0,0 @@ -define([ - 'knockout', - 'databindings', -], function ( - ko -) { - class RandomForestSettings { - constructor(data = {}) { - this.mtries = ko.observableArray((data.mtries && Array.isArray(data.mtries)) ? data.mtries.slice() : [-1]); - this.ntrees = ko.observableArray((data.ntrees && Array.isArray(data.ntrees)) ? data.ntrees.slice() : [500]); - this.maxDepth = ko.observableArray((data.maxDepth && Array.isArray(data.maxDepth)) ? data.maxDepth.slice() : []); - this.varImp = ko.observableArray((data.varImp && Array.isArray(data.varImp)) ? data.varImp.slice() : [true]); - this.seed = ko.observable(data.seed || null); - } - } - - return RandomForestSettings; -}); \ No newline at end of file diff --git a/js/pages/prediction/prediction-browser.html b/js/pages/prediction/prediction-browser.html deleted file mode 100644 index a85cdf631..000000000 --- a/js/pages/prediction/prediction-browser.html +++ /dev/null @@ -1,22 +0,0 @@ - - -
- - - - - -
- - \ No newline at end of file diff --git a/js/pages/prediction/prediction-browser.js b/js/pages/prediction/prediction-browser.js deleted file mode 100644 index 71592dd4d..000000000 --- a/js/pages/prediction/prediction-browser.js +++ /dev/null @@ -1,116 +0,0 @@ -define([ - 'knockout', - 'text!./prediction-browser.html', - 'appConfig', - './const', - 'services/MomentAPI', - './PermissionService', - 'pages/Page', - 'utils/CommonUtils', - 'utils/DatatableUtils', - 'services/Prediction', - 'services/AuthAPI', - 'faceted-datatable', - 'components/ac-access-denied', - 'components/heading', - 'components/empty-state', - 'less!./prediction-browser.less' -], function( - ko, - view, - config, - constants, - momentApi, - PermissionService, - Page, - commonUtils, - datatableUtils, - PredictionService, - authAPI, -) { - class PredictionBrowser extends Page { - constructor(params) { - super(params); - this.reference = ko.observableArray(); - this.loading = ko.observable(false); - this.config = config; - - this.canReadPredictions = PermissionService.isPermittedList; - this.canCreatePrediction = PermissionService.isPermittedCreate; - - this.isAuthenticated = authAPI.isAuthenticated; - this.hasAccess = authAPI.isPermittedReadPlps; - this.tableOptions = commonUtils.getTableOptions('L'); - this.options = { - Facets: [ - { - 'caption': ko.i18n('facets.caption.created', 'Created'), - 'binding': (o) => datatableUtils.getFacetForDate(o.createdDate) - }, - { - 'caption': ko.i18n('facets.caption.updated', 'Updated'), - 'binding': (o) => datatableUtils.getFacetForDate(o.modifiedDate) - }, - { - 'caption': ko.i18n('facets.caption.author', 'Author'), - 'binding': datatableUtils.getFacetForCreatedBy, - }, - { - 'caption': ko.i18n('facets.caption.designs', 'Designs'), - 'binding': datatableUtils.getFacetForDesign, - }, - ] - }; - - this.columns = [ - { - title: ko.i18n('columns.id', 'Id'), - data: 'id' - }, - { - title: ko.i18n('columns.type', 'Type'), - data: d => d.type, - visible: false, - }, - { - title: ko.i18n('columns.name', 'Name'), - render: datatableUtils.getLinkFormatter(d => ({ - link: constants.paths.analysis(d.id), - label: d['name'] - })), - - }, - { - title: ko.i18n('columns.created', 'Created'), - render: datatableUtils.getDateFieldFormatter('createdDate'), - }, - { - title: ko.i18n('columns.updated', 'Updated'), - render: datatableUtils.getDateFieldFormatter('modifiedDate'), - }, - { - title: ko.i18n('columns.author', 'Author'), - render: datatableUtils.getCreatedByFormatter(), - } - ]; - } - - onPageCreated() { - if (this.canReadPredictions()) { - this.loading(true); - PredictionService.getPredictionList() - .then(({ data }) => { - datatableUtils.coalesceField(data, 'modifiedDate', 'createdDate'); - this.loading(false); - this.reference(data); - }); - } - } - - newPrediction() { - document.location = constants.paths.createAnalysis(); - } - } - - return commonUtils.build('prediction-browser', PredictionBrowser, view); -}); \ No newline at end of file diff --git a/js/pages/prediction/prediction-browser.less b/js/pages/prediction/prediction-browser.less deleted file mode 100644 index 9c97fd3c7..000000000 --- a/js/pages/prediction/prediction-browser.less +++ /dev/null @@ -1,9 +0,0 @@ -.prediction-browser { - &__new-btn { - align-self: flex-end; - } - - &__empty-state { - justify-content: center; - } - } \ No newline at end of file diff --git a/js/pages/prediction/prediction-manager.html b/js/pages/prediction/prediction-manager.html deleted file mode 100644 index bbbe2754d..000000000 --- a/js/pages/prediction/prediction-manager.html +++ /dev/null @@ -1,94 +0,0 @@ - - - - - -
- - - - -
-
- -
- - - - - - - - - - -
-
- -
- - - -
- - - - diff --git a/js/pages/prediction/prediction-manager.js b/js/pages/prediction/prediction-manager.js deleted file mode 100644 index ab23b61cf..000000000 --- a/js/pages/prediction/prediction-manager.js +++ /dev/null @@ -1,495 +0,0 @@ -define([ - 'knockout', - 'text!./prediction-manager.html', - 'pages/Page', - 'pages/Router', - 'utils/CommonUtils', - 'assets/ohdsi.util', - 'appConfig', - './const', - 'const', - 'atlas-state', - './PermissionService', - 'services/Permission', - 'components/security/access/const', - 'services/Prediction', - 'services/analysis/Cohort', - './inputTypes/PatientLevelPredictionAnalysis', - 'featureextraction/InputTypes/CovariateSettings', - 'featureextraction/InputTypes/TemporalCovariateSettings', - 'services/analysis/ConceptSet', - 'services/analysis/ConceptSetCrossReference', - 'services/AuthAPI', - 'services/Poll', - 'lodash', - 'services/FeatureExtraction', - 'featureextraction/components/covariate-settings-editor', - 'featureextraction/components/temporal-covariate-settings-editor', - 'components/entityBrowsers/cohort-definition-browser', - 'faceted-datatable', - 'components/tabs', - './components/prediction-specification-view-edit', - './components/prediction-utilities', - 'less!./prediction-manager.less', - 'components/security/access/configure-access-modal', - 'databindings', - 'components/checks/warnings', - 'components/heading', - 'components/authorship', - 'components/name-validation', -], function ( - ko, - view, - Page, - router, - commonUtils, - ohdsiUtil, - config, - constants, - globalConstants, - sharedState, - PermissionService, - GlobalPermissionService, - { entityType }, - PredictionService, - Cohort, - PatientLevelPredictionAnalysis, - CovariateSettings, - TemporalCovariateSettings, - ConceptSet, - ConceptSetCrossReference, - authAPI, - {PollService}, - lodash -) { - const NOT_FOUND = 'NOT FOUND'; - - class PatientLevelPredictionManager extends Page { - constructor(params) { - super(params); - sharedState.predictionAnalysis.analysisPath = constants.paths.analysis; - - this.selectTab = this.selectTab.bind(this); - this.selectedTabKey = ko.observable(router.routerParams().section); - - this.isAuthenticated = ko.pureComputed(() => { - return authAPI.isAuthenticated(); - }); - this.isViewPermitted = ko.pureComputed(() => { - return authAPI.isPermittedReadPlps(); - }); - - this.options = constants.options; - this.config = config; - this.enablePermissionManagement = config.enablePermissionManagement; - this.loading = ko.observable(true); - this.patientLevelPredictionAnalysis = sharedState.predictionAnalysis.current; - this.selectedAnalysisId = sharedState.predictionAnalysis.selectedId; - this.dirtyFlag = sharedState.predictionAnalysis.dirtyFlag; - this.managerMode = ko.observable('summary'); - this.tabMode = ko.observable('specification'); - this.utilityPillMode = ko.observable('download'); - this.targetCohorts = sharedState.predictionAnalysis.targetCohorts; - this.outcomeCohorts = sharedState.predictionAnalysis.outcomeCohorts; - this.fullAnalysisList = ko.observableArray(); - this.defaultTemporalCovariateSettings = null; - this.fullSpecification = ko.observable(null); - this.packageName = ko.observable().extend({alphaNumeric: null}); - this.isSaving = ko.observable(false); - this.isCopying = ko.observable(false); - this.isDeleting = ko.observable(false); - this.executionTabTitle = config.useExecutionEngine ? "Executions" : ""; - this.isProcessing = ko.computed(() => { - return this.isSaving() || this.isCopying() || this.isDeleting(); - }); - this.defaultName = ko.unwrap(globalConstants.newEntityNames.plp); - this.canEdit = ko.pureComputed(() => parseInt(this.selectedAnalysisId()) ? PermissionService.isPermittedUpdate(this.selectedAnalysisId()) : PermissionService.isPermittedCreate()); - - this.canDelete = ko.pureComputed(() => { - return PermissionService.isPermittedDelete(this.selectedAnalysisId()); - }); - - this.canCopy = ko.pureComputed(() => { - return PermissionService.isPermittedCopy(this.selectedAnalysisId()); - }); - - this.isNewEntity = this.isNewEntityResolver(); - this.predictionCaption = ko.computed(() => { - if (this.patientLevelPredictionAnalysis()) { - if (this.selectedAnalysisId() === '0') { - return ko.unwrap(ko.i18n('predictions.newItem', 'New Patient Level Prediction')); - } else { - return ko.unwrap(ko.i18nformat('predictions.itemId', 'Patient Level Prediction #<%=id%>', {id: this.selectedAnalysisId()})); - } - } - }); - - this.isNameFilled = ko.computed(() => { - return this.patientLevelPredictionAnalysis() && this.patientLevelPredictionAnalysis().name() && this.patientLevelPredictionAnalysis().name().trim(); - }); - this.isNameCharactersValid = ko.computed(() => { - return this.isNameFilled() && commonUtils.isNameCharactersValid(this.patientLevelPredictionAnalysis().name()); - }); - this.isNameLengthValid = ko.computed(() => { - return this.isNameFilled() && commonUtils.isNameLengthValid(this.patientLevelPredictionAnalysis().name()); - }); - this.isDefaultName = ko.computed(() => { - return this.isNameFilled() && this.patientLevelPredictionAnalysis().name().trim() === this.defaultName; - }); - this.isNameCorrect = ko.computed(() => { - return this.isNameFilled() && !this.isDefaultName() && this.isNameCharactersValid() && this.isNameLengthValid(); - }); - - this.canSave = ko.computed(() => { - return this.dirtyFlag().isDirty() && this.isNameCorrect() && this.canEdit(); - }); - - this.selectedSourceId = ko.observable(router.routerParams().sourceId); - - this.criticalCount = ko.observable(0); - this.isDiagnosticsRunning = ko.observable(false); - - const extraExecutionPermissions = ko.computed(() => !this.dirtyFlag().isDirty() - && config.api.isExecutionEngineAvailable() - && this.canEdit() - && this.criticalCount() <= 0); - - const generationDisableReason = ko.computed(() => { - if (this.dirtyFlag().isDirty()) return ko.unwrap(globalConstants.disabledReasons.DIRTY); - if (this.criticalCount() > 0) return ko.unwrap(globalConstants.disabledReasons.INVALID_DESIGN); - if (!config.api.isExecutionEngineAvailable()) return ko.unwrap(globalConstants.disabledReasons.ENGINE_NOT_AVAILABLE); - return ko.unwrap(globalConstants.disabledReasons.ACCESS_DENIED); - }); - this.componentParams = ko.observable({ - analysisId: this.selectedAnalysisId, - patientLevelPredictionAnalysis: sharedState.predictionAnalysis.current, - targetCohorts: sharedState.predictionAnalysis.targetCohorts, - outcomeCohorts: sharedState.predictionAnalysis.outcomeCohorts, - dirtyFlag: sharedState.predictionAnalysis.dirtyFlag, - fullAnalysisList: this.fullAnalysisList, - packageName: this.packageName, - fullSpecification: this.fullSpecification, - loading: this.loading, - subscriptions: this.subscriptions, - isEditPermitted: this.canEdit, - PermissionService, - ExecutionService: PredictionService, - extraExecutionPermissions, - tableColumns: ['Date', 'Status', 'Duration', 'Results'], - executionResultMode: globalConstants.executionResultModes.DOWNLOAD, - downloadFileName: 'prediction-analysis-results', - downloadApiPaths: constants.apiPaths, - runExecutionInParallel: true, - PollService: PollService, - selectedSourceId: this.selectedSourceId, - generationDisableReason, - resultsPathPrefix: '/prediction/', - criticalCount: this.criticalCount, - afterImportSuccess: this.afterImportSuccess.bind(this), - }); - - this.warningParams = ko.observable({ - current: sharedState.predictionAnalysis.current, - warningsTotal: ko.observable(0), - warningCount: ko.observable(0), - infoCount: ko.observable(0), - criticalCount: this.criticalCount, - changeFlag: ko.pureComputed(() => this.dirtyFlag().isChanged()), - isDiagnosticsRunning: this.isDiagnosticsRunning, - onDiagnoseCallback: this.diagnose.bind(this), - checkChangesOnly: true, - }); - - GlobalPermissionService.decorateComponent(this, { - entityTypeGetter: () => entityType.PREDICTION, - entityIdGetter: () => this.selectedAnalysisId(), - createdByUsernameGetter: () => this.patientLevelPredictionAnalysis() && lodash.get(this.patientLevelPredictionAnalysis(), 'createdBy.login') - }); - } - - onPageCreated() { - const selectedAnalysisId = parseInt(this.selectedAnalysisId()); - if (selectedAnalysisId === 0 && !this.dirtyFlag().isDirty()) { - this.newAnalysis(); - } else if (selectedAnalysisId > 0 && selectedAnalysisId !== (this.patientLevelPredictionAnalysis() && this.patientLevelPredictionAnalysis().id())) { - this.onAnalysisSelected(); - } else { - this.setAnalysisSettingsLists(); - this.loading(false); - } - } - - onRouterParamsChanged({ id, section, sourceId }) { - if (section !== undefined) { - this.selectedTabKey(section); - } - if (sourceId !== undefined) { - this.selectedSourceId(sourceId); - } - if (id !== undefined && id !== parseInt(this.selectedAnalysisId())) { - this.onPageCreated(); - } - } - - selectTab(index, { key }) { - this.selectedTabKey(key); - return commonUtils.routeTo('/prediction/' + this.componentParams().analysisId() + '/' + key); - } - - patientLevelPredictionAnalysisForWebAPI() { - let definition = ko.toJS(this.patientLevelPredictionAnalysis); - definition = ko.toJSON(definition); - return JSON.stringify(definition); - } - - close () { - if (this.dirtyFlag().isDirty() && !confirm(ko.unwrap(ko.i18n('predictions.confirmChanges', 'Patient level prediction changes are not saved. Would you like to continue?')))) { - return; - } - this.loading(true); - this.patientLevelPredictionAnalysis(null); - this.selectedAnalysisId(null); - this.targetCohorts.removeAll(); - this.outcomeCohorts.removeAll(); - this.dirtyFlag(new ohdsiUtil.dirtyFlag(this.patientLevelPredictionAnalysis())); - document.location = constants.paths.browser(); - } - - isNewEntityResolver() { - return ko.computed(() => this.patientLevelPredictionAnalysis() && this.selectedAnalysisId() === '0'); - } - - diagnose() { - if (this.patientLevelPredictionAnalysis()) { - // do not pass modifiedBy and createdBy parameters to check - const modifiedBy = this.patientLevelPredictionAnalysis().modifiedBy; - this.patientLevelPredictionAnalysis().modifiedBy = null; - const createdBy = this.patientLevelPredictionAnalysis().createdBy; - this.patientLevelPredictionAnalysis().createdBy = null; - const payload = this.prepForSave(); - this.patientLevelPredictionAnalysis().modifiedBy = modifiedBy; - this.patientLevelPredictionAnalysis().createdBy = createdBy; - return PredictionService.runDiagnostics(payload); - } - } - - async delete() { - if (!confirm(ko.unwrap(ko.i18n('predictions.confirmDelete', 'Delete patient level prediction specification? Warning: deletion can not be undone!')))) - return; - - this.isDeleting(true); - const analysis = PredictionService.deletePrediction(this.selectedAnalysisId()); - - this.loading(true); - this.patientLevelPredictionAnalysis(null); - this.selectedAnalysisId(null); - this.targetCohorts.removeAll(); - this.outcomeCohorts.removeAll(); - this.dirtyFlag(new ohdsiUtil.dirtyFlag(this.patientLevelPredictionAnalysis())); - document.location = constants.paths.browser() - } - - copy() { - this.isCopying(true); - this.loading(true); - PredictionService.copyPrediction(this.selectedAnalysisId()).then((analysis) => { - this.loadAnalysisFromServer(analysis); - this.isCopying(false); - this.loading(false); - document.location = constants.paths.analysis(this.patientLevelPredictionAnalysis().id()); - }); - } - - async save() { - this.isSaving(true); - this.loading(true); - - let predictionName = this.patientLevelPredictionAnalysis().name(); - this.patientLevelPredictionAnalysis().name(predictionName.trim()); - - // Next check to see that a prediction analysis with this name does not already exist - // in the database. Also pass the id so we can make sure that the current prediction analysis is excluded in this check. - try{ - const results = await PredictionService.exists(this.patientLevelPredictionAnalysis().name(), this.patientLevelPredictionAnalysis().id() == undefined ? 0 : this.patientLevelPredictionAnalysis().id()); - if (results > 0) { - alert(ko.unwrap(ko.i18n('predictions.confirmSave', 'A prediction analysis with this name already exists. Please choose a different name.'))); - } else { - this.fullAnalysisList.removeAll(); - const payload = this.prepForSave(); - const savedPrediction = await PredictionService.savePrediction(payload); - this.loadAnalysisFromServer(savedPrediction); - document.location = constants.paths.analysis(this.patientLevelPredictionAnalysis().id()); - } - } catch (e) { - alert(ko.unwrap(ko.i18n('predictions.confirmCatchSave', 'An error occurred while attempting to save a prediction analysis.'))); - } finally { - this.isSaving(false); - this.loading(false); - } - } - - prepForSave() { - const specification = ko.toJS(this.patientLevelPredictionAnalysis()); - - // createdBy/modifiedBy INSIDE the spec should not be objects, just a string - specification.createdBy = this.patientLevelPredictionAnalysis().createdBy ? this.patientLevelPredictionAnalysis().createdBy.login : null; - specification.modifiedBy = this.patientLevelPredictionAnalysis().modifiedBy ? this.patientLevelPredictionAnalysis().modifiedBy.login : null; - - specification.targetIds = []; - specification.outcomeIds = []; - specification.cohortDefinitions = []; - specification.conceptSets = []; - specification.conceptSetCrossReference = []; - specification.packageName = this.packageName(); - this.outcomeCohorts().forEach(o => { - specification.outcomeIds.push(o.id); - specification.cohortDefinitions.push(o); - }); - this.targetCohorts().forEach(t => { - specification.targetIds.push(t.id); - specification.cohortDefinitions.push(t); - }); - specification.covariateSettings.forEach((cs, index) => { - if (cs.includedCovariateConceptSet !== null && cs.includedCovariateConceptSet.id > 0) { - if (specification.conceptSets.filter(element => element.id === cs.includedCovariateConceptSet.id).length == 0) { - specification.conceptSets.push(cs.includedCovariateConceptSet); - } - specification.conceptSetCrossReference.push( - new ConceptSetCrossReference({ - conceptSetId: cs.includedCovariateConceptSet.id, - targetName: constants.conceptSetCrossReference.covariateSettings.targetName, - targetIndex: index, - propertyName: constants.conceptSetCrossReference.covariateSettings.propertyName.includedCovariateConcepts, - }) - ); - - } - if (cs.excludedCovariateConceptSet !== null && cs.excludedCovariateConceptSet.id > 0) { - if (specification.conceptSets.filter(element => element.id === cs.excludedCovariateConceptSet.id).length == 0) { - specification.conceptSets.push(cs.excludedCovariateConceptSet); - } - specification.conceptSetCrossReference.push( - new ConceptSetCrossReference({ - conceptSetId: cs.excludedCovariateConceptSet.id, - targetName: constants.conceptSetCrossReference.covariateSettings.targetName, - targetIndex: index, - propertyName: constants.conceptSetCrossReference.covariateSettings.propertyName.excludedCovariateConcepts, - }) - ); - } - - specification.covariateSettings[index] = ko.toJS(new CovariateSettings(cs)); - }); - - return { - id: this.patientLevelPredictionAnalysis().id(), - name: this.patientLevelPredictionAnalysis().name(), - description: this.patientLevelPredictionAnalysis().description(), - specification: ko.toJSON(specification), - }; - } - - newAnalysis() { - this.loading(true); - this.patientLevelPredictionAnalysis(new PatientLevelPredictionAnalysis({id: 0, name: this.defaultName})); - return new Promise(async (resolve, reject) => { - this.setAnalysisSettingsLists(); - this.resetDirtyFlag(); - this.loading(false); - - resolve(); - }); - } - - onAnalysisSelected() { - this.loading(true); - PredictionService.getPrediction(this.selectedAnalysisId()).then((analysis) => { - this.loadAnalysisFromServer(analysis); - this.loading(false); - }).catch(() => this.loading(false)); - } - - resetDirtyFlag() { - this.dirtyFlag(new ohdsiUtil.dirtyFlag({analysis: this.patientLevelPredictionAnalysis(), targetCohorts: this.targetCohorts, outcomeCohorts: this.outcomeCohorts})); - } - - loadAnalysisFromServer(analysis) { - var header = analysis.json; - var specification = JSON.parse(analysis.data.specification); - this.loadParsedAnalysisFromServer(header, specification); - } - - loadParsedAnalysisFromServer(header, specification) { - this.patientLevelPredictionAnalysis(new PatientLevelPredictionAnalysis({ - ...specification, - ...header, - })); - this.packageName(header.packageName); - this.setUserInterfaceDependencies(); - this.setAnalysisSettingsLists(); - this.fullSpecification(null); - this.resetDirtyFlag(); - } - - setUserInterfaceDependencies() { - this.targetCohorts.removeAll(); - this.patientLevelPredictionAnalysis().targetIds().forEach(c => { - let name = NOT_FOUND; - if (this.patientLevelPredictionAnalysis().cohortDefinitions().filter(a => a.id() === parseInt(c)).length > 0) { - name = this.patientLevelPredictionAnalysis().cohortDefinitions().filter(a => a.id() === parseInt(c))[0].name(); - this.targetCohorts.push(new Cohort({id: c, name: name})); - } - }); - - this.outcomeCohorts.removeAll(); - this.patientLevelPredictionAnalysis().outcomeIds().forEach(c => { - let name = NOT_FOUND; - if (this.patientLevelPredictionAnalysis().cohortDefinitions().filter(a => a.id() === parseInt(c)).length > 0) { - name = this.patientLevelPredictionAnalysis().cohortDefinitions().filter(a => a.id() === parseInt(c))[0].name(); - this.outcomeCohorts.push(new Cohort({id: c, name: name})); - } - }); - - const conceptSets = this.patientLevelPredictionAnalysis().conceptSets(); - const csXref =this.patientLevelPredictionAnalysis().conceptSetCrossReference(); - csXref.forEach((xref) => { - const selectedConceptSetList = conceptSets.filter((cs) => { return cs.id === xref.conceptSetId}); - if (selectedConceptSetList.length === 0) { - console.error("Concept Set: " + xref.conceptSetId + " not found in specification."); - } - const selectedConceptSet = new ConceptSet({id: selectedConceptSetList[0].id, name: selectedConceptSetList[0].name()}); - if (xref.targetName === constants.conceptSetCrossReference.covariateSettings.targetName) { - if (xref.propertyName === constants.conceptSetCrossReference.covariateSettings.propertyName.includedCovariateConcepts) { - this.patientLevelPredictionAnalysis().covariateSettings()[xref.targetIndex].includedCovariateConceptSet(selectedConceptSet); - } - if (xref.propertyName === constants.conceptSetCrossReference.covariateSettings.propertyName.excludedCovariateConcepts) { - this.patientLevelPredictionAnalysis().covariateSettings()[xref.targetIndex].excludedCovariateConceptSet(selectedConceptSet); - } - } - }); - } - - setAnalysisSettingsLists() { - this.covariateSettings = this.patientLevelPredictionAnalysis().covariateSettings; - this.modelSettings = this.patientLevelPredictionAnalysis().modelSettings; - this.populationSettings = this.patientLevelPredictionAnalysis().populationSettings; - } - - async afterImportSuccess(res) { - commonUtils.routeTo('/prediction/' + res.id); - }; - - getAuthorship() { - const createdDate = commonUtils.formatDateForAuthorship(this.patientLevelPredictionAnalysis().createdDate); - const modifiedDate = commonUtils.formatDateForAuthorship(this.patientLevelPredictionAnalysis().modifiedDate); - return { - createdBy: lodash.get(this.patientLevelPredictionAnalysis(), 'createdBy.name'), - createdDate, - modifiedBy: lodash.get(this.patientLevelPredictionAnalysis(), 'modifiedBy.name'), - modifiedDate, - } - } - } - - return commonUtils.build('prediction-manager', PatientLevelPredictionManager, view); -}); diff --git a/js/pages/prediction/prediction-manager.less b/js/pages/prediction/prediction-manager.less deleted file mode 100644 index fe7b1ef29..000000000 --- a/js/pages/prediction/prediction-manager.less +++ /dev/null @@ -1,112 +0,0 @@ -.prediction-specification-view-edit, .prediction-utilities { - .descriptionEntry { - width: 100%; - } - .panel-buffer { - margin-top: 15px; - } - .panel-buffer-left { - margin-left: 5px; - } - .panel-default, .panel-primary { - .panel-heading { - line-height: 30px; - font-size: 14px; - } - .panel-subheading { - padding-top: 2px; - padding-bottom: 2px; - font-size: 12px; - } - .panel-heading-collapsible { - cursor: pointer; - } - } - input.dateField { - width: 90px; - padding: 0px; - line-height: .9em; - } - &__filter-group-bordered { - margin-top: 5px; - padding-top: 15px; - margin-bottom: 10px; - border-top: #CCC 1px solid; - } - &__filter-view { - padding-left: 5px; - padding-right: 10px; - font-weight: 700; - font-size: 12px; - color: #959595; - text-transform: uppercase; - letter-spacing: 1px; - line-height: 25px; - vertical-align: middle; - } - &__info-message { - padding: 5px; - margin: 5px; - font-style: italic; - font-size: 12px; - } - &__subsection { - padding-top: 10px; - } - .col-remove { - width: 50px; - text-align: center; - } - - .col-copy { - width: 100px; - text-align: center; - } - /* Tooltip container */ - .tool-tip { - cursor: help; - position: relative; - display: inline-block; - border-bottom: 1px dotted #ccc; - color: #006080; - /* Tooltip text */ - .tooltiptext { - visibility: hidden; - position: absolute; - width: 400px; - background-color: #333; - color: #fff; - text-align: center; - padding: 5px; - margin: 5px; - border-radius: 6px; - z-index: 1; - opacity: 0; - transition: opacity .6s; - - top: 105%; - left: 50%; - margin-left: -200px; - .tooltipitem { - text-align: left; - display: list-item; - list-style-type: disc; - list-style-position: inside; - margin-top: 2px; - padding-bottom: 2px; - } - } - } - - /* Show the tooltip text when you mouse over the tooltip container */ - .tool-tip:hover { - .tooltiptext { - visibility: visible; - opacity: 1; - } - } - - .btn-set-default { - width: 141px; - } -} \ No newline at end of file diff --git a/js/pages/prediction/routes.js b/js/pages/prediction/routes.js deleted file mode 100644 index 496960c9e..000000000 --- a/js/pages/prediction/routes.js +++ /dev/null @@ -1,39 +0,0 @@ -define( - (require, factory) => { - const { AuthorizedRoute } = require('pages/Route'); - const atlasState = require('atlas-state'); - function routes(router) { - - const predictionViewEdit = new AuthorizedRoute((analysisId, section, sourceId) => { - require([ - './prediction-manager', - './components/editors/evaluation-settings-editor', - './components/editors/execution-settings-editor', - './components/editors/model-settings-editor', - './components/editors/population-settings-editor', - './components/editors/prediction-covariate-settings-editor', - ], function() { - atlasState.predictionAnalysis.selectedId(analysisId); - router.setCurrentView('prediction-manager', { - id: analysisId, - section: section || 'specification', - sourceId: section === 'executions' ? sourceId : null, - }); - }); - }); - - return { - '/prediction': new AuthorizedRoute(() => { - require(['./prediction-browser'], function() { - router.setCurrentView('prediction-browser'); - }) - }), - '/prediction/:analysisId:': predictionViewEdit, - '/prediction/:analysisId:/:section:': predictionViewEdit, - '/prediction/:analysisId:/:section:/:sourceId:': predictionViewEdit, - }; - } - - return routes; - } -); \ No newline at end of file diff --git a/js/pages/prediction/utils.js b/js/pages/prediction/utils.js deleted file mode 100644 index 84fba04e4..000000000 --- a/js/pages/prediction/utils.js +++ /dev/null @@ -1,48 +0,0 @@ -define( - (require, exports) => { - - const ModelSettings = require('./inputTypes/ModelSettings'); - const ko = require('knockout'); - - function getDefaultModelSettings(modelName) { - return ModelSettings.defaultModelSettings.find(item => item.name === modelName).modelSettings; - } - - function getDefaultModelSettingDescription(defaultModelSettings, settingName) { - const setting = defaultModelSettings.find(item => item.setting === settingName); - return setting.description + " (default = " + setting.defaultValue + "):"; - } - function getDefaultModelSettingDescriptionTranslate(defaultModelSettings, settingName) { - const setting = defaultModelSettings.find(item => item.setting === settingName); - return ko.unwrap(setting.description) + ko.unwrap(ko.i18nformat('predictions.default', '(default = <%=defaultValue%>):', {defaultValue: setting.defaultValue})); - } - - function getDefaultModelSettingValue(defaultModelSettings, settingName) { - return defaultModelSettings.find(item => item.setting === settingName).defaultValue; - } - - function getDefaultModelSettingName(defaultModelSettings, settingName) { - return defaultModelSettings.find(item => item.setting === settingName).name; - } - - function getDefaultModelSettingsValueList(modelName) { - const defaultModelSettings = getDefaultModelSettings(modelName); - const defaultValuesList = {}; - defaultModelSettings.forEach(element => { - const setting = element["setting"]; - defaultValuesList[setting] = element["defaultValue"]; - }); - return defaultValuesList; - } - - const utils = { - getDefaultModelSettings: getDefaultModelSettings, - getDefaultModelSettingDescription: getDefaultModelSettingDescription, - getDefaultModelSettingName: getDefaultModelSettingName, - getDefaultModelSettingValue: getDefaultModelSettingValue, - getDefaultModelSettingsValueList: getDefaultModelSettingsValueList, - getDefaultModelSettingDescriptionTranslate, - }; - - return utils; -}); \ No newline at end of file diff --git a/js/services/Estimation.js b/js/services/Estimation.js deleted file mode 100644 index af9f18cb3..000000000 --- a/js/services/Estimation.js +++ /dev/null @@ -1,116 +0,0 @@ -define(function (require, exports) { - - const config = require('appConfig'); - const authApi = require('services/AuthAPI'); - const httpService = require('services/http'); - const estimationEndpoint = "estimation/" - - function getEstimationList() { - return httpService.doGet(config.webAPIRoot + estimationEndpoint).catch(authApi.handleAccessDenied); - } - - async function saveEstimation(analysis) { - const url = config.webAPIRoot + estimationEndpoint + (analysis.id || ""); - let result; - if (analysis.id) { - result = await httpService - .doPut(url, analysis) - .catch((error) => { - console.log("Error: " + error); - authApi.handleAccessDenied(error); - }) - } else { - result = authApi.executeWithRefresh(httpService - .doPost(url, analysis) - .catch((error) => { - console.log("Error: " + error); - authApi.handleAccessDenied(error); - })) - } - return result; - } - - async function copyEstimation(id) { - return authApi.executeWithRefresh(httpService.doGet(config.webAPIRoot + estimationEndpoint + (id || "") + "/copy") - .catch((error) => { - console.log("Error: " + error); - authApi.handleAccessDenied(error); - })); - } - - function deleteEstimation(id) { - return httpService.doDelete(config.webAPIRoot + estimationEndpoint + (id || "")) - .catch((error) => { - console.log("Error: " + error); - authApi.handleAccessDenied(error); - }); - } - - async function getEstimation(id) { - return authApi.executeWithRefresh(httpService - .doGet(config.webAPIRoot + estimationEndpoint + id) - .catch((error) => { - console.log("Error: " + error); - authApi.handleAccessDenied(error); - })); - } - - function exportEstimation(id) { - return httpService - .doGet(config.webAPIRoot + estimationEndpoint + id + "/export") - .then(res => res.data); - } - - function generate(id, source) { - return httpService.doPost(config.webAPIRoot + estimationEndpoint + id + '/generation/' + source) - .then(res => res.data) - .catch(error => { - authApi.handleAccessDenied(error); - if (error.status == 400) { - alert((error && error.data && error.data.payload && error.data.payload.message) ? error.data.payload.message : 'Error occurred during analysis generion'); - } - }); - } - - function listExecutions(id) { - return httpService.doGet(config.webAPIRoot + estimationEndpoint + id + '/generation') - .then(res => res.data) - .catch(error => authApi.handleAccessDenied(error)); - } - - function importEstimation(specification) { - return authApi.executeWithRefresh(httpService - .doPost(config.webAPIRoot + estimationEndpoint + "import", specification) - .then(res => res.data)); - } - - function exists(name, id) { - return httpService - .doGet(`${config.webAPIRoot}${estimationEndpoint}${id}/exists?name=${name}`) - .then(res => res.data) - .catch(error => authApi.handleAccessDenied(error)); - } - - function runDiagnostics(design) { - return httpService - .doPost(`${config.webAPIRoot}${estimationEndpoint}check`, design) - .then(res => res.data); - } - - var api = { - getEstimationList: getEstimationList, - saveEstimation: saveEstimation, - copyEstimation: copyEstimation, - deleteEstimation: deleteEstimation, - getEstimation: getEstimation, - exportEstimation: exportEstimation, - importEstimation: importEstimation, - generate, - listExecutions, - exists, - runDiagnostics, - }; - - return api; -}); - diff --git a/js/services/JobDetailsService.js b/js/services/JobDetailsService.js index 15f265fea..c6dbddf7a 100644 --- a/js/services/JobDetailsService.js +++ b/js/services/JobDetailsService.js @@ -63,17 +63,6 @@ define(['knockout', 'appConfig', 'services/job/jobDetail', 'atlas-state', 'servi } case "cohortAnalysisJob": return 'cohortdefinition/' + n.jobParameters.cohortDefinitionIds + '/reporting?sourceKey=' + n.jobParameters.sourceKey; - case 'executionEngine': - switch (n.jobParameters.scriptType) { - case "CCA": - return 'estimation/' + n.jobParameters.cohortId; - case 'PLP': - return 'plp/' + n.jobParameters.cohortId; - } - case "generateEstimationAnalysis": - return 'estimation/cca/' + n.jobParameters.estimation_analysis_id + '/executions/' + n.jobParameters.source_id; - case "generatePredictionAnalysis": - return 'prediction/' + n.jobParameters.prediction_analysis_id + '/executions/' + n.jobParameters.source_id; case 'warmCacheByUser': return 'configure'; } diff --git a/js/services/Prediction.js b/js/services/Prediction.js deleted file mode 100644 index 348098937..000000000 --- a/js/services/Prediction.js +++ /dev/null @@ -1,111 +0,0 @@ -define(function (require, exports) { - - const config = require('appConfig'); - const authApi = require('services/AuthAPI'); - const httpService = require('services/http'); - const predictionEndpoint = "prediction/" - - function getPredictionList() { - return httpService.doGet(config.webAPIRoot + predictionEndpoint).catch(authApi.handleAccessDenied); - } - - async function savePrediction(analysis) { - const url = config.webAPIRoot + predictionEndpoint + (analysis.id || ""); - let result; - if (analysis.id) { - result = await httpService.doPut(url, analysis).catch((error) => { - console.log("Error: " + error); - authApi.handleAccessDenied(error); - }); - } else { - result = authApi.executeWithRefresh(httpService.doPost(url, analysis).catch((error) => { - console.log("Error: " + error); - authApi.handleAccessDenied(error); - })); - } - - return result; - } - - function copyPrediction(id) { - return authApi.executeWithRefresh(httpService.doGet(config.webAPIRoot + predictionEndpoint + (id || "") + "/copy") - .catch((error) => { - console.log("Error: " + error); - authApi.handleAccessDenied(error); - })); - } - - function deletePrediction(id) { - return httpService.doDelete(config.webAPIRoot + predictionEndpoint + (id || "")) - .catch((error) => { - console.log("Error: " + error); - authApi.handleAccessDenied(error); - }); - } - - function getPrediction(id) { - return authApi.executeWithRefresh(httpService.doGet(config.webAPIRoot + predictionEndpoint + id) - .catch((error) => { - console.log("Error: " + error); - authApi.handleAccessDenied(error); - })); - } - - function exportPrediction(id) { - return httpService - .doGet(config.webAPIRoot + predictionEndpoint + id + "/export") - .then(res => res.data); - } - - function generate(id, source) { - return httpService.doPost(config.webAPIRoot + predictionEndpoint + id + '/generation/' + source) - .then(res => res.data) - .catch(error => { - authApi.handleAccessDenied(error); - if (error.status == 400) { - alert((error && error.data && error.data.payload && error.data.payload.message) ? error.data.payload.message : 'Error occurred during analysis generion'); - } - }); - } - - function listExecutions(id) { - return httpService.doGet(config.webAPIRoot + predictionEndpoint + id + '/generation') - .then(res => res.data) - .catch(error => authApi.handleAccessDenied(error)); - } - - async function importPrediction(specification) { - return authApi.executeWithRefresh(httpService - .doPost(config.webAPIRoot + predictionEndpoint + "import", specification) - .then(res => res.data)); - } - - function exists(name, id) { - return httpService - .doGet(`${config.webAPIRoot}${predictionEndpoint}${id}/exists?name=${name}`) - .then(res => res.data) - .catch(error => authApi.handleAccessDenied(error)); - } - - function runDiagnostics(design) { - return httpService - .doPost(`${config.webAPIRoot}${predictionEndpoint}check`, design) - .then(res => res.data); - } - - - return { - getPredictionList: getPredictionList, - savePrediction: savePrediction, - copyPrediction: copyPrediction, - deletePrediction: deletePrediction, - getPrediction: getPrediction, - exportPrediction: exportPrediction, - importPrediction: importPrediction, - generate, - listExecutions, - exists, - runDiagnostics, - }; -}); - diff --git a/js/services/Tags.js b/js/services/Tags.js index 9928ed026..35c1c54f8 100644 --- a/js/services/Tags.js +++ b/js/services/Tags.js @@ -11,8 +11,6 @@ define(function (require) { COHORT_CHARACTERIZATION: 'cohort-characterization', PATHWAY_ANALYSIS: 'pathway-analysis', INCIDENCE_RATE: 'ir', - ESTIMATION: 'ple', - PREDICTION: 'plp', REUSABLE: 'reusable' }; From e5ac15c97a2bb8f2e22d5c532e41abe4abde41b0 Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Thu, 9 Apr 2026 17:09:58 -0400 Subject: [PATCH 07/21] Update permission checks for user management, tools, tags and source access. Re-Order role-details.js to refresh user permissions after save. --- .../security/access/configure-access-modal.js | 56 +++++++------- js/pages/configuration/configuration.html | 12 +-- js/pages/configuration/configuration.js | 73 +++---------------- .../roles/components/permissions.html | 2 +- .../roles/components/permissions.js | 2 +- .../roles/components/utilities.js | 5 +- js/pages/configuration/roles/role-details.js | 34 ++++----- js/pages/configuration/roles/role-import.html | 4 +- js/pages/configuration/roles/role-import.js | 2 +- .../configuration/roles/roleJsonParser.js | 12 +-- js/pages/configuration/roles/roles.html | 2 +- js/pages/configuration/roles/roles.js | 4 +- .../configuration/sources/source-manager.js | 6 +- .../tag-management/tag-management.js | 6 +- .../users-import/services/JobService.js | 2 +- .../services/PermissionService.js | 10 +-- .../users-import/users-import.html | 2 +- .../users-import/users-import.js | 14 ++-- js/pages/pathways/PermissionService.js | 2 +- js/pages/tools/PermissionService.js | 8 +- js/services/AuthAPI.js | 46 ++++++------ js/services/Permission.js | 2 +- js/services/SourceAPI.js | 7 +- js/services/role.js | 25 ++----- 24 files changed, 138 insertions(+), 200 deletions(-) diff --git a/js/components/security/access/configure-access-modal.js b/js/components/security/access/configure-access-modal.js index 61efbe232..b11248403 100644 --- a/js/components/security/access/configure-access-modal.js +++ b/js/components/security/access/configure-access-modal.js @@ -20,16 +20,16 @@ define([ this.isModalShown = params.isModalShown; this.isLoading = ko.observable(false); - this.writeRoleName = ko.observable(); - this.writeAccessList = ko.observable([]); + this.writeRoleName = ko.observable(); + this.writeAccessList = ko.observable([]); this.writeRoleSuggestions = ko.observable([]); this.writeRoleOptions = ko.computed(() => this.writeRoleSuggestions().map(r => r.name)); this.writeRoleSearch = ko.observable(); - this.writeRoleSearch.subscribe(str => this.loadWriteRoleSuggestions(str)); + this.writeRoleSearch.subscribe(str => this.loadWriteRoleSuggestions(str)); - this.readAccessList = ko.observable([]); - this.readRoleName = ko.observable(); - this.readRoleSuggestions = ko.observable([]); + this.readAccessList = ko.observable([]); + this.readRoleName = ko.observable(); + this.readRoleSuggestions = ko.observable([]); this.readRoleOptions = ko.computed(() => this.readRoleSuggestions().map(r => r.name)); this.readRoleSearch = ko.observable(); this.readRoleSearch.subscribe(str => this.loadReadRoleSuggestions(str)); @@ -58,7 +58,7 @@ define([ } ]; - this.writeAccessColumns = [ + this.writeAccessColumns = [ { class: this.classes('access-tbl-col-id'), title: ko.i18n('writeAccessColumns.id', 'ID'), @@ -81,13 +81,13 @@ define([ async _loadReadAccessList() { let accessList = await this.loadAccessListFn('READ'); - accessList = accessList.map(a => ({ ...a, revoke: () => this.revokeRoleAccess(a.id, 'READ') })); + accessList = accessList.map(a => ({ ...a, revoke: () => this.revokeRoleAccess(a.id, 'READ') })); this.readAccessList(accessList); } - async _loadWriteAccessList() { + async _loadWriteAccessList() { let accessList = await this.loadAccessListFn('WRITE'); - accessList = accessList.map(a => ({ ...a, revoke: () => this.revokeRoleAccess(a.id, 'WRITE') })); + accessList = accessList.map(a => ({ ...a, revoke: () => this.revokeRoleAccess(a.id, 'WRITE') })); this.writeAccessList(accessList); } @@ -96,7 +96,7 @@ define([ this.readRoleSuggestions(res); } - async loadWriteRoleSuggestions() { + async loadWriteRoleSuggestions() { const res = await this.loadRoleSuggestionsFn(this.writeRoleSearch()); this.writeRoleSuggestions(res); } @@ -104,8 +104,8 @@ define([ async loadAccessList() { this.isLoading(true); try { - await this._loadReadAccessList(); - await this._loadWriteAccessList(); + await this._loadReadAccessList(); + await this._loadWriteAccessList(); } catch (ex) { console.log(ex); } @@ -115,28 +115,28 @@ define([ async grantAccess(perm_type) { this.isLoading(true); try { - if (perm_type == 'WRITE'){ - const role = this.writeRoleSuggestions().find(r => r.name === this.writeRoleName()); - await this.grantAccessFn(role.id,'WRITE'); - await this._loadWriteAccessList(); - this.writeRoleName(''); - } else { - const role = this.readRoleSuggestions().find(r => r.name === this.readRoleName()); - await this.grantAccessFn(role.id,'READ'); - await this._loadReadAccessList(); - this.readRoleName(''); - } + if (perm_type == 'WRITE') { + const role = this.writeRoleSuggestions().find(r => r.name === this.writeRoleName()); + await this.grantAccessFn(role.id, 'WRITE'); + await this._loadWriteAccessList(); + this.writeRoleName(''); + } else { + const role = this.readRoleSuggestions().find(r => r.name === this.readRoleName()); + await this.grantAccessFn(role.id, 'READ'); + await this._loadReadAccessList(); + this.readRoleName(''); + } } catch (ex) { console.log(ex); } this.isLoading(false); } - async revokeRoleAccess(roleId, perm_type) { + async revokeRoleAccess(roleId, perm_type) { this.isLoading(true); - try { - await this.revokeAccessFn(roleId, perm_type); - await this.loadAccessList(); + try { + await this.revokeAccessFn(roleId, perm_type); + await this.loadAccessList(); } catch (ex) { console.log(ex); } diff --git a/js/pages/configuration/configuration.html b/js/pages/configuration/configuration.html index 831dcf859..e24e82152 100644 --- a/js/pages/configuration/configuration.html +++ b/js/pages/configuration/configuration.html @@ -21,7 +21,7 @@
- +
diff --git a/js/pages/configuration/sources/source-manager.js b/js/pages/configuration/sources/source-manager.js index 5c3adc693..a016bf0fe 100644 --- a/js/pages/configuration/sources/source-manager.js +++ b/js/pages/configuration/sources/source-manager.js @@ -35,7 +35,6 @@ define([ ) { - //todo yar should we translate daimons? var defaultDaimons = { CDM: { tableQualifier: '', enabled: false, priority: 0, sourceDaimonId: null }, Vocabulary: { tableQualifier: '', enabled: false, priority: 0, sourceDaimonId: null }, @@ -100,11 +99,7 @@ define([ this.appInitializationStatus = sharedState.appInitializationStatus; this.hasAccess = ko.pureComputed(() => { - return authApi.isPermittedEditConfiguration(); - }); - - this.canReadSource = ko.pureComputed(() => { - return authApi.isPermittedReadSource(this.selectedSourceId()) || !this.selectedSourceId(); + return true; }); this.isDeletePermitted = ko.pureComputed(() => { @@ -112,7 +107,7 @@ define([ }); this.canEdit = ko.pureComputed(() => { - return authApi.isPermittedEditSource(this.selectedSourceId()); + return authApi.isPermittedEditSource(this.selectedSource() && this.selectedSource().key()); }); this.isNameCorrect = ko.computed(() => { diff --git a/js/services/AuthAPI.js b/js/services/AuthAPI.js index 7551942a4..372d2bcab 100644 --- a/js/services/AuthAPI.js +++ b/js/services/AuthAPI.js @@ -329,20 +329,16 @@ define(function(require, exports) { return isPermittedUpdateConceptset(id); }; - var isPermittedEditSourcePriortiy = function() { - return isPermitted('admin:source') - }; - var isPermittedViewCdmResults = function () { return true; // TODO: Do we need general view permission + source?? }; var isPermittedViewProfiles = function (sourceKey) { - return isPermitted(`${sourceKey}:person:*:get`); + return hasSourceAccess(sourceKey); }; var isPermittedViewProfileDates = function() { - return isPermitted('*:person:*:get:dates'); + return hasSourceAccess(sourceKey); }; var isPermittedReadCohorts = function() { @@ -393,7 +389,7 @@ define(function(require, exports) { } var isPermittedEditConfiguration = function() { - return true; // everyone can view config, just need specific perms to make specific changes. + return isPermitted('admin:source'); // everyone can view config, just need specific perms to make specific changes. } var isPermittedCreateSource = function() { @@ -489,7 +485,7 @@ define(function(require, exports) { return isPermittedUpdateConceptset(conceptSetId); }; - const isPermittedRunAs = () => isPermitted('user:runas:post'); + const isPermittedRunAs = () => isPermitted('admin:run-as'); const isPermittedViewDataSourceReport = sourceKey => hasSourceAccess(sourceKey); @@ -575,7 +571,6 @@ define(function(require, exports) { isPermittedReadJobs: isPermittedReadJobs, isPermittedEditConfiguration: isPermittedEditConfiguration, - isPermittedEditSourcePriority: isPermittedEditSourcePriortiy, isPermittedReadRoles: isPermittedReadRoles, isPermittedReadRole: isPermittedReadRole, From 896ad3018cff17284ae0d4f70a572034cdbc3d34 Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Thu, 16 Apr 2026 14:24:46 -0400 Subject: [PATCH 09/21] Remove priority check logic on source delete. Implemented reusable permissions. --- .../configuration/sources/source-manager.js | 18 ---------------- js/pages/reusables/PermissionService.js | 21 ++++++++++++------- js/services/AuthAPI.js | 7 +++++++ js/services/ReusablesService.js | 12 +++-------- 4 files changed, 24 insertions(+), 34 deletions(-) diff --git a/js/pages/configuration/sources/source-manager.js b/js/pages/configuration/sources/source-manager.js index a016bf0fe..c4aad3eba 100644 --- a/js/pages/configuration/sources/source-manager.js +++ b/js/pages/configuration/sources/source-manager.js @@ -310,25 +310,7 @@ define([ this.goToConfigure(); } - hasSelectedPriotirizableDaimons() { - const otherSources = sharedState.sources().filter(s => s.sourceId !== this.selectedSource().sourceId); - const otherPriotirizableDaimons = lodash.flatten( - otherSources.map(s => s.daimons.filter(d => constants.priotirizableDaimonTypes.includes(d.daimonType) && d.sourceDaimonId)) - ); - const currenPriotirizableDaimons = this.selectedSource().daimons().filter(d => constants.priotirizableDaimonTypes.includes(d.daimonType) && d.sourceDaimonId); - const notSelectedCurrentDaimons = currenPriotirizableDaimons.filter(currentDaimon => { - // Daimon of the type with higher priority exists - return otherPriotirizableDaimons.find(otherDaimon => currentDaimon.daimonType === otherDaimon.daimonType && currentDaimon.priority < otherDaimon.priority); - }); - return notSelectedCurrentDaimons.length !== currenPriotirizableDaimons.length; - } - async delete() { - if (this.hasSelectedPriotirizableDaimons()) { - alert(ko.unwrap(ko.i18n('configuration.viewEdit.source.alerts.delete.hasSelectedPriotirizableDaimons', 'Some daimons of this source were given highest priority and are in use by application. Select new top-priority diamons to delete the source.'))); - return; - } - if (!confirm(ko.unwrap(ko.i18n('configuration.viewEdit.source.confirms.delete', 'Delete source? Warning: deletion can not be undone!')))) { return; } diff --git a/js/pages/reusables/PermissionService.js b/js/pages/reusables/PermissionService.js index b8ea7af30..a578441ae 100644 --- a/js/pages/reusables/PermissionService.js +++ b/js/pages/reusables/PermissionService.js @@ -1,31 +1,38 @@ define([ - 'services/AuthAPI', + 'services/AuthAPI', ], function ( AuthAPI, ) { function isPermittedList() { - return AuthAPI.isPermitted(`reusable:get`); + return true; } function isPermittedCreate() { - return AuthAPI.isPermitted(`reusable:post`); + return AuthAPI.isPermitted(`create:reusable`); } function isPermittedUpdate(id) { - return AuthAPI.isPermitted(`reusable:${id}:put`); + var grant = AuthAPI.getReusableGrant(id); + return grant.isOwner || + AuthAPI.isPermitted("write:reusable") || + AuthAPI.checkAccess("WRITE", grant.accessTypes); } function isPermittedLoad(id) { - return AuthAPI.isPermitted(`reusable:${id}:get`); + var grant = AuthAPI.getReusableGrant(id); + return grant.isOwner || + AuthAPI.isPermitted("read:reusable") || + AuthAPI.isPermitted("write:reusable") || + AuthAPI.checkAccess("READ", grant.accessTypes); } function isPermittedDelete(id) { - return AuthAPI.isPermitted(`reusable:${id}:delete`); + return isPermittedUpdate(id); } function isPermittedCopy(id) { - return AuthAPI.isPermitted(`reusable:${id}:post`); + return isPermittedLoad(id) && isPermittedCreate(); } return { diff --git a/js/services/AuthAPI.js b/js/services/AuthAPI.js index 372d2bcab..0623a04e8 100644 --- a/js/services/AuthAPI.js +++ b/js/services/AuthAPI.js @@ -254,6 +254,12 @@ define(function(require, exports) { return authz[pathwayId] || NONE_ENTITY_GRANT; // assign a falsy entity grant if not found } + var getReusableGrant = function(id) { + var reusaableId = +id; // force to numeric + var authz = permissions().reusableAccess; + return authz[reusaableId] || NONE_ENTITY_GRANT; // assign a falsy entity grant if not found + } + var getSourceGrant = function(id) { var sourceId = +id; // force to numeric var authz = permissions().sourceAccess; @@ -552,6 +558,7 @@ define(function(require, exports) { getFAGrant: getFAGrant, getIRGrant: getIRGrant, getPathwayGrant: getPathwayGrant, + getReusableGrant: getReusableGrant, getSourceGrant: getSourceGrant, isPermittedCreateConceptset: isPermittedCreateConceptset, diff --git a/js/services/ReusablesService.js b/js/services/ReusablesService.js index ea4277063..68674e809 100644 --- a/js/services/ReusablesService.js +++ b/js/services/ReusablesService.js @@ -36,9 +36,7 @@ define([ initialEventExpression: design.initialEventExpression, censoringEventExpression: design.censoringEventExpression, }); - let promise = httpService.doPost(servicePath, design).then(res => res.data); - promise.then(authApi.refreshToken); - return promise; + return authApi.executeWithRefresh(httpService.doPost(servicePath, design).then(res => res.data)); } function exists(name, id) { @@ -58,15 +56,11 @@ define([ } function copy(id) { - let promise = httpService.doPost(`${servicePath}/${id}`).then(res => res.data); - promise.then(authApi.refreshToken); - return promise; + return authApi.executeWithRefresh(httpService.doPost(`${servicePath}/${id}`).then(res => res.data)); } function del(id) { - return httpService - .doDelete(`${servicePath}/${id}`) - .then(res => res.data); + return authApi.executeWithRefresh(httpService.doDelete(`${servicePath}/${id}`).then(res => res.data)); } function getVersions(id) { From e86a14ab429710d45d46413bf851e62cb4a3808a Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Thu, 16 Apr 2026 20:40:03 -0400 Subject: [PATCH 10/21] Added protected tag permission checks. Fixed concept permission checks to haveSourceAccess(). --- js/pages/concept-sets/PermissionService.js | 8 +-- .../components/concept/concept-manager.js | 2 +- js/services/AuthAPI.js | 22 +++++-- js/services/Tags.js | 66 ++++++++++++++++++- 4 files changed, 87 insertions(+), 11 deletions(-) diff --git a/js/pages/concept-sets/PermissionService.js b/js/pages/concept-sets/PermissionService.js index db7cef7e9..e2acef666 100644 --- a/js/pages/concept-sets/PermissionService.js +++ b/js/pages/concept-sets/PermissionService.js @@ -8,15 +8,15 @@ define([ return class PermissionService { static isPermittedGetInfo(sourceKey, conceptId) { - return AuthAPI.isPermitted(`vocabulary:${sourceKey}:concept:${conceptId}:get`); + return AuthAPI.hasSourceAccess(sourceKey); } static isPermittedGetRC(sourceKey) { - return AuthAPI.isPermitted(`cdmresults:${sourceKey}:conceptRecordCount:post`); + return AuthAPI.hasSourceAccess(sourceKey); } static isPermittedLookupIds() { - return this.isVocabularyUrlExists && AuthAPI.isPermitted(`vocabulary:${sharedState.sourceKeyOfVocabUrl()}:lookup:identifiers:post`); + return this.isVocabularyUrlExists && AuthAPI.hasSourceAccess(sharedState.sourceKeyOfVocabUrl()); } static get isVocabularyUrlExists() { @@ -24,7 +24,7 @@ define([ } static isPermittedLookupCodes() { - return this.isVocabularyUrlExists && AuthAPI.isPermitted(`vocabulary:${sharedState.sourceKeyOfVocabUrl()}:lookup:sourcecodes:post`); + return this.isVocabularyUrlExists && AuthAPI.hasSourceAccess(sharedState.sourceKeyOfVocabUrl()); } } }); diff --git a/js/pages/concept-sets/components/concept/concept-manager.js b/js/pages/concept-sets/components/concept/concept-manager.js index c0be44453..abdbd4521 100644 --- a/js/pages/concept-sets/components/concept/concept-manager.js +++ b/js/pages/concept-sets/components/concept/concept-manager.js @@ -50,7 +50,7 @@ define([ this.isLoading = ko.observable(false); this.isAuthenticated = authApi.isAuthenticated; - this.hasInfoAccess = ko.computed(() => PermissionService.isPermittedGetInfo(sharedState.sourceKeyOfVocabUrl(), this.currentConceptId())); + this.hasInfoAccess = ko.pureComputed(() => PermissionService.isPermittedGetInfo(sharedState.sourceKeyOfVocabUrl(), this.currentConceptId())); this.tabParams = ko.observable({ currentConcept: this.currentConcept, diff --git a/js/services/AuthAPI.js b/js/services/AuthAPI.js index 0623a04e8..7d49b1b75 100644 --- a/js/services/AuthAPI.js +++ b/js/services/AuthAPI.js @@ -260,6 +260,18 @@ define(function(require, exports) { return authz[reusaableId] || NONE_ENTITY_GRANT; // assign a falsy entity grant if not found } + var getCohortGrant = function(id) { + var cohortId = +id; // force to numeric + var authz = permissions().cohortDefinitionAccess; + return authz[cohortId] || NONE_ENTITY_GRANT; // assign a falsy entity grant if not found + } + + var getConceptSetGrant = function(id) { + var csId = +id; // force to numeric + var authz = permissions().conceptSetAccess; + return authz[csId] || NONE_ENTITY_GRANT; // assign a falsy entity grant if not found + } + var getSourceGrant = function(id) { var sourceId = +id; // force to numeric var authz = permissions().sourceAccess; @@ -444,16 +456,16 @@ define(function(require, exports) { return isPermitted('admin:security'); } const isPermittedGetAllNotifications = function() { - return isPermitted('notifications:get'); + return isAuthenticated(); }; const isPermittedGetViewedNotifications = function() { - return isPermitted('notifications:viewed:get'); + return isAuthenticated(); }; const isPermittedPostViewedNotifications = function() { - return isPermitted('notifications:viewed:post'); + return isAuthenticated(); }; const isPermittedGetExecutionService = function() { - return isPermitted('executionservice:*:get'); + return true; }; const isPermittedGetSourceDaimonPriority = function() { return true; // isPermitted('source:daimon:priority:get'); //TODO: shouldn't everyone be able to lookup source daimon priority? @@ -559,6 +571,8 @@ define(function(require, exports) { getIRGrant: getIRGrant, getPathwayGrant: getPathwayGrant, getReusableGrant: getReusableGrant, + getCohortGrant: getCohortGrant, + getConceptSetGrant: getConceptSetGrant, getSourceGrant: getSourceGrant, isPermittedCreateConceptset: isPermittedCreateConceptset, diff --git a/js/services/Tags.js b/js/services/Tags.js index 35c1c54f8..7e8839ad5 100644 --- a/js/services/Tags.js +++ b/js/services/Tags.js @@ -65,11 +65,73 @@ define(function (require) { } function checkPermissionForAssignProtectedTag(assetType, assetId) { - return authService.isPermitted(`${assetType}:${assetId}:protectedtag:post`); + var grant = authService.NONE_ENTITY_GRANT; + var perm = null; + switch (assetType) { + case ASSET_TYPE.COHORT_DEFINITION: + grant = authService.getCohortGrant(assetId); + perm = 'write:cohort-definition'; + break; + case ASSET_TYPE.CONCEPT_SET: + grant = authService.getConceptSetGrant(assetId); + perm = 'write:conceptset'; + break; + case ASSET_TYPE.COHORT_CHARACTERIZATION: + grant = authService.getCCGrant(assetId); + perm = 'write:cohort-characterization'; + break; + case ASSET_TYPE.PATHWAY_ANALYSIS: + grant = authService.getPathwayGrant(assetId); + perm = 'write:pathway'; + break; + case ASSET_TYPE.INCIDENCE_RATE: + grant = authService.getIRGrant(assetId); + perm = 'write:incidence'; + break; + case ASSET_TYPE.REUSABLE: + grant = authService.getReusableGrant(assetId); + perm = 'write:reusable'; + break; + default: + return false; + } + + return (grant.isOwner || authService.isPermitted(perm) || authService.checkAccess('WRITE', grant.accessTypes)) && authService.isPermitted("admin:tags"); } function checkPermissionForUnassignProtectedTag(assetType, assetId, tagId) { - return authService.isPermitted(`${assetType}:${assetId}:protectedtag:${tagId}:delete`); + var grant = authService.NONE_ENTITY_GRANT; + var perm = null; + switch (assetType) { + case ASSET_TYPE.COHORT_DEFINITION: + grant = authService.getCohortGrant(assetId); + perm = 'write:cohort-definition'; + break; + case ASSET_TYPE.CONCEPT_SET: + grant = authService.getConceptSetGrant(assetId); + perm = 'write:conceptset'; + break; + case ASSET_TYPE.COHORT_CHARACTERIZATION: + grant = authService.getCCGrant(assetId); + perm = 'write:cohort-characterization'; + break; + case ASSET_TYPE.PATHWAY_ANALYSIS: + grant = authService.getPathwayGrant(assetId); + perm = 'write:pathway'; + break; + case ASSET_TYPE.INCIDENCE_RATE: + grant = authService.getIRGrant(assetId); + perm = 'write:incidence'; + break; + case ASSET_TYPE.REUSABLE: + grant = authService.getReusableGrant(assetId); + perm = 'write:reusable'; + break; + default: + return false; + } + + return (grant.isOwner || authService.isPermitted(perm) || authService.checkAccess('WRITE', grant.accessTypes)) && authService.isPermitted("admin:tags"); } async function getAssignmentPermissions() { From 8388ec3474cac1a4b391c3c869b702ebce7af361 Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Sun, 19 Apr 2026 23:32:25 -0400 Subject: [PATCH 11/21] Disable conceptset quickview. --- .../components/ConceptSetSelectorTemplate.html | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/js/components/cohortbuilder/components/ConceptSetSelectorTemplate.html b/js/components/cohortbuilder/components/ConceptSetSelectorTemplate.html index 74a77d520..88be28bc9 100644 --- a/js/components/cohortbuilder/components/ConceptSetSelectorTemplate.html +++ b/js/components/cohortbuilder/components/ConceptSetSelectorTemplate.html @@ -38,17 +38,6 @@ -
    - -
    -
    - -
    - -
-
\ No newline at end of file From e0299af2cb684cd233854ec0d157415fd2aeee3d Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Mon, 20 Apr 2026 11:01:50 -0400 Subject: [PATCH 12/21] Fixed logic when creating a new tag for a group directly in modal. --- js/components/tags/modal/tags-modal.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/components/tags/modal/tags-modal.js b/js/components/tags/modal/tags-modal.js index ed30c5158..b0b8c56e6 100644 --- a/js/components/tags/modal/tags-modal.js +++ b/js/components/tags/modal/tags-modal.js @@ -205,7 +205,7 @@ define([ await this.assignTagFn(tag); tag.assigned = true; this.assignedTagsList.unshift(tag); - if (tag.groups.filter(tg => tg.id === this.currentTagGroup().id).length > 0) { + if (this.currentTagGroup() && tag.groups.filter(tg => tg.id === this.currentTagGroup().id).length > 0) { this.tagsInGroupList.valueHasMutated(); } } catch (ex) { @@ -245,7 +245,7 @@ define([ const savedTag = savedTagRes.data; await this.assignTag(savedTag); this.allTagsList().unshift(savedTag); - if (this.newCustomTagGroup() === this.currentTagGroup().id) { + if (this.currentTagGroup() && this.newCustomTagGroup() === this.currentTagGroup().id) { this.tagsInGroupList().unshift(savedTag); this.sortByAssigned(this.tagsInGroupList); this.tagsInGroupList.valueHasMutated(); From a66f7a24c2f614fe260371026356383e10e2d79e Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Mon, 20 Apr 2026 22:51:31 -0400 Subject: [PATCH 13/21] Use pureComputed when doing simple calculations. --- js/components/userbar/user-bar.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/components/userbar/user-bar.js b/js/components/userbar/user-bar.js index cee16283b..46ecb7bf6 100644 --- a/js/components/userbar/user-bar.js +++ b/js/components/userbar/user-bar.js @@ -61,10 +61,10 @@ define([ componentParams: this.userJobParams, }); this.selectedTabKey(constants.jobTypes.USER_JOB.title); - this.jobNotificationsPending = ko.computed(() => this.userJobParams.jobListing().filter(j => !j.viewed()).length); + this.jobNotificationsPending = ko.pureComputed(() => this.userJobParams.jobListing().filter(j => !j.viewed()).length); } else { this.selectedTabKey(constants.jobTypes.ALL_JOB.title); - this.jobNotificationsPending = ko.computed(() => this.allJobParams.jobListing().filter(j => !j.viewed()).length); + this.jobNotificationsPending = ko.pureComputed(() => this.allJobParams.jobListing().filter(j => !j.viewed()).length); this.allJobParams.jobNameClick = this.jobNameClick.bind(this); } this.tabs.push({ @@ -73,7 +73,7 @@ define([ componentName: 'user-bar-jobs', componentParams: this.allJobParams, }); - this.jobsCount = ko.computed(() => { + this.jobsCount = ko.pureComputed(() => { if (this.selectedTabKey() === constants.jobTypes.USER_JOB.title) { return this.userJobParams.jobListing().length; } From 1c631a3217595b7f98d5b976724e56975faaa977 Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Tue, 21 Apr 2026 13:52:26 -0400 Subject: [PATCH 14/21] Add permission fetch to route change and poll interval. --- js/config/app.js | 1 + js/pages/Router.js | 3 +++ js/services/AuthAPI.js | 13 +++++++++++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/js/config/app.js b/js/config/app.js index 49ddae271..fff3239f7 100644 --- a/js/config/app.js +++ b/js/config/app.js @@ -13,6 +13,7 @@ define(function () { appConfig.enablePermissionManagement = true; // allow UI to assign read/write permissions to entities appConfig.cacheSources = false; appConfig.pollInterval = 60000; + appConfig.permissionsRefreshInterval = 60000; // poll for permission updates every 60 seconds appConfig.cohortComparisonResultsEnabled = false; appConfig.userAuthenticationEnabled = false; appConfig.enableSkipLogin = false; // automatically opens login window when user is not authenticated diff --git a/js/pages/Router.js b/js/pages/Router.js index 49d9e47b4..0deababe6 100644 --- a/js/pages/Router.js +++ b/js/pages/Router.js @@ -127,6 +127,9 @@ define( this.routerParams(routerParams); } this.currentView(view); + + // Refresh permissions when user navigates to a new route + authApi.loadUserInfo().catch(err => console.warn('Permissions refresh on navigation failed:', err)); } } return new AtlasRouter(); diff --git a/js/services/AuthAPI.js b/js/services/AuthAPI.js index 7d49b1b75..cf5ecb520 100644 --- a/js/services/AuthAPI.js +++ b/js/services/AuthAPI.js @@ -169,7 +169,7 @@ define(function(require, exports) { resetAuthParams(); break; case 403: - refreshToken(); + loadUserInfo(); break; } } @@ -535,7 +535,16 @@ define(function(require, exports) { const result = await httpPromise; await loadUserInfo(); return result; - } + }; + + // Start periodic permissions polling on module load + // Polls regardless of auth status (anonymous users have context too) + (function() { + const interval = (config && config.permissionsRefreshInterval) || 60000; // ms, default 60s + setInterval(() => { + loadUserInfo().catch(err => console.warn('Permissions refresh failed:', err)); + }, interval); + })(); var api = { AUTH_PROVIDERS: AUTH_PROVIDERS, From 32d1d2b1a0511cd738e0fb1b16ee37fc135e5c93 Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Wed, 22 Apr 2026 21:02:04 -0400 Subject: [PATCH 15/21] Remove Heracles reports from Cohort Definition. --- .../cohort-definition-manager.html | 179 ------------------ 1 file changed, 179 deletions(-) diff --git a/js/pages/cohort-definitions/cohort-definition-manager.html b/js/pages/cohort-definitions/cohort-definition-manager.html index 8764a6b87..1b6cf3fbf 100644 --- a/js/pages/cohort-definitions/cohort-definition-manager.html +++ b/js/pages/cohort-definitions/cohort-definition-manager.html @@ -80,17 +80,6 @@ data-bind="visible: !previewVersion(), css: { active: $component.tabMode() == 'samples' }, click: clickSampleTab"> - -
  • - -
  • -
  • @@ -333,174 +322,6 @@

  • -
    -
    -
    -
    - -
    -
    -
    -
    - - - - -
    -
    - -
    -
    - -
    -
    -
    -
    - -
    -
    -
    -
    - -
    -
    -
    - -
    -
    - -
    -
    -
    -
    - - -
    -
    - - -
    -
    -
    -
    - - -
    -
    - - -
    -
    -
    -
    - - -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    -
    - - -
    -
    - - -
    -
    -
    -
    - - -
    -
    - - - Github. -
    - -
    -
    -
    - - -
    -
    - - Github. -
    - -
    -
    -
    - - -
    -
    - - -
    -
    -
    -
    - - - - -
    -
    -
    - -
    -
    From 41ca87f63d0e09e514c35d64ac4d6bd6726767e4 Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Fri, 24 Apr 2026 16:25:30 -0400 Subject: [PATCH 16/21] Refactored cohort report into inclusion and demographics reports. --- .../cohort-definition-manager.js | 3 ++- .../cohort-reports/demographic-report.js | 12 ++++++------ .../feasibility-report-viewer-with-header.js | 2 +- js/services/CohortDefinition.js | 19 +++++++++++++++---- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/js/pages/cohort-definitions/cohort-definition-manager.js b/js/pages/cohort-definitions/cohort-definition-manager.js index 5af4cf57e..31fc645c8 100644 --- a/js/pages/cohort-definitions/cohort-definition-manager.js +++ b/js/pages/cohort-definitions/cohort-definition-manager.js @@ -1057,6 +1057,7 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html', if (source) { switch (source.status()) { case 'COMPLETE': + case 'ERROR': return false; break; case 'n/a': @@ -1071,7 +1072,7 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html', } isCancelDisabled(source) { - return this.isSourceStopping(source)() || (config.userAuthenticationEnabled ? this.isProcessingByAnother(source) : false); + return this.isSourceStopping(source)() || (this.isProcessingByAnother(source)); } isProcessingByAnother(source) { diff --git a/js/pages/cohort-definitions/components/reporting/cohort-reports/demographic-report.js b/js/pages/cohort-definitions/components/reporting/cohort-reports/demographic-report.js index fcf2fa579..3a48e329b 100644 --- a/js/pages/cohort-definitions/components/reporting/cohort-reports/demographic-report.js +++ b/js/pages/cohort-definitions/components/reporting/cohort-reports/demographic-report.js @@ -223,16 +223,16 @@ define([ this.loading(true); Promise.all([ - CohortDefinitionService.getReport(this.cohortId(), this.source().sourceKey, this.reportType, this.ccGenerateId()) + CohortDefinitionService.getDemographicReport(this.cohortId(), this.source().sourceKey, this.ccGenerateId()) ]).then(([ generationResults ]) => { - const count = generationResults?.demographicsStats?.length ? (generationResults.demographicsStats.reduce((prev, curr) => [...prev, ...curr.items],[]) || []).length : 0; - this.thresholdValuePct((generationResults.prevalenceThreshold || 0.01) * 100); + const count = generationResults?.length ? (generationResults.reduce((prev, curr) => [...prev, ...curr.items],[]) || []).length : 0; + this.thresholdValuePct((0.01) * 100); this.newThresholdValuePct(this.thresholdValuePct()); - this.showEmptyResults(generationResults.showEmptyResults || null); - this.resultsCountFiltered(generationResults.count || count); - this.getData(generationResults?.demographicsStats); + this.showEmptyResults(false); + this.resultsCountFiltered(count); + this.getData(generationResults); this.loading(false); }); } diff --git a/js/pages/cohort-definitions/components/reporting/cohort-reports/feasibility-report-viewer-with-header.js b/js/pages/cohort-definitions/components/reporting/cohort-reports/feasibility-report-viewer-with-header.js index 58a2f376a..7d190b207 100644 --- a/js/pages/cohort-definitions/components/reporting/cohort-reports/feasibility-report-viewer-with-header.js +++ b/js/pages/cohort-definitions/components/reporting/cohort-reports/feasibility-report-viewer-with-header.js @@ -41,7 +41,7 @@ define([ async loadReport() { this.isLoading(true); - const report = await CohortDefinitionService.getReport(this.cohortId(), this.source().sourceKey, this.reportType); + const report = await CohortDefinitionService.getInclusionReport(this.cohortId(), this.source().sourceKey); this.report(report); this.isLoading(false); } diff --git a/js/services/CohortDefinition.js b/js/services/CohortDefinition.js index 68c27f879..40f8f559d 100644 --- a/js/services/CohortDefinition.js +++ b/js/services/CohortDefinition.js @@ -122,10 +122,20 @@ define(function (require, exports) { return infoPromise; } - function getReport(cohortDefinitionId, sourceKey, modeId, ccGenerateId) { - const urlGetReportDemographic = `${config.webAPIRoot}cohortdefinition/${(cohortDefinitionId || '-1')}/report/${sourceKey}?mode=${modeId || 0}&ccGenerateId=${ccGenerateId}` + function getInclusionReport(cohortDefinitionId, sourceKey) { var reportPromise = $.ajax({ - url: modeId !== 2 ? `${config.webAPIRoot}cohortdefinition/${(cohortDefinitionId || '-1')}/report/${sourceKey}?mode=${modeId || 0}` : urlGetReportDemographic, + url: `${config.webAPIRoot}cohortdefinition/${(cohortDefinitionId || '-1')}/report/${sourceKey}/inclusion`, + error: function (error) { + console.log("Error: " + error); + authApi.handleAccessDenied(error); + } + }); + return reportPromise; + } + + function getDemographicReport(cohortDefinitionId, sourceKey, ccGenerateId) { + var reportPromise = $.ajax({ + url: `${config.webAPIRoot}cohortdefinition/${(cohortDefinitionId || '-1')}/report/${sourceKey}/demographics?ccGenerateId=${ccGenerateId}`, error: function (error) { console.log("Error: " + error); authApi.handleAccessDenied(error); @@ -199,7 +209,8 @@ define(function (require, exports) { translateSql, generate, getInfo, - getReport, + getInclusionReport, + getDemographicReport, runDiagnostics, cancelGenerate, getCohortCount, From 5eaf06392283d0e5edf08e35c6d7568a12b9867f Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Wed, 29 Apr 2026 12:35:52 -0400 Subject: [PATCH 17/21] Cleanup isAuthenticated() calls. Removed active-token-refresh to replace with idle-timeout-refresh. Refresh token on application startup (if not expired). --- js/Application.js | 21 +---- .../conceptAddBox/concept-add-box.js | 2 +- js/components/conceptset/expression.js | 2 +- .../conceptsetmodal/conceptSetSaveModal.js | 2 +- js/config/app.js | 1 + .../components/conceptsets-list.js | 2 +- js/services/AuthAPI.js | 91 ++++++++++++++++++- 7 files changed, 98 insertions(+), 23 deletions(-) diff --git a/js/Application.js b/js/Application.js index f3e376199..e6a856a5f 100644 --- a/js/Application.js +++ b/js/Application.js @@ -119,7 +119,7 @@ define( const exp = authApi.tokenExpirationDate(); const now = new Date(); - if (!exp || exp <= now) { authApi.resetAuthParams(); } + if (!exp || exp <= now) { authApi.resetAuthParams(); } else { await authApi.refreshToken(); } try{ await authApi.loadUserInfo(); @@ -132,23 +132,10 @@ define( this.attachGlobalEventListeners(); await executionService.checkExecutionEngineStatus(authApi.isAuthenticated()); - // Add user interaction listener that keeps refreshing the token as long - // as the user is active (either moving mouse, navigating with keyboard and/or typing): - var userInteractionCount = 0; - console.log("Adding user interaction listeners..."); + // Add user interaction listeners to reset idle timeout + // (throttled inside resetIdleTimeout to at most once per minute) ["mouseover", "keydown", "focusin"].forEach(eventType => { - window.addEventListener(eventType, (event) => { - userInteractionCount++; - if (userInteractionCount % 30 == 0) { - console.log(">>> Checking user token...."); - userInteractionCount = 0; - // Refresh the Atlas token if it is close to expiring: - if (authApi.isAuthenticated() && this.timeToExpire() < config.refreshTokenThreshold) { - console.log(">>> Token close to expiring. Refreshing user token...."); - authApi.refreshToken(); - } - } - }); + window.addEventListener(eventType, () => authApi.resetIdleTimeout()); }); resolve(); diff --git a/js/components/conceptAddBox/concept-add-box.js b/js/components/conceptAddBox/concept-add-box.js index 06ee5536f..7f970881e 100644 --- a/js/components/conceptAddBox/concept-add-box.js +++ b/js/components/conceptAddBox/concept-add-box.js @@ -37,7 +37,7 @@ define([ super(params); this.activeConceptSet = params.activeConceptSet || sharedState.activeConceptSet; this.canCreateConceptSet = ko.pureComputed(function () { - return ((AuthAPI.isAuthenticated() && AuthAPI.isPermittedCreateConceptset()) || !config.userAuthenticationEnabled); + return AuthAPI.isPermittedCreateConceptset(); }); this.isActive = params.isActive || ko.observable(true); this.onSubmit = params.onSubmit; diff --git a/js/components/conceptset/expression.js b/js/components/conceptset/expression.js index e61814aed..d24141723 100644 --- a/js/components/conceptset/expression.js +++ b/js/components/conceptset/expression.js @@ -41,7 +41,7 @@ define([ this.loading = params.loading; this.authApi = authApi; this.canCreateConceptSet = ko.computed( () => { - return ((this.authApi.isAuthenticated() && this.authApi.isPermittedCreateConceptset()) || !config.userAuthenticationEnabled); + return this.authApi.isPermittedCreateConceptset(); }); this.newConceptSetName = ko.observable(); this.saveConceptSetShow = ko.observable(); diff --git a/js/components/conceptsetmodal/conceptSetSaveModal.js b/js/components/conceptsetmodal/conceptSetSaveModal.js index 9a85a0715..6f8c865fe 100644 --- a/js/components/conceptsetmodal/conceptSetSaveModal.js +++ b/js/components/conceptsetmodal/conceptSetSaveModal.js @@ -38,7 +38,7 @@ define(['knockout', 'appConfig', 'services/AuthAPI', 'services/ConceptSet', 'com ); this.isNameUnique = ko.observable(false); - this.canCreate = ko.pureComputed(() => (authApi.isAuthenticated() && authApi.isPermittedCreateConceptset()) || !config.userAuthenticationEnabled); + this.canCreate = ko.pureComputed(() => authApi.isPermittedCreateConceptset()); this.canSave = ko.pureComputed(() => this.canCreate() && this.conceptSetName() && this.conceptSetName().length > 0 && this.isNameUnique()); } diff --git a/js/config/app.js b/js/config/app.js index fff3239f7..83e3381aa 100644 --- a/js/config/app.js +++ b/js/config/app.js @@ -168,6 +168,7 @@ define(function () { appConfig.enableTaggingSection = false; appConfig.refreshTokenThreshold = 1000 * 60 * 15; // refresh auth token if it will expire within 15 minutes. + appConfig.idleTimeout = 1000 * 60 * 5; // refresh auth token after 5 minutes of user inactivity return appConfig; }); diff --git a/js/pages/concept-sets/components/conceptsets-list.js b/js/pages/concept-sets/components/conceptsets-list.js index 53fb37f42..0a9afd621 100644 --- a/js/pages/concept-sets/components/conceptsets-list.js +++ b/js/pages/concept-sets/components/conceptsets-list.js @@ -33,7 +33,7 @@ define([ this.conceptSetStore = ConceptSetStore.getStore(ConceptSetStore.sourceKeys().repository); this.currentConceptSet = this.conceptSetStore.current; this.canCreateConceptSet = ko.pureComputed(function () { - return ((authApi.isAuthenticated() && authApi.isPermittedCreateConceptset()) || !config.userAuthenticationEnabled); + return authApi.isPermittedCreateConceptset(); }); this.tableOptions = commonUtils.getTableOptions('L'); } diff --git a/js/services/AuthAPI.js b/js/services/AuthAPI.js index cf5ecb520..5003fc416 100644 --- a/js/services/AuthAPI.js +++ b/js/services/AuthAPI.js @@ -159,7 +159,7 @@ define(function(require, exports) { cookie.setField("bearerToken", newValue); }); - var isAuthenticated = ko.computed(() => { + var isAuthenticated = ko.pureComputed(() => { return !!token(); }); @@ -320,6 +320,88 @@ define(function(require, exports) { return refreshTokenPromise; } + // Token refresh timer management + var tokenRefreshTimeoutId = null; + var idleTimeoutId = null; + var lastIdleReset = 0; + + /** + * Schedules a token refresh to occur at (tokenExpiration - refreshTokenThreshold). + * If already within the threshold (but not expired), refreshes immediately. + * If token is expired, does nothing (resetAuthParams handles that case). + */ + var scheduleTokenRefresh = function() { + if (tokenRefreshTimeoutId) { + clearTimeout(tokenRefreshTimeoutId); + tokenRefreshTimeoutId = null; + } + + if (!isAuthenticated()) { + return; + } + + var timeToExpire = tokenExpirationDate() - new Date(); + var delay = timeToExpire - config.refreshTokenThreshold; + + if (delay > 0) { + // Schedule refresh for when we enter the threshold window + tokenRefreshTimeoutId = setTimeout(function() { + refreshToken(); + }, delay); + console.log('Token refresh scheduled in ' + Math.round(delay / 1000 / 60) + ' minutes'); + } else if (timeToExpire > 0) { + // Within threshold but not expired - refresh immediately + console.log('Token within refresh threshold, refreshing now'); + refreshToken(); + } + // If timeToExpire <= 0, token is expired - do nothing, resetAuthParams will handle it + }; + + /** + * Resets the idle timeout timer. When the idle timeout fires, the token is refreshed. + * Throttled to only reset at most once per minute unless force=true. + * @param {boolean} force - If true, bypasses the throttle check + */ + var resetIdleTimeout = function(force) { + var now = Date.now(); + + // Throttle: only reset if more than 1 minute since last reset (unless forced) + if (!force && (now - lastIdleReset < 60000)) { + return; + } + + lastIdleReset = now; + + if (idleTimeoutId) { + clearTimeout(idleTimeoutId); + idleTimeoutId = null; + } + + if (!isAuthenticated()) { + return; + } + + idleTimeoutId = setTimeout(function() { + console.log('User idle timeout reached, refreshing token'); + refreshToken(); + }, config.idleTimeout); + }; + + /** + * Clears all refresh timers. Called when user logs out. + */ + var clearAllRefreshTimers = function() { + if (tokenRefreshTimeoutId) { + clearTimeout(tokenRefreshTimeoutId); + tokenRefreshTimeoutId = null; + } + if (idleTimeoutId) { + clearTimeout(idleTimeoutId); + idleTimeoutId = null; + } + lastIdleReset = 0; + }; + var isPermittedReadConceptset = function(conceptsetId) { var id = +conceptsetId; // force to numeric var authz = permissions().conceptSetAccess; @@ -478,7 +560,7 @@ define(function(require, exports) { const hasSourceAccess = function (sourceKey, accessType = "READ") { var sourceId = (sharedState.sources().find(s => s.sourceKey == sourceKey) || {}).sourceId; - if (!sourceId) return false; // source not found + if (!sourceId || !permissions()) return false; // source not found var authz = permissions().sourceAccess; var accessTypes = authz[sourceId] || []; // default to no access @@ -511,9 +593,13 @@ define(function(require, exports) { const setAuthParams = (jwt) => { !!jwt && token(jwt); + // Start refresh timers when token is set + scheduleTokenRefresh(); + resetIdleTimeout(true); // force=true to bypass throttle on auth }; var resetAuthParams = function () { + clearAllRefreshTimers(); token(null); subject(null); permissions(null); @@ -564,6 +650,7 @@ define(function(require, exports) { getAuthorizationHeader: getAuthorizationHeader, handleAccessDenied: handleAccessDenied, refreshToken: refreshToken, + resetIdleTimeout: resetIdleTimeout, isAuthenticated: isAuthenticated, signInOpened: signInOpened, From cd9e5f3de494252d3330269148941e714991a434 Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Thu, 30 Apr 2026 21:42:35 -0400 Subject: [PATCH 18/21] Pass correct modeId to inclusion rule report. --- .../cohort-reports/feasibility-report-viewer-with-header.js | 2 +- js/services/CohortDefinition.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/js/pages/cohort-definitions/components/reporting/cohort-reports/feasibility-report-viewer-with-header.js b/js/pages/cohort-definitions/components/reporting/cohort-reports/feasibility-report-viewer-with-header.js index 7d190b207..a3f5bdce0 100644 --- a/js/pages/cohort-definitions/components/reporting/cohort-reports/feasibility-report-viewer-with-header.js +++ b/js/pages/cohort-definitions/components/reporting/cohort-reports/feasibility-report-viewer-with-header.js @@ -41,7 +41,7 @@ define([ async loadReport() { this.isLoading(true); - const report = await CohortDefinitionService.getInclusionReport(this.cohortId(), this.source().sourceKey); + const report = await CohortDefinitionService.getInclusionReport(this.cohortId(), this.source().sourceKey, this.reportType); this.report(report); this.isLoading(false); } diff --git a/js/services/CohortDefinition.js b/js/services/CohortDefinition.js index 40f8f559d..ab3f25388 100644 --- a/js/services/CohortDefinition.js +++ b/js/services/CohortDefinition.js @@ -122,9 +122,9 @@ define(function (require, exports) { return infoPromise; } - function getInclusionReport(cohortDefinitionId, sourceKey) { + function getInclusionReport(cohortDefinitionId, sourceKey, modeId) { var reportPromise = $.ajax({ - url: `${config.webAPIRoot}cohortdefinition/${(cohortDefinitionId || '-1')}/report/${sourceKey}/inclusion`, + url: `${config.webAPIRoot}cohortdefinition/${(cohortDefinitionId || '-1')}/report/${sourceKey}/inclusion?mode=${modeId || 0}`, error: function (error) { console.log("Error: " + error); authApi.handleAccessDenied(error); From bdf572b5a5e9fe5dc8c8b3631c588e49e0ad237d Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Thu, 14 May 2026 00:52:54 -0400 Subject: [PATCH 19/21] Remove check that restricts generation to write-access to asset. Only need write access to source. --- .../characterization-exec-wrapper.js | 5 ++--- js/pages/pathways/components/tabs/pathway-exec-wrapper.js | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/js/pages/characterizations/components/characterizations/characterization-view-edit/characterization-exec-wrapper.js b/js/pages/characterizations/components/characterizations/characterization-view-edit/characterization-exec-wrapper.js index aea993f2b..f8addbd06 100644 --- a/js/pages/characterizations/components/characterizations/characterization-view-edit/characterization-exec-wrapper.js +++ b/js/pages/characterizations/components/characterizations/characterization-view-edit/characterization-exec-wrapper.js @@ -28,12 +28,11 @@ define([ this.design = params.design; this.designDirtyFlag = params.designDirtyFlag; - const extraExecutionPermissions = ko.computed(() => !this.designDirtyFlag().isDirty() + const extraExecutionPermissions = ko.pureComputed(() => !this.designDirtyFlag().isDirty() && this.design() && this.design().cohorts().length - && params.isEditPermitted() && this.criticalCount() <= 0); - const generationDisableReason = ko.computed(() => { + const generationDisableReason = ko.pureComputed(() => { if (this.designDirtyFlag().isDirty()) return ko.unwrap(consts.disabledReasons.DIRTY); if (this.criticalCount() > 0) return ko.unwrap(consts.disabledReasons.INVALID_DESIGN); if (this.design() && !this.design().cohorts().length) return ko.unwrap(consts.disabledReasons.EMPTY_COHORTS); diff --git a/js/pages/pathways/components/tabs/pathway-exec-wrapper.js b/js/pages/pathways/components/tabs/pathway-exec-wrapper.js index 74799debd..580ea5b14 100644 --- a/js/pages/pathways/components/tabs/pathway-exec-wrapper.js +++ b/js/pages/pathways/components/tabs/pathway-exec-wrapper.js @@ -27,11 +27,10 @@ define([ this.criticalCount = params.criticalCount; this.dirtyFlag = params.dirtyFlag; - const extraExecutionPermissions = ko.computed(() => !this.dirtyFlag().isDirty() - && params.isEditPermitted() + const extraExecutionPermissions = ko.pureComputed(() => !this.dirtyFlag().isDirty() && this.criticalCount() <= 0); - const generationDisableReason = ko.computed(() => { + const generationDisableReason = ko.pureComputed(() => { if (this.dirtyFlag().isDirty()) return ko.unwrap(consts.disabledReasons.DIRTY); if (this.criticalCount() > 0) return ko.unwrap(consts.disabledReasons.INVALID_DESIGN); return ko.unwrap(consts.disabledReasons.ACCESS_DENIED); From 6796495f628569b4be1d9028a1ce3c3de6d1e58c Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Thu, 14 May 2026 22:47:20 -0400 Subject: [PATCH 20/21] Use affirm logic when checking running state. --- js/pages/cohort-definitions/cohort-definition-manager.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/js/pages/cohort-definitions/cohort-definition-manager.js b/js/pages/cohort-definitions/cohort-definition-manager.js index 31fc645c8..962f0e2ed 100644 --- a/js/pages/cohort-definitions/cohort-definition-manager.js +++ b/js/pages/cohort-definitions/cohort-definition-manager.js @@ -658,9 +658,7 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html', } this.isRunning = ko.pureComputed(() => { - return this.cohortDefinitionSourceInfo().filter( (info) => { - return !(info.status() == "COMPLETE" || info.status() == "n/a"); - }).length > 0; + return this.cohortDefinitionSourceInfo().some((info) => ["PENDING", "RUNNING"].includes(info.status())); }); this.cohortDefinitionLink = ko.pureComputed(() => { From 6d94ebd9c2ec5b5ee415613a41404da430427439 Mon Sep 17 00:00:00 2001 From: Chris Knoll Date: Tue, 26 May 2026 09:40:08 -0400 Subject: [PATCH 21/21] Coerce withDemographics param in generate to boolean. --- js/services/CohortDefinition.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/services/CohortDefinition.js b/js/services/CohortDefinition.js index ab3f25388..12737c647 100644 --- a/js/services/CohortDefinition.js +++ b/js/services/CohortDefinition.js @@ -101,7 +101,7 @@ define(function (require, exports) { function generate(cohortDefinitionId, sourceKey, withDemographic) { - return httpService.doGet(`${config.webAPIRoot}cohortdefinition/${cohortDefinitionId}/generate/${sourceKey}?demographic=${withDemographic}`); } + return httpService.doGet(`${config.webAPIRoot}cohortdefinition/${cohortDefinitionId}/generate/${sourceKey}?demographic=${!!withDemographic}`); } function cancelGenerate(cohortDefinitionId, sourceKey) {