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);
+  });
+});

Reply via email to