Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Cohort and analyses execution / generation listings extensions with a button to publish/download Shiny applications #2957

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
17 changes: 17 additions & 0 deletions js/components/analysisExecution/analysis-execution-list.html
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,23 @@ <h2 data-bind="css: classes('title'), text: ko.i18n('components.analysisExecutio
<span data-bind="text: ko.i18nformat('components.analysisExecution.buttons.allExecutions', 'All executions (<%=submissions%>)', {submissions: submissions().length})"></span>
</button>
</li>
<!-- ko if: $component.config.shinyEnabled -->
<div class="btn-group">
<button class="btn btn-sm btn-primary dropdown-toggle" data-toggle="dropdown"
data-bind="attr: {disabled: !$component.isResultsViewPermitted(sourceKey) || $component.runningExecutionStatuses.includes(status()) || submissions().length < 1}">
<i class="fa fa-network-wired"></i>
<span data-bind="text: 'Shiny App'"></span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right" data-bind="foreach: $component.shinyOptions">
<li>
<a data-bind="click: () => $data.action($parent)" href="#">
<div class="optionText" data-bind="text: ko.i18n($data.title, $data.defaultTitle)"></div>
</a>
</li>
</ul>
</div>
<!-- /ko -->
</ul>
</div>
<ul data-bind="css: classes('result-list')">
Expand Down
68 changes: 68 additions & 0 deletions js/components/analysisExecution/analysis-execution-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ define([
'services/Source',
'services/JobDetailsService',
'services/file',
'services/http',
'moment',
'lodash',
'const',
'components/analysisExecution/shiny-const',
'text!./analysis-execution-list.html',
'less!./analysis-execution-list.less',
'components/modal-exit-message',
Expand All @@ -23,8 +26,11 @@ define([
SourceService,
JobDetailsService,
FileService,
httpService,
moment,
lodash,
consts,
shinyConsts,
view
) {
class AnalysisExecutionList extends Component {
Expand Down Expand Up @@ -89,6 +95,7 @@ define([
this.executionResultModes = consts.executionResultModes;
this.isExecutionDesignShown = ko.observable(false);
this.executionDesign = ko.observable(null);
this.config = config;

this.sourcesColumn = [{
render: (s, p, d) => {
Expand Down Expand Up @@ -147,6 +154,67 @@ define([
);

this.isViewGenerationsPermitted && this.startPolling();
this.shinyOptions = [
{
action: this.downloadShinyApp,
title: 'components.shiny.button.menu.download',
defaultTitle: 'Download'
},
{
action: this.publishShinyApp,
title: 'components.shiny.button.menu.publish',
defaultTitle: 'Publish'
}
];
}

downloadShinyApp = (source) => {
let submission = this.findLatestSubmission(source.sourceKey);
let submissionId;
if (submission) {
submissionId = submission.id;
}

let resultsPathPrefix = this.resultsPathPrefix;
let apiPath = (resultsPathPrefix && resultsPathPrefix.includes('characterizations'))
? shinyConsts.apiPaths.downloadShinyCC(submissionId, source.sourceKey)
: shinyConsts.apiPaths.downloadShinyPW(submissionId, source.sourceKey);

FileService.loadZipNoRename(
config.api.url + apiPath
)
.catch((e) => console.error("error when downloading: " + e))
.finally(() => this.loading(false));
}

publishShinyApp = async (source) => {
this.loading = true;
let submission = this.findLatestSubmission(source.sourceKey);
let submissionId;
if (submission) {
submissionId = submission.id;
}

let resultsPathPrefix = this.resultsPathPrefix;
let apiPath = (resultsPathPrefix && resultsPathPrefix.includes('characterizations'))
? shinyConsts.apiPaths.publishShinyCC(submissionId, source.sourceKey)
: shinyConsts.apiPaths.publishShinyPW(submissionId, source.sourceKey);

let alertPrefix = (resultsPathPrefix && resultsPathPrefix.includes('characterizations'))
? "Characterization"
: "Pathway";

try {
await httpService.doGet(config.api.url + apiPath);
alert("Cohort " + alertPrefix + " report is published");
} catch (e) {
console.error('An error has occurred when publishing', e);
if (e.status === 403) {
alert('Permission denied');
} else {
alert('Unexpected error occurred when publishing');
}
}
}

startPolling() {
Expand Down
13 changes: 13 additions & 0 deletions js/components/analysisExecution/shiny-const.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
define(
(require, exports) => {
const apiPaths = {
downloadShinyCC: (id, sourceKey) => `shiny/download/cohort_characterization/${id}/${sourceKey}`,
publishShinyCC: (id, sourceKey) => `shiny/publish/cohort_characterization/${id}/${sourceKey}`,
downloadShinyPW: (id, sourceKey) => `shiny/download/cohort_pathway/${id}/${sourceKey}`,
publishShinyPW: (id, sourceKey) => `shiny/publish/cohort_pathway/${id}/${sourceKey}`,
};
return {
apiPaths
};
}
);
16 changes: 16 additions & 0 deletions js/pages/cohort-definitions/cohort-definition-manager.html
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,22 @@ <h3 data-bind="text: ko.i18n('cohortDefinitions.cohortDefinitionManager.panels.a
? ko.i18n('cohortDefinitions.cohortDefinitionManager.panels.hideReports', 'Hide Reports')
: ko.i18n('cohortDefinitions.cohortDefinitionManager.panels.viewReports', 'View Reports'))"></span>
</button>
<!-- ko if: $component.config.shinyEnabled -->
<div class="btn-group">
<button class="btn btn-sm btn-primary dropdown-toggle" data-toggle="dropdown" data-bind="attr: {disabled: $component.isSourceRunning($data) || !isValid()}">
<i class="fa fa-network-wired"></i>
<span data-bind="text: 'Shiny App'"></span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right" data-bind="foreach: $component.shinyOptions">
<li>
<a data-bind="click: () => $data.action($parent)" href="#">
<div class="optionText" data-bind="text: ko.i18n($data.title, $data.defaultTitle)"></div>
</a>
</li>
</ul>
</div>
<!-- /ko -->
</div>
</script>

Expand Down
39 changes: 39 additions & 0 deletions js/pages/cohort-definitions/cohort-definition-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html',
'services/ConceptSet',
'services/Permission',
'services/Tags',
'moment',
'components/conceptset/utils',
'utils/DatatableUtils',
'components/cohortbuilder/CohortExpression',
Expand Down Expand Up @@ -70,6 +71,7 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html',
conceptSetService,
PermissionService,
TagsService,
moment,
conceptSetUitls,
datatableUtils,
CohortExpression,
Expand Down Expand Up @@ -213,6 +215,7 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html',
this.reportCohortDefinitionId = ko.observable();
this.reportSourceKey = ko.observable();
this.reportReportName = ko.observable();
this.loading = ko.observable(false);
this.loadingReport = ko.observable(false);
this.reportTriggerRun = ko.observable(false);
this.tabMode = sharedState.CohortDefinition.mode;
Expand Down Expand Up @@ -849,6 +852,19 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html',

}

this.shinyOptions = [
{
action: this.downloadShinyApp,
title: 'components.shiny.button.menu.download',
defaultTitle: 'Download'
},
{
action: this.publishShinyApp,
title: 'components.shiny.button.menu.publish',
defaultTitle: 'Publish'
}
];

PermissionService.decorateComponent(this, {
entityTypeGetter: () => entityType.COHORT_DEFINITION,
entityIdGetter: () => this.currentCohortDefinition().id(),
Expand Down Expand Up @@ -1181,6 +1197,29 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html',
}
}

downloadShinyApp(source) {
FileService.loadZipNoRename(
config.api.url + constants.paths.downloadShiny(this.currentCohortDefinition().id(), source.sourceKey)
)
.catch((e) => console.error("error when downloading: " + e))
.finally(() => this.loading(false));
}

async publishShinyApp(source) {
this.loading = true;
try {
await httpService.doGet(config.api.url + constants.paths.publishShiny(this.currentCohortDefinition().id(), source.sourceKey));
alert("Cohort is published");
} catch (e) {
console.error('An error has occurred when publishing', e);
if (e.status === 403) {
alert('Permission denied');
} else {
alert('Unexpected error occurred when publishing');
}
}
}

onRouterParamsChanged(params) {
let { cohortDefinitionId, conceptSetId, selectedSourceId, mode = 'definition', sourceKey, sampleId, version } = params;
this.cohortDefinitionIdOnRoute(cohortDefinitionId)
Expand Down
2 changes: 2 additions & 0 deletions js/pages/cohort-definitions/const.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ define(

const paths = {
details: id => `/cohortdefinition/${id}`,
downloadShiny: (id, sourceKey) => `shiny/download/cohort/${id}/${sourceKey}`,
publishShiny: (id, sourceKey) => `shiny/publish/cohort/${id}/${sourceKey}`,
};

const getPeriodTypeFilter = (chosenPeriods) => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,22 @@ <h3 data-bind="css: classes('report-title'), text: getSourceName()"></h3>
<button class="btn btn-sm btn-primary" data-bind="attr: {'disabled': !$data.info() || !$data.info().executionInfo.isValid || !$component.hasSourceAccess($data.source.sourceKey)}, click: () => $component.selectSource($data)">
<i class="fa fa-eye"></i> <span data-bind="text: 'View Reports'"></span>
</button>
<!-- ko if: $component.config.shinyEnabled -->
<div class="btn-group">
<button class="btn btn-sm btn-primary dropdown-toggle" data-toggle="dropdown" data-bind="attr: {disabled: !$data.info() || !$data.info().executionInfo.isValid || !$component.hasSourceAccess($data.source.sourceKey) || $component.isInProgress($data)}">
<i class="fa fa-network-wired"></i>
<span data-bind="text: 'Shiny App'"></span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right" data-bind="foreach: $component.shinyOptions">
<li>
<a data-bind="click: () => $data.action($parent)" href="#">
<div class="optionText" data-bind="text: ko.i18n($data.title, $data.defaultTitle)"></div>
</a>
</li>
</ul>
</div>
<!-- /ko -->
<button data-bind="attr: {'disabled': !$data.info() || !$data.info().executionInfo.isValid || !$component.hasSourceAccess($data.source.sourceKey)}, visible: $component.isEditable()" class="btn btn-sm btn-danger removeResult">
<i class="fa fa-trash"></i>
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ define([
'knockout',
'jquery',
'text!./results.html',
'appConfig',
'services/file',
'services/http',
'moment',
'utils/AutoBind',
'services/IRAnalysis',
'pages/incidence-rates/const',
Expand All @@ -19,6 +23,10 @@ define([
ko,
$,
view,
config,
FileService,
httpService,
moment,
AutoBind,
IRAnalysisService,
constants,
Expand All @@ -27,7 +35,7 @@ define([
authApi,
Component,
commonUtils,
sharedState
sharedState,
) {

class IRAnalysisResultsViewer extends AutoBind(Component) {
Expand All @@ -49,6 +57,7 @@ define([
this.cancelExecution = params.cancelExecution;
this.stoppingSources = params.stoppingSources;
this.criticalCount = params.criticalCount;
this.config = config;

this.dirtyFlag = params.dirtyFlag;
this.analysisCohorts = params.analysisCohorts;
Expand Down Expand Up @@ -149,6 +158,42 @@ define([
className: 'generation-buttons-column',
render: () => `<span data-bind="template: { name: 'generation-buttons', data: $data }"></span>`
}];
this.shinyOptions = [
{
action: this.downloadShinyApp,
title: 'components.shiny.button.menu.download',
defaultTitle: 'Download'
},
{
action: this.publishShinyApp,
title: 'components.shiny.button.menu.publish',
defaultTitle: 'Publish'
}
];
}

downloadShinyApp(source) {
let analysisId = source.info().executionInfo.id.analysisId;
FileService.loadZipNoRename(
config.api.url + constants.apiPaths.downloadShiny(analysisId, source.source.sourceKey)
)
.catch((e) => console.error("error when downloading: " + e))
.finally(() => this.isLoading(false));
}

async publishShinyApp(source) {
this.loading = true;
try {
await httpService.doGet(config.api.url + constants.apiPaths.publishShiny(source.info().executionInfo.id.analysisId, source.source.sourceKey));
alert("Incidence Rate report is published");
} catch (e) {
console.error('An error has occurred when publishing', e);
if (e.status === 403) {
alert('Permission denied');
} else {
alert('Unexpected error occurred when publishing');
}
}
}

reportDisabledReason(source) {
Expand Down
2 changes: 2 additions & 0 deletions js/pages/incidence-rates/const.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ define(
root: '/iranalysis/',
analysis: id => `/iranalysis${typeof id !== 'undefined' ? `/${id}` : ''}`,
createAnalysis: () => '/iranalysis/0',
downloadShiny: (id, sourceKey) => `shiny/download/incidence/${id}/${sourceKey}`,
publishShiny: (id, sourceKey) => `shiny/publish/incidence/${id}/${sourceKey}`,
};

const status = {
Expand Down
Loading
Loading