-
Daniel Göbel authoredDaniel Göbel authored
ArbitraryWorkflowView.vue 7.36 KiB
<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>