Skip to content
Snippets Groups Projects
WorkflowView.vue 9.23 KiB
<script setup lang="ts">
import { computed, onMounted, reactive, watch } from "vue";
import type { WorkflowOut, WorkflowVersionReduced } from "@/client/workflow";
import {
  Status,
  WorkflowService,
  WorkflowVersionService,
} from "@/client/workflow";
import { useRoute, useRouter } from "vue-router";
import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue";
import {
  latestVersion as calculateLatestVersion,
  sortedVersions,
} from "@/utils/Workflow";
import { determineGitIcon } from "@/utils/GitRepository";
import { useAuthStore } from "@/stores/auth";

const userRepository = useAuthStore();

// Props
// =============================================================================
const props = defineProps<{
  workflowId: string;
  versionId?: string;
}>();

// Constants
// =============================================================================
const router = useRouter();
const route = useRoute();

// Reactive State
// =============================================================================
const workflowState = reactive<{
  loading: boolean;
  workflow?: WorkflowOut;
  activeVersionId: string;
  initialOpen: boolean;
}>({
  loading: true,
  workflow: undefined,
  activeVersionId: "",
  initialOpen: true,
});

// Watchers
// =============================================================================
watch(
  () => props.workflowId,
  (newWorkflowId, oldWorkflowId) => {
    if (newWorkflowId !== oldWorkflowId) {
      updateWorkflow(newWorkflowId);
    }
  }
);

watch(
  () => props.versionId,
  (newWorkflowId) => {
    workflowState.activeVersionId = newWorkflowId ?? "";
  }
);

watch(
  () => workflowState.activeVersionId,
  (newVersionId, oldVersionId) => {
    if (
      newVersionId &&
      newVersionId !== oldVersionId &&
      route.name !== "workflow-start"
    ) {
      router.push({
        name: "workflow-version",
        params: { versionId: newVersionId },
        query: { tab: route.query.tab },
      });
    }
  }
);

// Computed Properties
// =============================================================================
const latestVersion = computed<WorkflowVersionReduced | undefined>(() =>
  calculateLatestVersion(workflowState.workflow?.versions || [])
);
const activeVersion = computed<WorkflowVersionReduced | undefined>(() =>
  workflowState.workflow?.versions.find(
    (w) => w.git_commit_hash === workflowState.activeVersionId
  )
);

const activeVersionString = computed<string>(
  () => activeVersion.value?.version ?? ""
);

const activeVersionIcon = computed<string | undefined>(
  () => activeVersion.value?.icon_url
);

const versionLaunchable = computed<boolean>(
  () => activeVersion.value?.status == Status.PUBLISHED ?? false
);

const gitIcon = computed<string>(() =>
  determineGitIcon(workflowState.workflow?.repository_url)
);

const allowVersionDeprecation = computed<boolean>(() => {
  if (activeVersion.value?.status === Status.PUBLISHED) {
    if (userRepository.workflowReviewer || userRepository.admin) {
      return true;
    } else if (
      userRepository.workflowDev &&
      workflowState.workflow?.developer_id === userRepository.currentUID
    ) {
      return true;
    }
  }
  return false;
});

// Functions
// =============================================================================
function updateWorkflow(workflowId: string) {
  workflowState.loading = true;
  WorkflowService.workflowGetWorkflow(workflowId)
    .then((workflow) => {
      workflowState.workflow = workflow;
      if (!workflowState.initialOpen || !route.params.versionId) {
        workflowState.activeVersionId =
          workflow.versions[workflow.versions.length - 1].git_commit_hash;
      } else {
        workflowState.activeVersionId = route.params.versionId as string;
      }
    })
    .catch(() => {
      workflowState.workflow = undefined;
    })
    .finally(() => {
      workflowState.loading = false;
      workflowState.initialOpen = false;
    });
}

function deprecateCurrentWorkflowVersion() {
  if (props.versionId) {
    WorkflowVersionService.workflowVersionDeprecateWorkflowVersion(
      props.versionId,
      props.workflowId
    ).then((version) => {
      if (workflowState.workflow) {
        const versionIndex = workflowState.workflow.versions.findIndex(
          (v) => v.git_commit_hash === version.git_commit_hash
        );
        if (versionIndex > -1) {
          workflowState.workflow.versions[versionIndex].status = version.status;
        }
      }
    });
  }
}

// Lifecycle Events
// =============================================================================
onMounted(() => {
  updateWorkflow(props.workflowId);
});
</script>

<template>
  <div v-if="workflowState.loading">
    <div
      class="d-flex mt-5 justify-content-between align-items-center placeholder-glow"
    >
      <span class="fs-0 placeholder col-6"></span>
      <span class="fs-0 placeholder col-1"></span>
    </div>
    <div class="fs-4 mb-5 mt-4 placeholder-glow">
      <span class="placeholder col-10"></span>
    </div>
    <div class="row align-items-center placeholder-glow my-1">
      <span class="mx-auto col-2 placeholder bg-success fs-0"></span>
      <span class="position-absolute end-0 col-1 placeholder fs-2"></span>
    </div>
    <div class="row w-100 mb-4 mt-3 mx-0 placeholder-glow">
      <span class="placeholder col-3 mx-auto"></span>
    </div>
  </div>
  <div v-else-if="workflowState.workflow != null">
    <div class="d-flex justify-content-between align-items-center">
      <div class="fs-0 w-fit text-light">
        {{ workflowState.workflow.name }}
        <span v-if="activeVersionString">@{{ activeVersionString }}</span>
      </div>
      <a :href="workflowState.workflow.repository_url" target="_blank">
        <img
          v-if="activeVersionIcon != null"
          :src="activeVersionIcon"
          class="img-fluid icon"
          alt="Workflow icon"
      /></a>
    </div>
    <p class="fs-4 mb-5 mt-3">{{ workflowState.workflow.short_description }}</p>
    <template v-if="route.name !== 'workflow-start'">
      <div
        v-if="!versionLaunchable"
        class="alert alert-warning w-fit mx-auto"
        role="alert"
      >
        This version can not be used.
        <router-link
          v-if="latestVersion != null"
          class="alert-link"
          :to="{
            name: 'workflow-version',
            params: {
              versionId: latestVersion.git_commit_hash,
            },
            query: { tab: route.query.tab },
          }"
          >Try the latest version {{ latestVersion?.version }}.</router-link
        >
      </div>
      <div class="row align-items-center">
        <div class="w-fit position-absolute start-0">
          <button
            v-if="props.versionId && allowVersionDeprecation"
            type="button"
            class="btn btn-warning"
            @click="deprecateCurrentWorkflowVersion"
          >
            Deprecate version
          </button>
        </div>
        <router-link
          role="button"
          class="btn btn-success btn-lg w-fit mx-auto"
          :class="{ disabled: !versionLaunchable }"
          :to="{
            name: 'workflow-start',
            params: {
              versionId: props.versionId,
              workflowId: props.workflowId,
            },
          }"
        >
          <font-awesome-icon icon="fa-solid fa-rocket" class="me-2" />
          <span class="align-middle">Launch {{ activeVersionString }}</span>
        </router-link>
        <div
          v-if="latestVersion != null"
          class="input-group w-fit position-absolute end-0"
        >
          <span class="input-group-text px-2" id="workflow-version-wrapping"
            ><font-awesome-icon icon="fa-solid fa-tags" class="text-secondary"
          /></span>
          <select
            class="form-select form-select-sm"
            aria-label="Workflow version selection"
            aria-describedby="workflow-version-wrapping"
            v-model="workflowState.activeVersionId"
          >
            <option
              v-for="version in sortedVersions(
                workflowState.workflow?.versions
              )"
              :key="version.git_commit_hash"
              :value="version.git_commit_hash"
            >
              {{ version.version }}
            </option>
          </select>
        </div>
      </div>
      <div class="row w-100 mb-4 mt-2 mx-0">
        <a
          :href="workflowState.workflow.repository_url"
          target="_blank"
          class="text-secondary text-decoration-none mx-auto w-fit p-0"
        >
          <font-awesome-icon :icon="gitIcon" class="me-1" />
          <span class="align-middle">
            {{ workflowState.workflow.repository_url }}</span
          ></a
        >
      </div>
    </template>
  </div>
  <router-view v-if="workflowState.loading || workflowState.workflow != null" />
  <div v-else 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 any Workflow with ID <br />'{{ workflowId }}'
    </p>
    <router-link :to="{ name: 'workflows' }" class="mt-5">Back</router-link>
  </div>
</template>

<style scoped>
.icon:hover {
  opacity: 0.8;
}

.icon {
  max-width: 60px;
  max-height: 60px;
  min-width: 50px;
  min-height: 50px;
}
</style>