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 7e7ddf4778719a0cf5d4892fa7dc32db08bf2cde
Author: yasithdev <[email protected]>
AuthorDate: Fri Apr 24 22:55:06 2026 -0400

    feat(launcher): Tab2Runtime assembly + readouts
---
 .../js/components/launch/Tab2Runtime.vue           | 47 ++++++++++++++++++-
 .../unit/components/launch/Tab2Runtime.spec.ts     | 52 ++++++++++++++++++++++
 2 files changed, 97 insertions(+), 2 deletions(-)

diff --git 
a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/launch/Tab2Runtime.vue
 
b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/launch/Tab2Runtime.vue
index 25a445eed..cb7733c2f 100644
--- 
a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/launch/Tab2Runtime.vue
+++ 
b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/launch/Tab2Runtime.vue
@@ -1,2 +1,45 @@
-<template><div /></template>
-<script setup lang="ts"></script>
+<template>
+  <div v-if="store.profile">
+    <RuntimeInputs
+      :profile="store.profile"
+      :model-value="store.draft.runtime"
+      @update:model-value="store.setRuntime($event)"
+    />
+    <p class="small text-muted mt-2">
+      Allocation <code>{{ store.profile.allocation_id }}</code> (auto from 
project) ·
+      <span v-if="pickedCR">
+        Resource <code>{{ pickedCR.compute_resource_id }}</code> ·
+        Compute storage <code>{{ pickedCR.mapped_storage.storage_id }}</code>
+        scratch <code>{{ pickedCR.mapped_storage.scratch_path }}</code>
+      </span>
+    </p>
+  </div>
+  <div v-else class="text-muted">Loading resource profile…</div>
+</template>
+
+<script setup lang="ts">
+import { computed, onMounted, watch } from "vue";
+import { useLaunchStore } from "django-airavata-common-ui/js/stores/launch";
+import { launcherService } from 
"django-airavata-common-ui/js/services/launcherService";
+import RuntimeInputs from "./runtime/RuntimeInputs.vue";
+
+const store = useLaunchStore();
+
+async function refetch(projectId: string) {
+  const p = await launcherService.getProjectResourceProfile(projectId);
+  store.setProfile(p);
+}
+
+onMounted(() => {
+  if (store.draft.project_id) void refetch(store.draft.project_id);
+});
+
+watch(
+  () => store.draft.project_id,
+  (id) => { if (id) void refetch(id); else store.setProfile(null); },
+);
+
+const pickedCR = computed(() =>
+  store.profile?.compute_resources.find((c) => c.compute_resource_id === 
store.draft.runtime.compute_resource_id) ?? null,
+);
+</script>
diff --git 
a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/tests/unit/components/launch/Tab2Runtime.spec.ts
 
b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/tests/unit/components/launch/Tab2Runtime.spec.ts
new file mode 100644
index 000000000..8d59fe6c9
--- /dev/null
+++ 
b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/tests/unit/components/launch/Tab2Runtime.spec.ts
@@ -0,0 +1,52 @@
+import { mount, flushPromises } from "@vue/test-utils";
+import { createPinia, setActivePinia } from "pinia";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+import Tab2Runtime from "../../../../js/components/launch/Tab2Runtime.vue";
+import { useLaunchStore } from "django-airavata-common-ui/js/stores/launch";
+
+const PROFILE = {
+  project_id: "p1", allocation_id: "NSF-1",
+  compute_resources: [{
+    compute_resource_id: "bridges-2", name: "Bridges-2",
+    mapped_storage: { storage_id: "scratch", scratch_path: "/scratch/p1" },
+    partitions: [{ name: "RM", max_walltime: "48:00:00", max_nodes: 64, 
cpus_per_node: 128 }],
+  }],
+};
+
+vi.mock("django-airavata-common-ui/js/services/launcherService", () => ({
+  launcherService: {
+    getProjectResourceProfile: vi.fn(),
+  },
+}));
+
+import { launcherService } from 
"django-airavata-common-ui/js/services/launcherService";
+
+describe("Tab2Runtime", () => {
+  beforeEach(() => {
+    setActivePinia(createPinia());
+    
vi.mocked(launcherService.getProjectResourceProfile).mockResolvedValue(PROFILE);
+    useLaunchStore().setMeta({ name: "x", project_id: "p1", description: "" });
+  });
+
+  it("renders the readout once a CR is picked", async () => {
+    const w = mount(Tab2Runtime);
+    await flushPromises();
+    useLaunchStore().setRuntime({
+      compute_resource_id: "bridges-2", partition: "RM",
+      walltime: "01:00:00", nodes: 1, cpus_per_node: 8,
+    });
+    await flushPromises();
+    expect(w.text()).toContain("NSF-1");
+    expect(w.text()).toContain("bridges-2");
+    expect(w.text()).toContain("/scratch/p1");
+  });
+
+  it("re-fetches the profile when project changes", async () => {
+    const w = mount(Tab2Runtime);
+    await flushPromises();
+    useLaunchStore().setMeta({ name: "x", project_id: "p2", description: "" });
+    await flushPromises();
+    
expect(launcherService.getProjectResourceProfile).toHaveBeenCalledWith("p2");
+    expect(w).toBeTruthy();
+  });
+});

Reply via email to