This is an automated email from the ASF dual-hosted git repository. yasith pushed a commit to branch feat/sdk-facade-migration in repository https://gitbox.apache.org/repos/asf/airavata-portals.git
commit ba5e2f42e294d12c7a970f0e9a4bd444da8afc07 Author: yasithdev <[email protected]> AuthorDate: Wed Apr 8 00:49:17 2026 -0500 refactor: migrate Vue 2 to Vue 3, update router and state management Entry points: - Replace `entry((Vue) => { new Vue({...}).$mount() })` pattern with `entry(({ createApp }) => { createApp({...}).mount() })` - Use `h()` from vue for render functions, pass props directly (not wrapped) - Use Vue 3 slot syntax in render functions (object with slot functions) Router: - Replace `new VueRouter({mode: 'history'})` with `createRouter({history: createWebHistory()})` - Replace catch-all `path: '*'` with `path: '/:pathMatch(.*)*'` - Export routes array separately from router.js State management: - Replace `new Vuex.Store()` with `createStore()` from vuex 4 - Remove `Vue.use(Vuex)` calls (app.use(store) in entry points instead) - Update package.json to use vuex ^4.1.0 (pragmatic choice over full pinia migration) Common UI: - Update entry.js to pass createApp factory with auto-installed error handler - Update GlobalErrorHandler to use app.config.errorHandler (not Vue.config) - Update VModelMixin: value -> modelValue, $emit('input') -> $emit('update:modelValue') - Update InputEditorMixin similarly, convert asyncComputed to watch-based approach - Update MainLayout: $slots.sidebar check to !!$slots.sidebar - Remove .native event modifier from 16 Vue files (not needed in Vue 3) Bootstrap / jQuery removal: - Replace jQuery-based tooltip init with Bootstrap 5 JS API in main.js and cms.js - Remove jQuery and popper.js dependencies Web components: - Remove `import Vue from "vue"` and `Vue.use(BootstrapVue)` from web components - Update WebComponentInputEditorMixin for Vue 3 compatibility - Update web-components/store.js to use createStore() - TODO: Full web component migration to defineCustomElement needed --- .../django_airavata/apps/admin/package.json | 2 +- .../statistics/ExperimentStatisticsContainer.vue | 6 +- .../IdentityServiceUserManagementContainer.vue | 2 +- .../admin/static/django_airavata_admin/src/main.js | 37 ++++++----- .../static/django_airavata_admin/src/router.js | 10 +-- .../django_airavata_admin/src/store/index.js | 9 ++- .../django_airavata/apps/auth/package.json | 2 +- .../js/components/UserProfileEditor.vue | 6 +- .../django_airavata_auth/js/entry-user-profile.js | 18 +++-- .../static/django_airavata_auth/js/store/index.js | 9 ++- .../js/entry-parser-details.js | 26 ++++---- .../js/parser-edit-entry-point.js | 25 +++---- .../js/parser-listing-entry-point.js | 14 ++-- .../js/group-create-entry-point.js | 25 +++---- .../js/group-edit-entry-point.js | 27 ++++---- .../js/group-listing-entry-point.js | 14 ++-- .../js/input-editors/InputEditorMixin.js | 77 ++++++++-------------- .../django_airavata/apps/workspace/package.json | 2 +- .../input-editors/CheckboxInputEditor.vue | 2 +- .../input-editors/RadioButtonInputEditor.vue | 2 +- .../experiment/input-editors/StringInputEditor.vue | 2 +- .../input-editors/TextareaInputEditor.vue | 2 +- .../InteractiveParameterStepperWidget.vue | 2 +- .../InteractiveParameterTextInputWidget.vue | 2 +- .../components/storage/UserStorageCreateView.vue | 2 +- .../js/containers/ExperimentListContainer.vue | 2 +- .../js/entry-create-experiment.js | 30 +++++---- .../js/entry-dashboard.js | 30 ++++----- .../js/entry-edit-experiment.js | 29 ++++---- .../js/entry-edit-project.js | 29 ++++---- .../js/entry-experiment-list.js | 28 ++++---- .../js/entry-project-list.js | 25 +++---- .../js/entry-user-storage.js | 35 +++++----- .../js/entry-view-experiment.js | 20 +++--- .../django_airavata_workspace/js/store/index.js | 9 ++- .../js/web-components/ComputeResourceSelector.vue | 2 +- .../ExperimentComputeResourceSelector.vue | 2 +- .../js/web-components/ExperimentEditor.vue | 4 +- .../GroupResourceProfileSelector.vue | 6 +- .../js/web-components/ProjectSelector.vue | 4 +- .../js/web-components/QueueSettingsEditor.vue | 14 ++-- .../input-editors/WebComponentInputEditorMixin.js | 28 ++------ .../js/web-components/store.js | 7 +- .../django_airavata/static/common/js/cms.js | 13 ++-- .../common/js/components/AutocompleteTextInput.vue | 6 +- .../static/common/js/components/MainLayout.vue | 2 +- .../django_airavata/static/common/js/entry.js | 24 +++---- .../static/common/js/errors/GlobalErrorHandler.js | 10 ++- .../django_airavata/static/common/js/main.js | 22 +++---- .../static/common/js/mixins/VModelMixin.js | 19 +++--- .../django_airavata/static/common/js/notices.js | 40 +++++------ 51 files changed, 374 insertions(+), 391 deletions(-) diff --git a/airavata-django-portal/django_airavata/apps/admin/package.json b/airavata-django-portal/django_airavata/apps/admin/package.json index ab02e0593..56c956906 100644 --- a/airavata-django-portal/django_airavata/apps/admin/package.json +++ b/airavata-django-portal/django_airavata/apps/admin/package.json @@ -24,7 +24,7 @@ "vuedraggable": "^4.1.0", "@vuelidate/core": "^2.0.0", "@vuelidate/validators": "^2.0.0", - "pinia": "^2.2.0" + "vuex": "^4.1.0" }, "devDependencies": { "@vitejs/plugin-vue": "^5.0.0", diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentStatisticsContainer.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentStatisticsContainer.vue index db4628e8a..2d2af69bc 100644 --- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentStatisticsContainer.vue +++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentStatisticsContainer.vue @@ -14,7 +14,7 @@ <b-form-input v-model.trim="experimentId" placeholder="Experiment ID" - @keydown.native.enter=" + @keydown.enter=" experimentId && showExperimentDetails(experimentId) " /> @@ -37,7 +37,7 @@ <b-form-input v-model.trim="jobId" placeholder="Job ID" - @keydown.native.enter=" + @keydown.enter=" jobId && showExperimentDetailsForJobId(jobId) " /> @@ -103,7 +103,7 @@ <b-form-input v-model="usernameFilter" placeholder="Username" - @keydown.native.enter="loadStatistics" + @keydown.enter="loadStatistics" /> <b-input-group-append> <b-button @click="removeUsernameFilter"> diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/IdentityServiceUserManagementContainer.vue b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/IdentityServiceUserManagementContainer.vue index 11a2e24b1..57a91bf93 100644 --- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/IdentityServiceUserManagementContainer.vue +++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/IdentityServiceUserManagementContainer.vue @@ -8,7 +8,7 @@ <b-form-input v-model="search" placeholder="Search by name, email or username" - @keydown.native.enter="searchUsers" + @keydown.enter="searchUsers" /> <b-input-group-append> <b-button @click="resetSearch">Reset</b-button> diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/main.js b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/main.js index 8d0fb8fe1..cc6dbf6cd 100644 --- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/main.js +++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/main.js @@ -1,25 +1,32 @@ +import { h } from "vue"; import { components, entry } from "django-airavata-common-ui"; -import VueResource from "vue-resource"; -import VueRouter from "vue-router"; +import { createRouter, createWebHistory } from "vue-router"; import VueFlatPickr from "vue-flatpickr-component"; import App from "./App.vue"; -import router from "./router"; +import { routes } from "./router"; +import createStore from "./store"; import "flatpickr/dist/flatpickr.css"; -import createStore from "./store"; -entry((Vue) => { - Vue.config.productionTip = false; +entry(({ createApp }) => { + const router = createRouter({ + history: createWebHistory("/admin/"), + routes, + }); + + const store = createStore(); - Vue.use(VueResource); - Vue.use(VueRouter); - Vue.use(VueFlatPickr); + const app = createApp({ + render() { + return h(components.MainLayout, null, { + default: () => h(App), + }); + }, + }); - const store = createStore(Vue); + app.use(router); + app.use(store); + app.use(VueFlatPickr); - new Vue({ - store, - render: (h) => h(components.MainLayout, [h(App)]), - router, - }).$mount("#app"); + app.mount("#app"); }); diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/router.js b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/router.js index b5e722e97..bb6d3adea 100644 --- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/router.js +++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/router.js @@ -16,9 +16,7 @@ import IdentityServiceUserManagementContainer from "./components/users/IdentityS import UnverifiedEmailUserManagementContainer from "./components/users/UnverifiedEmailUserManagementContainer.vue"; import UserManagementContainer from "./components/users/UserManagementContainer.vue"; import NoticesManagementContainer from "./components/notices/NoticesManagementContainer.vue"; -import VueRouter from "vue-router"; - -const routes = [ +export const routes = [ { path: "/applications/new", component: ApplicationEditorContainer, @@ -162,8 +160,4 @@ const routes = [ name: "developers", } ]; -export default new VueRouter({ - mode: "history", - base: "/admin/", - routes: routes, -}); +export default routes; diff --git a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/store/index.js b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/store/index.js index 0ee4817ac..0f13350b6 100644 --- a/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/store/index.js +++ b/airavata-django-portal/django_airavata/apps/admin/static/django_airavata_admin/src/store/index.js @@ -1,11 +1,10 @@ -import Vuex from "vuex"; +import { createStore } from "vuex"; import extendedUserProfile from "./modules/extendedUserProfile"; const debug = process.env.NODE_ENV !== "production"; -function createStore(Vue) { - Vue.use(Vuex); - return new Vuex.Store({ +function makeStore() { + return createStore({ modules: { extendedUserProfile, }, @@ -13,4 +12,4 @@ function createStore(Vue) { }); } -export default createStore; +export default makeStore; diff --git a/airavata-django-portal/django_airavata/apps/auth/package.json b/airavata-django-portal/django_airavata/apps/auth/package.json index 298b9d5c4..6561c383e 100644 --- a/airavata-django-portal/django_airavata/apps/auth/package.json +++ b/airavata-django-portal/django_airavata/apps/auth/package.json @@ -18,7 +18,7 @@ "vue": "^3.4.0", "@vuelidate/core": "^2.0.0", "@vuelidate/validators": "^2.0.0", - "pinia": "^2.2.0" + "vuex": "^4.1.0" }, "devDependencies": { "@vitejs/plugin-vue": "^5.0.0", diff --git a/airavata-django-portal/django_airavata/apps/auth/static/django_airavata_auth/js/components/UserProfileEditor.vue b/airavata-django-portal/django_airavata/apps/auth/static/django_airavata_auth/js/components/UserProfileEditor.vue index bbac76ab1..cc9f20f36 100644 --- a/airavata-django-portal/django_airavata/apps/auth/static/django_airavata_auth/js/components/UserProfileEditor.vue +++ b/airavata-django-portal/django_airavata/apps/auth/static/django_airavata_auth/js/components/UserProfileEditor.vue @@ -10,21 +10,21 @@ <b-form-group label="First Name" :disabled="disabled"> <b-form-input v-model="$v.first_name.$model" - @keydown.native.enter="save" + @keydown.enter="save" :state="validateState($v.first_name)" /> </b-form-group> <b-form-group label="Last Name" :disabled="disabled"> <b-form-input v-model="$v.last_name.$model" - @keydown.native.enter="save" + @keydown.enter="save" :state="validateState($v.last_name)" /> </b-form-group> <b-form-group label="Email" :disabled="disabled"> <b-form-input v-model="$v.email.$model" - @keydown.native.enter="save" + @keydown.enter="save" :state="validateState($v.email)" /> <b-form-invalid-feedback v-if="!$v.email.email"> diff --git a/airavata-django-portal/django_airavata/apps/auth/static/django_airavata_auth/js/entry-user-profile.js b/airavata-django-portal/django_airavata/apps/auth/static/django_airavata_auth/js/entry-user-profile.js index 382bfcd21..17a04a0e5 100644 --- a/airavata-django-portal/django_airavata/apps/auth/static/django_airavata_auth/js/entry-user-profile.js +++ b/airavata-django-portal/django_airavata/apps/auth/static/django_airavata_auth/js/entry-user-profile.js @@ -1,11 +1,17 @@ +import { h } from "vue"; import { components, entry } from "django-airavata-common-ui"; import UserProfileContainer from "./containers/UserProfileContainer.vue"; import createStore from "./store"; -entry((Vue) => { - const store = createStore(Vue); - new Vue({ - store, - render: (h) => h(components.MainLayout, [h(UserProfileContainer)]), - }).$mount("#user-profile"); +entry(({ createApp }) => { + const store = createStore(); + const app = createApp({ + render() { + return h(components.MainLayout, null, { + default: () => h(UserProfileContainer), + }); + }, + }); + app.use(store); + app.mount("#user-profile"); }); diff --git a/airavata-django-portal/django_airavata/apps/auth/static/django_airavata_auth/js/store/index.js b/airavata-django-portal/django_airavata/apps/auth/static/django_airavata_auth/js/store/index.js index 8dd262a7c..bdb125868 100644 --- a/airavata-django-portal/django_airavata/apps/auth/static/django_airavata_auth/js/store/index.js +++ b/airavata-django-portal/django_airavata/apps/auth/static/django_airavata_auth/js/store/index.js @@ -1,12 +1,11 @@ -import Vuex from "vuex"; +import { createStore } from "vuex"; import userProfile from "./modules/userProfile"; import extendedUserProfile from "./modules/extendedUserProfile"; const debug = process.env.NODE_ENV !== "production"; -function createStore(Vue) { - Vue.use(Vuex); - return new Vuex.Store({ +function makeStore() { + return createStore({ modules: { userProfile, extendedUserProfile, @@ -15,4 +14,4 @@ function createStore(Vue) { }); } -export default createStore; +export default makeStore; diff --git a/airavata-django-portal/django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/entry-parser-details.js b/airavata-django-portal/django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/entry-parser-details.js index 5ef4a4a56..e16886133 100644 --- a/airavata-django-portal/django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/entry-parser-details.js +++ b/airavata-django-portal/django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/entry-parser-details.js @@ -1,21 +1,12 @@ +import { h } from "vue"; import { components, entry } from "django-airavata-common-ui"; import ParserDetailsContainer from "./containers/ParserDetailsContainer.vue"; -entry((Vue) => { - new Vue({ - render(h) { - return h(components.MainLayout, [ - h(ParserDetailsContainer, { - props: { - parserId: this.parserId, - }, - }), - ]); - }, +entry(({ createApp }) => { + const app = createApp({ data() { return { parserId: null, - launching: false, }; }, beforeMount() { @@ -23,5 +14,14 @@ entry((Vue) => { this.parserId = this.$el.dataset.parserId; } }, - }).$mount("#parser-details"); + render() { + return h(components.MainLayout, null, { + default: () => + h(ParserDetailsContainer, { + parserId: this.parserId, + }), + }); + }, + }); + app.mount("#parser-details"); }); diff --git a/airavata-django-portal/django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/parser-edit-entry-point.js b/airavata-django-portal/django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/parser-edit-entry-point.js index 1c4ed95df..d40bc7093 100644 --- a/airavata-django-portal/django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/parser-edit-entry-point.js +++ b/airavata-django-portal/django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/parser-edit-entry-point.js @@ -1,17 +1,9 @@ +import { h } from "vue"; import { components, entry } from "django-airavata-common-ui"; import ParserEditContainer from "./containers/ParserEditContainer.vue"; -entry((Vue) => { - new Vue({ - render(h) { - return h(components.MainLayout, [ - h(ParserEditContainer, { - props: { - parserId: this.parserId, - }, - }), - ]); - }, +entry(({ createApp }) => { + const app = createApp({ data() { return { parserId: null, @@ -22,5 +14,14 @@ entry((Vue) => { this.parserId = this.$el.dataset.parserId; } }, - }).$mount("#edit-parser"); + render() { + return h(components.MainLayout, null, { + default: () => + h(ParserEditContainer, { + parserId: this.parserId, + }), + }); + }, + }); + app.mount("#edit-parser"); }); diff --git a/airavata-django-portal/django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/parser-listing-entry-point.js b/airavata-django-portal/django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/parser-listing-entry-point.js index 63f8d00a8..5d162a41c 100755 --- a/airavata-django-portal/django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/parser-listing-entry-point.js +++ b/airavata-django-portal/django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/parser-listing-entry-point.js @@ -1,8 +1,14 @@ +import { h } from "vue"; import { components, entry } from "django-airavata-common-ui"; import ParsersManageContainer from "./containers/ParsersManageContainer.vue"; -entry((Vue) => { - new Vue({ - render: (h) => h(components.MainLayout, [h(ParsersManageContainer)]), - }).$mount("#parsers-manage"); +entry(({ createApp }) => { + const app = createApp({ + render() { + return h(components.MainLayout, null, { + default: () => h(ParsersManageContainer), + }); + }, + }); + app.mount("#parsers-manage"); }); diff --git a/airavata-django-portal/django_airavata/apps/groups/static/django_airavata_groups/js/group-create-entry-point.js b/airavata-django-portal/django_airavata/apps/groups/static/django_airavata_groups/js/group-create-entry-point.js index e99116d17..6947c8d53 100644 --- a/airavata-django-portal/django_airavata/apps/groups/static/django_airavata_groups/js/group-create-entry-point.js +++ b/airavata-django-portal/django_airavata/apps/groups/static/django_airavata_groups/js/group-create-entry-point.js @@ -1,17 +1,9 @@ +import { h } from "vue"; import { components, entry } from "django-airavata-common-ui"; import GroupCreateContainer from "./containers/GroupCreateContainer.vue"; -entry((Vue) => { - new Vue({ - render(h) { - return h(components.MainLayout, [ - h(GroupCreateContainer, { - props: { - next: this.next, - }, - }), - ]); - }, +entry(({ createApp }) => { + const app = createApp({ data() { return { next: "/groups/", @@ -22,5 +14,14 @@ entry((Vue) => { this.next = this.$el.dataset.next; } }, - }).$mount("#group-create"); + render() { + return h(components.MainLayout, null, { + default: () => + h(GroupCreateContainer, { + next: this.next, + }), + }); + }, + }); + app.mount("#group-create"); }); diff --git a/airavata-django-portal/django_airavata/apps/groups/static/django_airavata_groups/js/group-edit-entry-point.js b/airavata-django-portal/django_airavata/apps/groups/static/django_airavata_groups/js/group-edit-entry-point.js index b01913847..39d87ec81 100644 --- a/airavata-django-portal/django_airavata/apps/groups/static/django_airavata_groups/js/group-edit-entry-point.js +++ b/airavata-django-portal/django_airavata/apps/groups/static/django_airavata_groups/js/group-edit-entry-point.js @@ -1,18 +1,9 @@ +import { h } from "vue"; import { components, entry } from "django-airavata-common-ui"; import GroupEditContainer from "./containers/GroupEditContainer.vue"; -entry((Vue) => { - new Vue({ - render(h) { - return h(components.MainLayout, [ - h(GroupEditContainer, { - props: { - groupId: this.groupId, - next: this.next, - }, - }), - ]); - }, +entry(({ createApp }) => { + const app = createApp({ data() { return { groupId: null, @@ -27,5 +18,15 @@ entry((Vue) => { this.next = this.$el.dataset.next; } }, - }).$mount("#group-edit"); + render() { + return h(components.MainLayout, null, { + default: () => + h(GroupEditContainer, { + groupId: this.groupId, + next: this.next, + }), + }); + }, + }); + app.mount("#group-edit"); }); diff --git a/airavata-django-portal/django_airavata/apps/groups/static/django_airavata_groups/js/group-listing-entry-point.js b/airavata-django-portal/django_airavata/apps/groups/static/django_airavata_groups/js/group-listing-entry-point.js index b818dafc6..fc87eb6e2 100755 --- a/airavata-django-portal/django_airavata/apps/groups/static/django_airavata_groups/js/group-listing-entry-point.js +++ b/airavata-django-portal/django_airavata/apps/groups/static/django_airavata_groups/js/group-listing-entry-point.js @@ -1,8 +1,14 @@ +import { h } from "vue"; import { components, entry } from "django-airavata-common-ui"; import GroupsManageContainer from "./containers/GroupsManageContainer.vue"; -entry((Vue) => { - new Vue({ - render: (h) => h(components.MainLayout, [h(GroupsManageContainer)]), - }).$mount("#group-list"); +entry(({ createApp }) => { + const app = createApp({ + render() { + return h(components.MainLayout, null, { + default: () => h(GroupsManageContainer), + }); + }, + }); + app.mount("#group-list"); }); diff --git a/airavata-django-portal/django_airavata/apps/workspace/django-airavata-workspace-plugin-api/js/input-editors/InputEditorMixin.js b/airavata-django-portal/django_airavata/apps/workspace/django-airavata-workspace-plugin-api/js/input-editors/InputEditorMixin.js index dd2866f14..3af4e8655 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/django-airavata-workspace-plugin-api/js/input-editors/InputEditorMixin.js +++ b/airavata-django-portal/django_airavata/apps/workspace/django-airavata-workspace-plugin-api/js/input-editors/InputEditorMixin.js @@ -4,7 +4,7 @@ import { models } from "django-airavata-api"; export default { props: { - value: { + modelValue: { type: String, }, experimentInput: { @@ -24,51 +24,19 @@ export default { default: false, }, }, + emits: ["update:modelValue", "valid", "invalid"], data() { return { - data: this.value, + data: this.modelValue, inputHasBegun: false, + // TODO: asyncComputed removed in Vue 3 - these need to be converted to + // watch + async methods or composables + validationResults: { value: [] }, + validationMessages: [], + valid: false, + componentValidState: null, }; }, - asyncComputed: { - validationResults: { - get () { - let results = this.experimentInput.validate(this.data); - let value = [] - if ("value" in results) { - value = Promise.all(results["value"]).then( - arr => arr.filter(x => x !== null) - ) - } - return { - "value": value - }; - }, - default () { - return { - "value": [] - } - } - }, - validationMessages: function () { - return "value" in this.validationResults - ? this.validationResults["value"] - : []; - }, - valid: function () { - if (this.validationMessages) - return this.validationMessages.length === 0; - else - return false; - }, - componentValidState: function () { - if (this.inputHasBegun) { - return this.valid; - } else { - return null; - } - }, - }, computed: { editorConfig: function () { return this.experimentInput.editorConfig; @@ -77,7 +45,7 @@ export default { methods: { valueChanged: function () { this.inputHasBegun = true; - this.$emit("input", this.data); + this.$emit("update:modelValue", this.data); }, checkValidation: function () { if (this.valid) { @@ -86,19 +54,30 @@ export default { this.$emit("invalid", this.validationMessages); } }, + async updateValidation() { + const results = this.experimentInput.validate(this.data); + let value = []; + if ("value" in results) { + value = await Promise.all(results["value"]).then((arr) => + arr.filter((x) => x !== null) + ); + } + this.validationResults = { value }; + this.validationMessages = value; + this.valid = this.validationMessages.length === 0; + this.componentValidState = this.inputHasBegun ? this.valid : null; + this.checkValidation(); + }, }, created: function () { - this.checkValidation(); + this.updateValidation(); }, watch: { - value(newValue) { + modelValue(newValue) { this.data = newValue; }, - valid() { - this.checkValidation(); + data() { + this.updateValidation(); }, - validationMessages() { - this.checkValidation(); - } }, }; diff --git a/airavata-django-portal/django_airavata/apps/workspace/package.json b/airavata-django-portal/django_airavata/apps/workspace/package.json index 12c899212..ca8364386 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/package.json +++ b/airavata-django-portal/django_airavata/apps/workspace/package.json @@ -27,7 +27,7 @@ "vue-flatpickr-component": "^11.0.0", "vue-router": "^4.3.0", "vue-slider-component": "^4.1.0", - "pinia": "^2.2.0" + "vuex": "^4.1.0" }, "devDependencies": { "@vitejs/plugin-vue": "^5.0.0", diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/CheckboxInputEditor.vue b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/CheckboxInputEditor.vue index 1c363de4f..fb0343bff 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/CheckboxInputEditor.vue +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/CheckboxInputEditor.vue @@ -9,7 +9,7 @@ :state="componentValidState" :disabled="readOnly" @input="selectionsChanged" - @input.native.stop + @input.stop /> </template> diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/RadioButtonInputEditor.vue b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/RadioButtonInputEditor.vue index 3a19b171f..4edbc9cd3 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/RadioButtonInputEditor.vue +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/RadioButtonInputEditor.vue @@ -9,7 +9,7 @@ :state="componentValidState" :disabled="readOnly" @input="valueChanged" - @input.native.stop + @input.stop /> </template> diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/StringInputEditor.vue b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/StringInputEditor.vue index a272f2c79..2f87e65e1 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/StringInputEditor.vue +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/StringInputEditor.vue @@ -8,7 +8,7 @@ :state="componentValidState" :disabled="readOnly" @input="valueChanged" - @input.native.stop + @input.stop /> </template> diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/TextareaInputEditor.vue b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/TextareaInputEditor.vue index 8056840ad..ab44590be 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/TextareaInputEditor.vue +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/TextareaInputEditor.vue @@ -8,7 +8,7 @@ :disabled="readOnly" :state="componentValidState" @input="valueChanged" - @input.native.stop + @input.stop /> </template> diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/interactive-parameters/InteractiveParameterStepperWidget.vue b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/interactive-parameters/InteractiveParameterStepperWidget.vue index 9f61e93ff..6390ca832 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/interactive-parameters/InteractiveParameterStepperWidget.vue +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/interactive-parameters/InteractiveParameterStepperWidget.vue @@ -8,7 +8,7 @@ :max="parameter.max" :step="parameter.step || 'any'" @input="updateValue" - @keydown.native.enter="enterKeyPressed" + @keydown.enter="enterKeyPressed" /> <b-input-group-append> <b-button variant="primary" :disabled="disabled" @click="submit" diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/interactive-parameters/InteractiveParameterTextInputWidget.vue b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/interactive-parameters/InteractiveParameterTextInputWidget.vue index 6b9b65d14..c71fec375 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/interactive-parameters/InteractiveParameterTextInputWidget.vue +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/interactive-parameters/InteractiveParameterTextInputWidget.vue @@ -4,7 +4,7 @@ ref="textInput" :value="value" @input="currentValue = $event" - @keydown.native.enter="enterKeyPressed" + @keydown.enter="enterKeyPressed" /> <b-input-group-append> <b-button variant="primary" :disabled="disabled" @click="submit" diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStorageCreateView.vue b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStorageCreateView.vue index 7ff525da4..dc2291107 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStorageCreateView.vue +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStorageCreateView.vue @@ -26,7 +26,7 @@ <b-form-input v-model="dirName" placeholder="New directory name" - @keydown.native.enter="addDirectory" + @keydown.enter="addDirectory" ></b-form-input> <b-input-group-append> <b-button @click="addDirectory" :disabled="!this.dirName" diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/ExperimentListContainer.vue b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/ExperimentListContainer.vue index d2435787f..6ebb268a9 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/ExperimentListContainer.vue +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/ExperimentListContainer.vue @@ -14,7 +14,7 @@ v-if="defaultOptionSelected" v-model="search" placeholder="Search Experiments" - @keydown.native.enter="searchExperiments" + @keydown.enter="searchExperiments" /> <b-form-select v-if="applicationSelected" diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-create-experiment.js b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-create-experiment.js index 7e3b2b1b4..59bfb098c 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-create-experiment.js +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-create-experiment.js @@ -1,24 +1,15 @@ +import { h } from "vue"; import { components, entry } from "django-airavata-common-ui"; import CreateExperimentContainer from "./containers/CreateExperimentContainer.vue"; import "../../scss/styles.scss"; -entry((Vue) => { - new Vue({ - render(h) { - return h(components.MainLayout, [ - h(CreateExperimentContainer, { - props: { - appModuleId: this.appModuleId, - userInputValues: this.userInputValues, - experimentDataDir: this.experimentDataDir, - }, - }), - ]); - }, +entry(({ createApp }) => { + const app = createApp({ data() { return { appModuleId: null, userInputValues: null, + experimentDataDir: null, }; }, beforeMount() { @@ -32,5 +23,16 @@ entry((Vue) => { this.experimentDataDir = this.$el.dataset.experimentDataDir; } }, - }).$mount("#create-experiment"); + render() { + return h(components.MainLayout, null, { + default: () => + h(CreateExperimentContainer, { + appModuleId: this.appModuleId, + userInputValues: this.userInputValues, + experimentDataDir: this.experimentDataDir, + }), + }); + }, + }); + app.mount("#create-experiment"); }); diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-dashboard.js b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-dashboard.js index 1e04ed688..52812fe3d 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-dashboard.js +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-dashboard.js @@ -1,21 +1,10 @@ +import { h } from "vue"; import { components, entry } from "django-airavata-common-ui"; import DashboardContainer from "./containers/DashboardContainer.vue"; import RecentExperimentsContainer from "./containers/RecentExperimentsContainer.vue"; -entry((Vue) => { - new Vue({ - render(h) { - return h(components.MainLayout, [ - h(DashboardContainer), - h(RecentExperimentsContainer, { - props: { - viewAllExperiments: this.viewAllExperiments, - username: this.username, - }, - slot: "sidebar", - }), - ]); - }, +entry(({ createApp }) => { + const app = createApp({ data() { return { viewAllExperiments: null, @@ -26,5 +15,16 @@ entry((Vue) => { this.viewAllExperiments = this.$el.dataset.viewAllExperiments; this.username = this.$el.dataset.username; }, - }).$mount("#dashboard"); + render() { + return h(components.MainLayout, null, { + default: () => h(DashboardContainer), + sidebar: () => + h(RecentExperimentsContainer, { + viewAllExperiments: this.viewAllExperiments, + username: this.username, + }), + }); + }, + }); + app.mount("#dashboard"); }); diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-edit-experiment.js b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-edit-experiment.js index bce1d6b9c..68f1b56b8 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-edit-experiment.js +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-edit-experiment.js @@ -1,22 +1,10 @@ +import { h } from "vue"; import { components, entry } from "django-airavata-common-ui"; import EditExperimentContainer from "./containers/EditExperimentContainer.vue"; import "../../scss/styles.scss"; -// Expect a template with id "edit-experiment" and experiment-id data attribute -// -// <div id="edit-experiment" data-experiment-id="..expid.."/> - -entry((Vue) => { - new Vue({ - render(h) { - return h(components.MainLayout, [ - h(EditExperimentContainer, { - props: { - experimentId: this.experimentId, - }, - }), - ]); - }, +entry(({ createApp }) => { + const app = createApp({ data() { return { experimentId: null, @@ -25,5 +13,14 @@ entry((Vue) => { beforeMount() { this.experimentId = this.$el.dataset.experimentId; }, - }).$mount("#edit-experiment"); + render() { + return h(components.MainLayout, null, { + default: () => + h(EditExperimentContainer, { + experimentId: this.experimentId, + }), + }); + }, + }); + app.mount("#edit-experiment"); }); diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-edit-project.js b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-edit-project.js index c7bee575a..f6693d369 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-edit-project.js +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-edit-project.js @@ -1,21 +1,9 @@ +import { h } from "vue"; import { components, entry } from "django-airavata-common-ui"; import EditProjectContainer from "./containers/EditProjectContainer.vue"; -// Expect a template with id "edit-project" and project-id data attribute -// -// <div id="edit-project" data-project-id="..projectID.."/> - -entry((Vue) => { - new Vue({ - render(h) { - return h(components.MainLayout, [ - h(EditProjectContainer, { - props: { - projectId: this.projectId, - }, - }), - ]); - }, +entry(({ createApp }) => { + const app = createApp({ data() { return { projectId: null, @@ -24,5 +12,14 @@ entry((Vue) => { beforeMount() { this.projectId = this.$el.dataset.projectId; }, - }).$mount("#edit-project"); + render() { + return h(components.MainLayout, null, { + default: () => + h(EditProjectContainer, { + projectId: this.projectId, + }), + }); + }, + }); + app.mount("#edit-project"); }); diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-experiment-list.js b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-experiment-list.js index 4c0c32516..1f618ed1a 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-experiment-list.js +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-experiment-list.js @@ -1,20 +1,9 @@ +import { h } from "vue"; import { components, entry } from "django-airavata-common-ui"; import ExperimentListContainer from "./containers/ExperimentListContainer.vue"; -import VueFlatPickr from "vue-flatpickr-component"; -import "flatpickr/dist/flatpickr.css"; -entry((Vue) => { - Vue.use(VueFlatPickr); - new Vue({ - render(h) { - return h(components.MainLayout, [ - h(ExperimentListContainer, { - props: { - initialExperimentsData: this.experimentsData, - }, - }), - ]); - }, +entry(({ createApp }) => { + const app = createApp({ data() { return { experimentsData: null, @@ -25,5 +14,14 @@ entry((Vue) => { this.experimentsData = JSON.parse(this.$el.dataset.experimentsData); } }, - }).$mount("#experiment-list"); + render() { + return h(components.MainLayout, null, { + default: () => + h(ExperimentListContainer, { + initialExperimentsData: this.experimentsData, + }), + }); + }, + }); + app.mount("#experiment-list"); }); diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-project-list.js b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-project-list.js index 26bb41ea5..5bd06b050 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-project-list.js +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-project-list.js @@ -1,17 +1,9 @@ +import { h } from "vue"; import { components, entry } from "django-airavata-common-ui"; import ProjectListContainer from "./containers/ProjectListContainer.vue"; -entry((Vue) => { - new Vue({ - render(h) { - return h(components.MainLayout, [ - h(ProjectListContainer, { - props: { - initialProjectsData: this.projectsData, - }, - }), - ]); - }, +entry(({ createApp }) => { + const app = createApp({ data() { return { projectsData: null, @@ -22,5 +14,14 @@ entry((Vue) => { this.projectsData = JSON.parse(this.$el.dataset.projectsData); } }, - }).$mount("#project-list"); + render() { + return h(components.MainLayout, null, { + default: () => + h(ProjectListContainer, { + initialProjectsData: this.projectsData, + }), + }); + }, + }); + app.mount("#project-list"); }); diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-user-storage.js b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-user-storage.js index a6bb903c7..cc3266a26 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-user-storage.js +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-user-storage.js @@ -1,26 +1,29 @@ -import {components, entry} from "django-airavata-common-ui"; +import { h } from "vue"; +import { components, entry } from "django-airavata-common-ui"; +import { createRouter, createWebHistory } from "vue-router"; import UserStorageContainer from "./containers/UserStorageContainer.vue"; import UserStoragePathViewer from "./components/storage/UserStoragePathViewer.vue"; -import VueRouter from "vue-router"; - const routes = [ { - path: "*", + path: "/:pathMatch(.*)*", component: UserStoragePathViewer, }, ]; -const router = new VueRouter({ - mode: "history", - base: "/workspace/storage", - routes: routes, -}); -entry((Vue) => { - Vue.use(VueRouter); - new Vue({ - render(h) { - return h(components.MainLayout, [h(UserStorageContainer)]); + +entry(({ createApp }) => { + const router = createRouter({ + history: createWebHistory("/workspace/storage"), + routes, + }); + + const app = createApp({ + render() { + return h(components.MainLayout, null, { + default: () => h(UserStorageContainer), + }); }, - router, - }).$mount("#user-storage"); + }); + app.use(router); + app.mount("#user-storage"); }); diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-view-experiment.js b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-view-experiment.js index 7eb7cffea..ddd652abf 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-view-experiment.js +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-view-experiment.js @@ -1,15 +1,12 @@ +import { h } from "vue"; import { components, entry } from "django-airavata-common-ui"; import { mapActions } from "vuex"; import ExperimentSummary from "./components/experiment/ExperimentSummary.vue"; import createStore from "./store"; -entry((Vue) => { - const store = createStore(Vue); - new Vue({ - store, - render(h) { - return h(components.MainLayout, [h(ExperimentSummary)]); - }, +entry(({ createApp }) => { + const store = createStore(); + const app = createApp({ async beforeMount() { const fullExperimentData = JSON.parse( this.$el.dataset.fullExperimentData @@ -26,5 +23,12 @@ entry((Vue) => { "setLaunching", ]), }, - }).$mount("#view-experiment"); + render() { + return h(components.MainLayout, null, { + default: () => h(ExperimentSummary), + }); + }, + }); + app.use(store); + app.mount("#view-experiment"); }); diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/store/index.js b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/store/index.js index e833bd1a1..534cb8ba8 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/store/index.js +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/store/index.js @@ -1,11 +1,10 @@ -import Vuex from "vuex"; +import { createStore } from "vuex"; import viewExperiment from "./modules/view-experiment"; const debug = process.env.NODE_ENV !== "production"; -function createStore(Vue) { - Vue.use(Vuex); - return new Vuex.Store({ +function makeStore() { + return createStore({ modules: { viewExperiment, }, @@ -13,4 +12,4 @@ function createStore(Vue) { }); } -export default createStore; +export default makeStore; diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ComputeResourceSelector.vue b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ComputeResourceSelector.vue index b1c52fdb4..0ae5edb44 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ComputeResourceSelector.vue +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ComputeResourceSelector.vue @@ -6,7 +6,7 @@ :options="computeResourceOptions" required @input="computeResourceChanged" - @input.native.stop + @input.stop :disabled="disabled || computeResourceOptions.length === 0" > <template slot="first"> diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ExperimentComputeResourceSelector.vue b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ExperimentComputeResourceSelector.vue index 7f047775a..30f1b5f70 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ExperimentComputeResourceSelector.vue +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ExperimentComputeResourceSelector.vue @@ -4,7 +4,7 @@ :value="resourceHostId" :disabled="disabled" :includedComputeResources="computeResources" - @input.native.stop="computeResourceChanged" + @input.stop="computeResourceChanged" /> </div> </template> diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ExperimentEditor.vue b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ExperimentEditor.vue index c45d9f17c..79a222f94 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ExperimentEditor.vue +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ExperimentEditor.vue @@ -34,12 +34,10 @@ </template> <script> -import Vue from "vue"; + import store from "./store"; import { mapGetters } from "vuex"; -import { BootstrapVue } from "bootstrap-vue"; import urls from "../utils/urls"; -Vue.use(BootstrapVue); export default { props: { diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/GroupResourceProfileSelector.vue b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/GroupResourceProfileSelector.vue index 3546dc73b..b4e97c15a 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/GroupResourceProfileSelector.vue +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/GroupResourceProfileSelector.vue @@ -6,7 +6,7 @@ :options="groupResourceProfileOptions" required @change="groupResourceProfileChanged" - @input.native.stop + @input.stop :disabled="disabled" > <template slot="first"> @@ -19,11 +19,9 @@ </template> <script> -import Vue from "vue"; -import { BootstrapVue } from "bootstrap-vue"; + import store from "./store"; import { mapGetters } from "vuex"; -Vue.use(BootstrapVue); export default { name: "group-resource-profile-selector", diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ProjectSelector.vue b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ProjectSelector.vue index 801453ce2..cab84e859 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ProjectSelector.vue +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ProjectSelector.vue @@ -27,11 +27,9 @@ </template> <script> -import Vue from "vue"; + import store from "./store"; import { mapGetters } from "vuex"; -import { BootstrapVue } from "bootstrap-vue"; -Vue.use(BootstrapVue); export default { props: { diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/QueueSettingsEditor.vue b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/QueueSettingsEditor.vue index d8f8e9460..36aa03967 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/QueueSettingsEditor.vue +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/QueueSettingsEditor.vue @@ -42,7 +42,7 @@ :options="queueOptions" required @change="queueChanged" - @input.native.stop + @input.stop > </b-form-select> <div slot="description">{{ queueDescription }}</div> @@ -57,7 +57,7 @@ :max="maxAllowedNodes" :value="getNodeCount" required - @input.native.stop="updateNodeCount" + @input.stop="updateNodeCount" > </b-form-input> <div slot="description"> @@ -73,7 +73,7 @@ :max="maxAllowedCores" :value="getTotalCPUCount" required - @input.native.stop="updateTotalCPUCount" + @input.stop="updateTotalCPUCount" > </b-form-input> <div slot="description"> @@ -106,7 +106,7 @@ :max="maxAllowedWalltime" :value="getWallTimeLimit" required - @input.native.stop="updateWallTimeLimit" + @input.stop="updateWallTimeLimit" > </b-form-input> </b-input-group> @@ -127,7 +127,7 @@ min="0" :max="maxMemory" :value="getTotalPhysicalMemory" - @input.native.stop="updateTotalPhysicalMemory" + @input.stop="updateTotalPhysicalMemory" > </b-form-input> </b-input-group> @@ -148,11 +148,9 @@ <script> import { utils } from "django-airavata-api"; -import Vue from "vue"; + import store from "./store"; import { mapGetters } from "vuex"; -import { BootstrapVue } from "bootstrap-vue"; -Vue.use(BootstrapVue); export default { store: store, diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/input-editors/WebComponentInputEditorMixin.js b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/input-editors/WebComponentInputEditorMixin.js index da7bf54f3..ba837c3ed 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/input-editors/WebComponentInputEditorMixin.js +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/input-editors/WebComponentInputEditorMixin.js @@ -1,33 +1,18 @@ -import Vue from "vue"; -import { BootstrapVue } from "bootstrap-vue"; -import AsyncComputed from "vue-async-computed"; import { utils } from "django-airavata-common-ui"; import store from "../store"; -Vue.use(BootstrapVue); -Vue.use(AsyncComputed); export default { props: { - value: String, + modelValue: String, name: String, }, - store: store, - mounted() { - this.$nextTick(() => { - for (const key of Object.keys(this.$props)) { - // workaround for issues around setting props before WC connected, - // see https://github.com/vuejs/vue-web-component-wrapper/pull/81 - - // copy properties set on host element to wrapper component - // (mostly this is done so that the options array can be set by client code) - this.$parent.props[key] = this.$el.getRootNode().host[key]; - } - }) - }, + emits: ["update:modelValue"], + // TODO: web components need Vue 3 defineCustomElement migration + // store: store, data() { return { - data: this.value, + data: this.modelValue, }; }, computed: { @@ -45,6 +30,7 @@ export default { valueChanged(value) { if (value !== this.data) { this.data = value; + this.$emit("update:modelValue", this.data); const inputEvent = new CustomEvent("input", { detail: [this.data], composed: true, @@ -55,7 +41,7 @@ export default { }, }, watch: { - value(value) { + modelValue(value) { this.data = value; }, }, diff --git a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/store.js b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/store.js index 132249943..971d09f81 100644 --- a/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/store.js +++ b/airavata-django-portal/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/store.js @@ -1,8 +1,5 @@ import { errors, services, utils } from "django-airavata-api"; -import Vue from "vue"; -import Vuex from "vuex"; - -Vue.use(Vuex); +import { createStore } from "vuex"; const PROMISES = { workspacePreferences: null, @@ -836,7 +833,7 @@ export const getters = { : false, }; -export default new Vuex.Store({ +export default createStore({ strict: process.env.NODE_ENV !== "production", state: { experiment: null, diff --git a/airavata-django-portal/django_airavata/static/common/js/cms.js b/airavata-django-portal/django_airavata/static/common/js/cms.js index 44becdf9d..91eb64aec 100644 --- a/airavata-django-portal/django_airavata/static/common/js/cms.js +++ b/airavata-django-portal/django_airavata/static/common/js/cms.js @@ -1,9 +1,14 @@ -import bootstrap from "bootstrap"; // eslint-disable-line no-unused-vars -import $ from "jquery"; +import * as bootstrap from "bootstrap"; import "bootstrap/dist/css/bootstrap.css"; import "@fortawesome/fontawesome-free/css/all.css"; -$(function () { - $('[data-toggle="tooltip"]').tooltip(); +// Initialize Bootstrap tooltips +document.addEventListener("DOMContentLoaded", () => { + const tooltipTriggerList = document.querySelectorAll( + '[data-bs-toggle="tooltip"]' + ); + tooltipTriggerList.forEach( + (tooltipTriggerEl) => new bootstrap.Tooltip(tooltipTriggerEl) + ); }); diff --git a/airavata-django-portal/django_airavata/static/common/js/components/AutocompleteTextInput.vue b/airavata-django-portal/django_airavata/static/common/js/components/AutocompleteTextInput.vue index 18eb10096..9fe760b69 100644 --- a/airavata-django-portal/django_airavata/static/common/js/components/AutocompleteTextInput.vue +++ b/airavata-django-portal/django_airavata/static/common/js/components/AutocompleteTextInput.vue @@ -9,9 +9,9 @@ :value="searchValue" :placeholder="placeholder" @input="updateSearchValue" - @keydown.native.enter="enter" - @keydown.native.down="down" - @keydown.native.up="up" + @keydown.enter="enter" + @keydown.down="down" + @keydown.up="up" ></b-form-input> </b-input-group> <b-list-group class="autocomplete-suggestion-list" v-if="open"> diff --git a/airavata-django-portal/django_airavata/static/common/js/components/MainLayout.vue b/airavata-django-portal/django_airavata/static/common/js/components/MainLayout.vue index 081ddeafe..c1c0af9df 100644 --- a/airavata-django-portal/django_airavata/static/common/js/components/MainLayout.vue +++ b/airavata-django-portal/django_airavata/static/common/js/components/MainLayout.vue @@ -20,7 +20,7 @@ export default { name: "main-layout", computed: { hasSidebar() { - return this.$slots.sidebar; + return !!this.$slots.sidebar; }, }, components: { diff --git a/airavata-django-portal/django_airavata/static/common/js/entry.js b/airavata-django-portal/django_airavata/static/common/js/entry.js index a9041c653..5f45d795b 100644 --- a/airavata-django-portal/django_airavata/static/common/js/entry.js +++ b/airavata-django-portal/django_airavata/static/common/js/entry.js @@ -1,25 +1,21 @@ -import Vue from "vue"; -import BootstrapVue from "bootstrap-vue"; +import { createApp as vueCreateApp } from "vue"; import GlobalErrorHandler from "./errors/GlobalErrorHandler"; -import AsyncComputed from "vue-async-computed"; GlobalErrorHandler.init(); -// This is imported globally on the website (see main.js) so no need to include -// it again in this view -// import 'bootstrap/dist/css/bootstrap.css' -import "bootstrap-vue/dist/bootstrap-vue.css"; - /** * Common entry point function. Sets up common entry point functionality and - * then calls the passed function with the Vue class as the first argument. + * then calls the passed function with a createApp factory that auto-installs + * the global error handler. * - * @param {Function} entryPointFunction + * @param {Function} entryPointFunction - receives { createApp } */ export default function entry(entryPointFunction) { - // Common Vue configuration - Vue.use(BootstrapVue); - Vue.use(AsyncComputed) + function createApp(options) { + const app = vueCreateApp(options); + GlobalErrorHandler.installVueErrorHandler(app); + return app; + } - entryPointFunction(Vue); + entryPointFunction({ createApp }); } diff --git a/airavata-django-portal/django_airavata/static/common/js/errors/GlobalErrorHandler.js b/airavata-django-portal/django_airavata/static/common/js/errors/GlobalErrorHandler.js index 99dfefb74..ad6aef25f 100644 --- a/airavata-django-portal/django_airavata/static/common/js/errors/GlobalErrorHandler.js +++ b/airavata-django-portal/django_airavata/static/common/js/errors/GlobalErrorHandler.js @@ -1,11 +1,17 @@ -import Vue from "vue"; import { errors } from "django-airavata-api"; class GlobalErrorHandler { init() { console.log("Initializing GlobalErrorHandler..."); // eslint-disable-line no-console window.onerror = this.handleGlobalError; - Vue.config.errorHandler = this.vueGlobalErrorHandler; + } + + /** + * Install the Vue error handler on a Vue 3 app instance. + * Call this after createApp() to attach the Vue error handler. + */ + installVueErrorHandler(app) { + app.config.errorHandler = this.vueGlobalErrorHandler; } handleGlobalError(msg, url, lineNo, columnNo, error) { diff --git a/airavata-django-portal/django_airavata/static/common/js/main.js b/airavata-django-portal/django_airavata/static/common/js/main.js index 52575a24d..3608f83f5 100644 --- a/airavata-django-portal/django_airavata/static/common/js/main.js +++ b/airavata-django-portal/django_airavata/static/common/js/main.js @@ -1,17 +1,15 @@ -import bootstrap from "bootstrap"; // eslint-disable-line no-unused-vars -import $ from "jquery"; - -// Expose jQuery on the global object -window.$ = window.jQuery = $; +import * as bootstrap from "bootstrap"; import "bootstrap/dist/css/bootstrap.css"; import "@fortawesome/fontawesome-free/css/all.css"; import "../scss/main.scss"; -$(function () { - $('[data-toggle="tooltip"]').tooltip(); -}); -// CMS integration -// $('.carousel').carousel({ -// interval: 2000 -// }) +// Initialize Bootstrap tooltips +document.addEventListener("DOMContentLoaded", () => { + const tooltipTriggerList = document.querySelectorAll( + '[data-bs-toggle="tooltip"]' + ); + tooltipTriggerList.forEach( + (tooltipTriggerEl) => new bootstrap.Tooltip(tooltipTriggerEl) + ); +}); diff --git a/airavata-django-portal/django_airavata/static/common/js/mixins/VModelMixin.js b/airavata-django-portal/django_airavata/static/common/js/mixins/VModelMixin.js index d3887c089..b3c8068c6 100644 --- a/airavata-django-portal/django_airavata/static/common/js/mixins/VModelMixin.js +++ b/airavata-django-portal/django_airavata/static/common/js/mixins/VModelMixin.js @@ -4,21 +4,21 @@ export default { watch: { data: { handler: function (newValue, oldValue) { - // Only emit 'input' for objects when one of their deep properties has + // Only emit 'update:modelValue' for objects when one of their deep properties has // changed to prevent infinite loop since 'data' is recloned whenever - // 'value' changes - if (typeof this.value === "object" && newValue === oldValue) { - this.$emit("input", newValue); + // 'modelValue' changes + if (typeof this.modelValue === "object" && newValue === oldValue) { + this.$emit("update:modelValue", newValue); } else if ( - (this.value === null || typeof this.value !== "object") && + (this.modelValue === null || typeof this.modelValue !== "object") && newValue !== oldValue ) { - this.$emit("input", newValue); + this.$emit("update:modelValue", newValue); } }, deep: true, }, - value: { + modelValue: { handler: function (newValue) { this.data = this.copyValue(newValue); }, @@ -45,12 +45,13 @@ export default { }, data: function () { return { - data: this.copyValue(this.value), + data: this.copyValue(this.modelValue), }; }, props: { - value: { + modelValue: { required: true, }, }, + emits: ["update:modelValue"], }; diff --git a/airavata-django-portal/django_airavata/static/common/js/notices.js b/airavata-django-portal/django_airavata/static/common/js/notices.js index 5ad32f63f..26fd32def 100644 --- a/airavata-django-portal/django_airavata/static/common/js/notices.js +++ b/airavata-django-portal/django_airavata/static/common/js/notices.js @@ -1,23 +1,25 @@ -import Vue from "vue"; +import { createApp, h } from "vue"; import GatewayNoticesContainer from "./components/GatewayNoticesContainer"; -new Vue({ - render(h) { - return h(GatewayNoticesContainer, { - props: { +const el = document.getElementById("gateway-notices"); +if (el) { + const app = createApp({ + data() { + return { + unreadCount: null, + notices: null, + }; + }, + beforeMount() { + this.unreadCount = parseInt(this.$el.dataset.unreadCount); + this.notices = JSON.parse(this.$el.dataset.notices); + }, + render() { + return h(GatewayNoticesContainer, { unreadCount: this.unreadCount, notices: this.notices, - }, - }); - }, - data() { - return { - unreadCount: null, - notices: null, - }; - }, - beforeMount() { - this.unreadCount = parseInt(this.$el.dataset.unreadCount); - this.notices = JSON.parse(this.$el.dataset.notices); - }, -}).$mount("#gateway-notices"); + }); + }, + }); + app.mount("#gateway-notices"); +}
