-
Daniel Göbel authored
#53
Daniel Göbel authored#53
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>