Skip to content
Snippets Groups Projects
ArbitraryWorkflowModal.vue 6.21 KiB
<script setup lang="ts">
import BootstrapModal from "@/components/modals/BootstrapModal.vue";
import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue";
import { computed, onMounted, reactive, ref } from "vue";
import { useRouter } from "vue-router";
import {
  GitRepository,
  requiredRepositoryFiles,
  determineGitIcon,
} from "@/utils/GitRepository";
import { Modal } from "bootstrap";

const props = defineProps<{
  modalID: string;
}>();

let createWorkflowModal: Modal | null = null;
const arbitraryWorkflowForm = ref<HTMLFormElement | undefined>(undefined);
const workflowRepositoryElement = ref<HTMLInputElement | undefined>(undefined);
const router = useRouter();

const workflow = reactive<{
  repository_url: string;
  git_commit_hash: string;
}>({
  repository_url: "",
  git_commit_hash: "",
});

const formState = reactive<{
  loading: boolean;
  checkRepoLoading: boolean;
  validated: boolean;
  allowUpload: boolean;
  missingFiles: string[];
  unsupportedRepository: boolean;
}>({
  validated: false,
  allowUpload: false,
  loading: false,
  checkRepoLoading: false,
  missingFiles: [],
  unsupportedRepository: false,
});

function modalClosed() {
  formState.validated = false;
}

function viewWorkflow() {
  console.log("View", workflow);
  createWorkflowModal?.hide();
  router.push({
    name: "arbitrary-workflow",
    query: {
      repository: encodeURI(workflow.repository_url),
      commit_hash: workflow.git_commit_hash,
    },
  });
}

function checkRepository() {
  formState.validated = true;
  if (arbitraryWorkflowForm.value?.checkValidity() && !formState.allowUpload) {
    formState.unsupportedRepository = false;
    formState.missingFiles = [];
    workflowRepositoryElement.value?.setCustomValidity("");
    try {
      const repo = GitRepository.buildRepository(
        workflow.repository_url,
        workflow.git_commit_hash
      );
      repo
        .checkFilesExist(requiredRepositoryFiles, true)
        .then(() => {
          formState.allowUpload = true;
        })
        .catch((e: Error) => {
          formState.missingFiles = e.message.split(",");
          // Allow execution of the workflow if main.nf and parameter schema are not missing
          if (
            formState.missingFiles.findIndex(
              (file) => file === "main.nf" || file === "nextflow_schema.json"
            ) < 0
          ) {
            formState.allowUpload = true;
          }
        });
    } catch (e) {
      formState.unsupportedRepository = true;
      workflowRepositoryElement.value?.setCustomValidity(
        "Repository is not supported"
      );
    }
  }
}
const gitIcon = computed<string>(() =>
  determineGitIcon(workflow.repository_url)
);

onMounted(() => {
  createWorkflowModal = new Modal("#" + props.modalID);
});
</script>

<template>
  <bootstrap-modal
    :modalID="modalID"
    :static-backdrop="false"
    modal-label="Create Workflow Modal"
    v-on="{ 'hidden.bs.modal': modalClosed }"
  >
    <template v-slot:header>Start arbitrary Workflow</template>
    <template v-slot:body>
      <form
        id="arbitraryWorkflowForm"
        :class="{ 'was-validated': formState.validated }"
        ref="arbitraryWorkflowForm"
      >
        <div class="mb-3">
          <label for="workflowRepositoryInput" class="form-label"
            >Git Repository URL</label
          >
          <div class="input-group">
            <div class="input-group-text">
              <font-awesome-icon :icon="gitIcon" />
            </div>
            <input
              type="url"
              class="form-control"
              id="workflowRepositoryInput"
              placeholder="https://..."
              required
              ref="workflowRepositoryElement"
              v-model="workflow.repository_url"
              @change="formState.allowUpload = false"
              aria-describedby="gitRepoProviderHelp"
            />
          </div>
          <div id="gitRepoProviderHelp" class="form-text">
            We support Github and GitLab Repositories
          </div>
          <div class="text-danger">
            <div v-if="formState.unsupportedRepository">
              Repository is not supported
            </div>
          </div>
        </div>
        <div class="mb-3">
          <label for="workflowGitCommitInput" class="form-label"
            >Git Commit Hash</label
          >
          <div class="input-group">
            <div class="input-group-text">
              <font-awesome-icon icon="fa-solid fa-code-commit" />
            </div>
            <input
              type="text"
              class="form-control text-lowercase"
              id="workflowGitCommitInput"
              placeholder="ba8bcd9..."
              required
              ref="workflowGitCommitHashElement"
              maxlength="40"
              minlength="40"
              pattern="[0-9a-f]{40}"
              v-model="workflow.git_commit_hash"
              @change="formState.allowUpload = false"
            />
          </div>
        </div>
        <div v-if="formState.missingFiles.length > 0" class="text-danger">
          The following files are missing in the repository
          <ul>
            <li v-for="file in formState.missingFiles" :key="file">
              {{ file }}
            </li>
          </ul>
        </div>
      </form>
    </template>
    <template v-slot:footer>
      <button
        type="button"
        class="btn btn-info me-auto"
        @click="checkRepository"
        :disabled="formState.allowUpload"
      >
        <span
          v-if="formState.checkRepoLoading"
          class="spinner-border spinner-border-sm"
          role="status"
          aria-hidden="true"
        ></span>
        Check Repository
      </button>
      <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
        Close
      </button>
      <button
        type="submit"
        form="workflowCreateForm"
        class="btn btn-primary"
        :disabled="formState.loading || !formState.allowUpload"
        @click.prevent="viewWorkflow"
      >
        <span
          v-if="formState.loading"
          class="spinner-border spinner-border-sm"
          role="status"
          aria-hidden="true"
        ></span>
        View
      </button>
    </template>
  </bootstrap-modal>
</template>

<style scoped></style>