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.

207 lines
7.6KB

  1. import { h, Component, createRef } from 'preact';
  2. import WBNavbarCommon from 'wb-navbar-common';
  3. import WBArvadosCrumbs from 'wb-arvados-crumbs';
  4. import WBToolboxDialog from 'wb-toolbox-dialog';
  5. import makeArvadosRequest from 'make-arvados-request';
  6. import linkState from 'linkstate';
  7. function createInputsTemplate(workflow) {
  8. const g = JSON.parse(workflow.definition)['$graph'];
  9. const main = g.find(it => (it.id === '#main'));
  10. let res = '';
  11. main.inputs.map(it => {
  12. let id = it.id.split('/');
  13. id = id[id.length - 1];
  14. if (it.label) res += ' // ' + it.label + '\n';
  15. if (it.doc) res += ' // ' + it.doc + '\n';
  16. res += ' // Type: ' + ((typeof(it.type) === 'string') ?
  17. it.type : JSON.stringify(it.type)) + '\n\n';
  18. res += ' \'' + id + '\': \'\',\n\n';
  19. //res += ' // ' + ' '.repeat(id.length) + '^^^^\n\n';
  20. });
  21. /* let res = main.inputs.map(it => { it.value = null; return it; });
  22. res = JSON.stringify(res, null, 2);
  23. res = res.split('\n');
  24. res = res.map((ln, i) => (i == 0 ? ln : ' ' + ln));
  25. res = res.join('\n'); */
  26. return res;
  27. }
  28. function uuidsToCwlObjects(spec) {
  29. if (typeof(spec) === 'string') {
  30. if (/^[a-z0-9]{5}-[a-z0-9]{5}-[a-z0-9]{15}/.exec(spec)) {
  31. return {
  32. 'class': 'Directory',
  33. 'location': 'keep:' + spec
  34. };
  35. } else if (/^[a-f0-9]{32}\+[0-9]+/.exec(spec)) {
  36. return {
  37. 'class': 'Directory',
  38. 'location': 'keep:' + spec
  39. };
  40. } else {
  41. return spec;
  42. }
  43. } else if (typeof(spec) === 'object') {
  44. const res = (spec instanceof Array) ? [] : {};
  45. Object.keys(spec).map(k => (res[k] = uuidsToCwlObjects(spec[k])));
  46. return res;
  47. } else {
  48. return spec;
  49. }
  50. }
  51. class WBLaunchWorkflowPage extends Component {
  52. constructor(...args) {
  53. super(...args);
  54. this.state.browseDialogId = uuid.v4();
  55. this.state.insertDialogId = uuid.v4();
  56. this.state.insertManyDialogId = uuid.v4();
  57. this.inputsTextArea = createRef();
  58. }
  59. componentDidMount() {
  60. let { app, workflowUuid } = this.props;
  61. let { arvHost, arvToken } = app.state;
  62. let prom = makeArvadosRequest(arvHost, arvToken,
  63. '/arvados/v1/workflows/' + workflowUuid);
  64. prom = prom.then(xhr => this.setState({
  65. 'workflow': xhr.response,
  66. 'defaultProcessName': xhr.response.name + ' ' + (new Date().toISOString()),
  67. 'defaultProcessDescription': xhr.response.description,
  68. 'inputsFunctionText': '(() => {\n return {\n' +
  69. createInputsTemplate(xhr.response) +
  70. ' };\n})()'
  71. }));
  72. }
  73. render({ app, workflowUuid },
  74. { workflow, projectUuid, processName, processDescription,
  75. defaultProcessName, defaultProcessDescription,
  76. inputsFunctionText, browseDialogId,
  77. insertDialogId, insertManyDialogId,
  78. inputsPreview }) {
  79. return (
  80. <div>
  81. <WBNavbarCommon app={ app } />
  82. <WBToolboxDialog app={ app } id={ browseDialogId }
  83. items={ app.state.toolboxItems } onAccepted={ value =>
  84. this.setState({ 'projectUuid': value }) } />
  85. <WBToolboxDialog app={ app } id={ insertDialogId }
  86. items={ app.state.toolboxItems }
  87. onAccepted={ value => {
  88. const t = this.inputsTextArea.current;
  89. const start = t.selectionStart;
  90. const end = t.selectionEnd;
  91. this.setState({
  92. 'inputsFunctionText': t.value.substr(0, start) + value +
  93. t.value.substr(end)
  94. });
  95. } } />
  96. <WBToolboxDialog app={ app } id={ insertManyDialogId }
  97. items={ app.state.toolboxItems } selectMany={ true }
  98. onAccepted={ values => alert(values) } />
  99. { workflow ?
  100. (<form class="container-fluid">
  101. <h1>Launch Workflow</h1>
  102. <div class="form-group">
  103. <label>Workflow</label>
  104. <WBArvadosCrumbs app={ app } uuid={ workflowUuid } />
  105. </div>
  106. <div class="form-group">
  107. <label for="projectUuid">Project UUID</label>
  108. <div>
  109. { projectUuid ? (
  110. <WBArvadosCrumbs app={ app } uuid={ projectUuid } />
  111. ) : null }
  112. <div class="input-group mb-3">
  113. <input type="text" class="form-control" id="projectUuid"
  114. placeholder="Enter Project UUID" aria-label="Project UUID"
  115. aria-describedby="button-addon2" value={ projectUuid }
  116. onChange={ linkState(this, 'projectUuid') } />
  117. <div class="input-group-append">
  118. <button class="btn btn-primary" type="button"
  119. id="button-addon2" onclick={ e => { e.preventDefault();
  120. $('#' + browseDialogId).modal(); } }>Browse</button>
  121. </div>
  122. </div>
  123. </div>
  124. </div>
  125. <div class="form-check">
  126. <input type="checkbox" class="form-check-input" id="createSubproject" />
  127. <label class="form-check-label" for="createSubproject">Create subproject</label>
  128. </div>
  129. <div class="form-group">
  130. <label for="processName">Process Name</label>
  131. <input type="text" class="form-control" id="processName"
  132. placeholder={ defaultProcessName } value={ processName }
  133. onChange={ linkState(this, 'processName') }/>
  134. </div>
  135. <div class="form-group">
  136. <label for="processDescription">Process Description</label>
  137. <input type="text" class="form-control" id="processDescription"
  138. placeholder={ defaultProcessDescription } value={ processDescription }
  139. onChange={ linkState(this, 'processDescription') } />
  140. </div>
  141. <div class="form-group">
  142. <label for="inputs">Inputs</label>
  143. <div>
  144. <div class="mb-2">
  145. <button class="btn btn-primary mr-2" onclick={ e => {
  146. e.preventDefault();
  147. $('#' + insertDialogId).modal();
  148. } }>Insert</button>
  149. <button class="btn btn-primary mr-2" onclick={ e => {
  150. e.preventDefault();
  151. $('#' + insertManyDialogId).modal();
  152. } }>Insert Many</button>
  153. </div>
  154. <textarea class="form-control" ref={ this.inputsTextArea } id="inputs"
  155. style="font-family: monospace;" rows="20"
  156. value={ inputsFunctionText }
  157. onChange={ linkState(this, 'inputsFunctionText') }></textarea>
  158. <div class="my-2">
  159. <button class="btn btn-primary" onclick={ e => {
  160. e.preventDefault();
  161. try {
  162. let inputsVal = eval(inputsFunctionText);
  163. inputsVal = uuidsToCwlObjects(inputsVal);
  164. this.setState({ 'inputsPreview': JSON.stringify(inputsVal, null, 2) });
  165. } catch (exc) {
  166. this.setState({ 'inputsPreview': exc });
  167. }
  168. } }>Preview</button>
  169. </div>
  170. <textarea class="form-control" readonly="readonly"
  171. style="font-family: monospace;" rows="10"
  172. value={ inputsPreview }></textarea>
  173. </div>
  174. </div>
  175. </form>) : <div>Loading...</div> }
  176. </div>
  177. );
  178. }
  179. }
  180. export default WBLaunchWorkflowPage;