diff --git a/package-lock.json b/package-lock.json
index 1daf7226448ad521408f28f94b660b3a6194444b..baa4cb993ffbc021f306aa5da9b6b2ea85658ec3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,6 +18,7 @@
         "dompurify": "^3.0.1",
         "filesize": "^10.0.6",
         "pinia": "^2.0.32",
+        "semver": "^7.3.8",
         "showdown": "^2.1.0",
         "vue": "^3.2.47",
         "vue-router": "^4.1.6",
@@ -30,6 +31,7 @@
         "@types/bootstrap": "^5.2.6",
         "@types/dompurify": "^2.4.0",
         "@types/node": "^16.11.45",
+        "@types/semver": "^7.3.13",
         "@types/showdown": "^2.0.0",
         "@vitejs/plugin-vue": "^3.2.0",
         "@vue/eslint-config-prettier": "^7.0.0",
@@ -2363,6 +2365,12 @@
       "integrity": "sha512-3rKg/L5x0rofKuuUt5zlXzOnKyIHXmIu5R8A0TuNDMF2062/AOIDBciFIjToLEJ/9F9DzkHNot+BpNsMI1OLdQ==",
       "dev": true
     },
+    "node_modules/@types/semver": {
+      "version": "7.3.13",
+      "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
+      "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
+      "dev": true
+    },
     "node_modules/@types/showdown": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/@types/showdown/-/showdown-2.0.0.tgz",
@@ -4988,7 +4996,6 @@
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
       "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-      "dev": true,
       "dependencies": {
         "yallist": "^4.0.0"
       },
@@ -5937,10 +5944,9 @@
       }
     },
     "node_modules/semver": {
-      "version": "7.3.7",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
-      "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
-      "dev": true,
+      "version": "7.3.8",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
       "dependencies": {
         "lru-cache": "^6.0.0"
       },
@@ -6674,8 +6680,7 @@
     "node_modules/yallist": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-      "dev": true
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
     },
     "node_modules/yocto-queue": {
       "version": "0.1.0",
@@ -8694,6 +8699,12 @@
       "integrity": "sha512-3rKg/L5x0rofKuuUt5zlXzOnKyIHXmIu5R8A0TuNDMF2062/AOIDBciFIjToLEJ/9F9DzkHNot+BpNsMI1OLdQ==",
       "dev": true
     },
+    "@types/semver": {
+      "version": "7.3.13",
+      "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
+      "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
+      "dev": true
+    },
     "@types/showdown": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/@types/showdown/-/showdown-2.0.0.tgz",
@@ -10495,7 +10506,6 @@
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
       "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-      "dev": true,
       "requires": {
         "yallist": "^4.0.0"
       }
@@ -11152,10 +11162,9 @@
       }
     },
     "semver": {
-      "version": "7.3.7",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
-      "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
-      "dev": true,
+      "version": "7.3.8",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
       "requires": {
         "lru-cache": "^6.0.0"
       }
@@ -11671,8 +11680,7 @@
     "yallist": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-      "dev": true
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
     },
     "yocto-queue": {
       "version": "0.1.0",
diff --git a/package.json b/package.json
index ca88bc33a4c626fbff6e516e4522158c6449f3e1..c184236b1dc8476c76f6d563ff8331ab60798e83 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
     "dompurify": "^3.0.1",
     "filesize": "^10.0.6",
     "pinia": "^2.0.32",
+    "semver": "^7.3.8",
     "showdown": "^2.1.0",
     "vue": "^3.2.47",
     "vue-router": "^4.1.6",
@@ -36,6 +37,7 @@
     "@types/dompurify": "^2.4.0",
     "@types/node": "^16.11.45",
     "@types/showdown": "^2.0.0",
+    "@types/semver": "^7.3.13",
     "@vitejs/plugin-vue": "^3.2.0",
     "@vue/eslint-config-prettier": "^7.0.0",
     "@vue/eslint-config-typescript": "^11.0.2",
diff --git a/src/components/object-storage/modals/UploadObjectModal.vue b/src/components/object-storage/modals/UploadObjectModal.vue
index 12851500b4c9b61b2c2abdd311bb4b06cbec51c7..5a4e8c4971321b49f74b4136eeb592ff4f630a38 100644
--- a/src/components/object-storage/modals/UploadObjectModal.vue
+++ b/src/components/object-storage/modals/UploadObjectModal.vue
@@ -94,7 +94,7 @@ async function uploadObject() {
       bucket: props.bucketName,
       size: formState.file?.size ?? 0,
       last_modified: dayjs().toISOString(),
-      content_type: formState.file?.type ?? "text/plain",
+      content_type: formState.file?.type ?? "binary/octet-stream",
     });
     formState.key = "";
     (
diff --git a/src/components/workflows/modals/CreateWorkflowModal.vue b/src/components/workflows/modals/CreateWorkflowModal.vue
new file mode 100644
index 0000000000000000000000000000000000000000..9a4a96c54a423a86e7487b7353a08ba3e55f5245
--- /dev/null
+++ b/src/components/workflows/modals/CreateWorkflowModal.vue
@@ -0,0 +1,386 @@
+<script setup lang="ts">
+import { computed, onMounted, reactive, ref } from "vue";
+import type { ComputedRef } from "vue";
+import { Modal, Toast } from "bootstrap";
+import type {
+  Body_Workflow_create_workflow,
+  WorkflowOut,
+} from "@/client/workflow";
+import BootstrapModal from "@/components/modals/BootstrapModal.vue";
+import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue";
+import { ApiError, WorkflowService } from "@/client/workflow";
+import { GitRepository } from "@/utils/GitRepository";
+import valid from "semver/functions/valid";
+
+let createWorkflowModal: Modal | null = null;
+let successToast: Toast | null = null;
+const workflowCreateForm = ref<HTMLFormElement | undefined>(undefined);
+const workflowIconInput = ref<HTMLInputElement | undefined>(undefined);
+const workflowVersionElement = ref<HTMLInputElement | undefined>(undefined);
+const workflowGitCommitHashElement = ref<HTMLInputElement | undefined>(
+  undefined
+);
+const workflowNameElement = ref<HTMLInputElement | undefined>(undefined);
+const workflowRepositoryElement = ref<HTMLInputElement | undefined>(undefined);
+const randomIDSuffix = Math.random().toString(16).substr(2, 8);
+
+const workflow = reactive<Body_Workflow_create_workflow>({
+  icon: undefined,
+  name: "",
+  short_description: "",
+  repository_url: "",
+  git_commit_hash: "",
+  initial_version: undefined,
+});
+
+const gitIcon: ComputedRef<string> = computed(() => {
+  let gitProvider = "git-alt";
+  if (workflow.repository_url.includes("github")) {
+    gitProvider = "github";
+  } else if (workflow.repository_url.includes("gitlab")) {
+    gitProvider = "gitlab";
+  } else if (workflow.repository_url.includes("bitbucket")) {
+    gitProvider = "bitbucket";
+  }
+  return "fa-brands fa-".concat(gitProvider);
+});
+
+const emit = defineEmits<{
+  (e: "workflow-created", workflow: WorkflowOut): void;
+}>();
+
+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,
+});
+
+const props = defineProps<{
+  modalID: string;
+}>();
+
+const formValid = computed<boolean>(
+  () => workflowCreateForm.value?.checkValidity() ?? false
+);
+
+function modalClosed() {
+  formState.validated = false;
+}
+
+function createWorkflow() {
+  formState.validated = true;
+  workflow.name = workflow.name.trim();
+  workflow.short_description = workflow.short_description.trim();
+  workflow.initial_version = workflow.initial_version?.trim();
+  if (formValid.value && formState.allowUpload) {
+    formState.loading = true;
+    workflowNameElement.value?.setCustomValidity("");
+    workflowGitCommitHashElement.value?.setCustomValidity("");
+    WorkflowService.workflowCreateWorkflow(workflow)
+      .then((w) => {
+        emit("workflow-created", w);
+        successToast?.show();
+        createWorkflowModal?.hide();
+        resetForm();
+      })
+      .catch((error: ApiError) => {
+        const errorText = error.body["detail"];
+        if (errorText.startsWith("Workflow with name")) {
+          workflowNameElement.value?.setCustomValidity("Name is already taken");
+        } else if (errorText.startsWith("Workflow with git_commit_hash")) {
+          workflowGitCommitHashElement.value?.setCustomValidity(
+            "Git commit is already used by a workflow"
+          );
+        }
+      })
+      .finally(() => {
+        formState.loading = false;
+      });
+  }
+}
+
+function resetForm() {
+  formState.validated = false;
+  workflow.icon = undefined;
+  workflow.name = "";
+  workflow.short_description = "";
+  workflow.repository_url = "";
+  workflow.git_commit_hash = "";
+  workflow.initial_version = undefined;
+  if (workflowIconInput.value != undefined) {
+    workflowIconInput.value.value = "";
+  }
+}
+
+function iconChanged() {
+  workflow.icon = workflowIconInput.value?.files?.[0].slice();
+}
+
+function checkRepository() {
+  formState.validated = true;
+  if (formValid.value && !formState.allowUpload) {
+    formState.unsupportedRepository = false;
+    formState.missingFiles = [];
+    workflowRepositoryElement.value?.setCustomValidity("");
+    workflowGitCommitHashElement.value?.setCustomValidity("");
+    try {
+      const repo = GitRepository.buildRepository(
+        workflow.repository_url,
+        workflow.git_commit_hash
+      );
+      repo
+        .checkFilesExist(
+          ["main.nf", "CHANGELOG.md", "README.md", "nextflow_schema.json"],
+          true
+        )
+        .then(() => {
+          formState.allowUpload = true;
+        })
+        .catch((e: Error) => {
+          formState.missingFiles = e.message.split(",");
+          workflowGitCommitHashElement.value?.setCustomValidity(
+            "Files are missing in the repository"
+          );
+        });
+    } catch (e) {
+      formState.unsupportedRepository = true;
+      workflowRepositoryElement.value?.setCustomValidity(
+        "Repository is not supported"
+      );
+    }
+  }
+}
+
+function checkVersionValidity() {
+  if (valid(workflow.initial_version) == null) {
+    workflowVersionElement.value?.setCustomValidity(
+      "Please use semantic versioning"
+    );
+  } else {
+    workflowVersionElement.value?.setCustomValidity("");
+  }
+}
+
+onMounted(() => {
+  createWorkflowModal = new Modal("#" + props.modalID);
+  successToast = new Toast("#successToast-" + randomIDSuffix);
+});
+</script>
+
+<template>
+  <div class="toast-container position-fixed top-toast end-0 p-3">
+    <div
+      role="alert"
+      aria-live="assertive"
+      aria-atomic="true"
+      class="toast text-bg-success align-items-center border-0"
+      data-bs-autohide="true"
+      :id="'successToast-' + randomIDSuffix"
+    >
+      <div class="d-flex">
+        <div class="toast-body">Successfully created Workflow</div>
+        <button
+          type="button"
+          class="btn-close btn-close-white me-2 m-auto"
+          data-bs-dismiss="toast"
+          aria-label="Close"
+        ></button>
+      </div>
+    </div>
+  </div>
+  <bootstrap-modal
+    :modalID="modalID"
+    :static-backdrop="true"
+    modal-label="Create Workflow Modal"
+    v-on="{ 'hidden.bs.modal': modalClosed }"
+  >
+    <template v-slot:header> Create new Workflow</template>
+    <template v-slot:body>
+      <form
+        id="workflowCreateForm"
+        :class="{ 'was-validated': formState.validated }"
+        ref="workflowCreateForm"
+      >
+        <div class="mb-3">
+          <label for="workflowNameInput" class="form-label"
+            >Workflow Name</label
+          >
+          <input
+            type="text"
+            class="form-control"
+            id="workflowNameInput"
+            placeholder="Short descriptive name"
+            required
+            ref="workflowNameElement"
+            minlength="3"
+            maxlength="64"
+            v-model="workflow.name"
+          />
+        </div>
+        <div class="mb-3">
+          <label for="workflowDescriptionInput" class="form-label">
+            Short Description {{ workflow.short_description.length }} / 64
+          </label>
+          <div class="input-group">
+            <textarea
+              class="form-control"
+              id="workflowDescriptionInput"
+              required
+              rows="3"
+              minlength="64"
+              maxlength="256"
+              v-model="workflow.short_description"
+              placeholder="Describe the purpose of the workflow in a few words."
+            ></textarea>
+            <div class="invalid-feedback">
+              Requirements
+              <ul class="mb-0">
+                <li>At least 64 Characters long</li>
+              </ul>
+            </div>
+          </div>
+        </div>
+        <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"
+              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>
+        <div class="row mb-3">
+          <div class="col-4">
+            <label for="workflowVersionInput" class="form-label"
+              >Initial Version</label
+            >
+            <div class="input-group">
+              <div class="input-group-text">
+                <font-awesome-icon icon="fa-solid fa-tag" />
+              </div>
+              <input
+                type="text"
+                class="form-control"
+                id="workflowRepositoryInput"
+                placeholder="v1.0.0"
+                maxlength="10"
+                ref="workflowVersionElement"
+                @change="checkVersionValidity"
+                v-model="workflow.initial_version"
+              />
+            </div>
+          </div>
+          <div class="col-8">
+            <label for="workflowIconInput" class="form-label"
+              >Optional Icon</label
+            >
+            <input
+              type="file"
+              ref="workflowIconInput"
+              accept="image/*"
+              class="form-control"
+              id="workflowIconInput"
+              @change="iconChanged"
+            />
+          </div>
+        </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="createWorkflow"
+      >
+        <span
+          v-if="formState.loading"
+          class="spinner-border spinner-border-sm"
+          role="status"
+          aria-hidden="true"
+        ></span>
+        Save
+      </button>
+    </template>
+  </bootstrap-modal>
+</template>
+
+<style scoped></style>
diff --git a/src/utils/GitRepository.ts b/src/utils/GitRepository.ts
new file mode 100644
index 0000000000000000000000000000000000000000..04e183394da94378cb1266ff70723436eb549b8b
--- /dev/null
+++ b/src/utils/GitRepository.ts
@@ -0,0 +1,80 @@
+import axios from "axios";
+
+export abstract class GitRepository {
+  protected repo: URL;
+  protected gitCommitHash: string;
+  protected constructor(repoUrl: string, gitCommitHash: string) {
+    this.repo = new URL(repoUrl);
+    this.gitCommitHash = gitCommitHash;
+  }
+  async checkFileExist(filepath: string): Promise<boolean> {
+    try {
+      await axios.head(this.fileUrl(filepath));
+    } catch (e) {
+      return false;
+    }
+    return true;
+  }
+
+  async checkFilesExist(
+    files: string[],
+    raiseError = false
+  ): Promise<boolean[]> {
+    const checks = Promise.all(
+      files.map((filepath) => this.checkFileExist(filepath))
+    );
+    const results = await checks;
+    if (raiseError) {
+      const missingFiles = files.filter((file, index) => !results[index]);
+      if (missingFiles.length > 0) {
+        throw new Error(missingFiles.reduce((a, b) => a + "," + b));
+      }
+    }
+    return results;
+  }
+  protected abstract fileUrl(filepath: string): string;
+
+  static buildRepository(
+    repoUrl: string,
+    gitCommitHash: string
+  ): GitRepository {
+    if (repoUrl.includes("github")) {
+      return new GithubRepository(repoUrl, gitCommitHash);
+    } else if (repoUrl.includes("gitlab")) {
+      return new GitlabRepository(repoUrl, gitCommitHash);
+    }
+    throw new Error(`Repository is not supported.`);
+  }
+}
+
+class GithubRepository extends GitRepository {
+  private readonly account: string;
+  private readonly repoName: string;
+  constructor(repoUrl: string, gitCommitHash: string) {
+    super(repoUrl, gitCommitHash);
+    const pathParts = this.repo.pathname.slice(1).split("/");
+    this.account = pathParts[0];
+    this.repoName = pathParts[1];
+  }
+
+  fileUrl(filepath: string): string {
+    return `https://raw.githubusercontent.com/${this.account}/${this.repoName}/${this.gitCommitHash}/${filepath}`;
+  }
+}
+
+class GitlabRepository extends GitRepository {
+  private readonly account: string[];
+  private readonly repoName: string;
+  constructor(repoUrl: string, gitCommitHash: string) {
+    super(repoUrl, gitCommitHash);
+    const pathParts = this.repo.pathname.slice(1).split("/");
+    this.account = pathParts.slice(0, pathParts.length - 2);
+    this.repoName = pathParts[pathParts.length - 1];
+  }
+
+  fileUrl(filepath: string): string {
+    return `https://${this.repo.host}/${this.account.reduce((a, b) =>
+      a.concat(`/${b}`)
+    )}/${this.repoName}/-/raw/${this.gitCommitHash}/${filepath}`;
+  }
+}
diff --git a/src/views/workflows/ListWorkflowsView.vue b/src/views/workflows/ListWorkflowsView.vue
index f133a3b899b73c1c37e1ada8babbe59a9e0c8c34..f1e0d6ef15a4bd20e26e51234024c058461b07e4 100644
--- a/src/views/workflows/ListWorkflowsView.vue
+++ b/src/views/workflows/ListWorkflowsView.vue
@@ -22,7 +22,10 @@ const workflowsState = reactive({
   sortDesc: boolean;
 });
 
-const bla: Record<string, (a: WorkflowOut, b: WorkflowOut) => boolean> = {
+const filterFunctionMapping: Record<
+  string,
+  (a: WorkflowOut, b: WorkflowOut) => boolean
+> = {
   name: (a: WorkflowOut, b: WorkflowOut) =>
     workflowsState.sortDesc ? a.name > b.name : a.name < b.name,
   release: (a: WorkflowOut, b: WorkflowOut) => {
@@ -51,7 +54,9 @@ const processedWorkflows: ComputedRef<WorkflowOut[]> = computed(() => {
         filterWorkflowByString(workflow) &&
         filterWorkflowWithoutVersion(workflow)
     ),
-  ].sort((a, b) => (bla[workflowsState.sortByAttribute](a, b) ? 1 : -1));
+  ].sort((a, b) =>
+    filterFunctionMapping[workflowsState.sortByAttribute](a, b) ? 1 : -1
+  );
 });
 
 onMounted(() => {
diff --git a/src/views/workflows/MyWorkflowsView.vue b/src/views/workflows/MyWorkflowsView.vue
index 7f091d39c85a89ba216343a92fcae15a31ce54b2..079aa54799a1d01281e291bb8beb28f50ea99d03 100644
--- a/src/views/workflows/MyWorkflowsView.vue
+++ b/src/views/workflows/MyWorkflowsView.vue
@@ -4,6 +4,8 @@ import { Status, WorkflowService } from "@/client/workflow";
 import type { WorkflowOut } from "@/client/workflow";
 import { useAuthStore } from "@/stores/auth";
 import WorkflowWithVersionsCard from "@/components/workflows/WorkflowWithVersionsCard.vue";
+import CreateWorkflowModal from "@/components/workflows/modals/CreateWorkflowModal.vue";
+import CardTransitionGroup from "@/components/transitions/CardTransitionGroup.vue";
 
 const userRepository = useAuthStore();
 const workflowsState = reactive<{
@@ -30,8 +32,21 @@ onMounted(() => {
 </script>
 
 <template>
-  <h1 class="mt-5">My Workflows</h1>
-  <div
+  <create-workflow-modal
+    modal-i-d="createWorkflowModal"
+    @workflow-created="(w) => workflowsState.workflows.push(w)"
+  />
+  <div class="d-flex justify-content-between align-items-center mt-5">
+    <div class="fs-1 w-fit">My Workflows</div>
+    <button
+      class="btn btn-lg btn-primary w-fit"
+      data-bs-toggle="modal"
+      data-bs-target="#createWorkflowModal"
+    >
+      Create
+    </button>
+  </div>
+  <card-transition-group
     v-if="!workflowsState.loading"
     class="d-flex flex-wrap align-items-center justify-content-between mt-5"
   >
@@ -41,7 +56,7 @@ onMounted(() => {
       :workflow="workflow"
       :loading="false"
     />
-  </div>
+  </card-transition-group>
   <div
     v-else
     class="d-flex flex-wrap align-items-center justify-content-between mt-5"
diff --git a/src/views/workflows/WorkflowView.vue b/src/views/workflows/WorkflowView.vue
index 8cd5816839dcca992fb49ae6415bc3760818b464..a89cc5d7b76560e73aa521a9b6d5d7e781ebc427 100644
--- a/src/views/workflows/WorkflowView.vue
+++ b/src/views/workflows/WorkflowView.vue
@@ -111,7 +111,7 @@ const versionLaunchable: ComputedRef<boolean> = computed(
 );
 
 const gitIcon: ComputedRef<string> = computed(() => {
-  let gitProvider = "git";
+  let gitProvider = "git-alt";
   if (workflowState.workflow !== undefined) {
     if (workflowState.workflow.repository_url.includes("github")) {
       gitProvider = "github";