This is an automated email from the ASF dual-hosted git repository. yasithdev pushed a commit to branch feat/generic-experiment-launcher in repository https://gitbox.apache.org/repos/asf/airavata-portals.git
commit bbff3c557460f4ca7de13a1e6613c8b687797744 Author: yasithdev <[email protected]> AuthorDate: Fri Apr 24 22:19:02 2026 -0400 feat(launcher): ExperimentMetaHeader (name/project/description) --- .../js/components/launch/ExperimentMetaHeader.vue | 55 ++++++++++++++++++++++ .../components/launch/ExperimentMetaHeader.spec.ts | 31 ++++++++++++ 2 files changed, 86 insertions(+) diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/launch/ExperimentMetaHeader.vue b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/launch/ExperimentMetaHeader.vue new file mode 100644 index 000000000..52fddd29b --- /dev/null +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/launch/ExperimentMetaHeader.vue @@ -0,0 +1,55 @@ +<template> + <div class="row g-2 mb-2"> + <div class="col-md-6"> + <input + data-test="exp-name" + class="form-control" + :value="store.draft.name" + placeholder="Experiment name" + maxlength="256" + @input="onName(($event.target as HTMLInputElement).value)" + /> + </div> + <div class="col-md-6"> + <select + data-test="exp-project" + class="form-select" + :value="store.draft.project_id ?? ''" + @change="onProject(($event.target as HTMLSelectElement).value)" + > + <option value="" disabled>Select a project</option> + <option v-for="p in projects" :key="p.project_id" :value="p.project_id"> + {{ p.name }} + </option> + </select> + </div> + <div class="col-12"> + <textarea + data-test="exp-description" + class="form-control" + rows="2" + :value="store.draft.description" + placeholder="Description (optional)" + @input="onDescription(($event.target as HTMLTextAreaElement).value)" + /> + </div> + </div> +</template> + +<script setup lang="ts"> +import { useLaunchStore } from "django-airavata-common-ui/js/stores/launch"; + +defineProps<{ projects: Array<{ project_id: string; name: string }> }>(); + +const store = useLaunchStore(); + +function onName(v: string) { + store.setMeta({ name: v, project_id: store.draft.project_id, description: store.draft.description }); +} +function onProject(v: string) { + store.setMeta({ name: store.draft.name, project_id: v || null, description: store.draft.description }); +} +function onDescription(v: string) { + store.setMeta({ name: store.draft.name, project_id: store.draft.project_id, description: v }); +} +</script> diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/tests/unit/components/launch/ExperimentMetaHeader.spec.ts b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/tests/unit/components/launch/ExperimentMetaHeader.spec.ts new file mode 100644 index 000000000..484086527 --- /dev/null +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/tests/unit/components/launch/ExperimentMetaHeader.spec.ts @@ -0,0 +1,31 @@ +import { mount } from "@vue/test-utils"; +import { setActivePinia, createPinia } from "pinia"; +import { beforeEach, describe, expect, it } from "vitest"; +import ExperimentMetaHeader from "../../../../js/components/launch/ExperimentMetaHeader.vue"; +import { useLaunchStore } from "django-airavata-common-ui/js/stores/launch"; + +const PROJECTS = [ + { project_id: "p1", name: "my-lab-2026" }, + { project_id: "p2", name: "shared" }, +]; + +describe("ExperimentMetaHeader", () => { + beforeEach(() => setActivePinia(createPinia())); + + it("binds name input to the store", async () => { + const w = mount(ExperimentMetaHeader, { props: { projects: PROJECTS } }); + await w.find("input[data-test='exp-name']").setValue("my-run"); + expect(useLaunchStore().draft.name).toBe("my-run"); + }); + + it("binds project dropdown to the store", async () => { + const w = mount(ExperimentMetaHeader, { props: { projects: PROJECTS } }); + await w.find("select[data-test='exp-project']").setValue("p2"); + expect(useLaunchStore().draft.project_id).toBe("p2"); + }); + + it("renders description as a textarea", () => { + const w = mount(ExperimentMetaHeader, { props: { projects: PROJECTS } }); + expect(w.find("textarea[data-test='exp-description']").exists()).toBe(true); + }); +});
