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!
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

231 wiersze
7.5KB

  1. import { h, Component, createRef } from 'preact';
  2. import WBNavbarCommon from 'wb-navbar-common';
  3. import WBArvadosCrumbs from 'wb-arvados-crumbs';
  4. import WBBrowseDialog from 'wb-browse-dialog';
  5. import WBTable from 'wb-table';
  6. import WBNameAndUuid from 'wb-name-and-uuid';
  7. import makeArvadosRequest from 'make-arvados-request';
  8. import linkState from 'linkstate';
  9. function parseDefinition(text) {
  10. let definition;
  11. try {
  12. definition = JSON.parse(text);
  13. } catch (_) {
  14. definition = jsyaml.load(text);
  15. }
  16. return definition;
  17. }
  18. function encodeURIComponentIncludingDots(s) {
  19. return encodeURIComponent(s).replace('.', '%2E');
  20. }
  21. class WBPathDisplay extends Component {
  22. fetchData() {
  23. const { app, path } = this.props;
  24. const { arvHost, arvToken } = app.state;
  25. let m;
  26. if (m = /^[0-9a-f]{32}\+[0-9]+/.exec(path));
  27. else if (m = /^[a-z0-9]{5}-[a-z0-9]{5}-[a-z0-9]{15}/.exec(path));
  28. else return;
  29. let prom = makeArvadosRequest(arvHost, arvToken,
  30. '/arvados/v1/collections/' + m[0]);
  31. prom = prom.then(xhr => this.setState({
  32. item: xhr.response,
  33. tail: path.substr(m[0].length)
  34. }));
  35. }
  36. componentDidMount() {
  37. this.fetchData();
  38. }
  39. componentWillReceiveProps(nextProps) {
  40. this.props = nextProps;
  41. this.fetchData();
  42. }
  43. render({}, { item, tail }) {
  44. if (!item)
  45. return 'Loading...';
  46. return (
  47. <span>
  48. <a href={ '/collection-browse/' + item.uuid }>
  49. { item.name || item.uuid }
  50. </a><a href={ '/collection-browse/' + item.uuid + '/' + encodeURIComponentIncludingDots(tail) }>
  51. { tail }
  52. </a>
  53. </span>
  54. );
  55. }
  56. }
  57. class WBLaunchWorkflowPage extends Component {
  58. constructor(...args) {
  59. super(...args);
  60. this.browseDialogRef = createRef();
  61. this.state.inputs = {};
  62. }
  63. componentDidMount() {
  64. let { app, workflowUuid } = this.props;
  65. let { arvHost, arvToken } = app.state;
  66. let prom = makeArvadosRequest(arvHost, arvToken,
  67. '/arvados/v1/workflows/' + workflowUuid);
  68. prom = prom.then(xhr => this.setState({
  69. 'workflow': xhr.response,
  70. 'workflowDefinition': parseDefinition(xhr.response.definition),
  71. 'defaultProcessName': xhr.response.name + ' ' + (new Date().toISOString()),
  72. 'defaultProcessDescription': xhr.response.description
  73. }));
  74. }
  75. renderInput(inputSpec) {
  76. const { app } = this.props;
  77. const isFile = (inputSpec.type === 'File' || inputSpec.type === 'File[]' ||
  78. (inputSpec.type.type === 'array' && inputSpec.type.items === 'File'));
  79. const isDirectory = (inputSpec.type === 'Directory' || inputSpec.type === 'Directory[]' ||
  80. (inputSpec.type.type === 'array' && inputSpec.type.items === 'Directory'));
  81. const isArray = true; // (inputSpec.type === 'File[]' || inputSpec.type === 'Directory[]' ||
  82. // inputSpec.type.type === 'array');
  83. if (!isFile && !isDirectory)
  84. return (
  85. <div>
  86. <input class="form-control w-100" type="text" placeholder={ inputSpec.label }
  87. value={ this.state.inputs[inputSpec.id] }
  88. onchange={ e => (this.state.inputs[inputSpec.id] = e.target.value) }></input>
  89. <div class="mt-2 text-muted">{ inputSpec.doc }</div>
  90. </div>
  91. );
  92. const button = (
  93. <button class="btn btn-outline-primary"
  94. onclick={ e => {
  95. e.preventDefault();
  96. this.browseDialogRef.current.show(isFile ? 'file' : 'directory', isArray,
  97. v => {
  98. this.state.inputs[inputSpec.id] = JSON.stringify(v);
  99. this.setState({});
  100. });
  101. } }>
  102. Browse...
  103. </button>
  104. );
  105. let value = this.state.inputs[inputSpec.id];
  106. if (value) {
  107. try {
  108. value = jsyaml.load(value);
  109. } catch (_) {}
  110. }
  111. return (
  112. <div>
  113. <div class="input-group">
  114. <input class="form-control w-100" type="text" placeholder={ inputSpec.label }
  115. value={ this.state.inputs[inputSpec.id] }
  116. onchange={ e => (this.state.inputs[inputSpec.id] = e.target.value) }></input>
  117. <div class="input-group-append">
  118. { button }
  119. </div>
  120. </div>
  121. <div class="mt-2 text-muted">{ inputSpec.doc }</div>
  122. { value ?
  123. isArray ? (
  124. <ul class="mb-0">
  125. { value.map(path => (
  126. <li>
  127. <WBPathDisplay app={ app } path={ path } />
  128. </li>
  129. )) }
  130. </ul>
  131. ) : (
  132. <WBPathDisplay app={ app } path={ value } />
  133. ) : null }
  134. </div>
  135. );
  136. }
  137. render({ app, workflowUuid },
  138. { workflow, workflowDefinition, projectUuid, processName, processDescription,
  139. defaultProcessName, defaultProcessDescription }) {
  140. return (
  141. <div>
  142. <WBNavbarCommon app={ app } />
  143. <WBBrowseDialog app={ app } ref={ this.browseDialogRef } />
  144. { workflow ?
  145. (<form class="container-fluid">
  146. <h1>Launch Workflow</h1>
  147. <div class="form-group">
  148. <label>Workflow</label>
  149. <WBArvadosCrumbs app={ app } uuid={ workflowUuid } />
  150. </div>
  151. <div class="form-group">
  152. <label for="projectUuid">Project UUID</label>
  153. <div class="input-group mb-3">
  154. <input type="text" class="form-control" id="projectUuid"
  155. placeholder="Enter Project UUID" aria-label="Project UUID"
  156. aria-describedby="button-addon2" value={ projectUuid }
  157. onChange={ linkState(this, 'projectUuid') } />
  158. <div class="input-group-append">
  159. <button class="btn btn-primary" type="button"
  160. id="button-addon2" onclick={ e => { e.preventDefault();
  161. this.browseDialogRef.current.show('owner', false,
  162. projectUuid => this.setState({ projectUuid })); } }>Browse</button>
  163. </div>
  164. </div>
  165. { projectUuid ? (
  166. <WBArvadosCrumbs app={ app } uuid={ projectUuid } />
  167. ) : null }
  168. </div>
  169. <div class="form-group">
  170. <label for="processName">Process Name</label>
  171. <input type="text" class="form-control" id="processName"
  172. placeholder={ defaultProcessName } value={ processName }
  173. onChange={ linkState(this, 'processName') }/>
  174. </div>
  175. <div class="form-group">
  176. <label for="processDescription">Process Description</label>
  177. <input type="text" class="form-control" id="processDescription"
  178. placeholder={ defaultProcessDescription } value={ processDescription }
  179. onChange={ linkState(this, 'processDescription') } />
  180. </div>
  181. <div class="form-group">
  182. <label for="inputs">Inputs</label>
  183. <WBTable columns={ [ 'Name', 'Value'] }
  184. rows={ workflowDefinition.$graph.find(a => (a.id === '#main')).inputs.map(it => [
  185. it.label || it.id,
  186. this.renderInput(it)
  187. ]) } />
  188. </div>
  189. <div class="form-group">
  190. <button class="btn btn-success" onclick={ e => { e.preventDefault(); this.submit(); } }>
  191. Submit
  192. </button>
  193. </div>
  194. </form>) : <div>Loading...</div> }
  195. </div>
  196. );
  197. }
  198. }
  199. export default WBLaunchWorkflowPage;