<script setup lang="ts"> import WorkflowDocumentationTabs from "@/components/workflows/WorkflowDocumentationTabs.vue"; import { onMounted, reactive, ref, watch } from "vue"; import { GitRepository, requiredRepositoryFiles } from "@/utils/GitRepository"; import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue"; import { useRouter } from "vue-router"; import { Toast } from "bootstrap"; import { useWorkflowStore } from "@/stores/workflows"; import type { WorkflowIn } from "@/client/workflow"; import { useWorkflowExecutionStore } from "@/stores/workflowExecutions"; import ParameterSchemaFormComponent from "@/components/parameter-schema/ParameterSchemaFormComponent.vue"; import BootstrapToast from "@/components/BootstrapToast.vue"; import type { WorkflowParameters } from "@/types/WorkflowParameters"; const props = defineProps<{ wid: string; }>(); const router = useRouter(); const workflowStore = useWorkflowStore(); const executionRepository = useWorkflowExecutionStore(); const workflowState = reactive<{ workflow?: WorkflowIn; loading: boolean; changelogMarkdown?: string; descriptionMarkdown?: string; usageMarkdown?: string; outputMarkdown?: string; parameterSchema?: Record<string, never>; repo: GitRepository; }>({ loading: true, workflow: undefined, repo: GitRepository.buildRepository( "https://github.de/eample/example", "0123456789abcdef", ), }); const workflowExecutionState = reactive<{ loading: boolean; errorType?: string; }>({ loading: false, errorType: undefined, }); const showDocumentation = ref<boolean>(true); let errorToast: Toast | null = null; function downloadVersionFiles() { if (workflowState.workflow) { workflowState.loading = true; Promise.all( requiredRepositoryFiles(workflowState.workflow.modes).map((file) => workflowState.repo.downloadFile(file).then((response) => { if (file.includes("README")) { workflowState.descriptionMarkdown = response.data; } else if (file.includes("CHANGELOG")) { workflowState.changelogMarkdown = response.data; } else if (file.includes("usage")) { workflowState.usageMarkdown = response.data; } else if (file.includes("output")) { workflowState.outputMarkdown = response.data; } else if (file.endsWith("json")) { workflowState.parameterSchema = response.data; } }), ), ).finally(() => { workflowState.loading = false; }); } } watch( () => workflowState.workflow, (newWorkflow, oldWorkflow) => { if ( newWorkflow && newWorkflow?.git_commit_hash !== oldWorkflow?.git_commit_hash ) { workflowState.repo = GitRepository.buildRepository( newWorkflow.repository_url, newWorkflow.git_commit_hash, newWorkflow.token ?? undefined, ); downloadVersionFiles(); } }, ); function startWorkflow( parameters: WorkflowParameters, notes?: string, logs_s3_path?: string, debug_s3_path?: string, provenance_s3_path?: string, ) { if (workflowState.workflow) { errorToast?.hide(); workflowExecutionState.loading = true; executionRepository .startDevExecution({ git_commit_hash: workflowState.workflow.git_commit_hash, parameters: parameters, logs_s3_path: logs_s3_path ? logs_s3_path : undefined, debug_s3_path: debug_s3_path ? debug_s3_path : undefined, provenance_s3_path: provenance_s3_path ? provenance_s3_path : undefined, repository_url: workflowState.workflow.repository_url, token: workflowState.workflow.token ?? undefined, mode: (workflowState.workflow.modes ?? []).length > 0 ? { name: "", // eslint-disable-next-line @typescript-eslint/no-non-null-assertion entrypoint: workflowState.workflow.modes![0].entrypoint, // eslint-disable-next-line @typescript-eslint/no-non-null-assertion schema_path: workflowState.workflow.modes![0].schema_path, } : undefined, }) .then(() => { router.push({ name: "workflow-executions", }); }) .catch((err) => { console.error(err); if (err.body["detail"].includes("workflow execution limit")) { workflowExecutionState.errorType = "limit"; } errorToast?.show(); }) .finally(() => { workflowExecutionState.loading = false; }); } } onMounted(() => { errorToast = new Toast("#arbitraryWorkflowExecutionViewErrorToast"); workflowStore.getArbitraryWorkflow(props.wid).then((workflow) => { workflowState.workflow = workflow; }); }); </script> <template> <bootstrap-toast toast-id="arbitraryWorkflowExecutionViewErrorToast" color-class="danger" > <template #default> Error starting workflow </template> <template #body> <template v-if="workflowExecutionState.errorType === 'limit'"> You have too many active workflow executions to start a new one. </template> <template v-else> There was an error with starting the workflow execution. Look in the console for more information. </template> </template> </bootstrap-toast> <template v-if="workflowState.workflow"> <div class="row m-1 border-bottom mb-4"> <h1 class="mb-2">Arbitrary Workflow</h1> </div> <h5> Git Repository: <a target="_blank" :href="workflowState.workflow?.repository_url">{{ workflowState.workflow?.repository_url }}</a> </h5> <h5 :class="{ 'mb-5': workflowState.workflow.modes!.length < 1 }"> Git Commit Hash: {{ workflowState.workflow?.git_commit_hash }} </h5> <template v-if="workflowState.workflow.modes!.length > 0"> <h5>Entrypoint: {{ workflowState.workflow?.modes?.[0].entrypoint }}</h5> <h5 class="mb-5"> Schema File: {{ workflowState.workflow?.modes?.[0].schema_path }} </h5> </template> <div class="d-flex justify-content-center mb-5" v-if="showDocumentation"> <a role="button" href="#" class="btn btn-success btn-lg mx-auto fs-4" :class="{ disabled: !workflowState.parameterSchema }" @click="showDocumentation = false" > <font-awesome-icon icon="fa-solid fa-rocket" class="me-2" /> <span class="align-middle">Launch</span> </a> </div> <workflow-documentation-tabs v-if="showDocumentation" :loading="workflowState.loading" :output-markdown="workflowState.outputMarkdown" :usage-markdown="workflowState.usageMarkdown" :description-markdown="workflowState.descriptionMarkdown" :changelog-markdown="workflowState.changelogMarkdown" :parameter-schema="workflowState.parameterSchema" /> <parameter-schema-form-component v-else :loading="workflowExecutionState.loading" :schema="workflowState.parameterSchema" @start-workflow="startWorkflow" /> </template> <template v-else> <div class="text-center fs-1 mt-5"> <font-awesome-icon icon="fa-solid fa-magnifying-glass" class="my-5 fs-0" style="color: var(--bs-secondary)" /> <p class="my-5">Could not find your workflow.<br />Please re-enter it.</p> <router-link :to="{ name: 'workflows' }" class="mt-5">Back</router-link> </div> </template> </template> <style scoped></style>