IF YOU WOULD LIKE TO GET AN ACCOUNT, please write an email to s dot adaszewski at gmail dot com. User accounts are meant only to report issues and/or generate pull requests. This is a purpose-specific Git hosting for ADARED projects. Thank you for your understanding!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

186 lines
6.8KB

  1. //
  2. // Copyright (C) Stanislaw Adaszewski, 2020
  3. // Contact: s.adaszewski@gmail.com
  4. // Website: https://adared.ch/wba
  5. // License: GNU Affero General Public License, Version 3
  6. //
  7. import { h, Component, createRef } from 'preact';
  8. import { route } from 'preact-router';
  9. import WBNavbarCommon from 'wb-navbar-common';
  10. import WBArvadosCrumbs from 'wb-arvados-crumbs';
  11. import WBBrowseDialog from 'wb-browse-dialog';
  12. import WBTable from 'wb-table';
  13. import makeArvadosRequest from 'make-arvados-request';
  14. import { wbDisableControls, wbEnableControls } from 'wb-disable-controls';
  15. import linkState from 'linkstate';
  16. import wbParseWorkflowDef from 'wb-parse-workflow-def';
  17. import { wbParseWorkflowInputs, wbSubmitContainerRequest } from 'wb-submit-container-request';
  18. import WBWorkflowInput from 'wb-workflow-input';
  19. import { parseKeepRef } from 'wb-process-misc';
  20. class WBLaunchWorkflowPage extends Component {
  21. constructor(...args) {
  22. super(...args);
  23. this.browseDialogRef = createRef();
  24. this.state.inputs = {};
  25. this.state.errors = [];
  26. this.state.placeInSubProject = true;
  27. }
  28. componentDidMount() {
  29. let { app, workflowUuid } = this.props;
  30. let { arvHost, arvToken } = app.state;
  31. let prom = makeArvadosRequest(arvHost, arvToken,
  32. '/arvados/v1/workflows/' + workflowUuid);
  33. prom = prom.then(xhr => {
  34. const def = wbParseWorkflowDef(xhr.response.definition);
  35. const inputs = {};
  36. const main = def['$graph'].find(a => (a.id === '#main'));
  37. main.inputs.map(a => (inputs[a.id] = JSON.stringify(parseKeepRef(a.default))));
  38. this.setState({
  39. 'workflow': xhr.response,
  40. 'workflowDefinition': def,
  41. 'defaultProcessName': xhr.response.name + ' ' + (new Date().toISOString()),
  42. 'defaultProcessDescription': xhr.response.description,
  43. inputs
  44. });
  45. });
  46. }
  47. submit() {
  48. // first see if all inputs are parseable
  49. const { app, workflowUuid } = this.props;
  50. const { arvHost, arvToken, currentUser } = app.state;
  51. const { workflowDefinition, projectUuid,
  52. processName, processDescription,
  53. defaultProcessName, defaultProcessDescription,
  54. placeInSubProject } = this.state;
  55. const errors = [];
  56. const inputs = wbParseWorkflowInputs(workflowDefinition,
  57. this.state.inputs, errors);
  58. if (errors.length > 0) {
  59. this.setState({ errors });
  60. return;
  61. }
  62. const params = {
  63. arvHost, arvToken, inputs,
  64. processName: processName || defaultProcessName,
  65. processDescription: processDescription || defaultProcessDescription,
  66. projectUuid: projectUuid || currentUser.uuid,
  67. workflowUuid, workflowDefinition, placeInSubProject
  68. }
  69. wbDisableControls();
  70. let prom = wbSubmitContainerRequest(params);
  71. prom = prom.then(xhr => {
  72. wbEnableControls();
  73. route('/process/' + xhr.response.uuid);
  74. });
  75. prom = prom.catch(exc => {
  76. wbEnableControls();
  77. this.setState({ errors: [ exc.message ] });
  78. });
  79. }
  80. render({ app, workflowUuid },
  81. { workflow, workflowDefinition, projectUuid, processName, processDescription,
  82. defaultProcessName, defaultProcessDescription, errors, placeInSubProject }) {
  83. return (
  84. <div>
  85. <WBNavbarCommon app={ app } />
  86. <WBBrowseDialog app={ app } ref={ this.browseDialogRef } />
  87. { workflow ?
  88. (<form class="container-fluid">
  89. <h1>Launch Workflow</h1>
  90. <div class="form-group">
  91. <label>Workflow</label>
  92. <WBArvadosCrumbs app={ app } uuid={ workflowUuid } />
  93. </div>
  94. <div class="form-group">
  95. <label for="projectUuid">Project UUID</label>
  96. <div class="input-group mb-3">
  97. <input type="text" class="form-control" id="projectUuid"
  98. placeholder="Enter Project UUID" aria-label="Project UUID"
  99. aria-describedby="button-addon2" value={ projectUuid }
  100. onChange={ linkState(this, 'projectUuid') } />
  101. <div class="input-group-append">
  102. <button class="btn btn-primary" type="button"
  103. id="button-addon2" onclick={ e => { e.preventDefault();
  104. this.browseDialogRef.current.show('owner', false,
  105. projectUuid => this.setState({ projectUuid })); } }>Browse</button>
  106. </div>
  107. </div>
  108. { projectUuid ? (
  109. <WBArvadosCrumbs app={ app } uuid={ projectUuid } />
  110. ) : null }
  111. </div>
  112. <div class="form-check mb-3">
  113. <input class="form-check-input" type="checkbox"
  114. checked={ placeInSubProject ? 'checked' : null }
  115. onchange={ e => (this.state.placeInSubProject = e.target.checked) }
  116. id="placeInSubProject" />
  117. <label class="form-check-label" for="placeInSubProject">
  118. Place in a daily sub-project
  119. </label>
  120. </div>
  121. <div class="form-group">
  122. <label for="processName">Process Name</label>
  123. <input type="text" class="form-control" id="processName"
  124. placeholder={ defaultProcessName } value={ processName }
  125. onChange={ linkState(this, 'processName') }/>
  126. </div>
  127. <div class="form-group">
  128. <label for="processDescription">Process Description</label>
  129. <input type="text" class="form-control" id="processDescription"
  130. placeholder={ defaultProcessDescription } value={ processDescription }
  131. onChange={ linkState(this, 'processDescription') } />
  132. </div>
  133. <div class="form-group">
  134. <label for="inputs">Inputs</label>
  135. <WBTable columns={ [ 'Name', 'Value'] }
  136. rows={ workflowDefinition.$graph.find(a => (a.id === '#main')).inputs.map(it => [
  137. it.label || it.id,
  138. ( <WBWorkflowInput app={ app } inputSpec={ it }
  139. inputsDict={ this.state.inputs }
  140. browseDialogRef={ this.browseDialogRef } /> )
  141. ]) } />
  142. </div>
  143. { errors.length > 0 ? (
  144. <div class="form-group">
  145. { errors.map(err => (
  146. <div class="alert alert-danger" role="alert">
  147. { err }
  148. </div>
  149. ))}
  150. </div>
  151. ) : null }
  152. <div class="form-group">
  153. <button class="btn btn-success" onclick={ e => { e.preventDefault(); this.submit(); } }>
  154. Submit
  155. </button>
  156. </div>
  157. </form>) : <div>Loading...</div> }
  158. </div>
  159. );
  160. }
  161. }
  162. export default WBLaunchWorkflowPage;