From 09d8d36678ec97cbb971010dbebbefa6a7f896df Mon Sep 17 00:00:00 2001 From: Ramon Wenger Date: Wed, 23 Mar 2022 16:21:06 +0100 Subject: [PATCH] Apply code changes from migration guide for Vue 3 --- client/build/webpack.base.conf.js | 2 +- client/src/App.vue | 68 ++-- client/src/components/HeaderBar.vue | 17 +- client/src/components/MobileHeader.vue | 2 +- client/src/components/ScrollUp.vue | 2 +- client/src/components/StudentSubmission.vue | 28 +- .../book-navigation/ContentNavigation.vue | 10 +- .../book-navigation/TopicNavigation.vue | 2 +- .../content-block-form/ContentBlockForm.vue | 4 +- .../ContentElementActions.vue | 4 +- .../src/components/content-forms/TipTap.vue | 46 +++ .../components/instruments/FilterGroup.vue | 5 +- .../components/page-form/PageFormInput.vue | 2 +- .../components/portfolio/ProjectEntryForm.vue | 37 +- .../src/components/portfolio/ProjectForm.vue | 32 ++ .../src/components/profile/EditNameWizard.vue | 24 ++ .../ui/file-upload/SimpleFileUpload.vue | 12 + .../file-upload/SimpleFileUploadWithIcon.vue | 2 +- .../directives/{auto-grow.js => auto-grow.ts} | 6 +- client/src/directives/click-outside.js | 14 - client/src/directives/click-outside.ts | 23 ++ client/src/layouts/DefaultFooter.vue | 217 +++++++----- client/src/layouts/PublicLayout.vue | 103 +++--- client/src/main.js | 160 +++++---- client/src/pages/article.vue | 212 ++++++------ client/src/pages/createContentBlock.vue | 145 ++++---- client/src/pages/portfolio/project.vue | 2 +- client/src/pages/topic-page.vue | 324 +++++++++--------- client/src/plugins/modal.ts | 51 +-- client/src/shims-vue.d.ts | 20 +- 30 files changed, 903 insertions(+), 673 deletions(-) rename client/src/directives/{auto-grow.js => auto-grow.ts} (80%) delete mode 100644 client/src/directives/click-outside.js create mode 100644 client/src/directives/click-outside.ts diff --git a/client/build/webpack.base.conf.js b/client/build/webpack.base.conf.js index 6ef67bcb..1e4a0590 100644 --- a/client/build/webpack.base.conf.js +++ b/client/build/webpack.base.conf.js @@ -42,7 +42,7 @@ module.exports = { '@': resolve('src'), styles: resolve('src/styles'), gql: resolve('src/graphql/gql'), - // vue: '@vue/compat', + vue: '@vue/compat', }, }, module: { diff --git a/client/src/App.vue b/client/src/App.vue index 253967df..8eda5d14 100644 --- a/client/src/App.vue +++ b/client/src/App.vue @@ -9,38 +9,54 @@ diff --git a/client/src/components/book-navigation/ContentNavigation.vue b/client/src/components/book-navigation/ContentNavigation.vue index 5edec89a..dd1d171d 100644 --- a/client/src/components/book-navigation/ContentNavigation.vue +++ b/client/src/components/book-navigation/ContentNavigation.vue @@ -7,7 +7,7 @@ :to="topicRoute" active-class="content-navigation__link--active" class="content-navigation__link" - @click.native="close" + @click="close" > {{ $flavor.textTopics }} @@ -20,7 +20,7 @@ to="/instruments" active-class="content-navigation__link--active" class="content-navigation__link" - @click.native="close" + @click="close" > {{ $flavor.textInstruments }} @@ -33,7 +33,7 @@ class="content-navigation__link" data-cy="news-navigation-link" v-if="!me.readOnly" - @click.native="close" + @click="close" > News @@ -51,7 +51,7 @@ to="/rooms" active-class="content-navigation__link--active" class="content-navigation__link content-navigation__link--secondary" - @click.native="close" + @click="close" > Räume @@ -62,7 +62,7 @@ to="/portfolio" active-class="content-navigation__link--active" class="content-navigation__link content-navigation__link--secondary" - @click.native="close" + @click="close" > Portfolio diff --git a/client/src/components/book-navigation/TopicNavigation.vue b/client/src/components/book-navigation/TopicNavigation.vue index f42e7c55..77fc9e34 100644 --- a/client/src/components/book-navigation/TopicNavigation.vue +++ b/client/src/components/book-navigation/TopicNavigation.vue @@ -8,7 +8,7 @@ class="topic-navigation__topic book-subnavigation__item" v-for="topic in topics" :key="topic.id" - @click.native="closeSidebar('navigation')" + @click="closeSidebar('navigation')" > {{ topic.order }}. {{ topic.title }} diff --git a/client/src/components/content-block-form/ContentBlockForm.vue b/client/src/components/content-block-form/ContentBlockForm.vue index 96408ad4..d49b3f78 100644 --- a/client/src/components/content-block-form/ContentBlockForm.vue +++ b/client/src/components/content-block-form/ContentBlockForm.vue @@ -105,7 +105,7 @@ diff --git a/client/src/layouts/PublicLayout.vue b/client/src/layouts/PublicLayout.vue index 83152953..319b4f70 100644 --- a/client/src/layouts/PublicLayout.vue +++ b/client/src/layouts/PublicLayout.vue @@ -1,73 +1,80 @@ + diff --git a/client/src/main.js b/client/src/main.js index 00ee9f5b..7a10cf2d 100644 --- a/client/src/main.js +++ b/client/src/main.js @@ -1,5 +1,5 @@ import '@babel/polyfill'; -import Vue from 'vue'; +import {createApp, inject} from 'vue'; import VueVimeoPlayer from 'vue-vimeo-player'; import apolloClientFactory from './graphql/client'; import VueApollo from 'vue-apollo'; @@ -13,42 +13,9 @@ import ME_QUERY from '@/graphql/gql/queries/meQuery.gql'; import VueModal from '@/plugins/modal'; import VueRemoveEdges from '@/plugins/edges'; import VueMatomo from 'vue-matomo'; +import VueLogger from 'vuejs3-logger'; import { joiningClass, loginRequired, unauthorizedAccess } from '@/router/guards'; import flavorPlugin from '@/plugins/flavor'; -import log from 'loglevel'; - -window.log = log; // make log available in app when built, to change log level: log.setLevel('debug') - -Vue.config.productionTip = false; -const isProduction = process.env.NODE_ENV === 'production'; - -const logLevel = isProduction ? 'error' : 'warn'; - -log.setDefaultLevel(logLevel); - -Vue.use(VueModal); -Vue.use(VueRemoveEdges); -Vue.use(VueApollo); -Vue.use(VueVimeoPlayer); - -Vue.use(VueScrollTo, { - duration: 500, - easing: 'ease-out', - offset: -50, -}); - -Vue.use(flavorPlugin); - -if (process.env.MATOMO_HOST) { - Vue.use(VueMatomo, { - host: process.env.MATOMO_HOST, - siteId: process.env.MATOMO_SITE_ID, - router: router, - }); -} - -Vue.directive('click-outside', clickOutside); -Vue.directive('auto-grow', autoGrow); const publicApolloClient = apolloClientFactory('/api/graphql-public/', null); const privateApolloClient = apolloClientFactory('/api/graphql/', networkErrorCallback); @@ -60,56 +27,96 @@ const apolloProvider = new VueApollo({ defaultClient: privateApolloClient, }); +const app = createApp({ + store, + router, + apolloProvider, + render: h => h(App), +}); + + +const isProduction = process.env.NODE_ENV === 'production'; + +app.use(VueModal); +app.use(VueRemoveEdges); +app.use(VueApollo); +app.use(VueVimeoPlayer); +app.use(VueLogger, { + isEnabled: true, + logLevel: isProduction ? 'error' : 'debug', + stringifyArguments: false, + showConsoleColors: true, +}); + +// VueScrollTo.setDefaults({ +// duration: 500, +// easing: 'ease-out', +// offset: -50, +// }); + +app.directive('scroll-to', VueScrollTo); + + +app.use(flavorPlugin); + +if (process.env.MATOMO_HOST) { + app.use(VueMatomo, { + host: process.env.MATOMO_HOST, + siteId: process.env.MATOMO_SITE_ID, + router: router, + }); +} + +app.directive('click-outside', clickOutside); +app.directive('auto-grow', autoGrow); + /* guards */ + + function redirectUsersWithoutValidLicense() { - return privateApolloClient - .query({ - query: ME_QUERY, - }) - .then(({ data }) => data.me.expiryDate == null); + return privateApolloClient.query({ + query: ME_QUERY, + }).then(({data}) => data.me.expiryDate == null); } function redirectStudentsWithoutClass() { - return privateApolloClient - .query({ - query: ME_QUERY, - }) - .then(({ data }) => data.me.schoolClasses.length === 0 && !data.me.isTeacher); + return privateApolloClient.query({ + query: ME_QUERY, + }).then(({data}) => data.me.schoolClasses.length === 0 && !data.me.isTeacher); } function redirectUsersToOnboarding() { - return privateApolloClient - .query({ - query: ME_QUERY, - }) - .then(({ data }) => !data.me.onboardingVisited); + return privateApolloClient.query({ + query: ME_QUERY, + }).then(({data}) => !data.me.onboardingVisited); } function networkErrorCallback(statusCode) { if (statusCode === 402) { - log.debug('status code 402, redirecting'); - router.push({ name: 'licenseActivation' }); + router.push({name: 'licenseActivation'}); } } + router.beforeEach(async (to, from, next) => { - log.debug('navigation guard called', to, from); + // todo: make logger work outside vue app + // const logger = inject('vuejs3-logger'); + // logger.$log.debug('navigation guard called', to, from); if (to.path === '/logout') { - log.debug('logout', to); - publicApolloClient.resetStore(); + await publicApolloClient.resetStore(); if (process.env.LOGOUT_REDIRECT_URL) { location.replace(`https://sso.hep-verlag.ch/logout?return_to=${process.env.LOGOUT_REDIRECT_URL}`); next(false); return; } else { - next({ name: 'hello' }); + next({name: 'hello'}); return; } } if (unauthorizedAccess(to)) { - log.debug('unauthorized', to); + //logger.$log.debug('unauthorized', to); const postLoginRedirectionUrl = to.path; const redirectUrl = `/hello/`; @@ -117,46 +124,33 @@ router.beforeEach(async (to, from, next) => { localStorage.setItem(postLoginRedirectUrlKey, postLoginRedirectionUrl); } - log.debug('redirecting to hello', to); + // logger.$log.debug('redirecting to hello', to); next(redirectUrl); return; } - if (to.name && to.name !== 'licenseActivation' && loginRequired(to) && (await redirectUsersWithoutValidLicense())) { - log.debug('redirecting to licenseActivation', to, null); + if (to.name && to.name !== 'licenseActivation' && loginRequired(to) && await redirectUsersWithoutValidLicense()) { + // logger.$log.debug('redirecting to licenseActivation', to, null); console.log('redirecting to licenseActivation', to, null); - next({ name: 'licenseActivation' }); + next({name: 'licenseActivation'}); return; } - if (!joiningClass(to) && loginRequired(to) && (await redirectStudentsWithoutClass())) { - log.debug('redirecting to join-class', to); - log.debug('await redirectStudentsWithoutClass()', await redirectStudentsWithoutClass()); - next({ name: 'join-class' }); + if (!joiningClass(to) && loginRequired(to) && await redirectStudentsWithoutClass()) { + //logger.$log.debug('redirecting to join-class', to); + //logger.$log.debug('await redirectStudentsWithoutClass()', await redirectStudentsWithoutClass()); + next({name: 'join-class'}); return; } - if ( - to.name && - to.name.indexOf('onboarding') === -1 && - !joiningClass(to) && - loginRequired(to) && - (await redirectUsersToOnboarding()) - ) { - log.debug('redirecting to onboarding-start', to); - next({ name: 'onboarding-start' }); + if ((to.name && to.name.indexOf('onboarding') === -1) && !joiningClass(to) && loginRequired(to) && await redirectUsersToOnboarding()) { + //logger.$log.debug('redirecting to onboarding-start', to); + next({name: 'onboarding-start'}); return; } - log.debug('End of Guard reached', to); + //logger.$log.debug('End of Guard reached', to); next(); }); -/* eslint-disable no-new */ -new Vue({ - el: '#app', - store, - router, - apolloProvider, - render: (h) => h(App), -}); +app.mount('#app'); diff --git a/client/src/pages/article.vue b/client/src/pages/article.vue index 9e781ef6..1781fc08 100644 --- a/client/src/pages/article.vue +++ b/client/src/pages/article.vue @@ -4,128 +4,132 @@
-

+

{{ roomEntry.title }}

- +
- +
diff --git a/client/src/pages/createContentBlock.vue b/client/src/pages/createContentBlock.vue index e9e3fa0b..725a77cd 100644 --- a/client/src/pages/createContentBlock.vue +++ b/client/src/pages/createContentBlock.vue @@ -1,82 +1,85 @@ diff --git a/client/src/pages/portfolio/project.vue b/client/src/pages/portfolio/project.vue index 8614e71e..966eb8a8 100644 --- a/client/src/pages/portfolio/project.vue +++ b/client/src/pages/portfolio/project.vue @@ -8,7 +8,7 @@ :final="project.final" data-cy="project-share-link" class="project__share" - @click.native="updateProjectShareState(project.slug, !project.final)" + @click="updateProjectShareState(project.slug, !project.final)" /> diff --git a/client/src/pages/topic-page.vue b/client/src/pages/topic-page.vue index 379f6b89..fe29f0ad 100644 --- a/client/src/pages/topic-page.vue +++ b/client/src/pages/topic-page.vue @@ -5,14 +5,21 @@
-

+

{{ topic.title }}

{{ topic.teaser }}

diff --git a/client/src/plugins/modal.ts b/client/src/plugins/modal.ts index 8f8f2b00..1fde72e7 100644 --- a/client/src/plugins/modal.ts +++ b/client/src/plugins/modal.ts @@ -1,51 +1,51 @@ // adapted from // https://stackoverflow.com/questions/41791193/vuejs-reactive-binding-for-a-plugin-how-to/41801107#41801107 -import Vue, { VueConstructor } from 'vue'; +import {reactive, App} from 'vue'; class ModalStore { - vm: Vue; + data: any; constructor() { - this.vm = new Vue({ - data: () => ({ - component: '', - payload: {}, - }), + this.data = reactive({ + component: '', + payload: {} }); } get state() { - return this.vm.$data; + return this.data; } } interface Modal { - state: any; - component: string; - payload?: any; - confirm: (res: any) => void; - open: (component: string, payload?: any) => Promise<(resolve: () => any, reject: () => any) => void>; - cancel: () => void; - _resolve: (r?: any) => any; - _reject: (r?: any) => any; + state: any, + component: string, + payload?: any, + confirm: (res: any) => void, + open: (component: string, payload?: any) => Promise<(resolve: () => any, reject: () => any) => void>, + cancel: () => void, + _resolve: (r?: any) => any, + _reject: (r?: any) => any } -declare module 'vue/types/vue' { - interface Vue { - $modal: Modal; +declare module '@vue/runtime-core' { + interface ComponentCustomProperties { + $modal: Modal } } const ModalPlugin = { - install(Vue: VueConstructor) { + install(app: App) { const store = new ModalStore(); + console.log('installing modal plugin'); + const reset = () => { store.state.component = ''; store.state.payload = {}; }; - const modal: Modal = { + app.config.globalProperties.$modal = { state: store.state, component: store.state.component, payload: store.state.payload, @@ -65,12 +65,13 @@ const ModalPlugin = { reset(); this._reject(); }, - _resolve: () => {}, - _reject: () => {}, + _resolve: () => { + }, + _reject: () => { + }, }; - Vue.prototype.$modal = modal; - }, + } }; export default ModalPlugin; diff --git a/client/src/shims-vue.d.ts b/client/src/shims-vue.d.ts index cbcbd6f8..aec01676 100644 --- a/client/src/shims-vue.d.ts +++ b/client/src/shims-vue.d.ts @@ -1,13 +1,13 @@ // from https://stackoverflow.com/questions/64213461/vuejs-typescript-cannot-find-module-components-navigation-or-its-correspon -declare module '*.vue' { - import Vue from 'vue'; - export default Vue; -} +// declare module "*.vue" { +// import Vue from 'vue'; +// export default Vue; +// } // for Vue 3 -// declare module '*.vue' { -// import type { DefineComponent } from 'vue' -// const component: DefineComponent<{}, {}, any> -// export default component -// } -// +declare module '*.vue' { + import type { DefineComponent } from 'vue'; + const component: DefineComponent<{}, {}, any>; + export default component; +} +