|
76 | 76 | /** @type {{ [id: string]: import('$lib/types').Task[] }} */ |
77 | 77 | let newVersionsMap = {}; |
78 | 78 |
|
| 79 | + /** @type {import('$lib/types').ApplyWorkflow|undefined} */ |
| 80 | + let selectedRunningJob; |
| 81 | +
|
79 | 82 | $: updatableWorkflowList = workflow.task_list || []; |
80 | 83 |
|
81 | 84 | workflowTaskContext.subscribe((value) => { |
|
393 | 396 | // @ts-ignore |
394 | 397 | // eslint-disable-next-line |
395 | 398 | runWorkflowModal.toggle(); |
| 399 | + const job = await response.json(); |
| 400 | + selectedRunningJob = job; |
396 | 401 | await loadJobsStatus(); |
397 | 402 | } else { |
398 | 403 | console.error(response); |
|
479 | 484 | if (selectedInputDatasetId === undefined || selectedOutputDatasetId === undefined) { |
480 | 485 | return; |
481 | 486 | } |
482 | | - if (workflowErrorAlert) { |
483 | | - workflowErrorAlert.hide(); |
484 | | - } |
| 487 | + selectedRunningJob = await getSelectedRunningJob( |
| 488 | + selectedInputDatasetId, |
| 489 | + selectedOutputDatasetId |
| 490 | + ); |
485 | 491 | const outputStatusResponse = await fetch( |
486 | 492 | `/api/v1/project/${project.id}/dataset/${selectedOutputDatasetId}/status`, |
487 | 493 | { |
|
491 | 497 | ); |
492 | 498 | const outputStatus = await outputStatusResponse.json(); |
493 | 499 | if (!outputStatusResponse.ok) { |
494 | | - workflowErrorAlert = displayStandardErrorAlert(outputStatus, 'workflowErrorAlert'); |
| 500 | + console.error('Error retrieving dataset status', outputStatus) |
495 | 501 | return; |
496 | 502 | } |
497 | 503 | statuses = outputStatus.status; |
|
501 | 507 | if (runningOrSubmitted.length > 0) { |
502 | 508 | clearTimeout(statusWatcherTimer); |
503 | 509 | statusWatcherTimer = setTimeout(loadJobsStatus, updateJobsInterval); |
| 510 | + } else { |
| 511 | + selectedRunningJob = undefined; |
| 512 | + } |
| 513 | + } |
| 514 | +
|
| 515 | + /** |
| 516 | + * @param {number} inputDatasetId |
| 517 | + * @param {number} outputDatasetId |
| 518 | + * @return {Promise<import('$lib/types').ApplyWorkflow|undefined>} |
| 519 | + */ |
| 520 | + async function getSelectedRunningJob(inputDatasetId, outputDatasetId) { |
| 521 | + if ( |
| 522 | + selectedRunningJob && |
| 523 | + selectedRunningJob.input_dataset_id === inputDatasetId && |
| 524 | + selectedRunningJob.output_dataset_id === outputDatasetId |
| 525 | + ) { |
| 526 | + return selectedRunningJob; |
| 527 | + } |
| 528 | + const response = await fetch(`/api/v1/project/${project.id}/workflow/${workflow.id}/job`, { |
| 529 | + method: 'GET', |
| 530 | + credentials: 'include' |
| 531 | + }); |
| 532 | + if (response.ok) { |
| 533 | + /** @type {import('$lib/types').ApplyWorkflow[]} */ |
| 534 | + const allJobs = await response.json(); |
| 535 | + const jobs = allJobs |
| 536 | + .filter( |
| 537 | + (j) => j.input_dataset_id === inputDatasetId && j.output_dataset_id === outputDatasetId |
| 538 | + ) |
| 539 | + .sort((a, b) => (a.start_timestamp < b.start_timestamp ? 1 : -1)); |
| 540 | + if (jobs.length > 0) { |
| 541 | + return jobs[0]; |
| 542 | + } |
| 543 | + } else { |
| 544 | + console.error('Unable to load workflow jobs', await response.json()); |
| 545 | + } |
| 546 | + } |
| 547 | +
|
| 548 | + async function stopWorkflow() { |
| 549 | + if (!selectedRunningJob) { |
| 550 | + return; |
| 551 | + } |
| 552 | + if (workflowErrorAlert) { |
| 553 | + workflowErrorAlert.hide(); |
| 554 | + } |
| 555 | + const response = await fetch( |
| 556 | + `/api/v1/project/${project.id}/job/${selectedRunningJob.id}/stop`, |
| 557 | + { |
| 558 | + method: 'GET', |
| 559 | + credentials: 'include' |
| 560 | + } |
| 561 | + ); |
| 562 | + if (response.ok) { |
| 563 | + await loadJobsStatus(); |
| 564 | + } else { |
| 565 | + console.error('Error stopping job'); |
| 566 | + const errorResponse = await response.json(); |
| 567 | + workflowErrorAlert = displayStandardErrorAlert(errorResponse, 'workflowErrorAlert'); |
504 | 568 | } |
505 | 569 | } |
506 | 570 |
|
|
565 | 629 | </div> |
566 | 630 | </div> |
567 | 631 | <div class="col-lg-4 col-md-12"> |
568 | | - <button |
569 | | - class="btn btn-success" |
570 | | - on:click|preventDefault={() => { |
571 | | - if (argumentsWithUnsavedChanges === false) { |
572 | | - runWorkflowModal.toggle(); |
573 | | - } else { |
574 | | - toggleUnsavedChangesModal(); |
575 | | - } |
576 | | - }} |
577 | | - ><i class="bi-play-fill" /> Run workflow |
578 | | - </button> |
| 632 | + {#if selectedRunningJob && (selectedRunningJob.status === 'running' || selectedRunningJob.status === 'submitted')} |
| 633 | + <button class="btn btn-danger" on:click={stopWorkflow}> |
| 634 | + <i class="bi-stop-circle-fill" /> Stop workflow |
| 635 | + </button> |
| 636 | + {:else} |
| 637 | + <button |
| 638 | + class="btn btn-success" |
| 639 | + on:click|preventDefault={() => { |
| 640 | + if (argumentsWithUnsavedChanges === false) { |
| 641 | + runWorkflowModal.toggle(); |
| 642 | + } else { |
| 643 | + toggleUnsavedChangesModal(); |
| 644 | + } |
| 645 | + }} |
| 646 | + ><i class="bi-play-fill" /> Run workflow |
| 647 | + </button> |
| 648 | + {/if} |
579 | 649 | </div> |
580 | 650 | </div> |
581 | 651 | </div> |
|
0 commit comments